python调用32位的ControlCan.dll实现can报文的收发

python调用ControlCan.dll实现can报文的收发。

1. ControlCan.dll资源获取

实现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封装好能够外部调用的函数有哪些。

python调用32位的ControlCan.dll实现can报文的收发_第1张图片

2. 32位环境配置

本人实操发现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(安装包名称)

3. python调用ControlCan.dll内部函数的准备工作

参考文章:
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动态链接库。

3.1 了解python调用controlcan.dll的方式

python调用32位的ControlCan.dll实现can报文的收发_第2张图片

3.2 了解python中ctypes数据类型

C#中的结构体如何转换:
python高级ctypes数据类型—结构体
https://blog.csdn.net/qq_33287871/article/details/100127524

python中ctypes和C语言中数据类型的对照表:

python调用32位的ControlCan.dll实现can报文的收发_第3张图片

4. 结合周立功官网的demo开始造代码

4.1 device类型

参考官网给的C# 的demo,获取controlcan.dll支持的device类型

python调用32位的ControlCan.dll实现can报文的收发_第4张图片

代码实现:

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
}

4.2 初始化can参数

python调用32位的ControlCan.dll实现can报文的收发_第5张图片

波特率设置:

python调用32位的ControlCan.dll实现can报文的收发_第6张图片

python调用32位的ControlCan.dll实现can报文的收发_第7张图片

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
}

4.3 按照can通讯的流程重新封装接口函数

python调用32位的ControlCan.dll实现can报文的收发_第8张图片

由以上流程图可以看出,实现can报文的收发操作主要涉及的函数如下:

python调用32位的ControlCan.dll实现can报文的收发_第9张图片

根据以上报文发送和接收流程,得到初始化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])

5. 完整代码

本人调用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.利用全局字典在上位机界面和报文发送线程间传递信息

你可能感兴趣的:(python,周立功can,controlcan.dll)