周立功爲CAN通訊提供了動態庫:官方提供了不少相關動態庫和lib等,如圖linux
,其中kerneldlls裏還有不少動態庫,還有一個配置文件。其實這麼多的文件,若是咱們只用到USBCAN2通訊,只須要kerneldlls裏面的usbcan.dll這個動態庫,裏面真正封裝了用了windows和can模塊經過usb通訊的函數。而後還須要ControlCAN.h這個頭文件,裏面有對使用dll函數時一些結構體的聲明和定義。對於ControlCAN.dll和ControlCAN.lib其實是對使用usbcan.dll動態庫的引導入口。編程
對於如何使用Qt加載這些動態庫來實現CAN通訊,有兩種方式,1是顯式,2是隱式。windows
顯式:經過代碼加載動態庫咱們須要的函數,把這些函數實際放在本身的工程之中;數組
隱式:經過在工程中加入動態庫入口的路徑,使可執行文件在運行時在相應路徑找動態庫,再使用其函數。app
1、顯式函數
一、新建工程,在工程中(和源文件放在一塊兒)添加ControlCAN.h頭文件、usbcan.dll動態庫。性能
ControlCAN.h是須要包含在工程中的(右鍵工程-》添加存在路徑-》此時默認勾選好了ControlCAN.h,確認便可);usbcan.dll是須要加載的動態庫編碼
二、使用QLibrary加載動態庫spa
QLibrary lib("usbcan.dll");線程
if(true == lib.load())
qDebug()<<"load ok";
三、聲明一個本身的函數,功能與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通訊重要的函數,所有爲本身定義的,名字隨便取均可以。
四、使用上面的函數聲明對應的函數對象
頭文件中:
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;
五、引入usbcan.dll動態庫
在源文件中:
QLibrary lib("usbcan.dll");
true == lib.load();
六、將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");
七、接下來就可使用自定義的函數來進行CAN總線編程了
2、隱式
一、把ControlCAN.h和ControlCAN.lib放在工程目錄下,和源文件放在一塊兒
二、把kerneldlls文件夾(裏面只須要放ini配置文件和usbcan.dll文件便可)和ControlCAN.dll和可執行文件放在一塊兒
三、右鍵Qt工程,添加庫->外部庫,在庫文件中找到ControlCAN.lib文件路徑,不勾選Mac和linux,不勾選爲debug版本添加d做爲後綴
四、下一步,肯定。此時已經把路徑加進去了
五、右鍵工程,添加已經存在文件,此時已經默認勾選了ControlCAN.h,肯定便可
PS:
一、周立功提供的動態庫不少變量類型沒有定義的,好比DWORD,能夠再ControlCAN.h中
#include "windows.h"//windows
#include "windef.h"//linux
二、打開ControlCAN.h時會提醒編碼不正確,選擇system編碼就好了
PS:
一、時間標識: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;
}
二、如何高速CAN通訊
根據我在項目中的實踐,發現利用PC裏能達到的最塊CAN通訊(使用USBCAN-2)速度是1ms,可是須要不少技巧。
①、使用3個線程類:1個用來接收,1個用來發送,1個用來解析
②、接收線程最好使用最高線程權限:QThread::HighestPriority,其餘的用第二高權限(這個根據計算機性能來考慮)
③、如何循環發送報文:在發送線程裏再多加一個定時器(這個定時器不是主界面的,而是發送線程的),定時器timeout時間爲須要循環發送的時間(可達到1ms);
用戶在主界面設置須要發送的報文爲OBJ結構體數組,而後經過狗仔函數的方式傳到發送線程,最後發送就好了。
④、解析過程:接收函數循環接收報文,每接收到n幀就發送到解析線程,而後根據ID解析,將解析數據發送主界面顯示(顯示的時候textedit不要滾動,即不要append,直接替換,不然會卡頓)
PS:
一、打開兩路CAN:VCI_OpenDevice只能調用一次,而且須要在同一個軟件中使用(dll只能調用一次)