• Qt配置USBCAN通信


    周立功为CAN通信提供了动态库:官方提供了很多相关动态库和lib等,如图

    ,其中kerneldlls里还有很多动态库,还有一个配置文件。其实这么多的文件,如果我们只用到USBCAN2通信,只需要kerneldlls里面的usbcan.dll这个动态库,里面真正封装了用了windows和can模块通过usb通信的函数。然后还需要ControlCAN.h这个头文件,里面有对使用dll函数时一些结构体的声明和定义。对于ControlCAN.dll和ControlCAN.lib实际上是对使用usbcan.dll动态库的引导入口。

    对于如何使用Qt加载这些动态库来实现CAN通信,有两种方式,1是显式,2是隐式。

    显式:通过代码加载动态库我们需要的函数,把这些函数实际放在自己的工程之中;

    隐式:通过在工程中加入动态库入口的路径,使可执行文件在运行时在相应路径找动态库,再使用其函数。

    一、显式

    1、新建工程,在工程中(和源文件放在一起)添加ControlCAN.h头文件、usbcan.dll动态库。

    ControlCAN.h是需要包含在工程中的(右键工程-》添加存在路径-》此时默认勾选好了ControlCAN.h,确认即可);usbcan.dll是需要加载的动态库

    2、使用QLibrary加载动态库

    QLibrary lib("usbcan.dll");

    if(true == lib.load())

      qDebug()<<"load ok";

    3、声明一个自己的函数,功能与usbcan.dll里的函数的功能想对应

    比如,usbcan.dll中有个打开设备的函数,那就自己定义一个打开设备的函数,把usbcan.dll中打开设备函数的功能赋值到自定义函数中--!

    头文件中:

    typedef DWORD(__stdcall VCI_OpenDevice)(DWORD,DWORD,DWORD);//不知道为什么,反正没有就会出错

    typedef DWORD(__stdcall VCI_ResetCAN)(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);

    typedef DWORD(__stdcall VCI_CloseDevice)(DWORD DeviceType,DWORD DeviceInd);

    typedef DWORD(__stdcall VCI_InitCAN)(DWORD DeviceType, DWORD DeviceInd, DWORD CANInd, PVCI_INIT_CONFIG pInitConfig);

    typedef DWORD(__stdcall VCI_StartCAN)(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);

    typedef ULONG(__stdcall VCI_Transmit)(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,PVCI_CAN_OBJ pSend,ULONG Len);

    typedef ULONG(__stdcall VCI_Receive)(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,PVCI_CAN_OBJ pReceive,ULONG Len,INT WaitTime/*=-1*/);

    typedef ULONG(__stdcall VCI_GetReceiveNum)(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);

    typedef DWORD(__stdcall VCI_ClearBuffer)(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);

    typedef DWORD(__stdcall VCI_ReadErrInfo)(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,PVCI_ERR_INFO pErrInfo);

    typedef DWORD(__stdcall VCI_ReadCANStatus)(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,PVCI_CAN_STATUS pCANStatus);

    以上函数全是can通信重要的函数,全部为自己定义的,名字随便取都可以。

    4、使用上面的函数声明对应的函数对象

    头文件中:

    VCI_OpenDevice *pOpenDevice;

    VCI_ResetCAN *pResetCAN;

    VCI_CloseDevice *pCloseDevice;

    VCI_InitCAN *pInitCAN;

    VCI_StartCAN *pStartCAN;

    VCI_Transmit *pTransmitCAN;

    VCI_Receive *pReceive;

    VCI_GetReceiveNum *pGetReceiveNum;

    VCI_ClearBuffer *pClearBuffer;

    VCI_ReadErrInfo *pReadErrInfoCAN;

    VCI_ReadCANStatus *pVCI_ReadCANStatus;

    5、引入usbcan.dll动态库

    在源文件中:

    QLibrary lib("usbcan.dll");

    true == lib.load();

    6、将usbcan.dll中的函数功能分解到自定义对应函数中

    源文件中:

    pOpenDevice = (VCI_OpenDevice *)lib.resolve("VCI_OpenDevice");

    pCloseDevice = (VCI_CloseDevice *)lib.resolve("VCI_CloseDevice");

    pInitCAN = (VCI_InitCAN *)lib.resolve("VCI_InitCAN");

    pStartCAN = (VCI_StartCAN *)lib.resolve("VCI_StartCAN");

    pTransmitCAN = (VCI_Transmit *)lib.resolve("VCI_Transmit");

    pReceive = (VCI_Receive *)lib.resolve("VCI_Receive");

    pGetReceiveNum = (VCI_GetReceiveNum *)lib.resolve("VCI_GetReceiveNum");

    pClearBuffer = (VCI_ClearBuffer *)lib.resolve("VCI_ClearBuffer");

    pReadErrInfoCAN = (VCI_ReadErrInfo*)lib.resolve("VCI_ReadErrInfo");

    7、接下来就可以使用自定义的函数来进行CAN总线编程了

     二、隐式

    1、把ControlCAN.h和ControlCAN.lib放在工程目录下,和源文件放在一起

    2、把kerneldlls文件夹(里面只需要放ini配置文件和usbcan.dll文件即可)和ControlCAN.dll和可执行文件放在一起

    3、右键Qt工程,添加库->外部库,在库文件中找到ControlCAN.lib文件路径,不勾选Mac和linux,不勾选为debug版本添加d作为后缀

    4、下一步,确定。此时已经把路径加进去了

    5、右键工程,添加已经存在文件,此时已经默认勾选了ControlCAN.h,确定即可

    PS:

    1、周立功提供的动态库很多变量类型没有定义的,比如DWORD,可以再ControlCAN.h中

    #include "windows.h"//windows

    #include "windef.h"//linux

    2、打开ControlCAN.h时会提醒编码不正确,选择system编码就行了

    PS:

    1、时间标识:CAN盒子接收到当前帧的时间,这个时间是CAN盒子启动的时间,最小单位是0.1ms,比较准

    如何将时间标识转为字符串:

    QString MyMethod::getTimeStampStr(UINT TimeStamp)

    {

    QString resultStr = "";

    int hour = TimeStamp/36000000;

    int minute = (TimeStamp - hour*36000000)/600000;

    int second = (TimeStamp - hour*36000000 - minute*600000)/10000;

    int ms = (TimeStamp - hour*36000000 - minute*600000 - second*10000)/10;

    int mms = (TimeStamp - hour*36000000 - minute*600000 - second*10000 - ms*10);

    resultStr = QString("%1:").arg(hour,2,10,QChar('0'));//时

    resultStr += QString("%1:").arg(minute,2,10,QChar('0'));//分

    resultStr += QString("%1:").arg(second,2,10,QChar('0'));//秒

    resultStr += QString("%1:").arg(ms,3,10,QChar('0'));//毫秒

    resultStr += QString::number(mms);//0.1ms

    return resultStr;

    }

    2、如何高速CAN通信

    根据我在项目中的实践,发现利用PC里能达到的最块CAN通信(使用USBCAN-2)速度是1ms,但是需要很多技巧。

    ①、使用3个线程类:1个用来接收,1个用来发送,1个用来解析

    ②、接收线程最好使用最高线程权限:QThread::HighestPriority,其他的用第二高权限(这个根据计算机性能来考虑)

    ③、如何循环发送报文:在发送线程里再多加一个定时器(这个定时器不是主界面的,而是发送线程的),定时器timeout时间为需要循环发送的时间(可达到1ms);

    用户在主界面设置需要发送的报文为OBJ结构体数组,然后通过狗仔函数的方式传到发送线程,最后发送就行了。

    ④、解析过程:接收函数循环接收报文,每接收到n帧就发送到解析线程,然后根据ID解析,将解析数据发送主界面显示(显示的时候textedit不要滚动,即不要append,直接替换,否则会卡顿)

    PS:

    1、打开两路CAN:VCI_OpenDevice只能调用一次,并且需要在同一个软件中使用(dll只能调用一次)

  • 相关阅读:
    高并发系统中的常见问题
    区块链需要解决诸多问题
    什么是“区块链”技术
    github源码开源区块链浏览器
    JavaScript 内存
    行为驱动开发(BDD)
    Vue.js
    Net程序员学习Linux
    Mybatis数据操作
    Metatable和Metamethod(转)
  • 原文地址:https://www.cnblogs.com/judes/p/6952079.html
Copyright © 2020-2023  润新知