class CAN – 控制器局域网通信总线

CAN 实现了对经典 CAN(适用于 F4、F7 MCU)和 CAN FD(H7 系列)控制器的支持。在物理层,CAN 总线由 2 条线组成:RX 和 TX。注意,要将 pyboard 连接到 CAN 总线,必须使用CAN 转换器将 pyboard 上的 CAN 逻辑信号转换为总线上的正确电压水平。

经典 CAN 控制器在回环(无需收发器)模式下的示例用法:

from pyb import CAN
can = CAN(1, CAN.LOOPBACK)
can.setfilter(0, CAN.LIST16, 0, (123, 124, 125, 126))  # set a filter to receive messages with id=123, 124, 125 and 126
can.send('message!', 123)   # send a message with id 123
can.recv(0)                 # receive message on FIFO 0

CAN FD 控制器在启用了所有可能的选项的示例用法:

# FD frame + BRS mode + Extended frame ID. 500 Kbit/s for arbitration phase, 1Mbit/s for data phase.
can = CAN(1, CAN.NORMAL, baudrate=500_000, brs_baudrate=1_000_000, sample_point=80)
can.setfilter(0, CAN.RANGE, 0, (0xFFF0, 0xFFFF))
can.send('a'*64, 0xFFFF, fdf=True, brs=True, extframe=True)
can.recv(0)

以下是经典CAN和FD CAN控制器可用的函数及其参数,除非另有说明。

构造

class pyb.CAN(bus, ...)

在给定的总线上构造一个 CAN 对象。bus 可以是 1-2,或者 'YA''YB'。如果没有额外的参数,则创建但不初始化 CAN 对象(使用上一次初始化总线的设置,如果有)。如果给定了额外的参数,则初始化总线。有关初始化参数,请参阅 CAN.init()

CAN总线的物理引脚如下:

  • CAN(1)YA 上:(RX, TX) = (Y3, Y4) = (PB8, PB9)

  • CAN(2)YB 上:(RX, TX) = (Y5, Y6) = (PB12, PB13)

方法

CAN.init(mode, prescaler=100, *, sjw=1, bs1=6, bs2=8, auto_restart=False, baudrate=0, sample_point=75,
num_filter_banks=14, brs_sjw=1, brs_bs1=8, brs_bs2=3, brs_baudrate=0, brs_sample_point=75)

使用给定参数初始化CAN总线:

  • mode 可以是以下之一:NORMAL、LOOPBACK、SILENT、SILENT_LOOPBACK

  • prescaler 是用于生成标称比特时间量的 CAN 输入时钟除数值。对于经典 CAN,预分频器可以是介于 1 和 1024(含1024) 之间的值,对于 CAN FD,可以是介于 1 和 512 (含512)之间的值。

  • sjw 是标称位的重新同步跳跃宽度,以时间单位计算;对于经典 CAN,它可以是介于 1 和 4 (含4)之间的值,对于 CAN FD,可以是介于 1 和 128 (含128)之间的值。

  • bs1 定义了采样点在标称位的时间单位中的位置;对于经典 CAN,它可以是介于 1 和 16(含16) 之间的值,对于 CAN FD,可以是介于 2 和 256 (含256)之间的值。

  • bs2 定义了传输点在标称位的时间单位中的位置;对于经典 CAN,它可以是介于 1 和 8(含8) 之间的值,对于 CAN FD,可以是介于 2 和 128 (含128)之间的值。

  • auto_restart 设置控制器是否会在进入总线关闭状态后自动尝试重新启动通信;如果禁用了此功能,则可以使用 restart() 来离开总线关闭状态

  • baudrate 如果提供了一个非 0 的波特率,该函数将尝试自动计算满足波特率和所需 sample_point 的 CAN 标称比特时间(覆盖 prescalerbs1bs2)。

  • sample_point 以标称比特时间的百分比给出,sample_point 指定位采样与整个标称比特时间的位置。默认的 sample_point 是 75%。

  • num_filter_banks 对于经典 CAN,这是将分配给 CAN(1) 的组数,剩下的 28 个将分配给 CAN(2)。

  • brs_prescaler 用于生成数据比特时间量的 CAN FD 输入时钟的值。预分频器可以是介于 1 和 32 (含32)之间的值。

  • brs_sjw 是数据位的重新同步跳跃宽度,以时间单位计算;它可以是介于 1 和 16(含16) 之间的值

  • brs_bs1 定义了采样点在数据位的时间单位中的位置;它可以是介于 1 和 32(含32) 之间的值

  • brs_bs2 定义了传输点在数据位的时间单位中的位置;它可以是介于 1 和 16 (含16)之间的值

  • brs_baudrate 如果提供了一个非 0 的波特率,该函数将尝试自动计算满足波特率和所需 brs_sample_point 的 CAN 数据比特时间(覆盖 brs_prescalerbrs_bs1brs_bs2)。

  • brs_sample_point 以数据比特时间的百分比给出,brs_sample_point 指定位采样与整个数据比特时间的位置。默认的 brs_sample_point 是 75%。

时间量 tq 是 CAN 总线的基本时间单位。tq 是 CAN 预分频器值除以 PCLK1(内部外围总线 1 的频率)得到的值;请参阅 pyb.freq() 以确定 PCLK1。

单个位由同步段组成,始终为 1 tq。然后是位段 1,然后是位段 2。采样点位于位段 1 结束后。传输点位于位段 2 结束后。波特率将是 1/比特时间,其中比特时间是 1 + BS1 + BS2 乘以时间量 tq。

例如,对于 PCLK1=42MHz,预分频器=100,sjw=1,bs1=6,bs2=8,tq 的值为 2.38 微秒。比特时间为 35.7 微秒,波特率为 28kHz。

更多细节请参阅STM32F405数据手册680页。

CAN.deinit()

关闭CAN总线。

CAN.restart()

强制软件重新启动CAN控制器,而不是重置其配置。

如果控制器进入总线关闭状态,则它将不再参与总线活动。如果控制器未配置为自动重新启动(请参阅 init()),则可以使用此方法触发重新启动,并且控制器将遵循 CAN 协议以离开总线关闭状态并进入错误激活状态。

CAN.state()

返回控制器的状态。返回值可以是以下之一:

  • CAN.STOPPED – 控制器完全关闭并重置;

  • CAN.ERROR_ACTIVE – 控制器开启且处于错误激活状态(TEC和REC都小于96);

  • CAN.ERROR_WARNING – 控制器开启且处于错误警告状态(TEC或REC至少为96);

  • CAN.ERROR_PASSIVE – 控制器开启且处于错误被动状态(TEC或REC至少为128);

  • CAN.BUS_OFF – 控制器开启但不参与总线活动(TEC溢出超过255)。

CAN.info([list])

获取有关控制器的错误状态以及 TX 和 RX 缓冲区的信息。如果提供了 list,则应该是一个至少有 8 个条目的列表对象,将用信息填充其中。否则将创建一个新列表并填充其中。在两种情况下,方法的返回值是填充的列表。

列表中的值为:

  • TEC值

  • REC值

  • 控制器进入错误警告状态的次数(在达到65535后环绕为0)

  • 控制器进入错误被动状态的次数(在达到65535后环绕为0)

  • 控制器进入总线关闭状态的次数(在达到65535后环绕为0)

  • 待处理的TX消息数

  • FIFO 0 上待处理的 RX 消息数

  • FIFO 1 上待处理的 RX 消息数

CAN.setfilter(bank, mode, fifo, params, *, rtr, extframe=False)

配置一个过滤器组:

  • bank 是要配置的经典 CAN 控制器过滤器组或 CAN FD 过滤器索引。

  • mode 是过滤器应该操作的模式,请参阅下表。

  • fifo 是应将消息存储在其中的 FIFO(0 或 1),如果它被此过滤器接受。

  • params 是定义过滤器的值数组。数组的内容取决于 mode 参数。

mode

经典 CAN 控制器所使用的 params 数组内容

CAN.LIST16

将被接受的四个16位ID

CAN.LIST32

将被接受的两个32位ID

CAN.MASK16

两个 16 位 ID/掩码对。例如 (1, 3, 4, 4)
第一对,1 和 3,将接受所有 ID
其中位 0 = 1 且位 1 = 0。
第二对,4 和 4,将接受所有 ID
其中位 2 = 1。

CAN.MASK32

与 CAN.MASK16 相同,但只有一个 32 位 ID/掩码对。

mode

CAN FD 控制器所使用的 params 数组内容

CAN.RANGE

代表接受的 ID 范围的两个 ID。

CAN.DUAL

将被接受的两个 ID。例如 (1, 2)

CAN.MASK

一个过滤器 ID 和掩码。例如 (0x111, 0x7FF)

  • rtr 对于经典 CAN 控制器,这是一个布尔值数组,指示过滤器是否应接受远程传输请求消息。如果未给出此参数,则对所有条目默认为 False。数组的长度取决于 mode 参数。对于 CAN FD,将忽略此参数。

mode

rtr 数组的长度

CAN.LIST16

4

CAN.LIST32

2

CAN.MASK16

2

CAN.MASK32

1

  • extframe 如果为 True,则帧将具有扩展标识符(29 位),否则将使用标准标识符(11 位)。

CAN.clearfilter(bank, extframe=False)

清除并禁用一个过滤器组:

  • bank 是要清除的经典 CAN 控制器过滤器组或 CAN FD 过滤器索引。

  • extframe 对于 CAN FD 控制器,如果为 True,则清除扩展过滤器(配置为 extframe=True),否则清除标准标识符(配置为 extframe=False)。

CAN.any(fifo)

如果 FIFO 上有任何消息等待,则返回 True,否则返回 False

CAN.recv(fifo, list=None, *, timeout=5000)

在总线上接收数据:

  • fifo 是一个整数,表示接收数据的 FIFO

  • list 是一个可选的列表对象,用作返回值

  • timeout 是等待接收的超时时间(以毫秒为单位)。

返回值:包含五个值的元组。

  • 消息的 ID。

  • 一个布尔值,指示消息 ID 是否为标准或扩展。

  • 一个布尔值,指示消息是否为 RTR 消息。

  • FMI(过滤器匹配索引)值。

  • 包含数据的数组。

如果 listNone,则将分配一个新的元组,以及一个新的字节对象来包含数据(作为元组的第五个元素)。

如果 list 不是 None,则它应该是一个列表对象,至少有五个元素。第五个元素应该是从 bytearray 或类型为 ‘B’ 或 ‘b’ 的数组创建的 memoryview 对象,此数组必须至少有 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)
CAN.send(data, id, *, timeout=0, rtr=False, extframe=False, fdf=False, brs=False)

在总线上发送消息:

  • *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()

如果超时为 0,则消息将放置在三个硬件缓冲区中的一个中,并立即返回该方法。如果三个缓冲区都在使用中,则会抛出异常。如果超时不为 0,则方法将等待消息发送。如果消息无法在指定时间内发送,则会抛出异常。

返回值:None

CAN.rxcallback(fifo, fun)

注册一个函数,在将消息接受到空的 fifo 时调用:

  • fifo 是接收 fifo。

  • fun 是 fifo 变为非空时要调用的函数。

回调函数接受两个参数,第一个是 CAN 对象本身,第二个是表示回调原因的整数。

原因

0

消息已被接受到空的FIFO中。

1

FIFO已满

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)

常量

CAN.NORMAL
CAN.LOOPBACK
CAN.SILENT
CAN.SILENT_LOOPBACK

init() 中使用的 CAN 总线模式。

CAN.STOPPED
CAN.ERROR_ACTIVE
CAN.ERROR_WARNING
CAN.ERROR_PASSIVE
CAN.BUS_OFF

从:meth: ` ~CAN.state()` 返回CAN控制器的可能状态。

CAN.LIST16
CAN.MASK16
CAN.LIST32
CAN.MASK32

state() 中用于经典 CAN的过滤器的操作模式。

CAN.DUAL
CAN.RANGE
CAN.MASK

用于在 setfilter() 中的 CAN FD 过滤器的操作模式。