周立功can相關資料下載下傳:https://www.zlg.cn/can/down/down/id/22.html
首先,把下載下傳的庫函數檔案(由上面連結下載下傳)都放在工作目錄下。庫函數檔案總共有三個檔案:ControlCAN.h、ControlCAN.lib、ControlCAN.dll 和一個檔案夾 kerneldlls。
但是其實我在使用的過程當中,隻用到了ControlCAN.dll,并非需要以上操作。
其中ControlCAN.h檔案中定義了各個接口函數,以及接口函數所需要的參數類型。
#ifndef CONTROLCAN_H
#define CONTROLCAN_H
檔案版本:v2.00 20150920
//#include <cvidef.h> //使用CVI平台開發,請使用該語句。
#include "windows.h"
//接口卡類型定義
#define VCI_USBCAN1 3
#define VCI_USBCAN2 4
#define VCI_USBCAN2A 4
#define VCI_USBCAN_E_U 20
#define VCI_USBCAN_2E_U 21
//函數調用傳回狀态值
#define STATUS_OK 1
#define STATUS_ERR 0
/*------------------------------------------------相容ZLG的函數及資料類型------------------------------------------------*/
//1.ZLGCAN系列接口卡資訊的資料類型。
typedef struct _VCI_BOARD_INFO{
USHORT hw_Version;
USHORT fw_Version;
USHORT dr_Version;
USHORT in_Version;
USHORT irq_Num;
BYTE can_Num;
CHAR str_Serial_Num[20];
CHAR str_hw_Type[40];
USHORT Reserved[4];
} VCI_BOARD_INFO,*PVCI_BOARD_INFO;
//2.定義CAN資訊幀的資料類型。
typedef struct _VCI_CAN_OBJ{
UINT ID;
UINT TimeStamp;
BYTE TimeFlag;
BYTE SendType;
BYTE RemoteFlag;//是否是遠端幀
BYTE ExternFlag;//是否是擴充幀
BYTE DataLen;
BYTE Data[8];
BYTE Reserved[3];
}VCI_CAN_OBJ,*PVCI_CAN_OBJ;
//3.定義初始化CAN的資料類型
typedef struct _VCI_INIT_CONFIG{
DWORD AccCode;
DWORD AccMask;
DWORD Reserved;
UCHAR Filter;
UCHAR Timing0;
UCHAR Timing1;
UCHAR Mode;
}VCI_INIT_CONFIG,*PVCI_INIT_CONFIG;
/ new add struct for filter /
typedef struct _VCI_FILTER_RECORD{
DWORD ExtFrame; //是否為擴充幀
DWORD Start;
DWORD End;
}VCI_FILTER_RECORD,*PVCI_FILTER_RECORD;
#define EXTERNC extern "C"
EXTERNC DWORD __stdcall VCI_OpenDevice(DWORD DeviceType,DWORD DeviceInd,DWORD Reserved);
EXTERNC DWORD __stdcall VCI_CloseDevice(DWORD DeviceType,DWORD DeviceInd);
EXTERNC DWORD __stdcall VCI_InitCAN(DWORD DeviceType, DWORD DeviceInd, DWORD CANInd, PVCI_INIT_CONFIG pInitConfig);
EXTERNC DWORD __stdcall VCI_ReadBoardInfo(DWORD DeviceType,DWORD DeviceInd,PVCI_BOARD_INFO pInfo);
EXTERNC DWORD __stdcall VCI_SetReference(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,DWORD RefType,PVOID pData);
EXTERNC ULONG __stdcall VCI_GetReceiveNum(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);
EXTERNC DWORD __stdcall VCI_ClearBuffer(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);
EXTERNC DWORD __stdcall VCI_StartCAN(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);
EXTERNC DWORD __stdcall VCI_ResetCAN(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd);
EXTERNC ULONG __stdcall VCI_Transmit(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,PVCI_CAN_OBJ pSend,ULONG Len);
EXTERNC ULONG __stdcall VCI_Receive(DWORD DeviceType,DWORD DeviceInd,DWORD CANInd,PVCI_CAN_OBJ pReceive,ULONG Len,INT WaitTime);
/*------------------------------------------------其他補充函數及資料結構描述------------------------------------------------*/
//USB-CAN總線擴充卡闆卡資訊的資料類型1,該類型為VCI_FindUsbDevice函數的傳回參數。
typedef struct _VCI_BOARD_INFO1{
USHORT hw_Version;
USHORT fw_Version;
USHORT dr_Version;
USHORT in_Version;
USHORT irq_Num;
BYTE can_Num;
BYTE Reserved;
CHAR str_Serial_Num[8];
CHAR str_hw_Type[16];
CHAR str_Usb_Serial[4][4];
} VCI_BOARD_INFO1,*PVCI_BOARD_INFO1;
//USB-CAN總線擴充卡闆卡資訊的資料類型2,該類型為VCI_FindUsbDevice函數的傳回參數。為擴充更多的裝置
typedef struct _VCI_BOARD_INFO2{
USHORT hw_Version;
USHORT fw_Version;
USHORT dr_Version;
USHORT in_Version;
USHORT irq_Num;
BYTE can_Num;
BYTE Reserved;
CHAR str_Serial_Num[8];
CHAR str_hw_Type[16];
CHAR str_Usb_Serial[10][4];
} VCI_BOARD_INFO2,*PVCI_BOARD_INFO2;
#define EXTERNC extern "C"
EXTERNC DWORD __stdcall VCI_GetReference2(DWORD DevType,DWORD DevIndex,DWORD CANIndex,DWORD Reserved,BYTE *pData);
EXTERNC DWORD __stdcall VCI_SetReference2(DWORD DevType,DWORD DevIndex,DWORD CANIndex,DWORD RefType,BYTE *pData);
EXTERNC DWORD __stdcall VCI_ConnectDevice(DWORD DevType,DWORD DevIndex);
EXTERNC DWORD __stdcall VCI_UsbDeviceReset(DWORD DevType,DWORD DevIndex,DWORD Reserved);
EXTERNC DWORD __stdcall VCI_FindUsbDevice(PVCI_BOARD_INFO1 pInfo);
EXTERNC DWORD __stdcall VCI_FindUsbDevice2(PVCI_BOARD_INFO2 pInfo);
#endif
此時你需要在你的下載下傳中找到相關說明檔案:

這裡面定義了接口函數詳細的解釋說明:
接下去就是用python實作can的收發了。
不過在這裡要注意的是,我安裝的是python32位,本來嘗試在64位上裝個32位的,多次嘗試無果,最後安裝成32位的才解決。
另外,如果下載下傳中有多個ControlCAN.dll,一個不行要嘗試使用另一個,我用的檔案中有的是不能用的。
from ctypes import *
class _VCI_INIT_CONFIG(Structure):
_fields_ = [('AccCode', c_ulong),
('AccMask', c_ulong),
('Reserved', c_ulong),
('Filter', c_ubyte),
('Timing0', c_ubyte),
('Timing1', c_ubyte),
('Mode', c_ubyte)]
class _VCI_CAN_OBJ(Structure):
_fields_ = [('ID', c_uint),
('TimeStamp', c_uint),
('TimeFlag', c_byte),
('SendType', c_byte),
('RemoteFlag', c_byte),
('ExternFlag', c_byte),
('DataLen', c_byte),
('Data', c_byte*8),
('Reserved', c_byte*3)]
class _RX_CAN_OBJ(Structure):
_fields_ = [('ID', c_uint),
('TimeStamp', c_uint),
('TimeFlag', c_byte),
('SendType', c_byte),
('RemoteFlag', c_byte),
('ExternFlag', c_byte),
('DataLen', c_byte),
('Data', c_byte*8),
('Reserved', c_byte*3)]
vic = _VCI_INIT_CONFIG()
vic.AccCode = 0x00000000
vic.AccMask = 0xffffffff
vic.Filter =1
vic.Timing0 = 0x01
vic.Timing1 = 0x1c
vic.Mode = 0
vco = _VCI_CAN_OBJ()
vco.ID = 0x18ff3010
vco.SendType = 0
vco.RemoteFlag = 0
vco.ExternFlag = 1
vco.DataLen = 8
vco.Data = (5, 2, 3, 4, 5, 6, 7, 8)
rxdata=_RX_CAN_OBJ()
canLib = windll.LoadLibrary('./ControlCAN.dll')
print("下面執行操作傳回“1”表示操作成功!")
print('打開裝置: %d' % (canLib.VCI_OpenDevice(3, 0, 0)))
print('設定波特率: %d' % (canLib.VCI_SetReference(3, 0, 0, 0, pointer(c_int(0x1C0008)))))
print('初始化: %d' % (canLib.VCI_InitCAN(3, 0, 0, pointer(vic))))
print('啟動: %d' % (canLib.VCI_StartCAN(3, 0, 0)))
print('清空緩沖區: %d' % (canLib.VCI_ClearBuffer(3, 0, 0)))
print('發送: %d' % (canLib.VCI_Transmit(3, 0, 0, pointer(vco), 1)))
# print('接收: %d' % (canLib.VCI_Receive(3, 0, 0, pointer(rxdata),100,400)))
while canLib.VCI_GetReceiveNum(3,0,0)==0 :
continue
print("接收緩存數量:",canLib.VCI_GetReceiveNum(3,0,0))
if(canLib.VCI_Receive(3, 0, 0, pointer(rxdata),100,400)):
print('從緩存讀取一幀資料:', bytearray(rxdata.Data).hex())
else:
print("接收緩存區為空")
print("接收緩存數量:",canLib.VCI_GetReceiveNum(3,0,0))
以上代碼接入can創芯的分析儀是可以實作自收自發的,不過要注意的是,其中3這個裝置号,像我的就是21。
波特率設定:0x060007 500k;0x060003 1000k
這其中還會遇到,如何打包自己的資料進行發送。
我們的資料一般是一串字元:"12 0f 25 13 2D 02 07 08"
def Data_input(data):
ubyte_array = (c_byte*8)()
for i in range(len(data)):
ubyte_array[i] = data[i]
return ubyte_array
data = "12 0f 25 13 2D 02 07 08"
#這裡是将字元轉成16進制
datas = Data_input([int(x,16) for x in data.strip(' ').split(' ')])
radar_data = _VCI_CAN_OBJ()
radar_data.ID = 0x0600
radar_data.SendType = 0
radar_data.RemoteFlag = 0
radar_data.ExternFlag = 0
radar_data.DataLen = 8
radar_data.Data = datas
其實就是對之前vco的指派。
在接收的過程當中,還會遇到位元組轉化問題。
比方收到的FF位元組,但是這個位元組是有符号的,那麼我們直接讀取的時候跟無符号是不同的。
def u2s8(n):
return n if n < (1 << 7) else n - (1 << 8)
def u2s16(n):
return n if n < (1 << 15) else n - (1 << 16)
#一個位元組的讀取
u2s8(can_data[2])
#兩個位元組的讀取,用intel解碼,兩個位元組拼接在一起,并轉化成無符号數。在python中可以直接識别正負。
u2s16(can_data[6]<<8|can_data[5])
參考文章:https://blog.csdn.net/u012577474/article/details/103953125?utm_medium=distribute.pc_relevant.none-task-blog-baidulandingword-3&spm=1001.2101.3001.4242