在嵌入式系统中使用CAN(Controller Area Network)通讯,需要掌握以下内容:
- CAN协议:了解CAN总线通讯的基本原理,包括帧格式、报文结构、消息ID等内容。
- CAN控制器:理解CAN控制器的工作原理以及如何配置和控制CAN控制器,包括波特率设置、过滤器配置等。
- CAN硬件:熟悉CAN硬件接口的相关信息,包括传输线路、终端电阻等。
- CAN通讯模式:了解CAN通讯的多种通讯模式,如标准帧模式、扩展帧模式、远程帧模式等。
- 数据处理:掌握CAN数据的发送和接收处理方法,包括数据打包、解析、校验等。
- 错误处理:了解CAN通讯中可能出现的错误类型,如位错误、帧错误等,以及相应的处理方法。
- 实时性:理解CAN通讯在嵌入式系统中的实时性要求,确保数据的及时性和可靠性。
- 调试工具:熟练掌握CAN通讯调试工具的使用,如CAN分析仪、逻辑分析仪等,以便快速排查问题。
下面就大致介绍一下CAN总线数据的组成以及帧格式的具体内容。
一、CAN数据的组成
1、头尾段
2、仲裁段
从该分析过程得出结论是:帧ID值越小,优先级越高。
对于同为扩展格式数据帧、标准格式远程帧和扩展格式远程帧的情况同理。
3、控制段
4、数据段
5、CRC段
6、ACK段
二、CAN数据的格式
CAN通信帧共分为数据帧、远程帧、错误帧、过载帧和帧间隔五种类型。
1、数据帧
结构上由7个段组成,其中根据仲裁段ID码长度的不同,分为标准帧(CAN2.0A)和扩展帧(CAN2.0B)。
2、远程帧
数据帧与远程帧的区别
3、错误帧
4、过载帧
5、帧间隔
————————————————
以上内容参考大佬文章:
原文链接:图解CAN总线数据的组成和帧格式_can总线帧头-CSDN博客
三、CAN控制器
CAN(控制器局域网)控制器是一种专门用于处理CAN通信协议的集成电路,它能够管理和控制CAN网络中的数据传输。CAN控制器的主要功能包括消息的发送、接收和过滤。以下是CAN控制器工作原理的详细介绍:
CAN控制器通常包含以下几个关键模块:
- 发送缓冲区:存储待发送的CAN消息。
- 接收缓冲区:存储接收到的CAN消息。
- 滤波器和掩码寄存器:用于消息的过滤。
- 协议控制逻辑:负责CAN协议的具体实现,包括帧格式的生成和校验。
- 错误管理模块:处理错误检测和纠正。
- 时钟和定时器模块:用于同步和控制消息的发送和接收时序。
1. 消息发送
CAN控制器在发送消息时,经历以下几个步骤:
- 消息装载:应用程序将消息数据和标识符(ID)装载到发送缓冲区。
- 仲裁过程:CAN总线上多个节点可能同时发送消息。CAN控制器通过标识符的仲裁机制确定优先级,ID值越低优先级越高。
- 消息发送:优先级最高的消息赢得仲裁后开始发送。发送过程中,包括了帧起始、标识符、控制字段、数据字段、CRC校验和帧结束等步骤。
- 发送确认:发送完成后,控制器等待其他节点的确认。如果未收到确认,将重试发送。
2. 消息接收
在接收消息时,CAN控制器执行以下步骤:
- 总线监听:控制器持续监听CAN总线上的所有通信。
- 消息捕获:接收到CAN消息后,首先将其存储在接收缓冲区。
- 消息过滤:通过滤波器和掩码寄存器,控制器判断消息是否与节点相关。只有通过过滤器的消息才会继续处理。
- 错误检测:控制器检查接收到的消息是否有错误,包括位错误、填充错误、CRC错误等。
- 消息处理:没有错误且通过过滤器的消息被传递给应用层进行处理。
3.错误处理
CAN控制器内置多种错误处理机制,以确保通信的可靠性:
- 错误检测:包括位错误、填充错误、CRC错误、确认错误和格式错误。
- 错误计数:控制器维护发送错误计数器(TEC)和接收错误计数器(REC),用于记录错误发生的次数。
- 错误状态管理:根据错误计数器的值,控制器可以进入不同的错误状态,如错误主动状态、错误被动状态和总线关闭状态。
4.时钟同步
CAN通信需要严格的时间控制,CAN控制器使用内部时钟和定时器模块来保持同步。通过同步段、传播段、相位缓冲段1和相位缓冲段2来控制比特时间,确保各节点能够在精确的时间点发送和接收数据。
四、通信模式
CAN总线控制器有4种通信模式:
◼ 静默(Silent)通信模式;
◼ 回环(Loopback)通信模式;
◼ 回环静默(Loopback and Silent)通信模式;
◼ 正常(Normal)通信模式。
1.静默(Silent)通信模式 【可以接收但不发送】
在静默通信模式下,可以从CAN总线接收数据,但不向总线发送任何数据。将CAN_BT寄存器中的SCMOD位置1,使CAN总线控制器进入静默通信模式,将其清0可以退出静默通信模式。 静默通信模式可以用来监控CAN网络上的数据传输。
2.回环(Loopback)通信模式 【自发自收用于自测】
在回环通信模式下,由CAN总线控制器发送的数据可以被自己接收并存入接收FIFO,同时这些发送数据也送至CAN网络。将CAN_BT寄存器中的LCMOD位置1,使CAN总线控制器进入回环通信模式,将其清0可以退出回环通信模式。 回环通信模式通常用来进行CAN通信自测。
3.回环静默(Loopback and Silent)通信模式
在回环静默通信模式下,CAN的RX和TX 引脚与CAN网络断开。CAN总线控制器既不从CAN网络接收数据,也不向CAN网络发送数据,其发送的数据仅可以被自己接收。将CAN_BT寄存器中的LCMOD位和SCMOD位置1,使CAN总线控制器进入回环静默通信模式,将它们清0可以退出回环静默通信模式。 609 GD32F30x 用户手册 回环静默通信模式通常用来进行CAN通信自测。对外TX引脚保持隐性状态(逻辑1),RX引脚保持高阻态。
4.正常(Normal)通信模式
CAN 总线控制器通常工作在正常通信模式下,可以从CAN总线接收数据,也可以向CAN总线发送数据。这时需要将CAN_BT寄存器的LCMOD位和SCMOD位清0。
五、数据发送
发送寄存器 数据发送通过3个发送邮箱进行,可以通过寄存器CAN_TMIx,CAN_TMPx,CAN_TMDATA0x和CAN_TMDATA1x 对发送邮箱进行配置
1.数据发送步骤如下:
第1步:选择一个空闲发送邮箱;
第2步:根据应用程序要求,配置4个发送寄存器;
第3步:将CAN_TMIx寄存器的TEN置1;
第4步:检测发送状态和错误信息。典型情况是检测到MTF和MTFNERR置1,说明数据被成功发送。
2.发送邮箱状态转换
当发送邮箱处于empty 状态时,应用程序才可以对邮箱进行配置。当邮箱被配置完成后,可以将CAN_TMIx寄存器的TEN位置 1,从而向CAN总线控制器提交发送请求,这时发送邮箱处于pending状态。当超过1个邮箱处于pending状态时,需要对多个邮箱进行调度,这时发送邮箱处于scheduled 状态。当调度完成后,发送邮箱中的数据开始向 CAN总线上发送,这时发送邮箱处于transmit 状态。当数据发送完成,邮箱变为空闲,可以再次交给应用程序使用。
3.发送状态检测
CAN_TSTAT寄存器中的MTF,MTFNERR,MAL和MTE位用来说明发送状态和错误信息。
◼ MTF:发送完成标志位。当数据发送完成时,MTF置1。
◼ MTFNERR:无错误发送完成标志位。当数据发送完成且没有错误时,MTFNERR置1。
◼ MAL:仲裁失败标志位。当发送数据过程中出现仲裁失败时,MAL置1。
◼ MTE:发送错误标志位。当发送过程中检测到总线错误时,MTE置1。
4.发送优先级
当有2个及其以上发送邮箱等待发送时,寄存器CAN_CTL的TFO位的值可以决定发送顺序。
当TFO为1,所有等待发送的邮箱按照先来先发送(FIFO)的顺序进行。
当TFO为0,具有最小标识符(Identifier)的邮箱最先发送。如果所有的标识符(Identifier)相等,具有最小邮箱编号的邮箱最先发送。
六、数据发送
应用程序通过2个深度为3的FIFO接收来自CAN网络的数据
1.数据接收步骤
第1步:查看FIFO中帧的数量。
第2步:通过CAN_RFIFOMIx , CAN_RFIFOMPx , CAN_RFIFOMDATA0x 和CAN_RFIFOMDATA1x读取数据。
第3步:将寄存器CAN_RFIFOx的RFD置1释放邮箱,并且等待其由硬件自动清0。
2.接收FIFO
每个接收FIFO包含3个接收邮箱,用来接收存储数据帧。这些邮箱按照先进先出方式进行组织,最早从CAN网络接收的数据,最早被应用程序处理。 寄存器CAN_RFIFOx包含FIFO状态信息和帧的数量。当FIFO中包含数据时,可以通过寄存器CAN_RFIFOMIx,CAN_RFIFOMPx,CAN_RFIFOMDATA0x和CAN_RFIFOMDATA1x读取数据,之后将寄存器CAN_RFIFOx的RFD置1释放邮箱。
3.接收FIFO状态信息
接收FIFO状态信息包含在寄存器CAN_RFIFOx中。
RFL:FIFO中包含的帧数量。FIFO为空时,RFL为0;FIFO为满时,RFL为3。
RFF:FIFO满状态标志位。这时RFL为3。
RFO:FIFO溢出标志位。当FIFO已经包含了3个数据帧时,新的数据帧到来使FIFO发生溢出。
如果CAN_CTL寄存器的RFOD位被置1,新的数据帧将丢弃。如果该位被清0,新的数据帧将覆盖接收FIFO中最后一帧数据。
七、滤功能
一个待接收的数据帧会根据其标识符(Identifier)进行过滤:硬件会将通过过滤的帧送至接收
硬件过滤的做法节省了CPU开销,否则就必须由软件过滤从而占用一定的CPU开销
1.过滤器关联的FIFO
28个过滤单元均可以关联接收FIFO0或接收FIFO1。一旦一个过滤单元关联到接收FIFO,只有通过这个过滤单元的帧才会被传送到接收FIFO中存储。
2.优先级
过滤器优先级规则如下:
1、32-bits位宽模式高于16-bits位宽模式;
2、列表模式高于掩码模式;
3、较小的过滤序号(Filter Number)具有较高的优先级。
3.过滤器模式
(1)掩码模式
对于一个待过滤的数据帧的标识符(Identifier),掩码模式用来指定哪些位必须与预设的标识符相同,哪些位无需判断。
设得宽,则可以通过的多(所有位为0,则不过任何过滤操作,则谁都可以通过),设得窄,则通过的少(所有位设为1,则只有一个能通过)。
(2)列表模式
对于一个待过滤的数据帧的标识符(Identifier),列表模式用来表示与预设的标识符列表中能够匹配则通过,否则丢弃。
4.过滤器的位宽
在非GD32F30x CL系列产品中,过滤器由14个单元( Bank)组成,它们是bank0到bank13。在GD32F30x CL系列产品中,过滤器包含28个单元,它们是bank0到bank27。
每一个过滤器单元有2个寄存器CAN_FxDATA0和CAN_ FxDATA1,它们可以配置为2种位宽:32-bit位宽和16-bit位宽。 【配置的位宽】
32位宽的掩码模式, 配置过滤2个不同的ID号
32位宽的列表模式, 配置过滤4个不同的ID号
16位宽的列表模式, 配置过滤2个不同的ID号
16位宽的掩码模式, 配置过滤1个不同的ID号
5.过滤器的代码实现
注意:若配置了多组标识符掩码,则只要接收到的标识符符合其中任意一组掩码的都会通过滤波器,所以千万不要有其中一组是通配的(即掩码为0x0000),否则你设置的其它掩码组都会无效
以下是实现每种CAN滤波器配置情况的实际代码示例。假设我们使用的CAN控制器支持相应的配置方式,并使用C语言或C++编写代码。
1. 32位宽的掩码模式,配置过滤2个不同的ID号
解释:
- 左移3位:空出低3位用于控制位(SRR、IDE、RTR等)。
- 右移16位:提取高16位部分用于高位寄存器。
- 与0xffff按位与:确保只取低16位。
- 或操作设置扩展ID标志位:标记该ID为扩展ID
假设使用的是某个CAN控制器的库函数CAN_SetFilter来配置滤波器:
// 设置32位宽掩码模式的过滤器1
CAN_FilterTypeDef sFilterConfig1;
sFilterConfig1.FilterIdHigh = (0x12345678 >> 13) & 0xFFFF;
sFilterConfig1.FilterIdLow = (0x12345678 << 3) & 0xFFFF;
sFilterConfig1.FilterMaskIdHigh = (0x1FFFFFFE >> 13) & 0xFFFF;
sFilterConfig1.FilterMaskIdLow = (0x1FFFFFFE << 3) & 0xFFFF;
sFilterConfig1.FilterFIFOAssignment = CAN_FILTER_FIFO0;
sFilterConfig1.FilterBank = 0; // 滤波器编号
sFilterConfig1.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig1.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig1.FilterActivation = ENABLE;
CAN_SetFilter(&sFilterConfig1);
// 设置32位宽掩码模式的过滤器2
CAN_FilterTypeDef sFilterConfig2;
sFilterConfig2.FilterIdHigh = (0x12345679 >> 13) & 0xFFFF;
sFilterConfig2.FilterIdLow = (0x12345679 << 3) & 0xFFFF;
sFilterConfig2.FilterMaskIdHigh = (0x1FFFFFFE >> 13) & 0xFFFF;
sFilterConfig2.FilterMaskIdLow = (0x1FFFFFFE << 3) & 0xFFFF;
sFilterConfig2.FilterFIFOAssignment = CAN_FILTER_FIFO0;
sFilterConfig2.FilterBank = 1; // 滤波器编号
sFilterConfig2.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig2.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig2.FilterActivation = ENABLE;
CAN_SetFilter(&sFilterConfig2);
2. 32位宽的列表模式,配置过滤4个不同的ID号
// 设置32位宽列表模式的过滤器
CAN_FilterTypeDef sFilterConfig;
// 过滤器1
sFilterConfig.FilterBank = 0; // 滤波器编号
sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
sFilterConfig.FilterIdHigh = (0x12345678 >> 13) & 0xFFFF;
sFilterConfig.FilterIdLow = (0x12345678 << 3) & 0xFFFF;
sFilterConfig.FilterMaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterActivation = ENABLE;
CAN_SetFilter(&sFilterConfig);
// 过滤器2
sFilterConfig.FilterBank = 1; // 滤波器编号
sFilterConfig.FilterIdHigh = (0x23456789 >> 13) & 0xFFFF;
sFilterConfig.FilterIdLow = (0x23456789 << 3) & 0xFFFF;
CAN_SetFilter(&sFilterConfig);
// 过滤器3
sFilterConfig.FilterBank = 2; // 滤波器编号
sFilterConfig.FilterIdHigh = (0x34567890 >> 13) & 0xFFFF;
sFilterConfig.FilterIdLow = (0x34567890 << 3) & 0xFFFF;
CAN_SetFilter(&sFilterConfig);
// 过滤器4
sFilterConfig.FilterBank = 3; // 滤波器编号
sFilterConfig.FilterIdHigh = (0x45678901 >> 13) & 0xFFFF;
sFilterConfig.FilterIdLow = (0x45678901 << 3) & 0xFFFF;
CAN_SetFilter(&sFilterConfig);
3. 16位宽的列表模式,配置过滤2个不同的ID号
// 设置16位宽列表模式的过滤器
CAN_FilterTypeDef sFilterConfig;
// 过滤器1
sFilterConfig.FilterBank = 0; // 滤波器编号
sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;
sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT;
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
sFilterConfig.FilterIdHigh = 0x1234 & 0xFFFF;
sFilterConfig.FilterIdLow = 0x5678 & 0xFFFF;
sFilterConfig.FilterMaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterActivation = ENABLE;
CAN_SetFilter(&sFilterConfig);
// 过滤器2
sFilterConfig.FilterBank = 1; // 滤波器编号
sFilterConfig.FilterIdHigh = 0x5678 & 0xFFFF;
sFilterConfig.FilterIdLow = 0x0000;
CAN_SetFilter(&sFilterConfig);
4. 16位宽的掩码模式,配置过滤1个不同的ID号
// 设置16位宽掩码模式的过滤器
CAN_FilterTypeDef sFilterConfig;
sFilterConfig.FilterBank = 0; // 滤波器编号
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT;
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
// 过滤器ID
sFilterConfig.FilterIdHigh = 0x1234 & 0xFFFF;
// 掩码
sFilterConfig.FilterMaskIdHigh = 0xFFFF; // 完全匹配
sFilterConfig.FilterActivation = ENABLE;
CAN_SetFilter(&sFilterConfig);
这些代码示例展示了如何配置不同位宽和模式的CAN滤波器,以实现对不同数量ID号的过滤。具体实现可能会因不同的CAN控制器和库函数有所不同,请参考具体硬件的文档和API。