python调用ControlCan.dll实现can报文的收发。
实现can通信报文的收发操作,不仅要借助ControlCan.dll,还需要kerneldlls这个文件夹下面的配置文件。一般需要将ControlCan.dll和kerneldlls这个文件夹放置到python调用ControlCan.dll代码程序.py文件的同级目录下。
欢迎免积分免费下载,32位ControlCan.dll和kerneldlls这个文件夹的获取链接:
https://download.csdn.net/download/Logintern09/86727513
除了获取ControlCan.dll,还需要获取ControlCan.dll的接口函数使用手册,这样才能够清楚的知道ControlCan.dll封装好能够外部调用的函数有哪些。
本人实操发现win10环境 64位的python也无法调用64位的ControlCan.dll,需要采用32位的python环境调用32位的ControlCan.dll。如果电脑上已经安装的是64位的python,需要借助miniconda配置一个32位的环境提供32位的ControlCan.dll运行。
miniconda配置一个32位的python环境参考以下链接:
1.anaconda3下64位python和32位python共存
https://blog.csdn.net/weixin_41710606/article/details/86747877
2.miniconda安装与使用
https://zhuanlan.zhihu.com/p/102564715?from_voters_page=true
3.64位Anaconda,64位python如何使用pycharm调用32位C#dll文件
https://blog.csdn.net/weixin_42071767/article/details/101065297
切换成32位的开发环境的指令: set CONDA_FORCE_32BIT=1
32位环境下安装python包:
(1)尝试触发刚创建的这个环境,输入: activate + 环境名
(2)conda install wxpython(安装包名称)
参考文章:
1.实践出真知——Python周立功CAN接口收发
https://zhuanlan.zhihu.com/p/195116941
2.使用python来调用CAN通讯的DLL实现方法
https://www.jb51.net/article/164497.htm
python语言调用C#语言封装好的动态链接库.dll文件,一般需要将.dll文件放置在.py文件的同级目录下,python采用ctypes模块,按照dll使用的调用约定来加载.dll动态链接库。
C#中的结构体如何转换:
python高级ctypes数据类型—结构体
https://blog.csdn.net/qq_33287871/article/details/100127524
python中ctypes和C语言中数据类型的对照表:
参考官网给的C# 的demo,获取controlcan.dll支持的device类型
代码实现:
device_dict = {
"VCI_PCI5121": 1,
"VCI_PCI9810": 2,
"VCI_USBCAN1": 3,
"VCI_USBCAN2": 4,
"VCI_USBCAN2A": 4,
"VCI_PCI9820": 5,
"VCI_CAN232": 6,
"VCI_PCI5110": 7,
"VCI_CANLITE": 8,
"VCI_ISA9620": 9,
"VCI_ISA5420": 10,
"VCI_PC104CAN": 11,
"VCI_CANETUDP": 12,
"VCI_CANETE": 12,
"VCI_DNP9810": 13,
"VCI_PCI9840": 14,
"VCI_PC104CAN2": 15,
"VCI_PCI9820I": 16,
"VCI_CANETTCP": 17,
"VCI_PEC9920": 18,
"VCI_PCI5010U": 19,
"VCI_USBCAN_E_U": 20,
"VCI_USBCAN_2E_U": 21,
"VCI_PCI5020U": 22,
"VCI_EG20T_CAN": 23,
"VCI_PCIE9221": 24,
"VCI_CANDTU200": 32
}
波特率设置:
Timing0和Timing1用来设置CAN波特率:
Timing0_dict = {
"10Kbps": 0x31,
"20Kbps": 0x18,
"40Kbps": 0x87,
"50Kbps": 0x09,
"80Kbps": 0x83,
"100Kbps": 0x04,
"125Kbps": 0x03,
"200Kbps": 0x81,
"250Kbps": 0x01,
"400Kbps": 0x80,
"500Kbps": 0x00,
"666Kbps": 0x80,
"800Kbps": 0x00,
"1000Kbps": 0x00,
"33.33Kbps": 0x09,
"66.66Kbps": 0x04,
"83.33Kbps": 0x03
}
Timing1_dict = {
"10Kbps": 0x1C,
"20Kbps": 0x1C,
"40Kbps": 0xFF,
"50Kbps": 0x1C,
"80Kbps": 0xFF,
"100Kbps": 0x1C,
"125Kbps": 0x1C,
"200Kbps": 0xFA,
"250Kbps": 0x1C,
"400Kbps": 0xFA,
"500Kbps": 0x1C,
"666Kbps": 0xB6,
"800Kbps": 0x16,
"1000Kbps": 0x14,
"33.33Kbps": 0x6F,
"66.66Kbps": 0x6F,
"83.33Kbps": 0x6F
}
baud_rate_dict = {
"1000Kbps": 0x060003,
"800Kbps": 0x060004,
"500Kbps": 0x060007,
"250Kbps": 0x1C0008,
"125Kbps": 0x1C0011,
"100Kbps": 0x160023,
"50Kbps": 0x1C002C,
"20Kbps": 0x1600B3,
"10Kbps": 0x1C00E0,
"5Kbps": 0x1C01C1
}
由以上流程图可以看出,实现can报文的收发操作主要涉及的函数如下:
根据以上报文发送和接收流程,得到初始化can通道的代码实现:
def init_can(baud_rate, DevType, DevIndex, CANIndex=0):
res_list = []
Timing0 = Timing0_dict[baud_rate]
Timing1 = Timing1_dict[baud_rate]
vci_initconfig = VCI_INIT_CONFIG(0x00000000, 0xFFFFFFFF, 0,
1, Timing0, Timing1, 0)
try:
res_list.append(open_device(DevType, DevIndex, 0))
res_list.append(set_reference(DevType, DevIndex, CANIndex, 0, baud_rate_dict[baud_rate]))
res_list.append(ini_can(DevType, DevIndex, CANIndex, vci_initconfig))
res_list.append(start_device(DevType, DevIndex, CANIndex))
res_list.append(clear_buffer(DevType, DevIndex, CANIndex))
except:
pass
if all(res_list):
return True
else:
return False
can报文发送的代码实现:
def send_msg(msg_id, extern_flag, msg_data, DevType, DevIndex, CANIndex=0):
# 发送报文
def data_input(data):
ubyte_array = (c_ubyte * 8)()
for i in range(len(data)):
ubyte_array[i] = data[i]
return ubyte_array
# 这里是将字符转成16进制
datas = data_input([int(x, 16) for x in msg_data.strip(' ').split(' ')])
radar_data = VCI_CAN_OBJ()
radar_data.ID = msg_id
radar_data.SendType = 0
radar_data.RemoteFlag = 0
radar_data.ExternFlag = extern_flag
radar_data.DataLen = 8
radar_data.Data = datas
return trans_msg(DevType, DevIndex, CANIndex, pointer(radar_data), 1)
can报文接收的代码实现:
def get_msg():
# 接收报文
receive_len = 50
vci_can_array = _RX_CAN_OBJ * receive_len
vci_can_obj = vci_can_array(_RX_CAN_OBJ())
while 1:
receive_res = receive_msg(DevType, DevIndex, CANIndex, vci_can_obj, receive_len, 0)
if receive_res > 0:
for i in range(receive_res):
analyse_msg(vci_can_obj[i])
else:
print("接收缓存区为空")
解析一帧报文数据的代码实现:
def analyse_msg(vci_can_obj):
# 解析一帧数据
msg_id = hex(vci_can_obj.ID)
print("帧ID ", msg_id)
if vci_can_obj.RemoteFlag == 0:
print("数据帧 ")
else:
print("远程帧 ")
if vci_can_obj.ExternFlag == 0:
print("标准帧 ")
else:
print("扩展帧 ")
if vci_can_obj.RemoteFlag == 0:
print("数据: ")
print("0", bytearray(vci_can_obj.Data).hex()[0:2])
print("1", bytearray(vci_can_obj.Data).hex()[2:4])
print("2", bytearray(vci_can_obj.Data).hex()[4:6])
print("3", bytearray(vci_can_obj.Data).hex()[6:8])
print("4", bytearray(vci_can_obj.Data).hex()[8:10])
print("5", bytearray(vci_can_obj.Data).hex()[10:12])
print("6", bytearray(vci_can_obj.Data).hex()[12:14])
print("7", bytearray(vci_can_obj.Data).hex()[14:16])
本人调用32位controlcan.dll内部函数实现can报文收发操作的二次封装函数文件命名为can_interface.py。完整程序代码下载请前往csdn资源链接:
python重新封装32位controlcan.dll内部函数可实现can报文收发
1.解决python使用controlcan.dll接收报文每次只能处理一条报文信息问题
2.上位机实现can报文的周期性发送(python3)
3.wxpython设计GUI:报文发送线程正在运行时,点击右上角的窗口关闭按钮,界面卡死无响应
4.使用ControlCAN.dll收发报文功能实现诊断仪与硬件的UDS报文交互
5.利用全局字典在上位机界面和报文发送线程间传递信息