测试型号:致远电子ZLG-USBCAN-I+型号
1.ZLG致远电子的CAN卡,都需要去官网下载USB驱动;
Windows和Linux下的驱动是不同的;在windows下,可以下载致远电子的上位机进行CAN口的收发通讯,Linux下则直接使用。
-
下载linux下的驱动后,会得到libusbcan.so文件,按照readme.txt,很详细。
USBCAN-II新版驱动基于libusb实现,请确保运行环境中有libusb-1.0的库。
如果是ubuntu,可连网在线安装,命令如下:apt-get install libusb-1.0-0
将libusbcan.so拷到/lib目录。
进入test目录,不带参数运行测试程序,会打印CAN测试参数说明:
./test
加入参数,调用test,可进行收发测试:
./test 4 0 3 0x1400 2 0 3 1000
CAN驱动库的调用demo在test.c中,可参考进行二次开发。
设备调试常用命令:
1、查看系统是否正常枚举到usb设备,打印它们的VID/PID(USBCAN为0471:1200):
# lsusb2、查看系统内所有USB设备节点及其访问权限:
# ls /dev/bus/usb/ -lR3、修改usb设备的访问权限使普通用户可以操作,其中xxx对应lsusb输出信息中的bus序号,yyy对应device序号:
# chmod 666 /dev/bus/usb/xxx/yyy4、如果要永久赋予普通用户操作USBCAN设备的权 限,需要修改udev配置,增加文件:/etc/udev/rules.d/50-usbcan.rules,内容如下:
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0
471", ATTRS{idProduct}=="1200", GROUP="users", MODE="0666"重新加载udev规则后插拔设备即可应用新权限: # udevadm control --reload
a. 刚开始运行./test的时候,会出现CAN口打不开的情况,需要运行下面设备调试命令,赋予can口权限!
b. test中每个参数的含义如下
printf("test [DevType] [DevIdx] [ChMask] [Baud] [TxType] [TxSleep] [TxFrames] [TxCount]\n"
" example: test 16 0 3 0x1400 2 3 10 1000\n"
" | | | | | | | | 1000 times\n"
" | | | | | | |\n"
" | | | | | | |10 frames once\n"
" | | | | | |\n"
" | | | | | |tx > sleep(3ms) > tx > sleep(3ms) ....\n"
" | | | | |\n"
" | | | | |0-normal, 1-single, 2-self_test, 3-single_self_test, 4-single_no_wait....\n"
" | | | |\n"
" | | | |0x1400-1M, 0x1c03-125K, ....\n"
" | | |\n"
" | | |bit0-CAN1, bit1-CAN2, bit2-CAN3, bit3-CAN4, 3=CAN1+CAN2, 7=CAN1+CAN2+CAN3\n"
" | |\n"
" | |Card0\n"
" |\n"
" |4-usbcan-ii, 5-pci9820, 14-pci9840, 16-pci9820i, ....\n"
这对后面用python调试很有帮助。
改进下面例程,让USBCAN卡能够用于自己的CAN总线
python
from ctypes import *
import threading
import time
lib = cdll.LoadLibrary("./libusbcan.so")
import platform
ZCAN_DEVICE_TYPE = c_uint32
ZCAN_DEVICE_INDEX = c_uint32
ZCAN_Reserved = c_uint32
ZCAN_CHANNEL = c_uint32
LEN = c_uint32
USBCAN2 = ZCAN_DEVICE_TYPE(4)
DEVICE_INDEX = ZCAN_DEVICE_INDEX(0)
Reserved = ZCAN_Reserved(0)
CHANNEL = ZCAN_CHANNEL(0)
def input_thread():
input()
class ZCAN_CAN_BOARD_INFO(Structure):
_fields_ = [("hw_Version",c_ushort),
("fw_Version",c_ushort),
("dr_Version",c_ushort),
("in_Version",c_ushort),
("irq_Num",c_ushort),
("can_Num",c_ubyte),
("str_Serial_Num",c_ubyte*20),
("str_hw_Type",c_ubyte*40),
("Reserved",c_ubyte*4)]
def __str__(self):
return "Hardware Version:%s\nFirmware Version:%s\nDriver Version:%s\nInterface:%s\nInterrupt Number:%s\nCAN_number:%d"%(\
self.hw_Version, self.fw_Version, self.dr_Version, self.in_Version, self.irq_Num, self.can_Num)
def serial(self):
serial=''
for c in self.str_Serial_Num:
if c>0:
serial +=chr(c)
else:
break
return serial
def hw_Type(self):
hw_Type=''
for c in self.str_hw_Type:
if c>0:
hw_Type +=chr(c)
else:
break
return hw_Type
class ZCAN_CAN_INIT_CONFIG(Structure):
_fields_ = [("AccCode",c_int),
("AccMask",c_int),
("Reserved",c_int),
("Filter",c_ubyte),
("Timing0",c_ubyte),
("Timing1",c_ubyte),
("Mode",c_ubyte)]
class ZCAN_CAN_OBJ(Structure):
_fields_ = [("ID",c_uint32),
("TimeStamp",c_uint32),
("TimeFlag",c_uint8),
("SendType",c_byte),
("RemoteFlag",c_byte),
("ExternFlag",c_byte),
("DataLen",c_byte),
("Data",c_ubyte*8),
("Reserved",c_ubyte*3)]
def GetDeviceInf(DeviceType,DeviceIndex):
try:
info = ZCAN_CAN_BOARD_INFO()
ret = lib.VCI_ReadBoardInfo(DeviceType,DeviceIndex,byref(info))
return info if ret==1 else None
except:
print("Exception on readboardinfo")
raise
def can_start(DEVCIE_TYPE,DEVICE_INDEX,CHANNEL):
init_config = ZCAN_CAN_INIT_CONFIG()
init_config.AccCode = 0
init_config.AccMask = 0xFFFFFFFF
init_config.Reserved = 0
init_config.Filter = 1
init_config.Timing0 = 0x00
init_config.Timing1 = 0x1c
init_config.Mode = 0
ret=lib.VCI_InitCAN(DEVCIE_TYPE,DEVICE_INDEX,0,byref(init_config))
if ret ==0:
print("InitCAN fail!")
else:
print("InitCAN success!")
ret=lib.VCI_StartCAN(DEVCIE_TYPE,DEVICE_INDEX,CHANNEL)
if ret ==0:
print("StartCAN fail!")
else:
print("StartCAN success!")
return ret
if __name__=="__main__":
ret=lib.VCI_OpenDevice(USBCAN2,DEVICE_INDEX,Reserved)
if ret ==0:
print("Opendevice fail!")
else:
print("Opendevice success!")
info= GetDeviceInf(USBCAN2,DEVICE_INDEX)
print("Devcie Infomation:\n%s"%(info))
canstart = can_start(USBCAN2,DEVICE_INDEX,CHANNEL)
LEN=10 #send frame number
msgs=(ZCAN_CAN_OBJ*LEN)()
for i in range(LEN):
msgs[i].ID = 0x100
msgs[i].TimeStamp = 0
msgs[i].TimeFlag = 0
msgs[i].SendType = 2 # 2 是自收自发模式,0是正常发送形式
msgs[i].RemoteFlag = 0 # 0---Data frame , 1---remote frame
msgs[i].ExternFlag = 0 # 0---Standard frame , 1---Extern frame
msgs[i].DataLen = 8 # DLC,0~8
for j in range(msgs[i].DataLen):
msgs[i].Data[j] = j
sendret = lib.VCI_Transmit(4,0,0,byref(msgs),10)
if LEN == sendret:
print("transmit success , sendcount is :%d "%sendret)
else:
print("transmit fail , sendcounet is :%d "%sendret)
if LEN == sendret:
print("transmit success , sendcount is :%d "%sendret)
else:
print("transmit fail , sendcounet is :%d "%sendret)
thread=threading.Thread(target=input_thread)
thread.start()
while True:
time.sleep(0.1)
ret = lib.VCI_GetReceiveNum(USBCAN2,DEVICE_INDEX,CHANNEL)
if ret:
rcv_msgs =(ZCAN_CAN_OBJ*ret)()
ret1 =lib.VCI_Receive(USBCAN2,DEVICE_INDEX,CHANNEL,byref(rcv_msgs),ret,100)
for i in range(ret1):
print("GetNum:%d, OrderNUM :%d,Timestamp:%d, id:%s , dlc:%d ,data:%s"%(ret,i,(rcv_msgs[i].TimeStamp),hex(rcv_msgs[i].ID),\
rcv_msgs[i].DataLen,''.join(hex(rcv_msgs[i].Data[j])+ ' 'for j in range(rcv_msgs[i].DataLen))))
if thread.is_alive() == False:
break
ret = lib.VCI_ResetCAN(USBCAN2,DEVICE_INDEX,CHANNEL)
if ret ==0:
print("ResetCAN fail!")
else:
print("ResetCAN success!")
ret=lib.VCI_CloseDevice(USBCAN2,DEVICE_INDEX)
if ret ==0:
print("Closedevice Failed!")
else:
print("Closedevice success!")
del lib
print('done')
a. 修改波特率:
python
def can_start(DEVCIE_TYPE,DEVICE_INDEX,CHANNEL):
init_config = ZCAN_CAN_INIT_CONFIG()
init_config.AccCode = 0
init_config.AccMask = 0xFFFFFFFF
init_config.Reserved = 0
init_config.Filter = 1
init_config.Timing0 = 0x00
init_config.Timing1 = 0x14
'''
这边的两个timing0和timing1,代表了波特率,还记得运行./test的时候,1M波特率需要设置的是0x1400,所以将这两个Timing的数值,改成了0x14和0x00;对于其他波特率的计算,可以通过windows下的上位机软件中的工具可以换算。
'''
init_config.Mode = 0
ret=lib.VCI_InitCAN(DEVCIE_TYPE,DEVICE_INDEX,0,byref(init_config))
if ret ==0:
print("InitCAN fail!")
else:
print("InitCAN success!")
ret=lib.VCI_StartCAN(DEVCIE_TYPE,DEVICE_INDEX,CHANNEL)
if ret ==0:
print("StartCAN fail!")
else:
print("StartCAN success!")
return ret
这边的两个timing0和timing1,代表了波特率,还记得运行./test的时候,1M波特率需要设置的是0x1400,所以将这两个Timing的数值,改成了0x14和0x00;对于其他波特率的计算,可以通过windows下的上位机软件中的工具可以换算。
b. 修改发送内容
python
LEN=1 #send frame number
msgs=(ZCAN_CAN_OBJ*LEN)()
msgs[0].ID = 0x100 #帧ID
msgs[0].TimeStamp = 0 #用于设定发送时间
msgs[0].TimeFlag = 0
msgs[0].SendType = 0 # 2 是自收自发模式(不用接设备),0是正常发送形式(要接设备)
msgs[0].RemoteFlag = 0 # 0---Data frame , 1---remote frame
msgs[0].ExternFlag = 0 # 0---Standard frame , 1---Extern frame
msgs[0].DataLen = 6 # DLC,0~8, 位数,这里设置6,意味着只发送6个数据
#数据内容,会将10进制转为16进制发送,例如
msgs[0].Data[0] = 0 #0x00
msgs[0].Data[1] = 138 #0x8A
msgs[0].Data[2] = 0 #0x00
msgs[0].Data[3] = 0 #0x00
msgs[0].Data[4] = 21 #0x15
msgs[0].Data[5] = 190 #0xBE
sendret = lib.VCI_Transmit(4,0,0,byref(msgs),10)
#发送,4代表的是USBCAN-II,0代表card0,0代表1号can口,msg是发送的数据,10表示发送的帧数?