C#编写CAN上位机与仪器通讯
1.前期准备
-
安装配置好winform环境
-
在文章结尾下载整理好的所需文件
-
将ControlCAN.dll文件放入项目的bin/Debug文件夹下
-
如果之后执行失败,就还需将kerneldlls文件夹也放入bin/Debug文件夹下
-
引用导入的ControlCAN.dll(右键项目引用->添加引用->浏览 然后找到dll文件导入)
-
将封装好的controlCAN.cs和ConnectCAN.cs拖入项目中(具体写法也可以参考二次开发说明书以及以下教程自行编写)
-
准备完成
2.编写讲解
- can通讯需要创建四个变量
devtype
选择can设备类型
devind
选择can设备索引(用于插入多个can卡后的选择)
canind
选择can通道(单个can卡一般具有两个通道)
DataReceiveBuffer
存放can总线上读取的数据
private UInt32 devtype;//设备类型
private UInt32 devind;//CAN设备索引
private UInt32 canind;//CAN通道索引
public Int32[] DataReceiveBuffer = new Int32[100];//存放数据
- 打开can的驱动程序,配置波特率等信息,打开can端口
打开can驱动函数:
controlCAN.VCI_OpenDevice(this.devtype, this.devind, 0)
- 参数为上面定义的参数,0为默认值
配置can信息:
controlCAN.VCI_InitCAN(devtype, devind, canind, ref config)
- 参数四为配置的结构体VCI_INIT_CONFIG,内包含可配置的波特率等信息
启动can函数:
controlCAN.VCI_StartCAN(devtype, devind, canind)
- 参数为上面定义的参数
public bool CANConnect(string[] canConfig)
{
try
{
//连接CAN
if (controlCAN.VCI_OpenDevice(this.devtype, this.devind, 0) == 0)
{
throw new Exception("");
}
//初始化CAN通讯
VCI_INIT_CONFIG config = new VCI_INIT_CONFIG();
config.AccCode = System.Convert.ToUInt32(canConfig[0], 16);
config.AccMask = System.Convert.ToUInt32(canConfig[1], 16);
config.Timing0 = System.Convert.ToByte(canConfig[2], 16);
config.Timing1 = System.Convert.ToByte(canConfig[3], 16);
config.Filter = 1;
config.Mode = 0;
controlCAN.VCI_InitCAN(devtype, devind, canind, ref config);
controlCAN.VCI_StartCAN(devtype, devind, canind);//启动CAN
}
catch
{
MessageBox.Show("测试模块连接失败!");
return false;
}
return true;
}
- 发送can命令
主要用到can发送函数
controlCAN.VCI_Transmit(devtype, devind, 0, ref Send_Data, 1)
- 参数四位需要发送的数据为VCI_CAN_OBJ结构体,可配置报文和数据 ,其余默认
unsafe public void CANSend(uint ID, string strdata)
{
VCI_CAN_OBJ Send_Data = new VCI_CAN_OBJ();
Send_Data.SendType = 0x1;//正常发送
Send_Data.RemoteFlag = 0x0;//数据帧设置
Send_Data.ExternFlag = 0x1;//扩展帧设置
//去除掉报文和数据中的空格
Send_Data.ID = Convert.ToUInt32(ID.ToString().Replace(" ", ""));
strdata = strdata.Replace(" ", "");
Send_Data.DataLen = Convert.ToByte(strdata.Length / 2);
byte len = Convert.ToByte(strdata.Length / 2);
int i = -1;
if (i++ < len - 1)
Send_Data.Data[0] = System.Convert.ToByte("0x" + strdata.Substring(i * 2, 2), 16);
if (i++ < len - 1)
Send_Data.Data[1] = System.Convert.ToByte("0x" + strdata.Substring(i * 2, 2), 16);
if (i++ < len - 1)
Send_Data.Data[2] = System.Convert.ToByte("0x" + strdata.Substring(i * 2, 2), 16);
if (i++ < len - 1)
Send_Data.Data[3] = System.Convert.ToByte("0x" + strdata.Substring(i * 2, 2), 16);
if (i++ < len - 1)
Send_Data.Data[4] = System.Convert.ToByte("0x" + strdata.Substring(i * 2, 2), 16);
if (i++ < len - 1)
Send_Data.Data[5] = System.Convert.ToByte("0x" + strdata.Substring(i * 2, 2), 16);
if (i++ < len - 1)
Send_Data.Data[6] = System.Convert.ToByte("0x" + strdata.Substring(i * 2, 2), 16);
if (i++ < len - 1)
Send_Data.Data[7] = System.Convert.ToByte("0x" + strdata.Substring(i * 2, 2), 16);
if (controlCAN.VCI_Transmit(devtype, devind, 0, ref Send_Data, 1) == 0)
{
MessageBox.Show("发送失败", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
4.can接受数据
主要用到获取can数据数量函数
controlCAN.VCI_GetReceiveNum(devtype, devind, canind);
can数据接收函数
controlCAN.VCI_Receive(devtype, devind, timer_canind, pt, 50, 100)
参数4为一个存放数据的指针
unsafe public void CANRec()
{
UInt32 timer_canind = canind;
UInt32 res = new UInt32();//存放返回值
res = controlCAN.VCI_GetReceiveNum(devtype, devind, timer_canind);
if (res == 0) return;
IntPtr pt = Marshal.AllocHGlobal(
Marshal.SizeOf(typeof(VCI_CAN_OBJ)) * (Int32)50
);//分配一个能存放50can消息的内存
res = controlCAN.VCI_Receive(devtype, devind, timer_canind, pt, 50, 100);//接收数据
for (UInt32 i = 0; i < res; i++)
{
VCI_CAN_OBJ obj = (VCI_CAN_OBJ)Marshal.PtrToStructure(
(IntPtr)((UInt32)pt + i * Marshal.SizeOf(typeof(VCI_CAN_OBJ))),
typeof(VCI_CAN_OBJ));//读取ptr内存中获取到的数据
DataReceiveBuffer[0] = (Int32)(obj.ID);
if (obj.RemoteFlag == 0)
{
byte len = (byte)(obj.DataLen % 9);
for (byte j = 0; j < len; j++)
{
DataReceiveBuffer[j + 1] = obj.Data[j];
}
}
}
Marshal.FreeHGlobal(pt);
}