3、CAN总线基础:从CAN 2.0A到2.0B,那些你必须懂的细节
大家好,我是老张。今天咱们聊聊CAN总线的基础知识。说实话,这玩意儿我玩了十几年,踩过的坑比走过的路还多。但别担心,我会把最核心的东西掰开了揉碎了讲给你听。
CAN总线,说白了就是汽车电子系统的"神经系统"。你想想看,一辆车上有几十个ECU,它们之间怎么通信?靠的就是CAN总线。我刚开始做OBD逆向时,第一件事就是搞懂CAN帧长什么样。
3.1 CAN 2.0A vs 2.0B:到底差在哪?
这个问题,我面试新人时必问。很多人背得滚瓜烂熟,但一问到实际应用就懵了。
CAN 2.0A 是标准帧,ID只有11位。什么意思?就是你的报文ID范围是0到0x7FF,总共2048个ID。够用吗?早期车型还行,现在?呵呵,一个现代豪华车光动力系统就能用掉一半。
CAN 2.0B 是扩展帧,ID有29位。范围从0到0x1FFFFFFF,将近5.3亿个ID。这才叫"想怎么玩就怎么玩"。
我个人习惯,做逆向时先看DBC文件里ID的长度。如果全是0x7FF以内的,那就是2.0A;如果出现0x18F00000这种,妥妥的2.0B。
核心区别速览:
| 特性 | CAN 2.0A(标准帧) | CAN 2.0B(扩展帧) |
|---|---|---|
| ID长度 | 11位 | 29位 |
| ID范围 | 0x000 ~ 0x7FF | 0x00000000 ~ 0x1FFFFFFF |
| 帧头长度 | 47位(含填充) | 67位(含填充) |
| 兼容性 | 2.0B节点可接收 | 2.0A节点无法识别 |
我的经验:做OBD逆向时,如果发现某些报文抓不到,先检查一下是不是标准帧和扩展帧混用了。我曾经在一个项目里折腾了两天,最后发现是某个ECU发了扩展帧,而我的工具默认只解析标准帧。
3.2 CAN帧结构:一帧数据到底长啥样?
来,咱们把CAN帧拆开看看。我习惯把它分成7个部分,就像拆快递一样,一层层剥开。
SOF(Start of Frame):1位,显性电平(0)。说白了就是"我要开始说话了"的信号。我刚开始学的时候,总觉得这玩意儿可有可无,后来才知道没有它,总线上的节点都不知道什么时候该听。
ID(Identifier):11位或29位。这是报文的"身份证号"。优先级怎么定?ID越小,优先级越高。所以0x000的报文,谁抢得过它?
RTR(Remote Transmission Request):1位。0表示数据帧,1表示远程帧。远程帧是啥?就是"你把你那个数据发给我看看"。实际项目中,远程帧用得不多,但OBD诊断时会用到。
DLC(Data Length Code):4位。表示数据段有多少字节。范围0到8。注意,DLC可以写0到8,但实际数据长度不能超过8。我见过有人写DLC=8但只发了3个字节,结果接收方解析全乱套了。
Data:0~8字节。这才是真正的"干货"。OBD逆向时,我们解析的就是这一段。比如车速、转速、水温,全藏在这里面。
CRC(Cyclic Redundancy Check):15位。校验用的。发送方算一遍,接收方再算一遍,对不上就说明数据被干扰了。嗯,这里要注意,CRC只校验SOF到Data段,不校验ACK和EOF。
ACK(Acknowledge):2位。接收方收到正确数据后,会在ACK Slot位拉低电平,告诉发送方"我收到了"。如果没人应答,发送方会重发。我遇到过一种情况:总线终端电阻坏了,导致ACK信号反射,发送方以为没人应答,疯狂重发,总线直接瘫痪。
EOF(End of Frame):7位,隐性电平(1)。表示"我说完了,你们可以抢了"。
一帧CAN报文的总位数:
标准帧:1(SOF) + 11(ID) + 1(RTR) + 1(IDE) + 1(r0) + 4(DLC) + 0~64(Data) + 15(CRC) + 1(CRC Delimiter) + 1(ACK Slot) + 1(ACK Delimiter) + 7(EOF) = 44~108位
扩展帧:1(SOF) + 11(ID Base) + 1(SRR) + 1(IDE) + 18(ID Extended) + 1(RTR) + 1(r1) + 1(r0) + 4(DLC) + 0~64(Data) + 15(CRC) + 1(CRC Delimiter) + 1(ACK Slot) + 1(ACK Delimiter) + 7(EOF) = 64~128位
3.3 位填充机制:为什么CAN总线要"捣乱"?
这个问题很有意思。你想想看,如果连续发了5个相同的电平,接收方怎么知道这是5个连续的位,还是时钟漂移了?
CAN总线的解决办法是:每连续5个相同电平,就插入一个相反的电平。这就是位填充。
举个例子:你要发送 11111 00000,经过位填充后变成 111110 000001。注意,填充位是接收方自动去掉的,你不需要操心。
我曾经在调试一个CAN总线干扰问题时,发现数据总是对不上。查了半天,原来是位填充机制导致的。发送方发了连续的6个1,接收方以为只有5个1加1个填充位,结果解析全错了。
避坑指南:位填充只在SOF到CRC段有效。ACK和EOF不参与位填充。另外,如果连续出现5个相同电平后,第6个还是相同电平,那就是位填充错误,节点会发送错误帧。我见过有人用逻辑分析仪抓CAN信号,看到连续6个显性电平,以为是正常数据,其实是总线错误。
3.4 CAN总线终端电阻:为什么必须要有?
这个问题,我面试时必问第二题。很多人说"防止信号反射",但再问一句"为什么是120欧姆?"就答不上来了。
CAN总线是差分信号,CAN_H和CAN_L之间的特性阻抗大约是120欧姆。如果不加终端电阻,信号到了总线末端会反射回来,跟后面的信号叠加,导致数据错误。
终端电阻的位置:总线两端各一个120欧姆电阻。为什么是两个?因为两个120欧姆并联,正好是60欧姆,跟总线特性阻抗匹配。
我遇到过最坑的事:一个同事在调试CAN总线时,发现通信时好时坏。查了三天,最后发现终端电阻焊在了中间位置,而不是两端。结果信号在两端反射,中间节点收的数据全是错的。
我的习惯:做OBD逆向时,先拿万用表量一下CAN_H和CAN_L之间的电阻。如果量到60欧姆左右,说明终端电阻正常。如果量到120欧姆,说明只有一个终端电阻。如果量到无穷大,说明两个电阻都没焊。如果量到0欧姆,说明短路了——这种情况我见过,结果是CAN收发器烧了。
好了,CAN总线的基础就讲到这里。下一章咱们聊聊CAN报文的解析实战,我会手把手教你从原始数据里读出车速、转速、水温这些关键信息。到时候记得带上你的CAN工具,咱们一起动手干。