[020] [STM32] CAN总线通信协议分析与应用

STM32
Contents
CAN物理层
CAN协议层
STM32的CAN外设
STM32的CAN控
制相关结构体
CAN通讯实验

1 CAN物理层

image-20220705103141493

CAN是一种异步通讯,只具有CAN_HighCAN_Low两条信号线,共同构成一组差分信号线,以差分信号的形式进行通讯。

物理层形式分为两种:

  • 闭环总线网络:适用于高速通讯;(最高1Mbps,距离40m

image-20220705103250029

数据传输终端实际上就是两个阻抗为120欧姆的电阻,也称为终端电阻。总线上的总阻抗大概是60-70欧姆左右。 终端电阻的大小和传输线相关。

  • 开环总线网络:适合于远距离通讯。(最高125kbps,距离1km

image-20220705103300492

1.1 通讯节点

CAN总线上可以挂载多个通讯节点,节点之间的信号经过总线传输,实现节点间通讯。

由于CAN通讯协议不对节点进行地址编码,而是对数据内容进行编码,所以网络中的节点个数理论上不受限制,只要总线的负载足够即可,可以通过中继器增强负载。

1.2 差分信号

差分(差模)信号,与传统使用单根信号线电压表示逻辑的方式有区别,使用差分信号传输时,需要两根信号线,这两个信号线的振幅相等,相位相反,通过两根信号线的电压差值来表示逻辑0和逻辑1。

image-20220705103532813

差分信号传输优点

  • 抗干扰能力强,外界的共模噪声可以被完全抵消;
  • 能有效抑制本身对外部的电磁干扰;
  • 时序定位精确;(由于差分信号的开关变化是位于两个信号的交点,而不像普通单端信号依靠高低两个阈值电压判断)

基于以上优点,USB协议、485协议、以太网协议及CAN协议的物理层中,都使用了差分信号传输。

1.2.1 CAN协议中的差分信号

CAN协议中对它使用的CAN_HighCAN_Low表示的差分信号做了规定。以高速CAN协议为例:

  • 当表示逻辑1时(隐性电平),CAN_High和CAN_Low线上的电压均为2.5v,即它们的电压差VH-VL=0V;
  • 当表示逻辑0时(显性电平),CAN_High的电平为3.5V,CAN_Low线的电平为1.5V,即它们的电压差为VH-VL=2V。

image-20220705103643827

CAN总线遵循如下逻辑:高速CAN和低速CAN的电压差大于0.9V时为显性电平(逻辑0)小于0.5V为隐性电平(逻辑1)。

image-20220705103738460

CAN网络基于**“线与”**逻辑。显性总线电平会覆盖隐性总线电平。如果不同的CAN节点同时发送显性电平和隐性电平,那么CAN总线会处于显性电平的逻辑“0”。隐性电平的逻辑“1”仅在所有CAN节点隐性传输时才发生。

在CAN总线中,必须使它处于隐性电平(逻辑1)或显性电平(逻辑0)中的其中一个状态。假如有三个CAN通讯节点,在同一时间,A/B输出隐性电平,C输出显性电平,类似I2C总线的“线与”特性将使它处于显性电平状态,即可认为显性具有优先的意味。

image-20220705103802932

2 CAN协议层

2.1 CAN的报文种类及结构

什么是报文?

当使用CAN协议进行通讯时,需要对数据、操作命令(如读/写)以及同步信号进行打包,打包后的这些内容称为报文。

当总线空闲时任何连接的单元都可以开始发送新的报文。

2.1.1 报文(帧)的种类

帧用途
数据帧 用于发送单元向接收单元传送数据的帧
遥控帧 用于接收单元向具有相同 ID 的发送单元请求数据的帧。
错误帧 用于向远端节点通知校验错误,请求重新发送上一个数据
过载帧 用于接收单元通知其尚未做好接收准备的帧
帧间隔 用于将数据帧及遥控帧与前面的帧分离开来

发送单元(TRANSMITTER):产生报文的单元被称之为报文的“发送单元”。此单元保持作为报文发送单元直到总线出现空闲或此单元失去仲裁(ARBITRATION)为止。
接收单元(RECEIVER):如果有一单元不作为报文的发送单元并且总线也不空闲,则这一单元就被称之为报文的“接收单元”。

2.1.1.1 数据帧

image-20220705104207707

D-Dominant :显性电平;R-Recessive:隐性电平

白块:显性位逻辑1;黑块:隐性位逻辑0

数据帧具有标准格式和扩展格式两种,主要区别在于ID信息的长度,标准格式的ID为11位,扩展格式的ID为29位,相对于标准帧其ID多出18位。

数据帧以一个显性位(逻辑0)开始,以7个连续的隐性位(逻辑1)结束,在它们之间,分别有仲裁段、控制段、数据段、CRC段和ACK段。

名称 描述
帧起始 表示帧的开始,产生一个bit的显性电平。
仲裁段 表示帧的优先级, 由标识符(ID)和传送帧类型(RTR)组成。
控制段 表示数据的字节数,由6个bit构成
数据段 数据的具体内容,可发送0~8 个字节的数据。
CRC段 用于校验传输是否正确。
ACK段 表示确认是否正常接收。
帧结束 表示此帧结束。

「帧起始 SOF(Start Of Frame)段」

image-20220705104348094

帧起始信号(图中色部分)只有一个数据位,是一个显性电平,它用于通知各个节点将有数据传输,其它节点通过帧起始信号的电平跳变沿来进行硬同步。

「仲裁段」

image-20220705110521144

仲裁段的内容主要为本数据帧的ID信息(标识符)和扩展/请求位,表示数据的优先级,通过对ID的仲裁来确定的。如果总线上同时出现显性电平和隐性电平,总线的状态会被置为显性电平,总线会根据仲裁段的内容决定哪个数据包能被传输。

因而CAN控制器大多具有根据ID过滤报文的功能,它可以控制自己只接收某些ID的报文。

】标准格式ID有11位,从ID28~ID18被依次发送,禁止高7位为隐性逻辑电平1(禁止格式:ID=1111111XXXX);扩展格式ID有29位,基本ID从ID28~ID18(与标准格式相同),扩展ID从ID17~ID0,同样禁止高位全为隐性。(禁止设定:基本ID=1111111XXXX)

RTR、IDE、SRR位:

  • RTR(Remote Transmission Request Bit) 远程传输请求位:它是用于区分数据帧和遥控帧的,当它全为显性电平时表示数据帧,全为隐性电平时则表示遥控帧。

  • IDE(Identifier Extension Bit) 标识符扩展位:它是用于区分标准格式与扩展格式,当它为显性电平时表示标准格式,隐性电平时表示扩展格式。

  • SRR(Substitute Remote Request Bit)替换远程请求位:只存在于扩展格式,它用于替代标准格式中的RTR位。由于扩展帧中的SRR位为隐性位,RTR在数据帧为显性位,所以在两个ID相同的标准格式报文与扩展格式报文中,标准格式的优先级较高

「控制段」

image-20220705114506780

控制段由 6 个位构成,表示数据段的字节数

  • r1r0为保留位,必须全部以显性电平发送。但接收方可以接收显性、隐性及其任意组合的电平。
  • DLC(Data Length Code)数据长度码,它由4个数据位组成,用于表示本报文中的数据段含有多少个字节,DLC段表示的数据字节数必须为 0~8 字节。但接收方对DLC = 9~15 的情况并不视为错误。数据长度码DLC和字节数的关系如下图所示:

image-20220705115003795

「数据段」

image-20220705133356535

数据段可包含 0~8 个字节的数据。从MSB(最高位)开始输出。

「CRC段」

image-20220705133443574

CRC段是检查帧传输错误的帧。由15个位的CRC 顺序11个位的CRC 界定符(隐性位,用于分隔CRC校验码与后面的ACK段)构成。

CRC部分的计算一般由CAN控制器硬件完成,出错时的处理则由软件控制最大重发数。

一旦接收节点算出的CRC码跟接收到的CRC码不同,则它会向发送节点反馈出错信息,利用错误帧请求它重新发送。

「ACK段」

image-20220705150815589

ACK段包括1个ACK应答间隙(ACK slot)位和1个ACK界定符位2

  • 发送单元的ACK段:发送2个位的隐性位。
  • 接收单元的ACK段:接收到正确消息3的单元在ACK槽发送显性位,通知发送单元正常接收结束。

「帧结束」

image-20220705152009809

EOF(End Of Frame)帧结束段,由发送节点发送的7个隐性位表示结束。

2.1.1.2 遥控帧

接收单元向发送单元请求发送数据所用的帧,由 6 个段组成,是没有数据帧的数据段。

image-20220705152155136

遥控帧和数据帧区别:遥控帧RTR位全为隐性电平,数据帧RTR位全为显性电平。此外,遥控帧没有数据端。

【Q&A】

  • 遥控帧没有数据段,其控制段中的数据长度码DLC如何表示?

遥控帧用所请求数据帧的DLC作为其DLC。

2.1.1.3 错误帧

用于在接收和发送消息时检测并通知错误的帧,由错误标志错误界定符构成。

image-20220705154518904

  • 主动错误标志:6 个连续的显性位,检测到错误条件的“错误主动”的单元通过发送主动错误标志,以指示错误。

主动错误标志的形式破坏了从起始段到CRC 界定符的位填充规则(参见“编码”),或者破坏了应答段或结束段的固定形式。导致其他单元产生错误,它们此时会检测到错误条件并与此同时开始发送错误标志。

因此,由于主动错误标志的“显性”特点,各个单独单元发送的不同的错误标志叠加在一起,该错误序列总长度最小为6个位,最大为12个位。(6 + 0~6)

  • 被动错误标志:6 个连续的极性相同的位,若为隐性位可能被其他单元的显性位重写。

错误界定符:由 8 个位的隐性位构成。错误标志传送了以后,每一单元就发送“隐性”的位并一直监视总线直到检测出一个“隐性”的位为止,然后就开始发送7位以上的“隐性”位。

2.1.1.4 过载帧

image-20220705161502920

过载帧是用于接收单元通知其尚未完成接收准备的帧,由过载标志过载界定符构成。

过载标志:6 个“显性”的位组成,其形式和主动错误标志的一样。

过载界定符:包括8 个“隐性”的位,其形式和错误界定符的一样。

2.1.1.5 帧间隔

帧间隔是用于分隔数据帧与其前面帧(数据帧、远程帧、错误帧、过载帧)的帧。

其中,过载帧和错误帧前不能插入帧间隔。

帧间隔的构成如图所示:

image-20220705162004496

间隔:3 个位的隐性位。间隔期间,所有单元均不允许传送数据帧或远程帧,唯一要做的是标示一个过载条件。

总线空闲:总线空闲的(时间)长度是任意的。只要总线被认定为空闲,任何等待发送信息的单元就会访问总线。总线上检测到的“显性”的位可被解释为帧的起始。

延迟传送(发送暂时停止):“错误被动”的单元发送报文后,会在下一报文开始传送之前或总线空闲之前发出8 个“隐性”的位跟随在间隔的后面。若与此同时另一单元开始发送报文(由另一单元引起),则此站就作为这个报文的接收器。

2.2 优先级仲裁

在总线空闲态,最先开始发送消息的单元获得发送权。

多个单元同时开始发送时,各发送单元从仲裁段的第一位开始进行仲裁。连续输出显性电平最多的单元可继续发送。其仲裁的过程如图所示:

image-20220705165707730

2.2.1 数据帧和遥控帧的优先级

具有相同 ID 的数据帧和遥控帧在总线上竞争时,仲裁段的最后一位(RTR)为显性位的数据帧具有优先权,可继续发送。

仲裁过程如下图所示,其中数据帧的RTR位为显性位,获得发送权。

image-20220705170112653

2.2.2 标准格式和扩展格式的优先级

ID相同的标准格式的数据帧与扩展格式的数据在总线上竞争时,扩展格式的SRR位为隐性,而标准格式的RTR 位为显性位,具有优先权,可继续发送。

image-20220705171620402

2.3 位时序与位同步

由于CAN属于异步通讯,没有时钟信号线,连接在同一个总线网络中的各节点使用约定好的波特率进行通讯,特别地,CAN还会使用“位同步”的方式来抗干扰、吸收误差,实现对总线电平信号进行正确的采样,确保通讯正常。

2.3.1 位时序

由发送单元在非同步的情况下发送的每秒钟的位数称为位速率。一个位可分为 4 段,分别为同步段、传播时间段、相位缓冲段1、相位缓冲段2。

每个段又由若干个Tq4组成,这称为位时序。

image-20220705173839330

▲ 段及其作用

image-20220705174058736

▲ 1个位的构成

采样点是读取总线电平,并将读到的电平作为位值的点。信号的采样点位于PBS1段之后通过控制各段的长度,可以对采样点的位置进行偏移,以便准确地采样

位时序分解:

image-20220705103932200

图中表示的CAN通讯信号每一个数据位的长度为19Tq,其中SS段占1Tq,PTS段占6Tq,PBS1段占5Tq,PBS2段占7Tq。因此,总线上的各个通讯节点只要约定好1个Tq的时间长度以及每一个数据位占据多少个Tq,就可以确定CAN通讯的波特率

假设上图中的1Tq=1us,而每个数据位由19个Tq组成,则传输一位数据需要时间T1bit =19us,从而每秒可传输的数据位个数为:1x10^6­/19 = 52631.6 (bps)

2.3.2 位同步

CAN 协议的通信方法为NRZ(Non-Return to Zero)方式。各个位的开头或者结尾都没有附加同步信号。发送单元以与位时序同步的方式开始发送数据。另外,接收单元根据总线上电平的变化进行同步并进行接收工作。

但是,发送单元和接收单元存在的时钟频率误差及传输路径上的(电缆、驱动器等)相位延迟会引起同步偏差。因此接收单元通过硬件同步或者再同步的方法调整时序进行接收。

2.3.2.1 硬同步

接收单元在总线空闲状态检测出帧起始时进行同步调整,硬同步后,内部的位时间从同步段SS重新开始。

image-20220705185447358

2.3.2.2 再同步

接收过程中检测出总线上的电平变化时进行的同步调整。(接收数据时电平理应处于稳态)

每当检测出边沿时,根据 SJW 值通过加长PBS1段,或缩短PBS2 段,以调整同步。但最大调整量不能超过SJW最大值4tq。

image-20220705191202395

2.3.2.3 调整同步的规则

硬同步和再同步遵从如下规则:

(1) 1 个位中进行一次同步调整。
(2) 只有当上次采样点的总线值和边沿后的总线值不同时,该边沿才能用于调整同步。
(3) 在总线空闲且存在隐性电平到显性电平的边沿时,则一定要进行硬件同步。
(4) 在总线非空闲时检测到的隐性电平到显性电平的边沿如果满足条件(1)和(2),将进行再同步。但还要满足下面条件。
(5) 发送单元观测到自身输出的显性电平有延迟时不进行再同步。
(6) 发送单元在帧起始到仲裁段有多个单元同时发送的情况下,对延迟边沿不进行再同步。

时序与同步等小节中某些知识点仅浅尝辄止,具体可参看文件夹中相关手册。

3 STM32的CAN外设

STM32的芯片中具有bxCAN控制器 (Basic Extended CAN),它支持CAN协议2.0A和2.0B标准,最高通讯速率为1Mb/s,两个 bxCAN 单元共享 512 字节 SRAM 存储。(注意CAN2为从 bxCAN,无法直接访问 SRAM 存储器。)

发送

  • 三个发送邮箱
  • 可配置发送报文的优先级,由报文标识符或发送的请求次序决定
  • 可记录发送报文SOF时刻的时间戳

接收

  • 2个具有三级深度的接收 FIFO

  • 28个可配置的报文过滤(筛选)器组,CAN1和CAN2共用28个过滤器。可设为32或16位模式,屏蔽位或标识符列表模式。

  • 可配置FIFO上溢与SOF接收时间戳

    image-20220705195435796

▲ STM32双CAN框图

3.1 CAN工作模式

bxCAN 有三种主要的工作模式:初始化、正常和睡眠。 跳转到的地方

image-20220706090230417

3.1.1 睡眠模式

进入条件

  • 硬件复位后
  • CAN_MCR 寄存器的SLEEP位置1。

功能特点:bxCAN时钟停止,同时 CANTX 上的内部上拉电阻激活,但软件仍可访问 bxCAN邮箱。

退出条件

  • bxCAN 处于睡眠模式时,软件将INRQ位置1请求进入初始化模式,与此同时必须将SLEEP位清零。
  • 软件将 SLEEP 位清零或是检测到 CAN 总线活动时,bxCAN 即被唤醒。其中当检测CAN活动时:
    • 若CAN_MCR寄存器AWUM位置1(使能硬件自动唤醒)或CAN_IER寄存器的WKUIE位置1(使能唤醒中断),硬件清除SLEEP位自动执行唤醒序列
    • 若上述两位均为0,发生唤醒中断时,软件必须将 SLEEP 位清 零才能退出睡眠模式。

SLEEP位清零后,一旦 bxCAN与CAN 总线同步,硬件将 SLAK 位清零,即退出睡眠模式。

3.1.2 初始化模式

进入条件:软件将 CAN_MCR 寄存 器的 INRQ 位置 1,并等待硬件通过将 CAN_MCR 寄存器的 INAK 位置 1 来确认请求。

功能特点

  • 所有从 CAN 总线传入和传出的消息都将停止,并且 CAN 总线输出 CANTX 的状态为隐性(高)
  • 为初始化CAN控制器,软件必须设置位定时 (CAN_BTR) 和 CAN 选项 (CAN_MCR) 寄存器。
  • 为初始化与CAN筛选器组相关的寄存器),软件必须FINIT位 (CAN_FMR) 置 1。(FINIT位置1时,CAN收发停用)。筛选器值也可通过停用(CAN_FA1R 寄存器的)相关筛选器激活位来修改。

筛选器的初始化也可以在初始化模式之外进行。

如果某个筛选器组未使用,建议将其保持未激活状态(将相应 FACT 位保持清零)。

退出条件:软件将 INQR 位清零,一旦硬件将 INAK 位清零,bxCAN 即退出初始化

3.1.3 正常模式

初始化完成,软件必须向硬件请求进入正常模式,这样才能在 CAN 总线上进行同步, 并开始接收和发送。

进入条件:CAN_MCR 寄存器的 INRQ 位清零,并等待出现一个由 11 个连续隐性位(总线空闲状态)组成的序列,即进入正常模式。硬件通过将 CAN_MSR 寄存器的 INAK 位清零,来确认切换到正常模式。

功能特点:正常通信收发数据

退出条件:SLEEP或INRQ位置1

3.2 CAN控制内核

CAN框图标号①处的CAN控制内核包含了各种控制寄存器及状态寄存器,主要分析主控制寄存器CAN_MCR和CAN_BTR寄存器。

3.2.1 主控制寄存器CAN_MCR

  • DBF调试冻结功能

DBF(Debug freeze)调试冻结,调试模式下(DBG外设模块中CAN1 的 DBG_CAN1_STOP 位或者 CAN2 的 DBG_CAN2_STOP置位),使CAN处于工作状态或禁止收发的状态,禁止收发时仍可访问接收FIFO中的数据。(注意该位不会影响正常模式)

  • TTCM时间戳触发模式

【Why】CAN通信总线繁忙时,容易造成低优先级的消息长时间阻塞,甚至无法满足其时限要求,时间戳触发模式可解决该瓶颈。

【What】TTCM(Time triggered communication mode)时间触发模式,它用于配置CAN的时间触发通信模式,在此模式下,CAN使用它内部定时器产生时间戳,并把它保存在CAN_RDTxR、CAN_TDTxR寄存器中。内部定时器在每个CAN位时间累加,在接收和发送帧起始位被采样,并生成时间戳。利用它可以实现ISO 11898-4 CAN标准的分时同步通信功能。

  • ABOM自动离线管理

ABOM(Automatic bus-off management) 自动离线管理,它用于设置是否使用自动离线管理功能。当节点检测到它发送错误或接收错误超过一定值时,会自动进入离线状态,在离线状态中,CAN不能接收或发送报文。处于离线状态的时候,可以软件控制恢复或者直接使用这个自动离线管理功能,它会在适当的时候自动恢复。

  • AWUM自动唤醒

AWUM(Automatic bus-off management),自动唤醒功能,CAN外设可以使用软件进入低功耗的睡眠模式,如果使能了这个自动唤醒功能,当CAN检测到总线活动的时候,会自动唤醒。

  • NART自动重传

NART(No automatic retransmission)报文自动重传功能,设置这个功能后,当报文发送失败时会自动重传至成功为止。若不使用这个功能,无论发送结果如何,消息只发送一次。

  • RFLM锁定模式

RFLM(Receive FIFO locked mode)FIFO锁定模式,该功能用于锁定接收FIFO。锁定后,当接收FIFO溢出时,会丢弃下一个接收的报文。若不锁定,则下一个接收到的报文会覆盖原报文。

  • TXFP报文发送优先级的判定方法

TXFP(Transmit FIFO priority)报文发送优先级的判定方法,当CAN外设的发送邮箱中有多个待发送报文时,本功能可以控制它是根据报文的ID优先级还是报文存进邮箱的顺序来发送。

3.2.2 测试模式

为方便调试,STM32的CAN提供了测试模式,配置位时序寄存器CAN_BTR的SILM及LBKM寄存器位可以控制使用正常(normal)模式、静默(silent)模式、回环(loopback)模式及静默回环(silent loopback)模式。

image-20220706103645265

  • 静默模式

CAN_BTR的SILM位置1。

节点不能向总线发送显性位(逻辑0),若发送会将其输出端的逻辑0传回至自己的输入端;隐性位(逻辑1)可正常发送至总线。因此,此模式不会影响总线状态,所以称之为silent mode。

  • 回环模式

CAN_BTR的LBKM位置1。

输出端消息会传回输入端,同时会发送至总线。输入端只接收自己发送端的内容,不接收来自总线上的内容。使用回环模式可以进行自检。

  • 静默回环模式

CAN_BTR的SILMLBKM位均置1。

给回环模式加了个限制条件:仅可向总线发送隐性位(向自己发送不收影响)。此方式可在“热自检”时使用,即自我检查的时候,不会干扰总线。

3.3 位时序与波特率

3.3.1 位时序

STM32外设位时序与CAN标准时序有一点区别:

image-20220706105501878

  • 同步段 (SYNC_SEG):长度固定为1tq,位变化应该在此时间段内发生。
  • 位段 1 (BS1):定义采样点的位置。包括标准CAN中的PTS 与 PBS1,长度为1~16 Tq,通过CAN_BTR位时序寄存器的TS1[3:0]设置。其长度可在再同步期间增长或缩短,以补偿负相位漂移。
  • 位段 2 (BS2):定义发送点的位置。包括标准CAN中PBS2,长度为1~8 Tq,通过CAN_BTR位时序寄存器的TS2[2:0]设置。其长度可在再同步期间增长或缩短,以补偿负相位漂移。

时序调整

再同步跳转宽度 (SJW) 定义位段加长或缩短的上限。它可在1~4 Tq间调整,在CAN_BTR中配置。

  • 若在 BS1 而不是 SYNC_SEG 中检测到有效边沿,则 BS1 会延长最多 SJW,以便延迟采样点
  • 若在 BS2 而不是 SYNC_SEG 中检测到有效边沿,则 BS2 会缩短最多 SJW,以便提前发送点

为了避免编程错误,位时序寄存器 (CAN_BTR) 只能在器件处于睡眠(待机)模式时进行配置。

「有效边沿」指一个位时间内总线电平从显性到隐性第一次转换(前提是控制器本身不发送隐性位)。

3.3.2 CAN通讯波特率计算

  • BS1段时间:TS1=Tq x (TS1[3:0] + 1)

  • BS2段时间:TS2= Tq x (TS2[2:0] + 1)

  • 一个数据位的时间:T1bit =1 +TS1+TS2 = [1+ (TS1[3:0] + 1)+ (TS2[2:0] + 1)] = N Tq

Tq与CAN外设的所挂载的时钟总线及分频器配置有关。其中,CAN1和CAN2外挂载在APB1总线上,CAN_BTR寄存器中的BRP[9:0]位配置CAN外设时钟分频值。因此:

Tq = TPCLK * (BRP[9:0]+1)

则CAN通讯的波特率:Bps = 1 / (N * Tq) = Fq / N

Fq为时间长度的倒数, Fq = FPCLK / (BRP[9:0]+1),个人倾向于此种计算方法。

一种把波特率配置为1Mbps的方式:

参数 说明
SYNC_SE段 固定为1Tq
BS1段 设置为5Tq (实际写入TS1[3:0]的值为4)
BS2段 设置为3Tq (实际写入TS2[2:0]的值为2)
TPCLK APB1按默认配置为F=36MHz,TPCLK=1/36M
CAN外设时钟分频 设置为4分频(实际写入BRP[9:0]的值为3)
1Tq时间长度 Tq = (BRP[9:0]+1) x TPCLK = 4 x 1/36M=1/9M
1位的时间长度 T1bit =1Tq+TS1+TS2 = 1+5+3 = 9Tq
波特率 BaudRate = 1/(N * Tq) = 1/(1/9M x 9)=1Mbps

用频率计算:FPCLK / (BRP[9:0]+1) * T1bit = 36 / 4 / (1+5+3) = 1Mbps

对应代码:

//配置成1Mbps
CAN_InitTypeStruct.CAN_BS1 = CAN_BS1_5tq;	// 实际写入TS1[3:0]的值为4
CAN_InitTypeStruct.CAN_BS2 = CAN_BS2_3tq;	// 实际写入TS2[3:0]的值为2
CAN_InitTypeStruct.CAN_SJW = CAN_SJW_2tq;
CAN_InitTypeStruct.CAN_Prescaler = 4;		// 实际写入BRP[9:0]的值为3

3.4 CAN发送邮箱

CAN外设一共有3个发送邮箱,即最多可以缓存3个待发送的报文

每个发送邮箱中包含有标识符寄存器CAN_TIxR、数据长度控制寄存器CAN_TDTxR及2个数据寄存器CAN_TDLxRCAN_TDHxR,它们的功能如下:

寄存器名 功能
标识符寄存器CAN_TIxR 存储待发送报文的ID、扩展ID、IDE位及RTR位
数据长度控制寄存器CAN_TDTxR 存储待发送报文的DLC段
低位数据寄存器CAN_TDLxR 存储待发送报文数据段的Data0-Data3这四个字节的内容
高位数据寄存器CAN_TDHxR 存储待发送报文数据段的Data4-Data7这四个字节的内容
发送状态寄存器CAN_TSR 设置发送/中止请求、发送优先级,指示发送成功/失败、仲裁丢失、邮箱空标志

标识符:对于CAN_TIxR的STID位。当报文使用扩展标识符(IDE位置1)时,STDID[10:0]=EXTID[18:28]位,它与EXTID[17:0]组成完整的29位扩展标识符。

发送流程

将CAN_TIxR中的发送请求寄存器位TXRQ置1,选择一个发送邮箱,此时邮箱会进入挂起状态,等待成为「发送优先级」最高的邮箱,一但此邮箱拥有最高优先级,将被安排发送,当CAN总线空闲时,即可将标识符、数据长度码DLC和0~8位数据组成报文发送出去。邮箱 一旦发送成功,即恢复空状态。

发送标志

  • 若发送成功,硬件通过将 CAN_TSR 寄存器的 RQCP位(发送邮箱请求完成)和 TXOK 位(发送成功)置1。
  • 若发送失败,将由 CAN_TSR 寄存器的ALST位(仲裁丢失)and/or TERR 位(检 测到发送错误)指示失败原因。

发送优先级

当多个发送邮箱挂起时,按以下规则决定发送顺序。

  • 发送请求顺序(CAN_MCR寄存器的TXFP置1):此时各发送邮箱按请求先后次序发送消息;
  • 报文标识符(CAN_MCR寄存器的TXFP置0):发送顺序由邮箱中所存消息的标识符确定,由CAN协议知,标识符(ID)值最低的消息拥有最高的优先级(显性位0占比高)。若标识符相等低编号的邮箱有更高的优先级。

发送中止

将CAN_TSR 寄存器的 ABRQ 位置 1,即可中止发送请求。

  • 此时若邮箱为挂起预发送状态,则立即停止发送
  • 若邮箱处于发送状态请求中止,则:
    • 若邮箱已成功发送,变为状态,CAN_TSR 寄存器的 TXOK 位置 1
    • 若发送失败,邮箱变为预发送状态,发送中止并变为状态,同时 TXOK 位清零

上述所有情况,邮箱均为变为状态。

image-20220706145547615

▲ 发送邮箱状态机

3.5 CAN接收FIFO

CAN外设一共有2个接收FIFO,每个FIFO中有3个邮箱,即最多可缓存6个接收到的报文。FIFO完全由硬件进行管理,应用程序通过 FIFO 输出邮箱访问 FIFO中所存储 的消息。

下列寄存器FIFO0FIFO1各拥有1个

寄存器名 功能
标识符寄存器CAN_RIxR 存储收到报文的基本ID、扩展ID、IDE位及RTR位
数据长度控制寄存器CAN_RDTxR 存储收到报文的DLC段
低位数据寄存器CAN_RDLxR 存储收到报文数据段的Data0-Data3
高位数据寄存器CAN_RDHxR 存储收到报文数据段的Data4-Data7
接收FIFO寄存器CAN_RFxR 指示挂起的消息数(0~3)、FIFO满/上溢标志,释放邮箱位控制

FIFO管理

有效消息:消息依据 CAN 协议正确接收(直到 EOF 字段的倒数第二位都没有发送错误)并成功通过标识符筛选,即视为有效。

初始状态FIFO为空,在接收到第一条有效消息存至其中后,变为Pending_1状态。CAN_RFxR的FMPx位(FIFO的报文计数器)会自增1,即FMP=0x01。软件读取FIFO数据后,通过将 CAN_RFxR 寄存器的 RFOM 位置 1,以释放邮箱(释放完后RFOM自动清零),此时FMPx自减1。邮箱恢复至空状态。(如果同时接收到新的有效消息,FIFO 将保持 Pending_1 状态,新消息将在输出邮箱中供读取。)

若软件未释放邮箱,下一条有效消息存至FIFO后,进入Pending_2状态(FMP=0x02)。以此类推,下一条有效消息使其进入Pending_3状态(FMP=0x03),3个邮箱均为

上溢

当邮箱均为满时,下一条消息会使其发生上溢FOVR位置1,导致该消息丢失,因此一般读完FIFO后就要释放邮箱。其中,消息丢弃方式取决于CAN_MCR的RFLM位:

  • 锁定模式(RFLM=1):FIFO溢出时会丢弃新报文
  • 非锁定模式(RFLM=0):FIFO溢出时会新报文会覆盖旧报文

image-20220706171305167

▲ 接收FIFO状态机

3.6 标识符筛选

CAN外设的验收筛选器,一共有28个筛选器组,每个筛选器组有2个寄存器,CAN1和CAN2共用一个筛选器。

CAN中标识符与节点地址无关,而与报文内容(仲裁段ID)有关,接收器根据报文标识符ID的值来确定是否接收,CAN外设中的筛选器可调整筛选ID的长度及过滤模式,不符合规则的报文被硬件丢弃。

筛选器尺度寄存器(CAN_FS1R)的FSCx位可设置28个筛选器的筛选ID长度,仅当筛选器在初始化模式(CAN_FMR的FINIT位为1)才可以设置:

  • FSCx = 1:单32位尺度,检查STDID[10:0]、 EXTID[17:0]、 IDE 和 RTR 位,末尾补个0位,一共32位
  • FSCx = 0:单16位尺度,检查STDID[10:0]、 RTR、 IDE 和 EXTID[17:15],一共16位

筛选器模式寄存器 (CAN_FM1R)的FBMx位可设置过滤方法(筛选器在初始化模式):

  • FBMx= 1:标识符列表模式,CAN_FxR1和CAN_FxR2均作为标识符寄存器,接收报文标识符ID的必须与其中一个标识符寄存器完全一致才通过筛选。
  • FBMx= 0:标识符屏蔽(掩码)模式,两个寄存器分别作为标识符寄存器和屏蔽寄存器,两者配合使用,可设置屏蔽寄存器某几位可作为掩码,只要掩码相同即通过筛选。

image-20220706195023458

要筛选一组标识符,应将掩码/标识符寄存器配置为掩码模式。
要选择单个标识符,应将掩码/标识符寄存器配置为标识符列表模式。
未使用的筛选器应保持停用。

image-20220706191304228

模式 说明
32位掩码模式 CAN_FxR1存储要筛选的ID,CAN_FxR2存储掩码,掩码为1的部分表示该位必须与ID中的内容一致。
32位标识符模式 CAN_FxR1和CAN_FxR2各存储1个ID,2个寄存器表示2个筛选的ID
16位掩码模式 CAN_FxR1低16位存储要筛选的ID,高16位存储掩码,掩码为1的部分表示必须要与低16位的ID一致;CAN_FxR2低16位存储要筛选的ID,高16位存储掩码,掩码为1的部分必须要与低16位的ID一致。
16位标识符模式 CAN_FxR1和CAN_FxR2各存储2个ID,2个寄存器表示4个筛选的ID

3.6.1 筛选器匹配索引

【why】消息接收到FIFO后,应用程序为将数据复制到正确的位置,需要根据标识符来识别数据。为了方便APP区分报文数据、方便访问SRAM位置,CAN控制器提供了一个筛选器匹配索引。

【what】CAN控制器给通过筛选器的报文提供了筛选器编号,该编号存放在CAN_RDTxR寄存器的FMI[7:0]位中,编号时不考虑过滤器是否激活。因此,每条成功接收的报文都有与之匹配的筛选器编号。

【how】

筛选器匹配索引有两种用法:

  • 将筛选器匹配索引用作阵列索引,以访问数据目标位置。
  • 将筛选器匹配索引与预期值列表进行比较。

对于标识符列表模式的筛选器,APP不再需要比较标识符,可直接比较筛选器索引。

对于标识符掩码模式的筛选器,APP只需比较掩码(屏蔽)位。

CAN控制器对于两个FIFO使用独立的编号方案,示例如下图所示:

image-20220707095208379

▲ 筛选器编号示例

3.6.2 筛选器优先级

当出现某个报文标识符通过多个筛选器时,将根据以下优先级规则选择接收邮箱中存储的筛选器匹配值:

  • 32位筛选器优先于16位筛选器。
  • 对于尺度(16/32位)相等的筛选器,标识符列表模式优先于标识符掩码模式。
  • 对于尺度和模式均相等的筛选器,则按筛选器编号确定优先级(编号越低,优先级越高)。

筛选优先级机制如下图所示,有3个筛选器组为32位标识符列表模式,其余处于32位标识符掩码模式。

image-20220707100919924

根据筛选器优先级规则,当前接收到的消息首先与32位标识符列表模式的筛选器组比较,若匹配则将消息存储到相应的FIFO中,将该筛选器的匹配索引存至CAN_RDTxR寄存器的FMI[7:0]中。若不匹配,则接收消息的标识符继续与后面的32位标识符掩码模式的筛选器比较,若标识符与筛选器中配置的任何标识符均不匹配,则丢弃该消息。

图中接收消息的标识符与标识符#4匹配。

3.7 CAN中断

CAN有四个中断向量:发送中断、FIFO0中断、FIFO1中断、错误和状态改变中断,每个中断通过中断使能寄存器 (CAN_IER) 来单独使能或禁止。

image-20220707103335810

发送中断可由以下事件产生:

  • 发送邮箱 0 变为空,CAN_TSR 寄存器的 RQCP0 位置 1。
  • 发送邮箱 1 变为空,CAN_TSR 寄存器的 RQCP1 位置 1。
  • 发送邮箱 2 变为空,CAN_TSR 寄存器的 RQCP2 位置 1。

FIFO 0中断可由以下事件产生:

  • 接收到新消息,CAN_RF0R 寄存器的 FMP0 位不是“00”。
  • FIFO0 满,CAN_RF0R 寄存器的 FULL0 位置 1。
  • FIFO0上溢,CAN_RF0R 寄存器的 FOVR0 位置 1。

FIFO 1中断可由以下事件产生:

  • 接收到新消息,CAN_RF1R 寄存器的 FMP1 位不是“00”。
  • FIFO0 满,CAN_RF1R 寄存器的 FULL1 位置 1。
  • FIFO0上溢,CAN_RF1R 寄存器的 FOVR1 位置 1。

错误和状态改变中断可由以下事件产生:

  • 出错状况,具体参考CAN_ESR寄存器中的LEC上次错误代号。BOFF离线状态标志、EPVF错误被动标志。EWGF错误警告标志。
  • 唤醒状况,CAN Rx 信号上监测到 SOF(start of frame 帧起始,详见前文CAN时序),于此同时CAN_MSR的WUKI被硬件置1。
  • 进入睡眠模式(CAN_MSR的SLAKI置1进入)

4 STM32的CAN控制相关结构体

4.1 CAN初始化结构体

typedef struct
{
    
    
  uint16_t CAN_Prescaler;    /* 配置CAN外设的时钟分频,可设置为1-1024 注意:固件库做了-1处理!*/
  uint8_t CAN_Mode;          /* 配置CAN的工作模式,(静默)回环或(静默)正常模式 */
  uint8_t CAN_SJW;           /* 配置SJW的极限长度,即CAN重新同步时单次可增加或缩短的最大长度,可配置为1~4Tq 写入0即为1Tq */
  uint8_t CAN_BS1;           /* 配置BS1段的长度,可配置为1~16Tq 写入0即为1Tq */
  uint8_t CAN_BS2;           /* 配置BS2段的长度,可配置为1~8Tq 写入0即为1Tq */
  FunctionalState CAN_TTCM;  /* 是否使能TTCM时间触发功能 */
  FunctionalState CAN_ABOM;  /* 是否使能ABOM自动离线管理功能 */
  FunctionalState CAN_AWUM;  /* 是否使能AWUM自动唤醒功能 */
  FunctionalState CAN_NART;  /* 是否使能NART自动重传功能 */
  FunctionalState CAN_RFLM;  /* 是否使能RFLM锁定FIFO功能 */
  FunctionalState CAN_TXFP;  /* 配置TXFP报文优先级的判断方法*/
} CAN_InitTypeDef;
  • CAN_Prescaler

设置CAN外设的时钟分频,它可控制时间片Tq的时间长度,这里设置的值最终会减1后再写入BRP寄存器位,即前面介绍的Tq计算公式: Tq = (BRP[9:0]+1) x TPCLK 等效于:Tq = CAN_Prescaler x TPCLK

  • CAN_Mode

设置CAN的工作模式,可设置为正常模式(CAN_Mode_Normal)、回环模式(CAN_Mode_LoopBack)、静默模式(CAN_Mode_Silent)以及回环静默模式(CAN_Mode_Silent_LoopBack)。

  • CAN_SJW

配置SJW的极限长度,即CAN重新同步时单次可增加或缩短的最大长度,它可以被配置为1-4Tq

  • CAN_BS1

设置CAN位时序中的BS1段的长度,它可以被配置为1-16个Tq长度。

  • CAN_BS2

设置CAN位时序中的BS2段的长度,它可以被配置为1-8个Tq长度

  • CAN_TTCM

设置是否使用时间触发功能(ENABLE/DISABLE),时间触发功能在某些CAN标准中会使用到。

  • CAN_ABOM

设置**是否使用自动离线管理(**ENABLE/DISABLE),使用自动离线管理可以在节点出错离线后适时自动恢复,不需要软件干预。

  • CAN_ AWUM

设置是否使用自动唤醒功能(ENABLE/DISABLE),使能自动唤醒功能后它会在监测到总线活动后自动唤醒。

  • CAN_NART

设置是否使用自动重传功能(ENABLE/DISABLE),使用自动重传功能时,会一直发送报文直到成功为止。

  • CAN_RFLM

设置是否使用锁定接收FIFO(ENABLE/DISABLE),锁定接收FIFO后,若FIFO溢出时会丢弃新数据,否则在FIFO溢出时以新数据覆盖旧数据。

  • CAN_TXFP

设置发送报文的优先级判定方法(ENABLE/DISABLE),使能时,以报文存入发送邮箱的先后顺序来发送,否则按照报文ID的优先级来发送。

4.2 CAN发送及接收结构体

4.2.1 发送结构体

typedef struct
{
    
    
  uint32_t StdId;  /* 存储报文的标准标识符11位,0-0x7FF */
  uint32_t ExtId;  /* 存储报文的扩展标识符29位,0-0x1FFFFFFF */
  uint8_t IDE;     /* 存储IDE扩展标志 */
  uint8_t RTR;     /* 存储RTR远程帧标志 */
  uint8_t DLC;     /* 存储报文数据段的长度,0-8 */
  uint8_t Data[8]; /* 存储报文数据段的内容 */
} CanTxMsg;
  • StdId

存储报文的11位标准标识符,范围是0-0x7FF

ExtId

存储报文的29位扩展标识符,范围是0-0x1FFFFFFF。ExtId与StdId这两个成员根据下面的IDE位配置,只有一个是有效的。

  • IDE

存储扩展标志IDE位,当它的值为宏CAN_ID_STD时表示本报文是标准帧,使用StdId成员存储报文ID;当它的值为宏CAN_ID_EXT时表示本报文是扩展帧,使用ExtId成员存储报文ID。

  • RTR

存储报文类型标志RTR位,当它的值为宏CAN_RTR_Data时表示本报文是数据帧;当它的值为宏CAN_RTR_Remote时表示本报文是遥控帧,由于遥控帧没有数据段,所以当报文是遥控帧时,下面的Data[8]成员的内容是无效的。

  • DLC

存储数据帧数据段的长度,它的值的范围是0-8,当报文是遥控帧时DLC值为0。

  • Data[8]

存储数据帧中数据段的数据。

4.2.2 接收结构体

typedef struct
{
    
    
  uint32_t StdId;  /* 存储了报文的标准标识符11位,0-0x7FF */
  uint32_t ExtId;  /* 存储了报文的扩展标识符29位,0-0x1FFFFFFF */
  uint8_t IDE;     /* 存储了IDE扩展标志 */
  uint8_t RTR;     /* 存储了RTR远程帧标志 */
  uint8_t DLC;     /* 存储了报文数据段的长度,0-8 */
  uint8_t Data[8]; /* 存储了报文数据段的内容 */
  uint8_t FMI;     /* 存储了筛选器的编号 */
} CanRxMsg

4.3 CAN筛选器结构体

typedef struct
{
    
    
  uint16_t CAN_FilterIdHigh;              /* CAN_FxR1寄存器的高16位 */
  uint16_t CAN_FilterIdLow;               /* CAN_FxR1寄存器的低16位 */
  uint16_t CAN_FilterMaskIdHigh;          /* CAN_FxR2寄存器的高16位 */
  uint16_t CAN_FilterMaskIdLow;           /* CAN_FxR2寄存器的低16位 */
  uint16_t CAN_FilterFIFOAssignment;      /* 设置经过筛选后数据存储到哪个接收FIFO FIFO0/FIFO1*/
  uint8_t CAN_FilterNumber;               /* 筛选器编号,范围0~27 F103:0~13 */
  uint8_t CAN_FilterMode;                 /* 筛选器模式 标识符列表/标识符掩码*/
  uint8_t CAN_FilterScale;                /* 设置筛选器的尺度 32位/16位*/
  FunctionalState CAN_FilterActivation;   /* 是否使能本筛选器 */
} CAN_FilterInitTypeDef;
模式 CAN_FilterIdHigh CAN_FilterIdLow CAN_FilterMaskIdHigh CAN_FilterMaskIdLow
32位列表模式 ID1的高16位 ID1的低16位 ID2的高16位 ID2的低16位
16位列表模式 ID1的完整数值 ID2的完整数值 ID3的完整数值 ID4的完整数值
32位掩码模式 ID1的高16位 ID1的低16位 ID1掩码的高16位 ID1掩码的低16位
16位掩码模式 ID1的完整数值 ID2的完整数值 ID1掩码的完整数值 ID2掩码完整数值

5 CAN通讯实验

将CAN配置为回环模式,采用串口打印出在CAN中断接收到的消息。

5.1 外设初始化

  • GPIO初始化
void CAN_GPIO_Config(void)
{
    
    
	GPIO_InitTypeDef GPIO_InitStructure;

	/* 使能CAN时钟 */
	RCC_APB1PeriphClockCmd (RCC_APB1Periph_CAN1 , ENABLE );

	/* 使能CAN引脚相关的时钟 */
	RCC_APB2PeriphClockCmd ( CAN_GPIO_CLK|RCC_APB2Periph_AFIO, ENABLE );
	
	/* 配置CAN的引脚,普通IO即可 */
	GPIO_InitStructure.GPIO_Pin = CAN_TX_GPIO_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Init(CAN_TX_GPIO_PROT, &GPIO_InitStructure);

	/* 配置CAN的引脚,普通IO即可 */
	GPIO_InitStructure.GPIO_Pin = CAN_RX_GPIO_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_Init(CAN_RX_GPIO_PORT, &GPIO_InitStructure);
}
  • CAN模式配置
void CAN_Mode_Config(void)	
{
    
    

	CAN_InitTypeDef CAN_InitTypeStruct;
	
	CAN_InitTypeStruct.CAN_ABOM = ENABLE; /* 是否使能ABOM自动离线管理功能 */
	CAN_InitTypeStruct.CAN_AWUM = ENABLE; /* 是否使能AWUM自动唤醒功能 */
	CAN_InitTypeStruct.CAN_Mode = CAN_Mode_LoopBack;//CAN_Mode_Normal;//调试时建议使用回环模式,调试完再改成NORMAL
	CAN_InitTypeStruct.CAN_NART = ENABLE;  /* 是否使能NART自动重传功能 */  //错误重传
	CAN_InitTypeStruct.CAN_RFLM = ENABLE;  /* 是否使能RFLM锁定FIFO功能 */
	CAN_InitTypeStruct.CAN_TTCM = DISABLE; /* 是否使能TTCM时间触发功能 */
	CAN_InitTypeStruct.CAN_TXFP = DISABLE; /* 配置TXFP报文优先级的判断方法*/ //DISABLE 按报文ID优先级来发送
	
	//配置成1Mbps
	CAN_InitTypeStruct.CAN_BS1 = CAN_BS1_5tq;   // 实际写入TS1[3:0]的值为4
	CAN_InitTypeStruct.CAN_BS2 = CAN_BS2_3tq;   // 实际写入TS2[3:0]的值为2
	CAN_InitTypeStruct.CAN_SJW = CAN_SJW_2tq;
	CAN_InitTypeStruct.CAN_Prescaler = 4;       // 实际写入BRP[9:0]的值为3
	
	CAN_Init(CAN1,&CAN_InitTypeStruct);
}

波特率配置为1M

  • CAN筛选器配置
#define PASS_ID   ((uint32_t)0x1314)
void CAN_Filter_Config(void)
{
    
    
	CAN_FilterInitTypeDef CAN_FilterInitTypeStruct;
	
	CAN_FilterInitTypeStruct.CAN_FilterActivation = ENABLE;   /* 是否使能本筛选器 */
	CAN_FilterInitTypeStruct.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;  /* 设置经过筛选后数据存储到哪个接收FIFO */
	CAN_FilterInitTypeStruct.CAN_FilterNumber = 0; /* 筛选器编号,范围0~27 F103:0~13 */
	CAN_FilterInitTypeStruct.CAN_FilterScale = CAN_FilterScale_32bit;  /* 设置筛选器的尺度 */
	CAN_FilterInitTypeStruct.CAN_FilterMode = CAN_FilterMode_IdMask; /* 筛选器模式 */
	
    // CAN_Id_Extended使用扩展帧, CAN_RTR_Data为数据帧
    // 左移3位是因为此摸下低3位分别为0、RTR、IDE(详见标识符筛选)
    CAN_FilterInitTypeStruct.CAN_FilterIdHigh = ((PASS_ID << 3 | CAN_Id_Extended | CAN_RTR_Data) & 0xFFFF0000) >> 16; /* CAN_FxR1寄存器的高16位 */
    CAN_FilterInitTypeStruct.CAN_FilterIdLow = ((PASS_ID << 3 | CAN_Id_Extended | CAN_RTR_Data) & 0xFFFF);            /* CAN_FxR1寄存器的低16位 */

    //掩码均为1表示报文标识符必须全部与筛选器中存储的ID一致,  即可视为列表模式
	CAN_FilterInitTypeStruct.CAN_FilterMaskIdHigh = 0xFFFF;  /* CAN_FxR2寄存器的高16位 */
	CAN_FilterInitTypeStruct.CAN_FilterMaskIdLow = 0xFFFF;	 /* CAN_FxR2寄存器的低16位 */  

	CAN_FilterInit(&CAN_FilterInitTypeStruct);
	
	CAN_ITConfig (CAN1, CAN_IT_FMP0, ENABLE);  // CAN_IT_FMP0 接收邮箱0中断
}

image-20220707151601045

  • CAN接收NVIC中断配置
void CAN_NVIC_Config(void)
{
    
    
	NVIC_InitTypeDef NVIC_InitStructure;

	/* 配置NVIC为优先级组1 */
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

	NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;  //接收邮箱0
	/* 配置抢占优先级 */
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	/* 配置子优先级 */
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	/* 使能中断通道 */
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	
	NVIC_Init(&NVIC_InitStructure);
}

5.2 收发数据

  • 发送数据
uint8_t mailbox;
//发送扩展帧
CAN_Tran_Data.StdId = 0; /* 存储报文的标准标识符11位,0-0x7FF */
CAN_Tran_Data.ExtId = PASS_ID;
CAN_Tran_Data.RTR = CAN_RTR_Data;       // 数据帧(CAN_RTR_Remote为遥控帧)
CAN_Tran_Data.IDE = CAN_Id_Extended; 
CAN_Tran_Data.DLC = 8; /* 存储了报文数据段的长度,0-8 */
memset(CAN_Tran_Data.Data, 'a', 8);
mailbox = CAN_Transmit(CAN1, &CAN_Tran_Data);  //CAN_Transmit 函数返回值为邮箱编号
while(CAN_TransmitStatus(CAN1, mailbox) == CAN_TxStatus_Failed); //检测数据是否传输完成		 
printf("\r\n 数据包发送完成\r\n");
  • CAN中断接收数据
void USB_LP_CAN1_RX0_IRQHandler(void)	
{
    
    
    if (CAN_GetITStatus(CAN1, CAN_IT_FMP0) != RESET)
    {
    
    
        CAN_ClearITPendingBit(CAN1, CAN_IT_FMP0);
        
        CAN_Receive(CAN1, CAN_FIFO0, &CAN_Rece_Data); 
        if(CAN_Rece_Data.ExtId == PASS_ID && CAN_Rece_Data.IDE == CAN_ID_EXT && CAN_Rece_Data.DLC == 8)  //确定ID 扩展帧  报文数据段的长度
            rec_flag = 1;
    }
}

打印出接收的数据:

if(rec_flag == 1)
{
    
    
    printf("\r\n接收到的数据: ");
    for(int i = 0; i < 8; i++)
        printf("%c ",CAN_Rece_Data.Data[i]);  //在USB_LP_CAN1_RX0_IRQHandler中接收
    printf("\r\n");
    rec_flag = 0;
}

参考

  • CAN协议中文版.pdf
  • CAN总线入门.pdf
  • 「野火」CAN—通讯实验(第1~3节).pptx
  • STM32F4xx中文参考手册.pdf

  1. CRC 顺序是根据多项式生成的CRC 值,CRC 的计算范围包括帧起始、仲裁段、控制段、数据段。接收方以同样的算法计算 CRC 值并进行比较,不一致时会通报错误。 ↩︎

  2. 将ACK应答间隙与帧结束符隔开,必须为“隐性” ↩︎

  3. 指不含填充错误、格式错误、CRC 错误的消息 ↩︎

  4. Time Quantum-最小时间单位 ↩︎

猜你喜欢

转载自blog.csdn.net/kouxi1/article/details/125665976