CAN(Controller Area Network,控制器局域网)总线是一种广泛应用于汽车和工业领域的串行通信协议,以其高可靠性、实时性和强大的错误检测能力而闻名。
核心概念:什么是CAN通信?
-
多主控制:CAN总线上的任何一个节点都可以在总线空闲时主动发送数据,不存在"主从"之分。
-
面向内容的编址 :总线上的报文不是通过节点地址(比如"节点1发送给节点2")来识别,而是通过报文本身的标识符(ID,Identifier) 。ID定义了报文的内容 和优先级 ,而不是目标地址。所有节点都会收到总线上的所有报文,并由各自的验收滤波器根据ID决定是接收还是忽略该报文。
-
非破坏性仲裁:这是CAN最核心的机制。当多个节点同时发送报文时,它们会从ID的最高位开始,在总线上逐位进行"线与"仲裁(显性位0覆盖隐性位1)。发送隐性位(逻辑1)的节点如果检测到总线上是显性位(逻辑0),就会立即停止发送,退为接收者。而ID值更小(优先级更高)的节点则不受影响地继续发送,整个过程中高优先级报文没有任何延时或损坏。
-
差分信号传输 :CAN使用CAN_H和CAN_L两条线进行差分信号传输,抗干扰能力强。总线电平分为显性(Dominant,逻辑0) 和**隐性(Recessive,逻辑1)**两种状态。
数据怎么传输?------ 报文与帧结构
CAN总线上传输的基本单位是报文(Message) 。CAN协议定义了四种不同类型的帧,其中数据帧是最主要的一种,用于传输数据。
1. 四种报文帧类型
| 帧类型 | 用途 |
|---|---|
| 数据帧 (Data Frame) | 发送节点向其他节点传输数据的帧。 |
| 远程帧 (Remote Frame) | 某个节点向总线上请求具有相同ID的数据帧。它没有数据段。 |
| 错误帧 (Error Frame) | 任何节点检测到总线错误时发送的帧,用于通知其他节点。 |
| 过载帧 (Overload Frame) | 接收节点因内部原因(如尚未准备好接收下一帧)而发送,用于在前后数据帧/远程帧之间插入额外延迟 |
2. 数据帧的完整结构(一次"包"的旅程)
一个标准的数据帧由以下7个段组成:
-
帧起始 (SOF, Start of Frame) :1个位的显性位(逻辑0),标志一个数据帧的开始,用于所有节点的硬同步。
-
仲裁段 (Arbitration Field):这是决定报文优先级和身份的关键。
-
包含11位(标准帧) 或29位(扩展帧) 的标识符(ID)。
-
RTR位 (远程传输请求位):用于区分数据帧(显性)和远程帧(隐性)。
-
-
控制段 (Control Field):共6位。
- 包含 DLC (Data Length Code,数据长度码) ,共4位,用二进制编码表示数据段包含0到8个字节 。例如,DLC为
1101表示数据段有8个字节。
- 包含 DLC (Data Length Code,数据长度码) ,共4位,用二进制编码表示数据段包含0到8个字节 。例如,DLC为
-
数据段 (Data Field) :这就是你关心的"一次性发送的包"的核心内容 。长度由DLC决定,最多可以包含0到8个字节的数据。这是为了保证实时性而设计的短帧结构,能有效降低干扰概率。
-
CRC校验段 (CRC Field):包含15位的CRC校验码和一个隐性位的CRC界定符。发送节点根据前面各段计算CRC值,接收节点用同样方法计算并比对,以实现强大的错误检测。
-
ACK段 (Acknowledgment Field) :包含1位的ACK槽 (ACK Slot) 和1位的ACK界定符。发送节点在ACK槽发送隐性位,而正确收到报文的接收节点会在该位发送显性位作为应答,告知发送节点"我收到了"。
-
帧结束 (EOF, End of Frame) :由7个连续的隐性位组成,标志着数据帧的结束。
关于"一次性发送的包"的细节
-
一个"包"的大小 :一个标准的CAN数据帧,其数据段(Payload)最多为8个字节 。算上帧起始、仲裁、控制、CRC、ACK和帧结束等所有开销,一个CAN报文的总长度通常在108到128位 之间,具体取决于ID、数据长度和位填充情况。
-
位填充与报文长度:CAN是一种异步串行通信。为了保证同步,协议规定,在帧起始、仲裁、控制、数据、CRC等段中,如果连续出现5个相同的电平(5个连续的0或1),则必须插入一个相反的位("填充位")。这意味着发送不同的数据,整个报文的总位数(即传输时间)会略有不同。
-
传输速度与距离 :CAN的通信速度与总线长度成反比。在高速CAN (ISO 11898) 下,最高速率可达1Mbit/s ,但总线长度限制在40米 以内;而在低速容错CAN (ISO 11519) 下,速率最高为125kbit/s ,但通信距离可达1公里。
STM32芯片使用CAN通信:
硬件:
这部分的目标是把STM32的CAN信号引脚,连接到真正的CAN总线上。
-
选择并连接CAN收发器,芯片是只有控制器没有收发器的需要电路收发器的芯片。
-
为什么需要它 :STM32的CAN控制器输出的是逻辑信号(TX/RX),而CAN总线传输的是差分信号(CAN_H/CAN_L)。CAN收发器就是在这两者之间进行信号转换的"翻译官"。常用的收发器芯片有TJA1050 、SN65HVD230 或MCP2551等。
-
如何连接:典型的连接方式如下:
-
STM32的CAN_TX引脚 → 收发器的TXD引脚
-
STM32的CAN_RX引脚 → 收发器的RXD引脚
-
并给收发器提供合适的工作电压(如3.3V或5V)。
-
-
-
处理总线终端电阻
- 为什么需要它 :CAN总线是一个双绞线网络,为了防止高速通信时信号在末端发生反射,导致数据错误,必须在总线的最远端(且仅在最远端 )的两个节点上,各接一个120Ω的终端电阻。
-
(可选)考虑隔离保护
- 如果应用在工业或汽车等电磁环境复杂的场合,可以在STM32和收发器之间加入隔离芯片(如带隔离的收发器CA-IS3050),以保护核心MCU免受总线上的浪涌和高压冲击。
软件部分:配置通信规则
这部分的核心任务是使用STM32CubeMX和HAL库,让CAN外设按预期工作。
-
使用STM32CubeMX进行基础配置
-
开启CAN外设:在Pinout视图中,选中并激活CAN1或CAN2对应的引脚。
-
配置时钟:确保为CAN外设提供合适的时钟源,这直接关系到通信波特率的准确性。
-
设置波特率 :这是非常重要 的一步,通信双方必须设置完全相同 的波特率。常见的速率有125kbps、250kbps、500kbps等。波特率由
Prescaler(分频系数)、TimeSeg1和TimeSeg2等参数共同决定,CubeMX提供了图形化的计算工具,可以直接输入目标速率进行配置。 -
使能中断:如果打算使用中断方式接收数据(更高效),需要在NVIC设置中使能CAN的接收中断。
-
-
配置接收过滤器
-
由于STM32的CubeMX默认不会生成过滤器代码,你需要手动添加。过滤器决定了芯片接收哪些CAN消息,可以有效减少不必要的中断,节省CPU资源。
-
你可以将过滤器配置为"掩码模式"或"列表模式"。例如,下面的代码配置了一个接收所有标准帧ID的过滤器(不过滤任何消息)
-
CAN_FilterTypeDef sFilterConfig;
sFilterConfig.FilterBank = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; // 掩码模式
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; // 32位过滤器
sFilterConfig.FilterIdHigh = 0x0000; // ID高位
sFilterConfig.FilterIdLow = 0x0000; // ID低位
sFilterConfig.FilterMaskIdHigh = 0x0000; // 掩码高位,全0表示不检查任何位
sFilterConfig.FilterMaskIdLow = 0x0000; // 掩码低位
sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; // 分配到FIFO0
sFilterConfig.FilterActivation = ENABLE; // 使能过滤器
HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig);
-
编写发送与接收代码
-
启动CAN外设 :在初始化最后,需要调用
HAL_CAN_Start()来开启CAN通信,并通过HAL_CAN_ActivateNotification()使能接收中断。 -
发送数据 :填充
CAN_TxHeaderTypeDef结构体(设置ID、DLC等),然后调用HAL_CAN_AddTxMessage()将数据放入发送邮箱。 -
接收数据 :实现中断回调函数
HAL_CAN_RxFifo0MsgPendingCallback()。当有消息到达时,HAL库会自动调用它,在此函数内使用HAL_CAN_GetRxMessage()读取数据。
-
关键调试要点
-
波特率一致性:这是最常见的问题,务必确保总线上所有节点的速率配置完全一致。
-
终端电阻:再次检查是否只在总线的两端各有一个120Ω电阻。
-
逻辑分析仪/CAN分析仪:如果通信不成功,强烈建议借助这些工具来观察总线上的实际信号,可以快速定位是硬件连接、波特率还是软件逻辑的问题。