首页 > 编程语言 >C#编写CAN上位机与仪器通讯

C#编写CAN上位机与仪器通讯

时间:2024-07-14 14:55:32浏览次数:15  
标签:机与 C# VCI Convert Send 上位 devtype devind Data

C#编写CAN上位机与仪器通讯

1.前期准备

  1. 安装配置好winform环境

  2. 在文章结尾下载整理好的所需文件

  3. 将ControlCAN.dll文件放入项目的bin/Debug文件夹下

  4. 如果之后执行失败,就还需将kerneldlls文件夹也放入bin/Debug文件夹下

  5. 引用导入的ControlCAN.dll(右键项目引用->添加引用->浏览 然后找到dll文件导入)
    请添加图片描述

  6. 将封装好的controlCAN.cs和ConnectCAN.cs拖入项目中(具体写法也可以参考二次开发说明书以及以下教程自行编写)

  7. 准备完成

2.编写讲解

  1. 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];//存放数据
  1. 打开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;
    }

  1. 发送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);
}

上述需要的所有文件的下载链接:下载地址,之后会在同地址上传GPIB、RS232的资料以及上位机示例软件,有问题可以随时发微信咨询

标签:机与,C#,VCI,Convert,Send,上位,devtype,devind,Data
From: https://blog.csdn.net/qq_51201480/article/details/140382049

相关文章

  • DedeCMS模板目录的文件目录结构
    templets ┣━default·······································默认模板目录 ┃   ┣━style·······································模板CSS样式目录 ┃   ┣━js··......
  • 巧用 DirectX 化解游戏频繁卡顿难题
    在游戏的精彩世界中,频繁的卡顿无疑是令人扫兴的体验。但别担心,通过合理利用DirectX(DX)的相关功能和设置,我们往往能够有效地解决这一问题。首先,我们需要确认当前系统中安装的DirectX版本是否是最新的。按下“Win+R”键,输入“dxdiag”并回车,在弹出的DirectX诊断工具中可......
  • 题解:CodeForces 346A Alice and Bob[博弈/数论]
    CodeForces346AA.AliceandBobtimelimitpertest2secondsmemorylimitpertest256megabytesinputstandardinputoutputstandardoutputItissoboringinthesummerholiday,isn'tit?SoAliceandBobhaveinventedanewgametoplay.Therulesa......
  • electron loadURL加载http协议(或内网)环境下使用navigator.mediaDevices.getUserMedi
    场景我使用的electron27版本。众所周知,navigator.mediaDevices.getUserMediaAPI只能在https环境下使用,在非https环境下使用时navigator.mediaDevices会返回undefined。除了例外的这几种情况。例外的几种情况在MDN安全上下文文章中进行了说明说明了。大致意思是在https,fi......
  • [rCore学习笔记 015]特权级机制
    写在前面本随笔是非常菜的菜鸡写的。如有问题请及时提出。可以联系:[email protected]:https://github.com/WindDevil(目前啥也没有官方文档仍然是一上来就丢出来的官方文档.只摘抄了我觉得有意思的部分:实现特权级机制的根本原因是应用程序运行的安全性不可充分信任......
  • 【Shader】ComputeScreenPos 的使用
     在顶点着色器中使用ComputeScreenPos.使用tex2Dproj搭配screenPos来按屏幕uv采样屏幕材质(如_CameraDepthTexture和_CameraNormalTexture).ComputeScreenPos:接受的输入顶点在裁剪空间(经过MVPmatrix的变换)的位置将输出从  ---转自 ComputeSc......
  • 高质量C/C++编程指南总结(三)—— 命名规则
    标识符应当直观,可望文知义。标识符的长度应当符合“min-length&& max-information”原则。命名规则尽量与所采用的操作系统或开发工具的风格保持一致。程序中不要仅靠大小写区分相似的标识符。程序中不要出现标识符完全相同的局部变量和全局变量。变量的名字应当使用“......
  • 【转载】【内存】buffers与cached的区别
    free命令是Linux系统上查看内存使用状况最常用的工具,然而很少有人能说清楚“buffers”与“cached”之间的区别:我们先抛出结论,如果你对研究过程感兴趣可以继续阅读后面的段落:buffers表示块设备(blockdevice)所占用的缓存页,包括:直接读写块设备、以及文件系统元数据(metada......
  • 题解:CodeForces 843A Sorting by Subsequences[模拟/排序]
    CodeForces843AA.SortingbySubsequencestimelimitpertest:1secondmemorylimitpertest:256megabytesinputstandardinputoutputstandardoutputYouaregivenasequence\(a_1, a_2, ..., a_n\)consistingofdifferentintegers.Itisrequiredtos......
  • 帝国CMS网站通过自定义扩展变量功能,用户可以自定义公共的程序使用变量,为用户扩展系统
    通过自定义扩展变量功能,用户可以自定义公共的程序使用变量,为用户扩展系统带来便利。比如可以增加像系统$public_r[newsurl]这样的变量,还比如扩展了某个系统模型,需要增加设置项都可以用扩展变量来实现...等等。 一、登录后台,单击“系统”菜单,选择“扩展变量”......