干CAN总线的人,几乎都经历过这种玄学时刻:同一套代码、同一块板子,在台架上跑一个月不出问题,换个环境就疯狂报错帧;示波器一量,波形上的毛刺长得吓人,可程序逻辑怎么查都查不出毛病。搞了三年CAN总线,我最大的感受是,八成以上的故障不在代码,而在物理层和那些你觉得“差不多就行”的参数上。
这篇就把我这几年攒下来的几句大实话一次性倒出来。从终端电阻、并联分支长度、SRR位,到采样点、保护电路和现场排查,尽量用操作现场的口吻说透。不管是正在调车的学生,还是被现场问题折磨的工程师,应该都能从这里找到几句能直接拿去用的东西。
1. 三年踩坑下来,我对CAN总线的整体认知
1.1 CAN到底“神”在哪里:两层东西要分开看
CAN总线经常被人当成一种“串口协议”,上来就照着例程配置波特率、发数据,出了问题就怀疑配置不对。实际上CAN是个分层的系统,你得把它拆成两件事来看。
物理层处理的是CANH和CANL两根线上的差分电压。IDE、DLC、CRC这些是协议层的内容,但不先把电平搞对,后面全白搭。ISO 11898-1定义了数据链路层,ISO 11898-2定义了高速物理层。物理层做的事很简单:把显性位(逻辑0)表现为CANH约3.5V、CANL约1.5V,差分电压约2V;把隐性位(逻辑1)表现为CANH和CANL都稳定在2.5V附近,差分电压接近0。
协议层做的事就有意思多了。CAN不是“主机问、从机答”的轮询模式,而是所有节点都挂在同一条总线上,谁先发数据由ID仲裁决定。ID数值小的帧优先,发送节点同时在监听总线,发完一个位后如果发现被别人抢占了,就自动转为接收。这种多主仲裁机制加上错误检测、错误帧重传,才是CAN能扛住汽车高噪声环境的根本原因。
所以排查CAN问题之前,先问自己一句:我到底是在查物理层的事,还是在查协议层的事?这两者的现象很像,但处理思路完全不一样。
1.2 为什么CAN的故障总是“偶发性”的
刚接触CAN时,我很不理解一个问题:明明程序逻辑完全正确,为什么总线偶尔就报一个错帧,然后又自己恢复?后来才明白,CAN的容错机制是“人类友好”的,但物理层信号质量的恶化,程序里根本看不出来。
可以这样理解:总线就是一根传输线,不是普通排线。信号从发送端传到末端,遇到阻抗变化的地方就会反射。反射回来的能量叠加在原信号上,轻则让波形出现一个台阶,重则直接让差分电压跌破接收器的判定阈值。ISO对接收器差分输入的要求是:显性电压大于0.9V必须识别为显性,隐性电压小于0.5V必须识别为隐性。如果反射导致电平在这个区间内来回晃动,接收器就可能误判。
这种误判不是每次都发生,它与温度、供电电压、干扰强度都有关。于是表现出来的就是“偶发错误帧”、“偶尔丢一帧”、“空调一开就有问题”等玄学故障。后面我学会了一件事:遇到偶发错误,第一时间别翻代码,先拿示波器看波形。这句话值得先记下来。
2. 物理层设计里最容易翻车的几个细节
2.1 终端电阻:两个120Ω,一个都不能少
先说终端电阻,这是CAN网络中最大的“隐性坑”。规范要求总线两端各接一个120Ω电阻,注意是物理两端,不是“设备两端”也不是“逻辑两端”。
为什么是120Ω?因为CAN总线用的双绞线特征阻抗大约是120Ω。在传输线末端接上跟特征阻抗相等的电阻,信号到达末端时能量会被电阻吸收,不再反射回来。如果没有这个匹配电阻,信号到了末端就会反射,叠加在原波形上形成振铃。
判断终端电阻是否正常,有个简单的万用表方法:把设备断电,直接在总线任意位置量CANH和CANL之间的电阻。如果系统里正好有两个终端电阻,读到的是两个120Ω并联,也就是60Ω左右。如果读到120Ω,说明有一个终端电阻没接或者接丢了。如果读数是无穷大,说明压根没有终端电阻,或者线缆已经断开。
这个60Ω的判断标准我用了很久,几乎百试百灵。但注意,一定要断电测量。我已经见过不止一个现场工程师带电去量电阻,量出来一个莫名其妙的几千欧,然后开始怀疑收发器芯片烧了,其实那是芯片内部的偏置电阻。断电再量,干净利落。
单终端电阻时波形长什么样?我实测过:显性位到隐性位的跳变沿会出现一个明显的“台阶”,然后回弹,像是信号犹豫了一下。如果波特率再高一点,这个台阶可能直接让后续采样点落在错误电平上。
2.2 并联分支的长度到底指哪个长度
“CAN总线并联分支的长度”这个话题在网上被搜爆了,说明大家确实分不清。这里把话说清楚:并联分支,也叫支线或stub,指的是从总线干线引出、连接到某个节点的那一小段线。它不是节点与节点之间的间距,更不是总线总长度。
比如一条主线上串了5个节点,每个节点通过一段30厘米的线缆接到干线上,这30厘米就是每个节点的分支长度。很多人布线的习惯是把总线像蜘蛛网一样接到各个设备,每个设备一段线,这些就是分支。
分支为什么不能太长?因为分支是一段末端开路的短截线。信号沿干线传播时,经过分支结点会分流,一部分能量进入分支,到达分支末端后发生反射,反射波回到干线,污染后续信号。分支越长,这个反射延迟越大,对高速通信的影响越明显。
我整理过一张经验表,算是比较好记的参考值:
| 波特率 | 建议最大分支长度 |
|---|---|
| 1 Mbps | 约 0.3 米 |
| 500 kbps | 约 1 米 |
| 250 kbps | 约 2.5 米 |
| 125 kbps | 约 5 米 |
这个表不是绝对严格的标准,但很能说明趋势:速度越快,支线越得短。除非用CAN中继器或有源集线器,否则别指望用一根两米长的线把一个节点挂在1Mbps的总线上还不出问题。我自己就干过这种事,结果误码率高得让人崩溃。
2.3 节点数量和线缆选择同样有讲究
一个高速CAN网络上能挂多少节点?ISO 11898-2给出的常见参考上限是32个节点。原因是每个节点的收发器输入阻抗都是有限值,节点越多,并联后的等效负载电阻越低,收发器驱动的差分电压就越小。节点数超过一定量之后,总线上可能连200mV的有效差分电压都保证不了。
实际项目中,别把32当铁律去卡。我曾经在一个测试台上挂了20多块板子,波形已经开始发“软”。这种时候尽量分层处理,多路总线通过网关互联,别指望单条总线包打天下。
线缆选择上,优先使用特性阻抗120Ω的双绞屏蔽线。车载环境常用AVSS 0.5平方或0.75平方的屏蔽双绞线,工业现场至少要选带有编织屏蔽层的线缆。很多朋友图便宜用普通双绞网线,这里提示一下:CAT5/CAT6网线的特性阻抗是100Ω,不是120Ω,用在CAN上阻抗不匹配,反射会比正规CAN线严重不少。短距离、低速场景可能能跑,但高速长距离时会有隐患。
还有一点容易被忽略:屏蔽层怎么接地。原则是一点接地,别让屏蔽层形成回路。常见做法是只在总线某一点把屏蔽层接到保护地,别把每个节点的屏蔽层都单独接一遍大地。
3. 协议层几个容易忽略的坑
3.1 SRR位和扩展帧仲裁:标准帧为什么总是“赢”
SRR位是热词搜索榜上的常客,说明很多人卡在这里。要理解SRR位,先得把标准帧和扩展帧的仲裁过程对比着看。
标准数据帧的仲裁段是:SOF + 11位ID + RTR + IDE。RTR位为显性0时表示数据帧,隐性1表示远程帧。扩展数据帧的仲裁段是:SOF + 11位基本ID + SRR + IDE + 18位扩展ID + RTR。这里注意,扩展帧在标准帧RTR的位置安放的是SRR位,固定为隐性1。
为什么会有这个设计?为了保证标准帧在仲裁时优先于同ID的扩展帧。假设一个11位基本ID相同的标准帧和扩展帧同时在总线上,标准帧走到RTR位时是显性0,扩展帧对应位置是SRR隐性1,显性位在CAN仲裁中会覆盖隐性位,于是标准帧赢得仲裁,扩展帧乖乖退出发送变为接收。
SRR全称是Substitute Remote Request,可以把它理解成一个“占位符”。它并不携带实际请求信息,存在的意义就是让标准帧和扩展帧在同ID前提下有一个确定的仲裁顺序。实际开发中要注意:如果总线上的设备既有标准帧又有扩展帧,且ID区段重叠,标准帧设备会持续抢占总线,可能导致扩展帧设备饿死。我在调试一个混合协议系统时就遇到过,标准帧流量大,扩展帧一帧都发不出去,查了半天才想到是仲裁顺序导致,最后把两边的ID区间错开才解决。
另外一个相关坑是RTR和远程帧。远程帧是节点请求对方发送数据时用的,RTR隐性1。很多人只用数据帧,完全没处理远程帧。如果上位机定时发远程帧请求,而节点没有响应,总线上的表现就是一直出现“请求-无应答”的状态,错误计数器还可能往上飙升。
3.2 波特率、采样点和位时序:配置不能只看波特率数字
波特率配置不匹配,出错帧一眼就能看出来:总线上一片错误帧,帧ID乱跳,看起来像广播风暴。但还有一个更隐蔽的坑:即使波特率一样,采样点不同也可能导致偶发错误。
CAN的一位时间在协议里被分成好几段:同步段、传播段、相位缓冲段1、相位缓冲段2。采样点就是接收器在每个位时间内采样电平的时刻,推荐位置一般在75%到85%之间。如果采样点太靠后,离下一位太近,总线抖动稍微大一点,就会把下一位的电平采进来。
以STM32的bxCAN为例,外设时钟36MHz,目标500kbps。波特率公式是:36MHz / (分频值 x (1 + BS1 + BS2))。要让等号右边等于500kHz,分频值x(1+BS1+BS2)必须等于72。取分频值Prescaler=4,1+BS1+BS2=18,那BS1=13、BS2=4就是一套很合理配置,采样点正好是(1+13)/18=77.8%。面板上只有波特率配置的工程师可能直接套BS1=15、BS2=2的例程,那样采样点算下来88.9%,偏晚,时序余量就差一截。
示波器测采样点比较麻烦,但对配置的理解很重要。给个小技巧:如果总线上偶发错误帧,而波特率明明一致,试着把采样点从87%调到80%附近,很多问题会自己消失。
3.3 位填充、错误帧和错误计数器
CAN协议有个很容易被忽略的规则:位填充。发送节点每发出5个连续相同电平的位之后,必须插入一个反相电平位,接收端收到后会自动把这个填充位删除。这样做是为了保证总线上有足够的电平跳变,便于接收器做时钟同步。
位填充机制会引发一个连锁反应:如果电磁干扰导致总线上的电平跳变异常,接收端检测到填充错误,就会发错误帧。错误帧的形态是6个连续显性位或6个连续隐性位加上定界的隐性位。而且CAN有个错误计数器机制:发送错误和接收错误的计数规则不一样,错误计数累积到一定等级,节点状态会从主动错误变为被动错误,最终变成总线关闭态。
总线关闭状态要特别小心:达到128次错误后,节点会进入Bus Off,相当于从总线上“隐身”,既不发送也不接收,直到软件让总线恢复或满足恢复条件。我见过一个项目,节点偶发Bus Off后没有处理逻辑,直接“掉线”,主站那边只能看到节点长时间没响应。排查时记得查节点驱动里的错误计数寄存器,别只盯着主站日志。
4. 通信协议实例:从报文到代码的一次完整调试
4.1 一个典型的控制报文长什么样
做CAN开发,读帧结构是基本功。拿一条经典的标准数据帧来说,完整序列是:SOF一位显性,11位ID,RTR位,IDE位一位显性(表示标准帧),r0保留位,4位DLC(数据长度),接着是0到8字节数据,15位CRC加1位CRC界定符,ACK槽和ACK界定符,最后7位EOF和3位IFS。
这条报文里,ID的作用不只是标识,它同时决定了总线仲裁优先级。比如ID=0x100的数据帧和ID=0x200的数据帧竞争总线,0x100因为数值更小,仲裁率先通过,于是它先占住总线完成发送。
CRC覆盖的范围包括SOF之后的全部位,用于检测传输中的位错误。ACK槽是发送节点发一个隐性位,所有正确接收到该帧的节点把这个位拉成显性,这样才能让发送节点确认“有节点收到我的报文了”。所以遇到发送节点报“无应答”错误时,八成是总线上只有发送节点自己,或者对方的验收滤波把帧过滤掉了。
4.2 报文收发流程与常见现象
实际调试中,协议栈里最容易出问题的不是CRC也不是DLC,而是验收滤波和缓冲器管理。
很多CAN控制器的硬件接收过滤是按ID区间配置的。你要接收ID=0x123,结果过滤器配成了标准帧ID,而对方发的是扩展帧,那帧在硬件层就被丢弃了,软件层面连影子都看不到。我调试时习惯先把过滤器设为全收,跑通了再逐步收窄ID范围,这样少走很多弯路。
发送流程的坑也很多。以常见CAN控制器为例,发送过程是:软件请求发送、等待总线空闲、参与仲裁、逐位发送、等待ACK。如果节点持续发不出去,先看总线是否一直忙,再看自己的CAN_TX引脚电平。一个排查的小技巧:把CAN收发器的TXD引脚接示波器,总线上没有报文时,TXD应该保持隐性高电平。如果看到TXD在持续拉低,说明芯片一直在尝试发送但发不出去,这往往是仲裁失败或者总线错误导致的。
接收丢帧的排查思路也是先分层:物理层用示波器量差分波形,确认每个帧都在线上;协议层用CAN卡看错误帧数量;软件层查FIFO溢出标志。一个酷似“软件丢帧”的故障,最后查出来是CAN控制器FIFO溢出后软件没有及时读数据,一帧丢了之后后续帧也全挤丢了。这种问题加一个接收中断里快速搬数据的逻辑就解决了。
4.3 实际调试中用到的工具和判断方法
调试CAN,我个人必备三样东西:一台带CAN解码的示波器或逻辑分析仪、一个USB转CAN适配器、一台万用表。示波器和逻辑分析仪看协议层和物理层,CAN卡主要用来模拟节点和监控总线流量。
用示波器测CAN是最直观的。正常波形上,隐性电平稳定在2.5V附近,显性位是CANH向上抬、CANL向下拉,像一对对称的翅膀。如果看到CANH和CANL的幅值不一致,比如一个抬高1.8V而另一个只降了0.6V,大概率是收发器的驱动能力出了问题,或者总线上的某个设备把某一根线轻微短路了。
逻辑分析仪的优势是能直接解码出ID、DLC、数据内容。抓一帧报错的数据,先用解码功能看ID和数据对不对,再用示波器看发生错误瞬间的物理波形。很多时候,错误帧是因为总线上某个瞬间出现了两个节点同时发帧的“位冲突”,在逻辑分析仪上看就是CRC校验失败,在示波器上看则是波形畸变。这两者一对照,问题定位就非常快了。
5. 总线保护与汽车级电路设计
5.1 为什么CAN这么容易坏:共模和ESD
很多人认为CAN是差分信号,两根线互相抵消干扰,抗干扰能力自然强。这话只说对了一半。差分确实能抑制共模干扰,但CAN收发器的输入引脚直接暴露在外部环境里,汽车上12V/24V系统电压波动、感性负载的浪涌、人体静电,都是直接攻击收发器的“杀手”。
收发器芯片内部对ESD有一定的承受能力,但绝对扛不住持续性的过压。最常见的情况是总线上的某个节点地电位升高,导致CANH和CANL相对本地地的电压超出共模输入范围。收发器一般允许的共模范围在-2V到+7V左右(具体看芯片手册),一旦超出,轻则信号失真,重则直接烧毁总线引脚。
另一个典型场景是两根总线线被错误地碰到电源线上。24V电源碰到CANH,瞬间的高压就可能把收发器击穿。我在现场见过一块板子的收发器烧出一个小洞,查了半天原因是线束在震动中磨破了绝缘层,CANH碰到了24V线。所以节点设计里,保护电路不是可选项,而是标配。
5.2 典型节点电路:TVS、共模电感、电阻怎么选
一个典型的CAN节点硬件链路,按信号流向是:MCU的CAN控制器(很多MCU内置)接CAN收发器,收发器的CANH/CANL引脚先经过共模电感和TVS保护,再接到外部连接器,最后是总线。如果在总线两端,还需要在总线最外侧各放一个120Ω终端电阻。
具体选型上,交流经验是这样的:
- TVS管选双向的,比如PESD1CAN这类专用于CAN的型号,钳位电压要低于收发器绝对最大额定值,结电容要尽量低。放在连接器入口处,用来泄放ESD和浪涌能量。
- 共模电感,常见封装是ACM7060或B82793系列。它主要抑制共模噪声,对差分信号本身的损耗很小。如果没有共模电感,仅靠TVS,高频共模干扰还是能耦合进收发器。
- 有些设计会在CANH/CANL上串接一个几欧到几十欧的电阻,比如22Ω或33Ω。这个电阻能限制故障状态下的电流,同时也能在一定程度上阻尼高频振铃。但注意电阻太大会衰减差分信号幅度,得不偿失。
- 终端120Ω电阻要直接连接在CANH和CANL之间。如果节点不是布线两端,终端电阻就不要放。很多节点为了“方便”每个板子上都预留120Ω跳线,一旦在中间节点上误接了终端电阻,总线上的等效电阻就会低于60Ω,信号幅度明显下降。
提示:能用集成方案就别自己拼保护电路。现在很多隔离收发器自带ESD和过流保护,比如ISO1042、CTM1051系列。自己做分立保护电路虽然省钱,但布局布线一不留神,保护就变成了噪声源。
5.3 隔离与非隔离的选择
什么时候需要隔离?记住一条经验:两个节点之间的地电位差超过收发器允许范围,或者现场环境存在持续大共模干扰,就老老实实用隔离。
非隔离方案里,所有节点共地,信号回路经过地线。如果节点间距离几十米甚至上百米,地线上的电位差可能达到几伏甚至十几伏,CANH和CANL相对地电压被整体抬高或拉低,通信就会间歇失败。隔离方案则是把节点内部的信号地与总线的地彻底分开,CAN收发器这一侧只跟总线的地电位发生关系。
我做过一个项目,现场有电机变频器,地线干扰很大。最初用非隔离收发器,表现为运行一段时间后偶发错误帧,电机一启动,错误帧就暴增。后来换成了带隔离电源的CAN收发器模块,把节点内部的信号地和总线地断开,问题直接消失。隔离会增加板子面积和成本,但在工业环境或新能源车上,这笔钱省不得。
6. 常见问题与排查技巧实录
6.1 故障速查表
三年折腾下来,我把高频故障整理成了一张速查表,遇到问题可以对着查。
| 故障现象 | 可能原因 | 排查方法 |
|---|---|---|
| 完全收不到报文 | 波特率不匹配 | CAN卡配置相同波特率,看错误帧数量 |
| 偶发错误帧 | 分支过长、终端电阻缺失 | 示波器测波形,测量总线静态电阻 |
| 发送超时无应答 | 只有发送节点在线,或验收滤波配置错误 | 用CAN卡监听,确认是否有节点在应答ACK |
| 波形幅值偏小 | 节点过多、终端电阻误接多处 | 断电测CANH-CANL电阻,正常应为60Ω左右 |
| 电机一启动就报错 | 共模干扰、地电位差 | 换隔离收发器,或检查地线连接 |
| 节点间歇掉线 | Bus Off | 读错误计数器,检查驱动软件恢复逻辑 |
| 能通信但数据偶发错乱 | ID仲裁冲突、混合标准扩展帧 | 检查ID分配策略,用CAN卡分帧监控 |
| 一根线断掉还能通信,但报错率高 | 单线工作依赖地回路 | 检查线束,CAN必须两根线才能差分传输 |
6.2 三个亲历案例
第一个案例是单终端电阻。一台设备在产线上测试,三个节点组网,偶尔报错。我去现场量总线静态电阻,发现只有120Ω,也就是说两个终端电阻只接了一个。补上另一个后,波形上的台阶消失,错误帧清零。这个案例我常拿来提醒别人:先量电阻,再看波形,不要一上来就改程序。
第二个案例是分支过长。一个项目中有一个传感器节点,供应商给的线束自带一条三米长的支线。波特率500kbps,系统表现是传感器数据偶尔丢一帧。我让供应商把这条支线改成在传感器端用短跳线就近接入干线,并把这段支线控制在1米以内,丢帧现象完全消失。那条三米支线就是典型的“末端开路反射源”。
第三个案例是地电位差。两个柜体相距50米,CAN线走桥架,信号地通过保护地回流。调试时发现通信时好时坏,两柜之间的地电位差实测有7V。普通收发器的共模范围根本受不了。最后两端都加了隔离,通信稳定得一批。这件事教育我:距离一长,隔离就得当默认选项。
6.3 给新手的几条实在建议
第一,排查顺序固定下来:断电量静态电阻、示波器看波形、CAN卡看协议、最后再看软件。按这个顺序来,至少能排除掉一半以上的“玄学”问题。
第二,开发阶段就把所有调试接口暴露出来。板子上预留CANH、CANL测试点,留出终端电阻跳线,MCU的CAN错误计数器寄存器做成可读状态,这些都能在出问题时省下大量时间。
第三,不要迷信“高速”。很多场合250kbps甚至125kbps完全够用,但抗干扰能力和布线容忍度成倍上升。能用低速解决就别追求高速,这是我用教训换来的。
第四,多备一台便宜的CAN分析仪,开发板上电之前先接上看看总线上有没有别人在发数据。两个设备用相同波特率但不同帧格式,互相不认识,但也会在总线上产生干扰,这类问题只看自己的日志永远发现不了。
这几句大实话,说到底就是一句话:CAN总线的问题,绝大多数不是它不行,而是设计时没把它当成一根传输线去认真对待。把物理层扎实做好,协议层的那些坑,其实都好填。
最后再分享一个小习惯,我现在每次设计CAN节点,都要在实验室把样板挂到真实线缆上跑一整晚,第二天看错误计数器。很多白天测不出来的偶发问题,过一夜就自己显形了。