从零开始认识CAN网通信

📅 2026/7/12 18:40:23 👁️ 阅读次数 📝 编程学习
从零开始认识CAN网通信

从零开始认识CAN网通信

  • 引言:为什么需要CAN总线?
  • 物理层:差分信号与“线与”逻辑
    • 电平定义
    • “线与”逻辑
    • 为什么用差分信号?
  • 数据链路层:报文、仲裁与帧结构
    • CAN通信模型
    • 非破坏性仲裁机制
    • 标准帧 vs 扩展帧
    • CAN报文接收与发送流程

引言:为什么需要CAN总线?

想象一下,现代的汽车里装着几十个电子控制单元(ECU):发动机控制、ABS防抱死、自动空调、车窗控制……如果每个模块之间都单独拉线,那汽车里的线束会多得像一团乱麻,不仅成本高、接线麻烦,还容易出故障。

传统点对点通信CAN总线通信
每个ECU之间都需要独立连线所有ECU挂载在同一对双绞线上
节点数量增加,线束呈指数增长节点增加只需并联接入,线束不变
故障排查困难,维护成本高分布式诊断,故障定位方便

CAN总线就是为了解决这个问题而生的。它全称是控制器局域网(Controller Area Network),由德国博世(BOSCH)公司在1986年开发,后来成为国际标准(ISO 11898)。简单来说,它就像一条数据高速公路,让所有电子控制单元都能挂在这条“路”上,通过一对双绞线进行高效、可靠的通信,大大减少了线束数量。

如今,CAN总线不仅统治了汽车电子,在工业自动化、医疗设备、船舶控制、机器人等领域也是应用广泛。

物理层:差分信号与“线与”逻辑

CAN总线物理层只用两根线:CAN_H 和 CAN_L。它通过两根线之间的电压差(差分信号)来传输数据,而不是像串口那样依赖对地电压。

电平定义

信号类型CAN_H电压CAN_L电压差分电压逻辑值
显性(Dominant)约3.5V约1.5V2V0
隐性(Recessive)约2.5V约1.5V2V0

“线与”逻辑

总线执行线与机制。可以把显性(0)理解为“强势”信号,隐性(1)理解为“弱势”信号。

节点A输出节点B输出总线最终电平
隐性 (1)隐性 (1)隐性 (1)
显性 (0)隐性 (1)显性 (0)
隐性 (1)显性 (0)显性 (0)
显性 (0)显性 (0)显性 (0)

为什么用差分信号?

  • 抗干扰能力强:外界噪声几乎同时耦合到两根线上,接收端只关心差分值,共模干扰相互抵消。
  • 电磁辐射低:两根线绞在一起(双绞线),对外辐射相互抵消。

数据链路层:报文、仲裁与帧结构

CAN总线通信是以“报文”为单位的。它不指定发送者和接收者,而是通过报文标识符(ID) 来区分不同的消息。

CAN通信模型


注意:CAN总线两端必须各接一个120Ω的终端电阻,用于匹配阻抗,防止信号在总线末端反射造成数据错误。

非破坏性仲裁机制

这是CAN最精妙的设计。当多个节点同时要发送数据时,它们会从ID的最高位开始,一位一位地比较。谁先发送出隐性位(1),而总线上却是显性位(0),谁就立即停止发送,转为接收状态。

关键结论:ID数值越小,优先级越高,所以一般比较重要的任务ID号都比较小

标准帧 vs 扩展帧

对比项标准帧 (Standard Frame)扩展帧 (Extended Frame)
ID位数11位29位
ID范围0x000 ~ 0x7FF0x00000000 ~ 0x1FFFFFFF
帧格式ID + RTR + IDE + DLCID + SRR + IDE + ID扩展 + RTR + DLC
可挂载节点数最多 2048 个最多 5.3 亿个
数据字节数0 ~ 8 字节0 ~ 8 字节
应用场景简单系统、传统汽车复杂系统、J1939协议

标准帧格式:

帧起始位(1位)仲裁段(11位ID)控制段(6位)数据段(0~64位)CRC段(16位)ACK段(2位)帧结束(7位)

扩展帧格式:

帧起始位(1位)基ID(11位)SRR(1位)IDE(1位)扩展ID(18位)控制段(6位)数据段(0~64位)CRC段(16位)ACK段(2位)帧结束(7位)

CAN报文接收与发送流程

发送流程图

Created with Raphaël 2.3.0开始发送检查总线是否空闲连续11个隐性位发送帧起始SOF(显性位0)发送仲裁段(ID)逐位发送并监听仲裁是否失败?退出发送转为接收状态继续发送遥控段/数据段发送CRC校验段等待ACK确认位(监测显性电平)是否接收ACK?发送帧结束(7个隐性位)重发或报错(错误帧)yesnoyesno

接收流程图

Created with Raphaël 2.3.0等待接收检测到帧起始SOF(显性位下降沿)接收仲裁段(ID)逐位接收并存储ID是否通过过滤器?继续接收控制段/数据段接收CRC校验段本地计算CRCCRC校验是否通过?发送ACK确认位(显性位)接收帧结束EOF(7个隐性位)处理并存储数据触发回调函数发送错误帧(显性位)忽略该帧(不发送ACK)yesnoyesno