CAN总线详解

CAN过滤器详解 需要了解的知识:
1.CAN:Controller Area Network,控制器局域网
2.CAN-bus: Controller Area Network-bus,控制器局 域网总线技术
3.运行流程:
CAN总线详解
文章图片

4.显性隐性:
CAN总线详解
文章图片

一、 CAN帧结构 【CAN总线详解】CAN-bus通信帧:数据帧、远程帧、错误帧、过载帧和帧间隔
1.数据帧 由7个段组成,其中根据仲裁段ID码长度的不同,分为标准帧(CAN2.0A)和扩展帧(CAN2.0B)。
CAN总线详解
文章图片

1.1 帧起始、帧结束:
CAN总线详解
文章图片

1.2 仲裁段
CAN总线详解
文章图片

1.2.1总线仲裁:
CAN总线详解
文章图片

CAN总线详解
文章图片

  • 从该分析过程得出结论是:帧ID值越小,优先级越高
  • 对于同为扩展格式数据帧、标准格式远程帧和扩展格式远程帧的情况同理。
CAN总线详解
文章图片

CAN总线详解
文章图片

1.3 控制段
CAN总线详解
文章图片

1.4 数据段
CAN总线详解
文章图片

1.5 CRC段
CAN总线详解
文章图片

1.6 ACK段
CAN总线详解
文章图片

2. 远程帧 CAN总线详解
文章图片

3. 数据帧与远程帧的区别 CAN总线详解
文章图片

4. CAN-bus 错误类型 CAN总线详解
文章图片

CAN总线详解
文章图片

CAN总线详解
文章图片

5. 过载帧 CAN总线详解
文章图片

6. 帧间隔 CAN总线详解
文章图片

7.CAN发送和接收 数据帧和远程帧最大的区别在于:远程帧没有数据域。数据帧分为标准数据帧和扩展数据帧,它们之间最大的区别在于:标识符(ID)长度不同(标准帧为11 位,扩展帧为29 位)。
为了能更好地理解下面的内容,让我们先来回忆一下标准数据帧是什么样子的:
CAN总线详解
文章图片

7.1 发送:
前面已经强调了CAN 总线上的节点接收或者发送数据都是以帧为单位。假如我们要发送一个字节的数据:0x5A,是不是像串口发送数据那样,直接把0x5A 写入发送缓冲寄存器,然后发送就可以了呢?
NO! 刚才已经强调了,CAN 总线上的数据都是以帧为单位的!!!我们必须按照帧的格式填充它!TNND,
这么复杂?没关系,ST 库函数已经提供了一个结构,我们只需要填充该结构就可以了。我们来看一下
这个结构的样子:
typedef struct { uint32_t StdId; //标准帧ID,如果您要发送扩展帧。可以不管它 uint32_t ExtId; //扩展帧ID,如果您要发送标准帧。可以不管它 uint8_t IDE; //您是想发送标准帧还是扩展帧? uint8_t RTR; //您是想发送数据帧还是远程帧? uint8_t DLC; // 您想发送数据的长度。 uint8_t Data[8]; //您想要发送的数据。 } CanTxMsg;

  • StdId
    StdId 用来设定标准标识符。它的取值范围为0 到0x7FF。
  • ExtId
    ExtId 用来设定扩展标识符。它的取值范围为0 到0x1FFFFFFF。
  • IDE
    IDE 用来设定消息标识符的类型。
  • IDE值
IDE 描述
CAN_Id_Standard 使用标准标识符
CAN_Id_Extended 使用扩展标识符
  • RTR
    RTR 用来设定待传输消息的帧类型。它可以设置为数据帧或者远程帧。
  • RTR值
RTR 描述
CAN_RTR_Data 数据帧
CAN_RTR_Remote 远程帧
  • DLC
    DLC 用来设定待传输消息的帧长度。它的取值范围是0 到0x8。
  • Data[8]
    Data[8]包含了待传输数据,它的取值范围为0 到0xFF。
1. 先声明一个CanTxMsg 类型的变量,然后按照自己具体的需要,填充此结构变量就可
以发送了(帧结构中其他没有填充的部分由硬件自动完成)。
2. 强调:这里的StdId 或者 ExtId 是根据自己的实际需要设置的!我们先抛开它们所
代表的实际意义,认为它们存在的目的是为了“进攻”。(发送出去让别人过滤)
7.2 接收
STM32 参考手册中提到:bxCAN 控制器为应用程序提供了14 个位宽可变的、可配置的过滤器组(13~0)。(互联型有28 个)。每个过滤器组的位宽都可以独立配置。可以配置成16
位或者32 位。过滤器组还可配置为屏蔽位模式或标识符列表模式。TNND,看起来好像很复杂!
先来理解一句话:共有14个过滤器组,每个过滤器组x由2个32位寄存器,CAN_FxR1和CAN_FxR2组成。搞定一个过滤器组,其他的都可以以此类推。
我们先来看1个32位过滤器-标示符屏蔽的情况CAN_FxR1作ID,CAN_FxR2作屏蔽:
先看图:
CAN总线详解
文章图片

这里的ID 是什么意思?难道就是前面所说的发送数据帧里面的ID?NO!这里的ID 和自己发送的帧里面的ID 没有一点关系。完全是两个东西,在硬件上属于不同的寄存器。强调:这里的ID也是根据自己的实际需要设置的!我们先抛开它们所代表的实际意义,认为它们存在的目的是为了“防守”。(过滤别人发送过来的帧的 ID)
这里的屏蔽是什么意思?这里的屏蔽和ID 共同配合完成过滤。
这里的映像是什么意思?映像的意思就是假定收到的帧的ID 信息。
下面举个例子,一切都会一目了然:
1.: 假如我们只想收到别人发过来的ID 为0x317 的标准数据帧:
0X317 二进制位:011 0001 0111
那么可以这样设置:
CAN_FxR1:0110 0010 111X XXXX XXXX XXXX XXXX X00X (ID) CAN_FxR2:1111 1111 1110 0000 0000 0000 0000 0110 (屏蔽)

这里是我们设置的想要收到的数据帧的ID。
这里为1 的位,意味着收到的数据帧中相应的ID 位必须和设置的ID 位一样(必须匹
配)。
2.: 假如我们想收到别人发过来的ID 为0x310 到0x317 的标准数据帧:
那么可以这样设置:
CAN_FxR1:0110 0010 xxxX XXXX XXXX XXXX XXXX X00X (ID) CAN_FxR2:1111 1111 0000 0000 0000 0000 0000 0110 (屏蔽)

这里的红色xxx 就代表000 到111 的任意组合。
这里为0 的位,意味着收到的数据帧中的相应位的ID 不一定非要与设置的ID 一样(不用关心)。
这里红色部分表明必须是标准数据帧。
3.: 假如我们想收到别人发过来的ID 为0x000 到0x7FF 的标准数据帧:
那么可以这样设置:
CAN_FxR1:xxxx xxxx xxxX XXXX XXXX XXXX XXXX X00X (ID)
CAN_FxR2:0000 0000 0000 0000 0000 0000 0000 0110 (屏蔽)
接下来看2个32位过滤器-标识符列表模式,CAN_FxR1和 CAN_FxR2都作为 ID.
这种情况就很简单了。只有收到的帧的ID 必须和CAN_FxR1 或者CAN_FxR2 完全一样才接收。这样的话,就只能接收两种不同的ID。
CAN总线详解
文章图片

举个例子:
如果我们把CAN_FxR1 和CAN_FxR2 设置为下面的样子。
CAN_FxR1:0110 0010 1110 0000 0000 0000 0000 0000 (ID)
CAN_FxR2:0000 0001 1110 0000 0000 0000 0000 0000 (ID)
这样的话,就只能过滤出ID 为0x317(与CAN_FxR1 必须一样)和0x00F(与CAN_FxR2 必须一样)两种标准数据帧了。
以上是32 位模式下标识符屏蔽模式和标识符列表模式下的设置方法。
在16 位模式下,只不过把两个32 位寄存器拆成了4 个16 位的而已,原理和32 位模式下是一样的。就不赘述了。
接收数据是通过指向CanRxMsg 结构体变量的指针传递的。直接调用 CAN_Receive 即可轻松完成。
typedef struct { uint32_t StdId; uint32_t ExtId; uint8_t IDE; uint8_t RTR; uint8_t DLC; uint8_t Data[8]; uint8_t FMI; } CanRxMsg;

CanRxMsg 结构与CanTxMsg 差不多。只是多了一个FMI 域。
  • FMI
    FMI 设定为消息将要通过的过滤器索引,这些消息存储于邮箱中。该参数取值范围0 到
    0xFF。
8. 9. 10. 11. 12.

    推荐阅读