CAN协议详解,配置,难点

本文详细介绍了CAN总线技术,包括其特点(多主控制、柔软性、速度与错误处理等)、电气标准、帧种类(数据帧、遥控帧等)、工作模式和通信模式,以及CAN过滤器和相关结构体的配置。重点回顾了CAN2.0协议的发展和应用,特别强调了CAN2.0A和2.0B的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、CAN简介

1.1 CAN特点

        1)多主控制。在总线空闲时,所有单元都可以发送消息,而两个以上的单元同时开始发送消息时,根据标识符ID决定优先级。两个以上的单元同时开始发送消息时,对各消息 ID 的每个位进行逐个仲裁比较。仲裁获胜(被判定为优先级最高)的单元可继续发送消息,仲裁失利的单元则立刻停止发送而进行接收工作。
        3)通信速度较快,通信距离远。最高 1Mbps(距离小于 40M),最远可达 10KM(速率低
于 5Kbps)。
        4) 具有错误检测、错误通知和错误恢复功能。所有单元都可以检测错误(错误检测功能),
检测出错误的单元会立即同时通知其他所有单元(错误通知功能),正在发送消息的单元一旦检测出错误,会强制结束当前的发送。强制结束发送的单元会不断反复地重新发送此消息直到成功发送为止(错误恢复功能)。
        6)连接节点多CAN 总线是可同时连接多个单元的总线。可连接的单元总数理论上是没
有限制的。但实际上可连接的单元数受总线上的时间延迟及电气负载的限制。降低通信速度,可连接的单元数增加;提高通信速度,则可连接的单元数减少。

1.2 电气标准

  • CAN有两根线:CAN_H,CAN_L,差分信号通信
  • 显性电平对应逻辑 0,CAN_H 和 CAN_L 之差为 2.5V 左右。
  • 隐性电平对应逻辑 1,CAN_H 和 CAN_L 之差为 0V。
  • 在总线上显性电平具有优先权,只要有一个单元输出显性电平,总线上即为显性电平。而隐形电平则具有包容的意味,只有所有的单元都输出隐性电平,总线上才为隐性电平(显性电平比隐性电平更强)。

1.3 帧种类

  • 数据帧  用于发送单元向接收单元传送数据的帧。
  • 遥控帧  用于接收单元向具有相同 ID 的发送单元请求数据的帧。
  • 错误帧  用于当检测出错误时向其它单元通知错误的帧。
  • 过载帧  用于接收单元通知其尚未做好接收准备的帧。
  • 帧间隔  用于将数据帧及遥控帧与前面的帧分离开来的帧。

PS: 数据帧和遥控帧有标准格式和扩展格式两种格式。标准格式有 11 个位的标识符(Identifier: 以下称 ID),扩展格式有 29 个位的 ID。扩展帧的29位是由标准帧的11位+拓展帧的18位组成

1.4 帧格式

数据帧一般由 7 个段构成,即:
(1) 帧起始。数据帧开始。标准帧和扩展帧都是由 1 个位的显性电平表示帧起始
(2) 仲裁段。帧优先级。 RTR 位用于标识是否是远程帧(0,数据帧;1,远程帧)
(3) 控制段。表示数据的字节数及保留位的段。IDE 位为标识符选择位(0,使用标准标识符;1,使用扩展标识符)。r0 和 r1 为保留位,必须全部以显性电平发送,但是接收端可以接收显性、隐性及任意组合的电平。DLC 段为数据长度表示段,高位在前,DLC 段有效值为 0~8
(4) 数据段。数据的内容,一帧可发送 0~8 个字节的数据。
(5) CRC 段。检查帧的传输错误的段。 15 个位的 CRC 顺序和 1 个位的 CRC 界定符(用
于分隔的位)组成
(6) ACK 段。表示确认正常接收的段。ACK 槽(ACK Slot)和 ACK 界定符 2 个位组成
(7) 帧结束。表示数据帧结束的段。 7 个位的隐性位组成

SRR 位为代替远程请求位,为隐性位,它代替了标准帧中的 RTR 位。

1.5 通信模式

(1)静默通信模式
        在静默通信模式下,可以从 CAN 总线接收数据,但不向总线发送任何数据

(2)回环通信模式
        在回环通信模式下,由 CAN 总线控制器发送的数据可以被自己接收并存入接收FIFO,同时这些发送数据也送至CAN 网络。

(3)回环静默通信模式
        在回环静默通信模式下,CAN 的 RX 和 TX 引脚与 CAN 网络断开。CAN 总线控制器既不从
CAN 网络接收数据,也不向 CAN 网络发送数据,其发送的数据仅可以被自己接收。
回环静默通信模式通常用来进行CAN 通信自测。

(4)正常通信模式
        CAN 总线控制器通常工作在正常通信模式下,可以从 CAN 总线接收数据,也可以向 CAN 总
线发送数据。这时需要将 CAN_BT 寄存器的LCMOD 位和 SCMOD 位清0。

1.6 CAN2.0协议

        CAN是Controller Area Network的缩写,译为控制器局域网,常称作CAN总线,多用于汽车电子和工业控制。CAN协议最早由博世公司提出,后被多个标准化组织进一步细化。目前CAN总线中使用最广泛的正是CAN 2.0 A/B协议,也称作传统CAN(Classic CAN)。

        其中CAN 2.0A协议仅支持标帧格式,而CAN 2.0B协议支持标准帧格式(Stand Frame,11位标识符)和扩展帧格式(Extend Frame,29位标识符)CAN 2.0B协议的存在只是为了解决标识符不够用的情况,所以CAN 2.0B和CAN 2.0A一样每个数据帧最多传输8个字节的数据。标准帧和扩展帧可以在同一条CAN总线上传输。仅支持CAN 2.0A的设备会丢弃接收到的扩展数据帧/扩展遥控帧,但是不会报错。

1.7 CAN硬件电路

 第一步,看硬件原理图,芯片内部是否配置120Ω终端电阻

 第二步,如果没有配置,需要人为在两端外接120Ω终端电阻

注意:主板自测CAN通信时,由于原理图上面都没有外接120Ω终端电阻,所以实现CAN1和CAN2通信时需要自己加入两个终端电阻,但是实际结果是,加入一个终端电阻也能正常通信,原因在于两个CAN通信距离较短。

1.8 位填充

二、CAN过滤器

2.1 概念

        CAN总线上面存在大量的CAN消息,通过设置过滤器,可以从硬件上过滤掉大部分CAN消息,降低了软件处理负担。注意:只有配置CAN过滤器之后才能接收到数据,仅仅使能接收中断不配置CAN过滤器也不能接收到数据。

2.2 过滤器有两种模式:掩码模式和列表模式

  • 掩码模式:对于一个待过滤的数据帧的标识符(Identifier),掩码模式用来指定哪些位必须与预设的标识符相同,哪些位无需判断。
  • 列表模式 :对于一个待过滤的数据帧的标识符(Identifier),列表模式用来表示与预设的标识符列表中能够匹配则通过,否则丢弃。

2.3 CAN过滤器的四种模式详解 

        a)16位列表模式

        16位宽的列表模式下,FilterIdHigh,FilterIdLow,FilterMaskIdHigh,FilterMaskIdLow这4个16位变量都是用来存储一个标准CAN ID,可以存放4个标准CAN ID了,需要注意地是,此种模式下,是不能处理扩展CANID,凡是需要过滤扩展CAN ID的,都是需要用到32位宽的模式。

        

        b)32位列表模式:

        FilterIdHigh或者FilterIdLow都可以存储一个标准CAN ID(16位),FilterMaskIdHigh和FilterMaskIdLow存储一个扩展CANID(28位)

        

         c)16位掩码模式:

        CAN_FxR1的低16位是作为验证码,对应的16位屏蔽码为CAN_FxR1的高16位,同样的,CAN_FxR2的低16位是作为验证码,对应与CAN_FxR2的高16位为屏蔽码。所以就是FilterIdHigh是验证码,FilterMaskIdHigh是屏蔽码;FilterIdLow是验证码,FilterMaskIdLow是屏蔽码。

        

        

        d)32位掩码模式:

        FilterIdHigh与FilterIdLow合在一起表示CAN_FxR1寄存器,用来存放验证码,而FilterMaskIdHigh与FilterMaskIdLow合在一起表示CAN_FxR2寄存器,用来存放屏蔽码,在32位宽的掩码模式下,既可以过滤标准CAN ID,也可以过滤扩展CAN ID,甚至两者混合这来也是可以的。(需要切记拓展ID是29位,配置时需要左移3位)

                 

2.4 CAN过滤器总结 

         

三、CAN协议涉及的几个结构体 

(1)CAN初始化配置结构体

typedef struct
{
/*!< 配置CAN外设的时钟分频,可以设置为1-102;它可控制时间片Tq的时间长度*/ 
uint16_t CAN_Prescaler;  
 
/*!< 配置CAN的工作模式:正常、回环、静默以及回环静默模式)*/
uint8_t CAN_Mode;         

/*!< 配置SJW的极限长度,可以被配置为1-4T,CAN重新同步时单次可增加或缩短的最大长度*/
uint8_t CAN_SJW;          

/*!<配置CAN位时序中的BS1段的长度,可以被配置为1-16个Tq长度*/
uint8_t CAN_BS1;         

/*!<设置CAN位时序中的BS2段的长度,它可以被配置为1-8个Tq长度*/
uint8_t CAN_BS2;          

/*!<是否使能TTCM时间触发功能*/  
FunctionalState CAN_TTCM; 

/*!<是否使能ABOM自动离线管理功能,使用自动离线管理可以在节点出错离线后适时自动恢复*/  
FunctionalState CAN_ABOM;  

/*!< 是否使能AWUM自动唤醒功能,使能自动唤醒功能后它会在监测到总线活动后自动唤醒。*/
FunctionalState CAN_AWUM;  

 /*!< 是否使用NART自动重传功能,使用自动重传功能时,会一直发送报文直到成功为止。*/
FunctionalState CAN_NART; 

/*!< 使能RELM锁定FIFO功能,若FIFO溢出时会丢弃新数据;不使能在FIFO溢出时以新数据覆盖旧数据*/
FunctionalState CAN_RFLM;

 /*!< 使能时,以报文存入发送邮箱的先后顺序来发送,否则按照报文ID的优先级来发送。*/
FunctionalState CAN_TXFP; 
} CAN_InitTypeDef;

(2)CAN发送消息结构体

typedef struct
{
//StdId: 本成员存储的是报文的11位标准标识符,范围是0-0x7FF。
uint32_t StdId; 

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

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

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

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

//本成员存储的就是数据帧中数据段的数据。
uint8_t Data[8]; 
} CanTxMsg;

 (3)CAN接收消息结构体

typedef struct
{
//StdId: 本成员存储的是报文的11位标准标识符,范围是0-0x7FF。
uint32_t StdId; 

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

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

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

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

//本成员存储的就是数据帧中数据段的数据。
uint8_t Data[8]; 

//本成员只存在于接收结构体,它存储了筛选器的编号,表示本报文是经过哪个筛选器存储进接收FIFO的
uint8_t FMI; 
}CanRxMsg;

(4)CAN过滤器结构体

typedef struct
{
//CAN_FilterIdHigh成员用于存储要筛选的ID,若筛选器工作在32位模式,它存储的是所筛选ID的高16位;若筛选器工作在16位模式,它存储的就是一个完整的要筛选的ID。
uint16_t CAN_FilterIdHigh;

//CAN_FilterIdLow成员也是用于存储要筛选的ID,若筛选器工作在32位模式,它存储的是所筛选ID的低16位;若筛选器工作在16位模式,它存储的就是一个完整的要筛选的ID。
uint16_t CAN_FilterIdLow;         

// CAN_FilterMaskIdHigh存储的内容分两种情况,当筛选器工作在标识符列表模式时,它的功能与CAN_FilterIdHigh相同,都是存储要筛选的ID;而当筛选器工作在掩码模式时,它存储的是CAN_FilterIdHigh成员对应的掩码,与CAN_FilterIdLow组成一组筛选器。
uint16_t CAN_FilterMaskIdHigh;   

//CAN_FilterMaskIdLow存储的内容也分两种情况,当筛选器工作在标识符列表模式时,它的功能与CAN_FilterIdLow相同,都是存储要筛选的ID;而当筛选器工作在掩码模式时,它存储的是CAN_FilterIdLow成员对应的掩码,与CAN_FilterIdLow组成一组筛选器。
uint16_t CAN_FilterMaskIdLow;     

//本成员用于设置当报文通过筛选器的匹配后,该报文会被存储到哪一个接收FIFO,它的可选值为FIFO0或FIFO1(宏CAN_Filter_FIFO0/1)。
uint16_t CAN_FilterFIFOAssignment;
  
//本成员用于设置筛选器的编号,即本过滤器结构体配置的是哪一组筛选器,CAN一共有28个筛选器,所以它的可输入参数范围为0-27。
uint8_t CAN_FilterNumber;        

//本成员用于设置筛选器的尺度,可以设置为32位长及16位长
uint8_t CAN_FilterScale;          

// 本成员用于设置是否激活这个筛选器(宏ENABLE/DISABLE)。
FunctionalState CAN_FilterActivation;
} CAN_FilterInitTypeDef;

四、CAN和CAN FD总线协议

4.1 CAN FD协议

是CAN with Flexible Data rate的缩写,翻译为【可变速率的 CAN】。 也可以简单的认为是传统CAN的升级版,其中要说明的是,只升级了协议,物理层没有改变。

4.2 为什么需要CAN FD?

原因主要是汽车功能越来越多,越来越复杂,传统的CAN总线(CAN2.0)的负载率越来越高,甚至负载率高达95%,以及传统CAN总线还存在一些局限性。

传统CAN总线的局限性包括:

· 传输率最大为1Mbiy/s(典型的<= 500kbit/s);

· 传统CAN数据帧超过50%的额外开销(overhead > 50%)。

对比其他协议,额外开销比例要小得多,如UDP (1500 bytes/datagram, 64 bytes overhead),FlexRay(254 bytes/frame, 8 bytes overhead)。

还有就是历史原因,汽车不可能直接放弃目前的传统CAN总线技术,重头来过。 那么为了解决CAN总线负载率问题,而又能兼容CAN总线,并且研发成本不能太高的问题,因此在2015年最新的修订版ISO 11898-1(classic CAN和CAN FD)发布。

目前的很多应用对于通讯的数据量要求越来越高,对于通讯的速率要求也越来越高,尤其是当速率高于1MBit/s的时候,传统的CAN通讯是无法满足的,所以基于这种应用的需求,CAN FD就应运而生了。 既然是出于这样的目的,CANFD的出现肯定是需要解决传输速率和传输字节的问题,带着这样的思路我们就可以更容易地理解CANFD协议,以及为什么会出现它了。

4.3 CAN与CANFD的比较

CAN与CAN-FD主要区别:传输速率不同、数据域长度不同、帧格式不同、ID长度不同。

4.3.1 传输速率

一般的工程中比较常用的为500K每秒的通讯速率。 这个速率在实际测试的时候也是非常可靠的。 CAN总线上任意两个节点的最大传输距离与其位速率有关。 最大通信距离指的是同一条总线上两个节点之间的距离。 从下面图中,可以看到速率越低通讯距离就越远,也就是说CAN总线的通讯距离和波特率成反比。 CAN最大传输速率为1Mbps

对于 CAN FD而言,是在 CAN 的基础上增加了一个数据域的传输速率,数据传输速率要大于等于原 CAN 总线用的速率。 也就是说 CAN FD 支持两种传输速率,两种速率可以保持一致,也可以不保持一致。 速率可变,仲裁比特率最高1Mbps,数据比特率最高8Mbps。

4.3.2 数据域长度不同

CAN的数据域长度,一帧数据最长8字节。 CAN FD数据域长度,一帧数据最长64字节。

4.3.3 ID长度不同

CAN标准帧ID长度最长11bit,CANFD标准帧ID长度可扩展到12bit。

五、多设备同时发送,如何分配总线资源

5.1 资源分配规则1 - 先占先得

  1. 若当前已经有设备正在操作总线发送数据帧/遥控帧,则其他任何设备不能再同时发送数据帧/遥控帧(可以发送错误帧/过载帧破坏当前数据)
  2. 任何设备检测到连续11个隐性电平,即认为总线空闲,只有在总线空闲时,设备才能发送数据帧/遥控帧
  3. 一旦有设备正在发送数据帧/遥控帧,总线就会变为活跃状态,必然不会出现连续11个隐性电平,其他设备自然也不会破坏当前发送
  4. 若总线活跃状态其他设备有发送需求,则需要等待总线变为空闲,才能执行发送需求

5.2 资源分配规则2 - 非破坏性仲裁

  1. 若多个设备的发送需求同时到来或因等待而同时到来,则CAN总线协议会根据ID号(仲裁段)进行非破坏性仲裁,ID号小的(优先级高)取到总线控制权,ID号大的(优先级低)仲裁失利后将转入接收状态。至于是否需要失败自动重传功能,需要配置
  2. 实现非破坏性仲裁需要两个要求:
  • 线与特性:总线上任何一个设备发送显性电平0时,总线就会呈现显性电平0状态,只有当所有设备都发送隐性电平1时,总线才呈现隐性电平1状态,即:0 & X & X = 0,1 & 1 & 1 = 1
  • 回读机制:每个设备发出一个数据位后,都会读回总线当前的电平状态,以确认自己发出的电平是否被真实地发送出去了,根据线与特性,发出0读回必然是0,发出1读回不一定是1

六、CAN邮箱

  1. 波特率最高可达1兆位/秒
  2. 3个可配置优先级的发送邮箱
  3. 2个3级深度的接收FIFO
  4. 14个过滤器组(互联型28个)

下面针对STM32F103C8T6而言

 每一个CAN有13个过滤器,都可以分别配置过滤的ID,也可以分别配置是FIFO0接收数据还是FIFO1接收数据,每一个FIFO又包含3个邮箱,当3个邮箱接收满时,再来新的数据,可以选择配置位锁存还是丢弃。

每一个CAN都有3个发送邮箱,HAL库提供了HAL_CAN_AddTxMessage函数来发送CAN消息。当所有邮箱都满时,函数返回HAL_ERROR。

  • CAN发送数据步骤
  • 步骤1:检查是否有空闲邮箱(通过HAL_CAN_GetTxMailboxesFreeLevel())。
  • 步骤2:若存在空闲邮箱,根据TransmitFifoPriority选择插入位置:
    • FIFO模式:填充第一个空闲邮箱。
    • ID模式:将消息插入到比当前邮箱中更低优先级ID的位置(需硬件支持排序)。
  • 步骤3:若所有邮箱已满,直接返回HAL_ERROR,或者(等待几us,判断邮箱是否大于1,如果满足,则可以继续发送,否则直接返回HAL_ERROR)

启用中断 → 触发中断 → 读取FIFO中所有待处理消息 → 释放邮箱 → 中断标志自动清除  

读取FIFO中所有待处理消息,读取所有邮箱的原因在于避免重复触发中断函数

  • 硬件行为:未读取的消息会持续触发中断,直至FIFO被清空。

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)

{

        CAN_RxHeaderTypeDef rx_header;

        uint8_t rx_data[8];

        while (HAL_CAN_GetRxFifoFillLevel(hcan, CAN_RX_FIFO0) > 0)

        {

                HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rx_header, rx_data);

                 // 处理数据...

        }

}

  • typedef enum 
    {
      HAL_OK       = 0x00U,
      HAL_ERROR    = 0x01U,
      HAL_BUSY     = 0x02U,
      HAL_TIMEOUT  = 0x03U
    } HAL_StatusTypeDef;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值