周立功为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只能调用一次)

最新文章

  1. html5 拖拽函数1--不兼容火狐
  2. 微信订阅号里实现oauth授权登录,并获取用户信息 (完整篇)
  3. NuGet学习笔记(转)
  4. java学习笔记_GUI(3)
  5. HTTP访问控制(CORS)
  6. JQuery select控件的相关操作
  7. 模糊语意变数、规则和模糊运算--AForge.NET框架的使用(二)
  8. TCP 协议
  9. UVA11627-Slalom(二分法)
  10. Python 用POP接收邮件
  11. Oracle添加含有脏数据的约束
  12. linux内核中断之看门狗
  13. ubuntu 16.04 安装和配置vncserver
  14. dos脚本
  15. c#通用配置文件读写类与格式转换(xml,ini,json)
  16. 异常 No module named &#39;numpy.core._multiarray_umath
  17. vue2.0细节剖析
  18. POJ-3252 Avenger
  19. 【python】python编码方式,chardet编码识别库
  20. Topic Model的分类和设计原则

热门文章

  1. 对Servlet容器的补充和一个问题的请教
  2. ZJU 17th 校赛
  3. 安装onlyoffice document server
  4. 关闭QQ看点
  5. JavaScript 变量,数据类型
  6. POJ1365 Prime Land【质因数分解】【素数】【水题】
  7. Codeforces Beta Round #25 (Div. 2)--A. IQ test
  8. python中json操作
  9. azure iothub create-device-identity样例报错: unable to find valid certification path ,及iothub-explorer Error: CERT_UNTRUSTED
  10. Xamarin.Forms学习之位图(二)