一、串口通信dmo实现
思路:
首先需要实例化一个SerialPort 对象,
对串口数据进行初始化,写成一个方法
listBox.DataSource = 数组 (有items属性的组件都可以用数组添加数据源)
(
串口号初始化:SerialPort.GetPortNames(), 字符串数组
波特率初始化:1200, 2400, 4800, 9600, 115200, 整数数组
数据位初始化:6,7,8, 整数数组
校验位初始化:Enum.GetNames(typeof(Parity)), 字符串数组
停止位初始化:Enum.GetNames(typeof(StopBits)) 字符串数组
)
串口通信步骤:配置串口--打开串口--发送数据--接收数据
1、配置串口:c#自带串口类 SerialPort sp
sp.PortName= str 配置串口号
sp.BaudRate= int 配置波特率
sp.DataBits= int 配置数据位
sp.Parity=(Parity)Enum.Parse(typeof(Parity), str) 配置校验位
sp.StopBits= (StopBits)Enum.Parse(typeof(StopBits),str) 配置停止位
2、打开关闭串口
sp.Open() 打开串口
sp.Close() 关闭串口
3、发送数据(发送的是字节数组,每个元素两个数 byte[]={01 03 00 00 00 03 05 CB})
sp.Write() 发送数据
先进行数据验证(打开串口才能发送,不能发送为空)
if (textBox.Text.Length==0)
{
MessageBox.Show("发送不能为空 ");
return;
}
字符串发送:将字符串值转字节数组发送
byte[] sendBuffer = Encoding.Default.GetBytes(str);
sp.Write(sendBuffer, 0, sendBuffer.Length);
16进制发送:将16进制写法字符串值两两分割,转十进制字节数组发送,写成一个方法
public byte[] HexStrToByteArray(string hexStr)
{
hexStr = hexStr.Replace(" ", ""); //将字符串的空值替换
hexStr = hexStr.Replace("0x", ""); //将字符串的字母替换
hexStr = hexStr.Replace("0X", "");
byte[] buffer = new byte[hexStr.Length/2]; //两个数一个字节,数组长度减半
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = Convert.ToByte(hexStr.Substring(i*2,2),16); //转16位(两个字节)无符号整数
}
return buffer;
}
4、开一个子线程循环接收数据(接收字节数组,byte[]={01 03 00 00 00 03 05 CB})
port.Read() 接收数据
先创建一个字节数组来存放缓存区数据
byte[] bys = new byte[lenth]; 新字节长度必须要跟缓存区字节数一致
int lenth = port.BytesToRead; //缓存区实际字节数
port.Read(bys, 0, bys.Length); //从缓冲区读取数据存入数组
区分字符串接收和16进制接收
字符串接收:将字节数组转字符串值接收显示
string str = Encoding.Default.GetString(bys);
16进制接收:将接收的十进制字节数组转16进制字符串显示,写一个方法
public string ByteArrayToHexStr(byte[] buffer)
{
string hexStr = "";
for (int i = 0; i < buffer.Length; i++)
{
hexStr+= buffer[i].ToString("X2");
}
return hexStr;
}
子窗体报文解析(接收到数据后直接做报文解析)---显示温度、湿度
用一个类装温度、湿度以及其他参数字段
ModbusRTU协议
读取温湿度值: 01 03 00 00 00 02 c4 0b
发送:按16进制发送(发送区写成16进制发送),(转十进制)发送过去十进制字节值数组 [1,3,0,0,0,2,196,11]
返回值:01 03 04 02 c8 01 0D BA 20
返回数据:返回十进制值,报文解析就需要这个十进制字节值,实际字节数组[1,3,4,2,200,1,13,186,32],转16进制显示后就是 01 03 04 02 c8 01 0D BA 20
(02 c8 为湿度值十六进制转十进制除以十得 71.2,01 0D 为温度值 26.9 )
只要四个字节数值,写一个截取子字节数组的方法
public byte[]GetChildArrayBytes(byte[]buffer,int indexStart,int len) 参数分别是原始数组、开始截取索引、截取长度
{
byte[] childBytes = new byte[len];
for (int i = 0; i < len; i++)
{
//01 03 04 02 c8 01 0D BA 20
childBytes[i] = buffer[indexStart + i];
}
return childBytes;
}
报文解析先获取数值,再转十进制求数值
byte[]chidlBytes=GetChildArrayBytes(bufferRec, 3, 4); //02 c8 01 0D
Array.Reverse(chidlBytes); //02 c8 01 0D-->0D 01 c8 02
short temperature=BitConverter.ToInt16(chidlBytes, 0); // 温度 0D 01
short humidity = BitConverter.ToInt16(chidlBytes,2);// 湿度 c8 02
sensorData.temprature = temperature / 10.0;//温度值-浮点型
sensorData.humidity = humidity / 10.0;//湿度值--浮点型
BitConverter.ToInt16(Bytes, 0) 反着转换的,要先反转数组
BitConverter--将字节数组转换为基数
ToInt16(Bytes, 0)---从数组索引0开始返回16位(2个字节)有符号整数
二、SDK---软件开发包(工程要用X64保存)
C#调用halcon的sdk
1、找dll库和C++库放入C#bin文件夹下 D:\haclon安装\bin\dotnet35\halcondotnet.dll D:\haclon安装\bin\x64-win64
2、添加引用 halcondotnet.dll
3、添加命名空间 using HalconDotNet;
*在halcon里写好代码,导出C#文件
*采图
用halcon的显示图像组件,组件页面右键--选择项,添加D:\haclon安装\bin\dotnet35\halcondotnet.dll
//打开文件夹选择图片
OpenFileDialog ofd = new OpenFileDialog();
ofd.FileName = "图片名"; //选择的图片名
ofd.InitialDirectory = @"D:\";
//ofd.Filter = "所有文件(*.*)|*.*";
ofd.Filter = "图片文件 (*.jpg; *.jpeg; *.png; *.gif; *.bmp;*.tif)|*.jpg; *.jpeg; *.png; *.gif; *.bmp;*.tif";
ofd.ShowDialog();
if (ofd.FileName=="")
{
return;
}
HOperatorSet.ReadImage(out ho_Image, ofd.FileName); // 采集图像
显示
HOperatorSet.GetImageSize(ho_Image, out hv_Width, out hv_Height); //获得图片大小
HOperatorSet.SetPart(hWindowControl1.HalconWindow, 0, 0, hv_Height-1, hv_Width-1); //设置图片大小(注意句柄)
HOperatorSet.DispObj(ho_Image, hWindowControl1.HalconWindow); //显示图像(注意句柄)
*镜像
HOperatorSet.MirrorImage(ho_Image, out ho_ImageMirror, "column"); //镜像
//显示
HOperatorSet.GetImageSize(ho_ImageMirror, out hv_Width, out hv_Height); //获得图片大小
HOperatorSet.SetPart(hWindowControl1.HalconWindow, 0, 0, hv_Height, hv_Width); //设置图片大小
HOperatorSet.DispObj(ho_ImageMirror, hWindowControl1.HalconWindow); //显示
C#调用迈德威视dll库
1、找dll库(sdk文件夹)
2、看demo例程 (demo文件夹下c#例程)
3、建工程
拷贝dll库-----把找到的dll库文件拷贝到C#工程文件下bin\X64\debug下
添加引用-----一般不可以直接添加,要找一个.cs文件,在demo文件夹下,添加这个即可
添加命名空间
调用----分4步
1、枚举设备---搜索enum
2、初始化(init)---一般是枚举下面的判断
绑定控件(绑定显示图像的控件名)--- 搜索(init)把初始化代码复制过来,控件的句柄、宽高替换自己的控件
3、注册回调函数---跟初始化在一个判断里面(有可能被注释,在命名空间外面写一个命令#define USE_CALL_BACK 解除)
回调函数定义:一个方法,从demo抄过来(方法体内容不用写过来)
显示预览---写在回调函数方法体里面,图像buffer改成方法传进来的值
4、开始采集
这时开始出图,如果图片颜色不对,可以增加处理
1、处理写在回调函数方法体里面,处理完后图像buffer改成处理完后的值
2、处理完后的图像需要开辟内存来存,申请内存(相机特性描述)写在初始化方法里面
如果要对图片进行处理,就要把图片转为HObject类型变量显示,然后用halcon的显示方法,获得图片大小,设置图片大小,显示
要把原有绑定的显示控件注释掉,新开一个halcon显示窗口
HOperatorSet.OpenWindow(0, 0, pictureBox1.Width, pictureBox1.Height, pictureBox1.Handle, "visible", "", out hv_WindowHandle);
HDevWindowStack.Push(hv_WindowHandle);
//图片转为HObject类型固定写法
int bytesByLineRGB= (pFrameHead.iWidth*3+3)/ 4 * 4;//彩色图像每行所占字节数 4 的倍数
int bytesByLineGray = (pFrameHead.iWidth + 3) / 4 * 4;//灰度图像每行所占字节数 4 的倍数
byte[] bufferRGB = new byte[bytesByLineRGB* pFrameHead.iHeight];
byte[] bufferR = new byte[bytesByLineGray * pFrameHead.iHeight];
byte[] bufferG = new byte[bytesByLineGray * pFrameHead.iHeight];
byte[] bufferB = new byte[bytesByLineGray * pFrameHead.iHeight];
byte[] bufferGray = new byte[bytesByLineGray * pFrameHead.iHeight];
Marshal.Copy(m_ImageBuffer, bufferRGB, 0, bytesByLineRGB * pFrameHead.iHeight); //拷贝原图像字节(m_ImageBuffer是原图)注意顺序是BGR
for (int i = 0; i < pFrameHead.iHeight; i++)
{
for (int j = 0; j < pFrameHead.iWidth; j++)
{
bufferB[i * bytesByLineGray + j] = bufferRGB[i * bytesByLineRGB + j * 3 + 0];//B分量
bufferG[i * bytesByLineGray + j] = bufferRGB[i * bytesByLineRGB + j * 3 + 1];//G分量
bufferR[i * bytesByLineGray + j] = bufferRGB[i * bytesByLineRGB + j * 3 + 2];//R分量
bufferGray[i * bytesByLineGray + j] =(byte)( 0.11 * bufferR[i * bytesByLineGray + j] + 0.5 * bufferG[i * bytesByLineGray + j] + 0.11 * bufferB[i * bytesByLineGray + j]);
}
}
指针操作--需要在项目配置里打开允许危险代码
halcon对应代码是
使用存储管理从像素上的三个指针创建一个三通道图像
gen_image3_extern (Image, 'byte', 512, 512, r, g,b , 0)
输出图像 图像类型 原图宽 高 R分量 G分量 B分量 内存
unsafe//允许操作指针
{
fixed (byte* r = bufferR,g=bufferG,b=bufferB)//使得内存固定 ---彩色
{
HOperatorSet.GenImage3Extern(out ho_BImageBGR1, "byte", pFrameHead.iWidth, pFrameHead.iHeight, new IntPtr(r), new IntPtr(g), new IntPtr(b), 0);
}
}
fixed (byte* gray = bufferGray)//使得内存固定 ---黑白
{
HOperatorSet.GenImage1Extern(out ho_Image, "byte", pFrameHead.iWidth, pFrameHead.iHeight, new IntPtr(gray), 0);
}
//显示
HOperatorSet.GetImageSize(ho_BImageBGR1, out hv_Width, out hv_Height); //获得图片大小
if (HDevWindowStack.IsOpen())
{
HOperatorSet.SetPart(HDevWindowStack.GetActive(), 0, 0, hv_Height - 1, hv_Width - 1); //设置图片
}
if (HDevWindowStack.IsOpen())
{
HOperatorSet.DispObj(ho_BImageBGR1, HDevWindowStack.GetActive()); //显示
}
主动抓取
1、找dll库(sdk文件夹)
2、看demo例程 (demo文件夹下c#例程)
3、建工程
拷贝dll库-----把找到的dll库文件拷贝到C#工程文件下bin\X64\debug下
添加引用-----一般不可以直接添加,要找一个.cs文件,在demo文件夹下,添加这个到bin文件夹下即可
添加命名空间
调用----分4步
1、枚举设备---搜索enum
2、初始化(init)---一般是枚举下面的判断
3、图像需要处理,申请内存(相机特性描述)写在初始化方法里面
4、主动抓取--开线程
Task.Factory.StartNew(Grab);
5、开始采集
MvApi.CameraPlay(m_hCamera);
新开线程写成方法Grab(循环抓取)
延时--图像处理--显示(halcon显示)--释放
6、想加按钮控制采图暂停,只需在对应按钮点击事件调用暂停代码
MvApi.CameraPause(m_hCamera);
7、想添加设置参数
在初始化配置一下--让SDK来根据相机的型号动态创建该相机的配置窗口
然后在对应的按钮事件复制代码