淘宝购买周立功can卡后即可根据卖家提供的资料进行二次开发,基于已有的can协议完成基于C语言或者python语言的can信号收发通信功能:

注意购买的周立功can卡需要根据系统选择,可以直接购买linux版本,适用于windows系统,也可以在ARM架构的开发板中使用!!!

python通信库 python can通信_Data

linux系统中(包含ARM架构,如果为ARM架构,找到arm文件夹下面的libcontrolcan.so文件,替换controlcan文件夹中的libcontrolcan.so即可),C语言开发版本主要需要修改mian.cpp文件,对照接口函数库去自行修改开发,注意通信时候的波特率,标准帧(扩展帧等)

python通信库 python can通信_ci_02


python通信库 python can通信_python通信库_03

python开发环境:

linux中的python环境包含libcontrolcan.so和python3.8.0.py

python通信库 python can通信_python_04


windows中的python环境包含ControlCan.dll和python3.8.0.py

python通信库 python can通信_python通信库_05


同样地,也可以使用接口函数库进行进一步的功能开发,实现与车子底盘的通信;

其中,can原始的自测代码为:

#python3.8.0 64位(python 32位要用32位的DLL)
#
from ctypes import *
 
VCI_USBCAN2 = 4
STATUS_OK = 1
class VCI_INIT_CONFIG(Structure):
    _fields_ = [("AccCode", c_uint),
                ("AccMask", c_uint),
                ("Reserved", c_uint),
                ("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_ubyte),
                ("SendType", c_ubyte),
                ("RemoteFlag", c_ubyte),
                ("ExternFlag", c_ubyte),
                ("DataLen", c_ubyte),
                ("Data", c_ubyte*8),
                ("Reserved", c_ubyte*3)
                ] 
 
CanDLLName = './ControlCAN.dll' #把DLL放到对应的目录下
canDLL = windll.LoadLibrary('./ControlCAN.dll')
#Linux系统下使用下面语句,编译命令:python3 python3.8.0.py
#canDLL = cdll.LoadLibrary('./libcontrolcan.so')


print(CanDLLName)
 
ret = canDLL.VCI_OpenDevice(VCI_USBCAN2, 0, 0)
if ret == STATUS_OK:
    print('调用 VCI_OpenDevice成功\r\n')
if ret != STATUS_OK:
    print('调用 VCI_OpenDevice出错\r\n')
 
#初始0通道
vci_initconfig = VCI_INIT_CONFIG(0x80000008, 0xFFFFFFFF, 0,
                                 0, 0x03, 0x1C, 0)#波特率125k,正常模式
ret = canDLL.VCI_InitCAN(VCI_USBCAN2, 0, 0, byref(vci_initconfig))
if ret == STATUS_OK:
    print('调用 VCI_InitCAN1成功\r\n')
if ret != STATUS_OK:
    print('调用 VCI_InitCAN1出错\r\n')
 
ret = canDLL.VCI_StartCAN(VCI_USBCAN2, 0, 0)
if ret == STATUS_OK:
    print('调用 VCI_StartCAN1成功\r\n')
if ret != STATUS_OK:
    print('调用 VCI_StartCAN1出错\r\n')
 
#初始1通道
ret = canDLL.VCI_InitCAN(VCI_USBCAN2, 0, 1, byref(vci_initconfig))
if ret == STATUS_OK:
    print('调用 VCI_InitCAN2 成功\r\n')
if ret != STATUS_OK:
    print('调用 VCI_InitCAN2 出错\r\n')
 
ret = canDLL.VCI_StartCAN(VCI_USBCAN2, 0, 1)
if ret == STATUS_OK:
    print('调用 VCI_StartCAN2 成功\r\n')
if ret != STATUS_OK:
    print('调用 VCI_StartCAN2 出错\r\n')
 
#通道1发送数据
ubyte_array = c_ubyte*8
a = ubyte_array(1,2,3,4, 5, 6, 7, 8)
ubyte_3array = c_ubyte*3
b = ubyte_3array(0, 0 , 0)
vci_can_obj = VCI_CAN_OBJ(0x1, 0, 0, 1, 0, 0,  8, a, b)#单次发送
 
ret = canDLL.VCI_Transmit(VCI_USBCAN2, 0, 0, byref(vci_can_obj), 1)
if ret == STATUS_OK:
    print('CAN1通道发送成功\r\n')
if ret != STATUS_OK:
    print('CAN1通道发送失败\r\n')
 
#通道2接收数据
a = ubyte_array(0, 0, 0, 0, 0, 0, 0, 0)
vci_can_obj = VCI_CAN_OBJ(0x0, 0, 0, 0, 0, 0,  0, a, b)#复位接收缓存
ret = canDLL.VCI_Receive(VCI_USBCAN2, 0, 1, byref(vci_can_obj), 2500, 0)
#print(ret)
while ret <= 0:#如果没有接收到数据,一直循环查询接收。
        ret = canDLL.VCI_Receive(VCI_USBCAN2, 0, 1, byref(vci_can_obj), 2500, 0)
if ret > 0:#接收到一帧数据
    print('CAN2通道接收成功\r\n')
    print('ID:')
    print(vci_can_obj.ID)
    print('DataLen:')
    print(vci_can_obj.DataLen)
    print('Data:')
    print(list(vci_can_obj.Data))
 
#关闭
canDLL.VCI_CloseDevice(VCI_USBCAN2, 0)

python通信库 python can通信_python通信库_06

在window下,通过can卡通道1即can1发送报文代码如下:

注意: can通道发送的报文一定要及时被接受,要不然就会出现报文发送失败的情况,对应的是否被接受即为 将can卡接入总线或者两个通道互相连接即可;

# python3.8.0 64位(python 32位要用32位的DLL)
#
from ctypes import *
import time

VCI_USBCAN2 = 4  # can卡类别为USBCAN-2A、USBCAN-2C、CANalyst-II中的一种
STATUS_OK = 1

class VCI_INIT_CONFIG(Structure):
    _fields_ = [("AccCode", c_uint),  # 验收码。SJA1000的帧过滤验收码。对经过屏蔽码过滤为“有关位”进行匹配,全部匹配成功后,此帧可以被接收。
                ("AccMask", c_uint),
                # 屏蔽码。SJA1000的帧过滤屏蔽码。对接收的CAN帧ID进行过滤,对应位为0的是“有关位”,对应位为1的是“无关位”。屏蔽码推荐设置为0xFFFFFFFF,即全部接收。
                ("Reserved", c_uint),  # 保留
                ("Filter", c_ubyte),  # 滤波方式
                ("Timing0", c_ubyte),  # 波特率定时器 0
                ("Timing1", c_ubyte),  # 波特率定时器 1
                ("Mode", c_ubyte)  # 模式。=0表示正常模式(相当于正常节点),=1表示只听模式(只接收,不影响总线),=2表示自发自收模式(环回模式)。
                ]


class VCI_CAN_OBJ(Structure):  # VCI_CAN_OBJ结构体是CAN帧结构体,即1个结构体表示一个帧的数据结构。在发送函数VCI_Transmit和接收函数VCI_Receive中,被用来传送CAN信息帧。
    _fields_ = [("ID", c_uint),  # 帧ID。32位变量,数据格式为靠右对齐
                ("TimeStamp", c_uint),  # 设备接收到某一帧的时间标识。时间标示从CAN卡上电开始计时,计时单位为0.1ms。
                ("TimeFlag", c_ubyte),  # 是否使用时间标识,为1时TimeStamp有效,TimeFlag和TimeStamp只在此帧为接收帧时有意义。
                ("SendType", c_ubyte),
                # 发送帧类型。=0时为正常发送(发送失败会自动重发,重发时间为4秒,4秒内没有发出则取消);=1时为单次发送(只发送一次,发送失败不会自动重发,总线只产生一帧数据);其它值无效。
                ("RemoteFlag", c_ubyte),  # 是否是远程帧。=0时为为数据帧,=1时为远程帧(数据段空)。
                ("ExternFlag", c_ubyte),  # 是否是扩展帧。=0时为标准帧(11位ID),=1时为扩展帧(29位ID)。
                ("DataLen", c_ubyte),  # 数据长度 DLC (<=8),即CAN帧Data有几个字节。约束了后面Data[8]中的有效字节
                ("Data", c_ubyte * 8),
                # CAN帧的数据。由于CAN规定了最大是8个字节,所以这里预留了8个字节的空间,受DataLen约束。如DataLen定义为3,即Data[0]、Data[1]、Data[2]是有效的
                ("Reserved", c_ubyte * 3)  # 系统保留
                ]


CanDLLName = './ControlCAN.dll'  # 把DLL放到对应的目录下
canDLL = windll.LoadLibrary('./ControlCAN.dll')
# Linux系统下使用下面语句,编译命令:python3 python3.8.0.py
# canDLL = cdll.LoadLibrary('./libcontrolcan.so')

ret = canDLL.VCI_OpenDevice(VCI_USBCAN2, 0, 0)
# VCI_USBCAN2 设备类型; 设备索引0:只有一个can卡; 保留参数,通常为 0。
# 返回值=1,表示操作成功;=0表示操作失败;=-1表示USB-CAN设备不存在或USB掉线。
if ret == STATUS_OK:
    print('调用 VCI_OpenDevice成功\r\n')
if ret != STATUS_OK:
    print('调用 VCI_OpenDevice出错\r\n')

# ############################# 初始0通道  ############################
# 验收码;  屏蔽码;  保留;  滤波方式:正常模式;  改为00 1C,对应500K;  最后0为正常模式,相当于正常节点,既发送也接收
vci_initconfig = VCI_INIT_CONFIG(0x80000008, 0xFFFFFFFF, 0,
                                 0, 0x00, 0x1C, 0)

# VCI_InitCAN用以初始化指定的CAN通道。有多个CAN通道时,需要多次调用。设备类型VCI_USBCAN2;设备索引0;CAN通道索引0,CAN1为0,CAN2为1;
ret = canDLL.VCI_InitCAN(VCI_USBCAN2, 0, 0, byref(vci_initconfig))
if ret == STATUS_OK:
    print('调用 VCI_InitCAN1成功\r\n')
if ret != STATUS_OK:
    print('调用 VCI_InitCAN1出错\r\n')

# VCI_StartCAN此函数用以启动CAN卡的某一个CAN通道。有多个CAN通道时,需要多次调用
ret = canDLL.VCI_StartCAN(VCI_USBCAN2, 0, 0)
if ret == STATUS_OK:
    print('调用 VCI_StartCAN1成功\r\n')
if ret != STATUS_OK:
    print('调用 VCI_StartCAN1出错\r\n')

# ######################################## 通道0发送数据 #####################################
ubyte_array = c_ubyte*8
a = ubyte_array(00, 00, 00, 00, 00, 00, 00, 10)   # can信号数据内容
ubyte_3array = c_ubyte*3
b = ubyte_3array(0, 0, 0)   # 系统保留位
vci_can_obj = VCI_CAN_OBJ(0x183, 0, 0, 0, 0, 0,  8, a, b)   # 第三位的1代表单次发送,为0代表正常发送,标准帧,数据帧,系统保留。
# vci_can_obj = VCI_CAN_OBJ(0x183, 0, 0, 0, 0, 0,  8, a, b)


# 设备类型;设备索引;CAN通道索引;要发送的帧结构体VCI_CAN_OBJ数组的首指针;要发送的帧结构体数组的长度(发送的帧数量)。
while True:
    # start = time.time();print(start)
    ret = canDLL.VCI_Transmit(VCI_USBCAN2, 0, 0, byref(vci_can_obj), 1)
    if ret == STATUS_OK:
        print('CAN1通道发送成功\r')
        print('ID:', vci_can_obj.ID)
        print('DataLen:', vci_can_obj.DataLen)
        print('Data:', list(vci_can_obj.Data))
    if ret != STATUS_OK:
        print('CAN1通道发送失败\r')
    # end = time.time();print(end)
    time.sleep(0.02)   # 循环发送时间为20ms
    # end1 = time.time();print(end1)
    # print(end - start)
    # print(end1 - start)
    # print('\n')



# canDLL.VCI_CloseDevice(VCI_USBCAN2, 0)

注意8个字节的排列方式,每个字节对应8个的二进制位也要十分注意!!!

否则可能看不懂CAN协议的内容(踩坑)


python通信库 python can通信_python通信库_07

————————————————————————————————————————————————————————————————————————————————
下面是早期写的内容,不过参考意义不大了

#!/usr/bin/env python
# coding: utf-8

"""
This example shows how sending a single message works.
"""

from __future__ import print_function

import can

def send_one():

    # this uses the default configuration (for example from the config file)
    # see https://python-can.readthedocs.io/en/stable/configuration.html
    bus = can.interface.Bus()

    # Using specific buses works similar:
    # bus = can.interface.Bus(bustype='socketcan', channel='vcan0', bitrate=250000)
    # bus = can.interface.Bus(bustype='pcan', channel='PCAN_USBBUS1', bitrate=250000)
    # bus = can.interface.Bus(bustype='ixxat', channel=0, bitrate=250000)
    # bus = can.interface.Bus(bustype='vector', app_name='CANalyzer', channel=0, bitrate=250000)
    # ...

    msg = can.Message(arbitration_id=0xc0ffee,
                      data=[0, 25, 0, 1, 3, 1, 4, 1],
                      is_extended_id=True)

    try:
        bus.send(msg)
        print("Message sent on {}".format(bus.channel_info))
    except can.CanError:
        print("Message NOT sent")

if __name__ == '__main__':
    send_one()