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

    在这里插入图片描述

    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的方式

    在这里插入图片描述

    3.2 了解python中ctypes数据类型

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

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

    在这里插入图片描述

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

    4.1 device类型

    参考官网给的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
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    4.2 初始化can参数

    在这里插入图片描述

    波特率设置:

    在这里插入图片描述

    在这里插入图片描述

    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
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

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

    在这里插入图片描述

    由以上流程图可以看出,实现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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    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("接收缓存区为空")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    解析一帧报文数据的代码实现:

    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])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

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

  • 相关阅读:
    特种设备怎么运输到国外
    高通410 随身WiFi 5分钟自动重启解决方案
    Node.js的Express简介
    恒源云-Pycharm远程训练避坑指南
    大语言模型的关键技术(二)
    【C++】 内存管理
    C语言指针面试题——第二弹
    计算机操作系统-第十二天
    Mybatis一对多关联查询,返回值Map,字段自动映射
    AI:75-基于生成对抗网络的虚拟现实场景增强
  • 原文地址:https://blog.csdn.net/Logintern09/article/details/127106646