class CAN -- 控制器局域网通信总线¶
CAN 同时支持经典 CAN(bxCAN,用于 OpenMV Cam M4 和 M7)和 CAN FD(FDCAN,用于 OpenMV Cam H7、H7 Plus 和 Pure Thermal)控制器。在物理层面上,CAN 总线由两条线组成,即 RX 和 TX。要将 OpenMV Cam 连接到 CAN 总线,必须使用 CAN 收发器,将 MCU 的 CAN 逻辑信号转换为总线上正确的电压电平。
回环(无收发器)模式下的经典 CAN:
from pyb import CAN
can = CAN(1, CAN.LOOPBACK)
# Accept messages with id 123, 124, 125 or 126.
can.setfilter(0, CAN.LIST16, 0, (123, 124, 125, 126))
can.send("message!", 123) # send a message with id 123
can.recv(0) # receive a message on FIFO 0
启用了全部可选特性的 CAN FD(FD 帧、比特率切换、扩展帧 ID;500 kbit/s 仲裁阶段、1 Mbit/s 数据阶段):
from pyb import CAN
can = CAN(
1,
CAN.NORMAL,
baudrate=500_000,
brs_baudrate=1_000_000,
sample_point=80,
)
# Accept any id in the range 0xFFF0 .. 0xFFFF.
can.setfilter(0, CAN.RANGE, 0, (0xFFF0, 0xFFFF))
can.send(b"a" * 64, 0xFFFF, fdf=True, brs=True, extframe=True)
can.recv(0)
除非另有说明,以下 CAN 模块函数及其参数对经典 CAN 和 FD CAN 控制器均可用。
构造函数¶
- class pyb.CAN(bus: int | str, *args, **kwargs)¶
在给定的
bus(一个整数外设索引,例如1对应CAN1,2对应CAN2)上构造一个 CAN 对象。若不提供其他参数,则只创建对象但不进行初始化(它会保留之前的总线设置,如果有的话);若给出额外参数,则会对总线进行初始化。可用参数请参阅CAN.init()。在每一款暴露
pyb.CAN的 OpenMV Cam(M4 / M7 / H7 / H7 Plus / Pure Thermal)上,CAN(2)都连接到相同的排针引脚:信号
排针引脚
说明
RXP3TXP2CAN 外设仅提供逻辑电平信号;要驱动真实的 CAN 总线需要外接 CAN 收发器。
pyb.CAN在 OpenMV Cam N6 上不可用。方法¶
- init(mode: int, prescaler: int = 100, *, sjw: int = 1, bs1: int = 6, bs2: int = 8, auto_restart: bool = False, baudrate: int = 0, sample_point: int = 75, num_filter_banks: int = 14, brs_sjw: int = 1, brs_bs1: int = 8, brs_bs2: int = 3, brs_baudrate: int = 0, brs_sample_point: int = 75) None¶
使用给定参数初始化 CAN 总线:
mode 取以下之一:NORMAL、LOOPBACK、SILENT、SILENT_LOOPBACK
prescaler 是 CAN 输入时钟用于生成标称位时间量子时的分频值。对于经典 CAN,预分频值可取 1 到 1024(含)之间;对于 CAN FD,可取 1 到 512(含)之间。
sjw 是标称位的重同步跳转宽度,以时间量子为单位;对于经典 CAN,可取 1 到 4(含)之间;对于 CAN FD,可取 1 到 128(含)之间。
bs1 定义采样点的位置,以标称位的时间量子为单位;对于经典 CAN,可取 1 到 16(含)之间;对于 CAN FD,可取 2 到 256(含)之间。
bs2 定义发送点的位置,以标称位的时间量子为单位;对于经典 CAN,可取 1 到 8(含)之间;对于 CAN FD,可取 2 到 128(含)之间。
auto_restart 设置控制器在进入总线关闭(bus-off)状态后是否会自动尝试重启通信;如果禁用此功能,则可以使用
restart()来退出总线关闭状态baudrate 如果提供的波特率不为 0,此函数将尝试自动计算同时满足 baudrate(误差在 0.1% 以内)和期望 sample_point(精确到最接近的 1%)的 CAN 标称位时间(覆盖 prescaler、bs1 和 bs2)。如需更精确地控制 CAN 时序,请直接设置 prescaler、bs1 和 bs2 参数。
sample_point 指定位采样相对于整个标称位时间的位置,以标称位时间的整数百分比表示。默认 sample_point 为 75%。除非设置了 baudrate,否则此参数将被忽略。
num_filter_banks 对于经典 CAN,这是分配给 CAN(1) 的滤波器组数量,28 个中剩余的部分则分配给 CAN(2)。
其余参数仅在支持 CAN FD 的开发板上存在,用于配置可选的 CAN FD 比特率切换(BRS)特性:
brs_prescaler 是 CAN FD 输入时钟用于生成数据位时间量子时的分频值。预分频值可取 1 到 32(含)之间。
brs_sjw 是数据位的重同步跳转宽度,以时间量子为单位;可取 1 到 16(含)之间
brs_bs1 定义采样点的位置,以数据位的时间量子为单位;可取 1 到 32(含)之间
brs_bs2 定义发送点的位置,以数据位的时间量子为单位;可取 1 到 16(含)之间
brs_baudrate 如果提供的波特率不为 0,此函数将尝试自动计算同时满足 brs_baudrate(误差在 0.1% 以内)和期望 brs_sample_point(精确到最接近的 1%)的 CAN 数据位时间(覆盖 brs_prescaler、brs_bs1 和 brs_bs2)。如需更精确地控制 BRS 时序,请直接设置 brs_prescaler、brs_bs1 和 brs_bs2 参数。
brs_sample_point 指定位采样相对于整个标称位时间的位置,以标称位时间的整数百分比表示。默认 brs_sample_point 为 75%。除非设置了 brs_baudrate,否则此参数将被忽略。
时间量子 tq 是 CAN 总线的基本时间单位。tq 等于 CAN 预分频值除以 PCLK1(内部外设总线 1 的频率);要确定 PCLK1,请参阅
pyb.freq()。单个位由同步段(始终为 1 tq)组成。其后是位段 1,然后是位段 2。采样点位于位段 1 结束之后。发送点位于位段 2 结束之后。波特率为 1/bittime,其中 bittime 等于 1 + BS1 + BS2 再乘以时间量子 tq。
例如,在 OpenMV Cam H7 上(PCLK1 = 100 MHz),采样点为 75% 的 250 kbps CAN 可配置为
prescaler=25, sjw=1, bs1=11, bs2=4:tq = 25 / 100 MHz = 250 ns、bittime = (1 + 11 + 4) × 250 ns = 4 µs、采样点 =(1 + 11) / 16 = 75%,波特率为1 / 4 µs = 250 kHz。更多细节请参阅 OpenMV Cam 所用 MCU 的 STM32 参考手册中的 bxCAN / FDCAN 章节。
- restart() None¶
强制软件重启 CAN 控制器,但不重置其配置。
如果控制器进入总线关闭状态,它将不再参与总线活动。如果控制器未配置为自动重启(参阅
init()),则可使用此方法触发重启,控制器随后将遵循 CAN 协议退出总线关闭状态并进入错误活动状态。
- state() int¶
返回控制器的状态。返回值可以是以下之一:
CAN.STOPPED—— 控制器完全关闭并已复位;CAN.ERROR_ACTIVE—— 控制器已开启并处于错误活动(Error Active)状态(TEC 和 REC 均小于 96);CAN.ERROR_WARNING—— 控制器已开启并处于错误警告(Error Warning)状态(TEC 或 REC 至少有一个达到或超过 96);CAN.ERROR_PASSIVE—— 控制器已开启并处于错误被动(Error Passive)状态(TEC 或 REC 至少有一个达到或超过 128);CAN.BUS_OFF—— 控制器已开启但不参与总线活动(TEC 溢出超过 255)。
- info(list: list | None = None) list¶
获取有关控制器错误状态以及 TX 和 RX 缓冲区的信息。如果提供了 list,则它应当是一个至少包含 8 个条目的列表对象,这些条目将被填入相应信息。否则将创建一个新列表并填入信息。两种情况下,该方法的返回值都是已填充的列表。
列表中的值为:
TEC 值
REC 值
控制器进入错误警告(Error Warning)状态的次数(超过 65535 后回绕到 0)
控制器进入错误被动(Error Passive)状态的次数(超过 65535 后回绕到 0)
控制器进入总线关闭(Bus Off)状态的次数(超过 65535 后回绕到 0)
待发送 TX 消息的数量
fifo 0 上待接收 RX 消息的数量
fifo 1 上待接收 RX 消息的数量
- setfilter(bank: int, mode: int, fifo: int, params: Tuple[int, ...], *, rtr: Tuple[bool, ...] | None = None, extframe: bool = False) None¶
配置一个滤波器组:
bank 是要配置的经典 CAN 控制器滤波器组,或 CAN FD 滤波器索引。
mode 是滤波器应当工作的模式,参见下面的表格。
fifo 指定如果消息被此滤波器接受,应存储到哪个 fifo(0 或 1)。
params 是一个定义滤波器的值数组。该数组的内容取决于 mode 参数。
经典 CAN 控制器(OpenMV Cam M4 / M7)的 params 数组内容:
mode
params 的内容
CAN.LIST16四个将被接受的 16 位 ID。
CAN.LIST32两个将被接受的 32 位 ID。
CAN.MASK16两个 16 位的 id/掩码对,例如
(1, 3, 4, 4)。第一对(1, 3)接受所有位 0 = 1 且位 1 = 0 的 ID;第二对(4, 4)接受所有位 2 = 1 的 ID。CAN.MASK32一个 32 位的 id/掩码对(其余与
CAN.MASK16相同)。CAN FD 控制器(OpenMV Cam H7 / H7 Plus / Pure Thermal)的 params 数组内容:
mode
params 的内容
CAN.RANGE两个 ID,构成接受 ID 的一个范围。
CAN.DUAL两个将被接受的 ID(例如
(1, 2))。CAN.MASK一个
(id, mask)对(例如(0x111, 0x7FF))。rtr 对于经典 CAN 控制器,这是一个布尔值数组,用于指定滤波器是否应接受远程传输请求消息。如果未给出此参数,则所有条目默认为
False。其长度取决于 mode:mode
len(rtr)说明
CAN.LIST164
CAN.LIST322
CAN.MASK162
CAN.MASK321
对于 CAN FD,此参数将被忽略。
extframe 如果为 True,则帧将使用扩展标识符(29 位),否则使用标准标识符(11 位)。
- clearfilter(bank: int, extframe: bool = False) None¶
清除并禁用一个滤波器组:
bank 是要清除的经典 CAN 控制器滤波器组,或 CAN FD 滤波器索引。
extframe 对于 CAN FD 控制器,如果为 True,则清除扩展滤波器(以 extframe=True 配置的),否则清除标准标识符(以 extframe=False 配置的)。
- recv(fifo: int, list: list | None = None, *, timeout: int = 5000) list¶
在总线上接收数据:
fifo 是一个整数,表示要在其上接收数据的 FIFO
list 是一个可选的列表对象,用作返回值
timeout 是等待接收的超时时间,以毫秒为单位。
返回值:一个包含五个值的列表。
消息的 id。
一个布尔值,指示消息 ID 是标准的还是扩展的。
一个布尔值,指示消息是否为 RTR 消息。
FMI(滤波器匹配索引)值。
一个包含数据的数组。
如果 list 为
None,则会分配一个新列表,以及一个用于存放数据的新 bytes 对象(作为列表中的第五个元素)。如果 list 不为
None,则它应当是一个至少包含五个元素的列表对象。第五个元素应当是一个 memoryview 对象,由 bytearray 或类型为 'B' 或 'b' 的 array 创建而来,且该数组必须至少有容纳 8 个字节的空间。然后列表对象将被填入上述前四个返回值,memoryview 对象将原地调整为数据的大小并填入相应数据。可以在后续对此方法的调用中重复使用同一个列表和 memoryview 对象,从而提供一种无需使用堆的接收数据方式。例如:buf = bytearray(8) lst = [0, 0, 0, 0, memoryview(buf)] # No heap memory is allocated in the following call can.recv(0, lst)
- send(data: int | bytes | bytearray, id: int, *, timeout: int = 0, rtr: bool = False, extframe: bool = False, fdf: bool = False, brs: bool = False) None¶
在总线上发送一条消息:
data 是要发送的数据(一个要发送的整数,或一个缓冲区对象)。
id 是要发送的消息的 id。
timeout 是等待发送的超时时间,以毫秒为单位。
rtr 是一个布尔值,指定该消息是否应作为远程传输请求发送。如果 rtr 为 True,则只使用 data 的长度来填充帧的 DLC 字段;data 中的实际字节不会被使用。
extframe 如果为 True,则帧将使用扩展标识符(29 位),否则使用标准标识符(11 位)。
fdf 对于 CAN FD 控制器,如果设置为 True,则帧将采用 FD 帧格式,支持最多 64 字节的数据载荷。
brs 对于 CAN FD 控制器,如果设置为 True,则启用比特率切换模式,此时数据阶段将以不同的比特率传输。数据位时序的配置参数请参阅
CAN.init()。
如果 timeout 为 0,则消息将被放入三个硬件缓冲区之一中,方法立即返回。如果三个缓冲区都在使用中,则抛出异常。如果 timeout 不为 0,则方法会等待直到消息被发送。如果消息无法在指定时间内发送,则抛出异常。
返回值:
None。
- rxcallback(fifo: int, fun: Callable[[CAN, int], None] | None) None¶
注册一个函数,当消息被接受进入一个空 FIFO 时调用:
fifo 是接收用的 FIFO。
fun 是当 FIFO 变为非空时要调用的函数。
回调函数接受两个参数:第一个是 CAN 对象本身;第二个是一个整数,指示回调的原因:
原因
含义
0一条消息已被接受进入空 FIFO。
1FIFO 已满。
2由于 FIFO 已满,一条消息已丢失。
rxcallback 的使用示例:
def cb0(bus, reason): print('cb0') if reason == 0: print('pending') if reason == 1: print('full') if reason == 2: print('overflow') can = CAN(1, CAN.LOOPBACK) can.rxcallback(0, cb0)
常量¶
总线模式常量(
init()的mode参数):控制器状态常量(由
state()返回):经典 CAN 滤波器模式(OpenMV Cam M4 / M7 上
setfilter()的mode参数):CAN FD 滤波器模式(OpenMV Cam H7 / H7 Plus / Pure Thermal 上
setfilter()的mode参数):