01模块简介
python-can库为Python提供控制器局域网支持 ,为不同的硬件设备提供通用抽象,以及一套用于在 CAN 总线上发送和接收消息的实用程序
import can
8
9
10def send_one():
11 """Sends a single message."""
12
13 # this uses the default configuration (for example from the config file)
14 # see https://python-can.readthedocs.io/en/stable/configuration.html
15 with can.interface.Bus() as bus:
16
17 # Using specific buses works similar:
18 # bus = can.interface.Bus(bustype='socketcan', channel='vcan0', bitrate=250000)
19 # bus = can.interface.Bus(bustype='pcan', channel='PCAN_USBBUS1', bitrate=250000)
20 # bus = can.interface.Bus(bustype='ixxat', channel=0, bitrate=250000)
21 # bus = can.interface.Bus(bustype='vector', app_name='CANalyzer', channel=0, bitrate=250000)
22 # ...
23
24 msg = can.Message(
25 arbitration_id=0xC0FFEE, data=[0, 25, 0, 1, 3, 1, 4, 1], is_extended_id=True
26 )
27
28 try:
29 bus.send(msg)
30 print(f"Message sent on {bus.channel_info}")
31 except can.CanError:
32 print("Message NOT sent")
33
34
35if __name__ == "__main__":
36 send_one()
bustype的类型一共有四种:
1)socketcan 对应的channel 为:vcan0
2)ixxat 对应的channel为:0
3)pcan 对应的channel为PCAN_USBBUS1
4)vector 对应的channel为0,需要额外增加一个app_name 为CANalyzer
5)。。。python-can库基于PCAN-USB使用方法
总线的比特率咱们自己是500ms
02准备的环境
1)Python安装:https://www.python.org/ftp/python/3.7.9/python-3.7.9-amd64.exe
2)PCAN-USB驱动:Home: PEAK-System
3)库:pip install python-can
03PCAN默认配置API
1)interface = pcan
2)channel = PCAN_USBBUS1
3)state = can.bus.BusState.ACTIVE
4)bitrate = 500000
class PcanBus(BusABC): def __init__( self, channel="PCAN_USBBUS1", state=BusState.ACTIVE, bitrate=500000, *args, **kwargs, ):
04PCAN可用参数
1)channel(通道)
:param str channel: The can interface name. An example would be 'PCAN_USBBUS1'. Alternatively the value can be an int with the numerical value. Default is 'PCAN_USBBUS1'
2)BusState(总线状态)
:param can.bus.BusState state: BusState of the channel. Default is ACTIVE
3)bitrate(比特率,非CANFD)
:param int bitrate: Bitrate of channel in bit/s. Default is 500 kbit/s. Ignored if using CanFD.
3)fd(布尔类型,判断是否为CANFD)
:param bool fd: Should the Bus be initialized in CAN-FD mode.
4)f_clock(时钟频率HZ,非CANFD)
:param int f_clock: Clock rate in Hz. Any of the following: 20000000, 24000000, 30000000, 40000000, 60000000, 80000000. Ignored if not using CAN-FD. Pass either f_clock or f_clock_mhz.
5)f_clock——mhz(时钟频率MHZ,非CANFD)
:param int f_clock_mhz: Clock rate in MHz. Any of the following: 20, 24, 30, 40, 60, 80. Ignored if not using CAN-FD. Pass either f_clock or f_clock_mhz.
05接收报文
from can.interfaces.pcan.pcan import PcanBus def bus_recv(): """轮询接收消息""" try: while True: msg = bus.recv(timeout=100) print(msg) except KeyboardInterrupt: pass if __name__ == '__main__': bus = PcanBus(channel='PCAN_USBBUS1', bitrate=500000) bus_recv()
用到的类:
1)bus.recv
def recv ( self, timeout : Optional [ float ] = None ) -> Optional [ Message ]: """阻塞等待来自总线的消息。 :param timeout: 等待消息的秒数或无无限期等待 :return: ``None`` 超时或 :class:`Message` 对象。 """ can.CanOperationError # 读取时发生错无的错误类型
06发送报文
from can.interfaces.pcan.pcan import PcanBus def bus_send(): """can消息发送""" while True: time.sleep(0.02) try: bus.send(msg) print("消息发送 {}".format(bus.channel_info)) except can.CanError: print("消息未发送") if __name__ == '__main__': msg = can.Message(arbitration_id=0x181DFF00, data=[0xEE, 0xFE, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFE], is_extended_id=True) # 报文 bus = PcanBus(channel='PCAN_USBBUS1', bitrate=500000) bus_send()
用到的类:
1)bus.send()
def send ( self , msg : Message , timeout : Optional [ float ] = None ) -> None : """向 CAN 总线发送消息。 覆盖此方法以启用传输路径。 :param Message msg:一个消息对象。 :param timeout: 如果 > 0,则等待这么多秒,以便消息被 ACK 或 传输队列准备好,具体取决于驱动程序实现。 如果超时,将引发异常。 可能并非所有接口都支持。 无无限期阻塞。 :raises can.CanOperationError: If an error occurred while sent """ raise NotImplementedError ( " Trying to write to a readonly bus?" )
07定期发送报文
def bus_send_periodic(): """周期发送报文""" print("开始每200毫秒发送一条消息。持续时间10s") task = bus.send_periodic(msg, 1.5) # 定期发送 if not isinstance(task, can.ModifiableCyclicTaskABC): # 断言task类型 print("此接口似乎不支持") task.stop() return time.sleep(5) # 持续时间 print("发送完成") print("更改运行任务的数据以99开头") msg.data[0] = 0x99 task.modify_data(msg) # 修改data首字节 time.sleep(10) task.stop() print("停止循环发送") print("将停止任务的数据更改为单个 ff 字节") msg.data = bytearray([0xff]) # 重新定向data
用到的类:
081)bus.send_periodic()
def send_periodic( self, msgs: Union[Message, Sequence[Message]], period: float, duration: Optional[float] = None, store_task: bool = True, ) -> can.broadcastmanager.CyclicSendTaskABC: :param msgs: 要传输的消息 :param period: 每条消息之间的周期(以秒为单位) :param duration: 继续发送消息的近似持续时间(以秒为单位)。如果 没有提供持续时间,则任务将无限期地继续。 :param store_task: 如果为 True(默认值),任务将附加到此 Bus 实例。 禁用改为手动管理任务。 :return: 一个启动的任务实例。
08循环收发消息
from can.interfaces.pcan.pcan import PcanBus def send_cyclic(stop_event): """循环发送消息""" print("开始每1秒发送1条消息") start_time = time.time() while not stop_event.is_set(): msg.timestamp = time.time() - start_time bus.send(msg) print(f"tx: {msg}") time.sleep(1) print("停止发送消息") def receive(stop_event): """循环接收消息""" print("开始接收消息") while not stop_event.is_set(): rx_msg = bus.recv(1) if rx_msg is not None: print(f"rx: {rx_msg}") print("停止接收消息") def send_and_recv_msg(): """发送一个消息并接收一个消息,需要双通道CAN""" stop_event = threading.Event() t_send_cyclic = threading.Thread(target=send_cyclic, args=(stop_event,)) t_receive = threading.Thread(target=receive, args=(stop_event,)) t_receive.start() t_send_cyclic.start() try: while True: time.sleep(0) # yield except KeyboardInterrupt: pass # 正常退出 stop_event.set() time.sleep(0.5) if __name__ == '__main__': msg = can.Message(arbitration_id=0x181DFF00, data=[0xEE, 0xFE, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFE], is_extended_id=True) # 报文 bus = PcanBus(channel='PCAN_USBBUS1', bitrate=500000) send_and_recv_msg()
09常用方法
can.message(timestamp=0.0, //时间戳
arbitration_id=0, //报文id
is_extended_id=True, //是否为扩展帧
is_remote_frame=False, //是否为远程帧
is_error_frame=False, //是否为错误帧
channel=None, //通道
dlc=None, //dlc大小
data=None, //数据
is_fd=False, //是否为canfd
is_rx=True, //是否为接收帧
bitrate_switch=False, //比特率开关
error_state_indicator=False,
check=False)