1. 先把“CAN”这个词拆开,争议才有解
前几天在一个技术群里,两位工程师为一个问题争了半个多小时:CAN 到底算协议还是算接口。一方摆出证据——它有帧格式、有位仲裁、有 CRC 校验、有错误计数器,是一整套完整的通信规则,这不明摆着是协议;另一方同样有依据——平时开口就是“这块板子给我留两路 CAN”“这个屏是 CAN 接口的”,明明是当插口在用,怎么就成协议了。两个人说的其实都对,只是站在了不同的层面上说话,谁也没往下追一步。
我做过几年车载和工业控制相关的项目,这个问题被问过不止一次,而且每次问的人出发点都不一样。刚入行的想搞清楚概念,画原理图的想知道该关注哪几个引脚,写驱动的想知道该配哪些寄存器,做系统集成的想知道采购清单上那行字到底指什么。如果没有把这件事说透,后面就容易出现一种很尴尬的局面:硬件说“我给了你两路 CAN”,软件说“我只看到一个控制器”,最后发现两个人从头到尾说的不是同一个东西。
这篇东西想解决的就是这一件事:把“CAN”这个词在不同语境下的含义一层层拆开,说清楚哪一层是协议、哪一层是接口、哪一层是芯片外设、哪一层是插头,以及这个区分在实际选型、配置和排错里到底会带来什么影响。不管你是刚接触总线的学生,还是已经在画板子、调波形的工程师,看完至少能保证在开会时不会跟人各说各话。中间我会给出一套可直接照做的排查顺序和几个参数计算示例,都是我在项目里反复用到的。
1.1 同一个词,被用在六个不同的层次上
“CAN”这三个字母在实际工作中至少承担了六种指代,而且这六种指代经常出现在同一场对话里,这才是混乱的根源。第一层是规范文档,指的是一整套白纸黑字写下来的标准文本,规定了电平、时序、帧结构、错误处理;第二层是协议,也就是这套规范里关于“怎么说话”的那部分规则——什么时候可以发、冲突了怎么办、对方没应答怎么办;第三层是控制器,指的是单片机或 SoC 内部那个负责组装和解析帧、计算 CRC、做位填充的硬件外设,它输出的是普通的单端逻辑电平;第四层是收发器,是一颗独立的芯片,负责把控制器出来的逻辑电平转换成总线上的差分电平,同时把总线上的差分电平转回来;第五层是连接器与线束,就是你能用手摸到的插头、端子、双绞线;第六层是软件接口,即驱动向上层暴露的那套 API,打开设备、配置波特率、发送一帧、注册接收回调。
这六层里,只有第二层能严格叫“协议”,只有第五层和第四层的组合最接近工程师口中的“接口”。但日常交流没人会把层数说全,于是“给我留两路 CAN”这句话,可能是“两个控制器外设”,可能是“两个收发器通道”,也可能是“两个物理连接器”,还可能是“两个可以独立配置波特率的逻辑通道”。这几种理解在成本、PCB 面积、软件复杂度上差得很远。我见过一个项目,需求文档写的是“预留两路 CAN 接口”,硬件按两个并联的连接器做,软件按两个独立控制器写,联调时才发现板子上只有一个控制器,两个连接器在电气上根本就是同一路,没法同时跑不同速率。这不是谁不专业,是从需求提出那一刻起,词就没对齐。
我的建议很土但很有效:在需求文档和原理图评审里,把“路”这个字拆成三个字段写——控制器数量、收发器数量、连接器数量。这三个数字可以相等,也可以不等,写清楚了,后面所有争论自动消失。
1.2 用寄快递的类比,把协议和接口彻底分开
我习惯用寄快递来解释这件事,几乎每个被我解释过的人都能一次听懂。协议相当于快递行业的整套规则:面单怎么填、收件人和地址写在哪一栏、包裹超重怎么算、签收要不要拍照、投递失败几次算异常件、异常件怎么退回。这套规则决定了包裹能不能准确送到、出了问题谁负责。接口相当于你家楼下那个快递柜或者门禁对讲——它是物理的、能看见能摸到的东西,决定了快递员有没有一个入口把东西交给你。
这两者缺一不可,但坏起来的表现完全不同。规则出问题,表现为包裹送错人、重复投递、丢了没人认账——对应到 CAN 上,就是 ID 配错、波特率不匹配、采样点不一致导致的偶发错误帧、应答丢失。入口出问题,表现为快递员压根进不了小区——对应到 CAN 上,就是终端电阻没焊、线接反了、收发器没供电、双绞线断了一根。你会发现这两类故障的排查手法完全不同:前者要翻配置、看时序、抓报文;后者拿万用表和示波器五分钟就能定位。分不清协议和接口,最直接的后果就是排错方向从一开始就是反的——有人抱着示波器去查 ID 冲突,也有人对着代码找了两天,最后发现是终端电阻少焊了一个。
还有一个更微妙的点:快递规则可以升级,比如新增了“必须本人签收”的条款,但你家的快递柜不用换。CAN 从经典格式演进到可变速率格式,本质就是规则升级了一次,而总线还是那两根线、接头还是那个接头——这本身就证明了协议和接口是可以分开演进的两件事。
1.3 一张表看清六个层次各自管什么
下面这张表是我自己整理的一页速查,贴在工位上用了很久。它解决的问题是:当有人跟你说“CAN 有问题”时,你能在三秒内判断该找谁、该拿什么工具。
| 层次 | 具体指什么 | 典型载体 | 出问题时的表现 | 主要排查工具 |
|---|---|---|---|---|
| 规范文档 | 电平、时序、帧格式、错误处理的完整定义 | 标准文本、协议手册 | 一般不会“坏”,但容易被误读 | 手册原文 |
| 协议 | 仲裁规则、帧类型、CRC、错误计数与故障界定 | 控制器内部的协议引擎 | 偶发错误帧、总线关闭、优先级倒挂 | 总线分析仪、报文记录 |
| 控制器 | 组装解析帧、位填充、验收滤波的硬件外设 | 单片机内部模块 | 收不到帧、滤波器把帧挡了、邮箱满 | 寄存器、驱动日志 |
| 收发器 | 单端逻辑电平与差分总线电平互转 | 独立芯片 | 完全不通、波形畸变、发热 | 万用表、示波器 |
| 连接器与线束 | 插头、端子、双绞线、屏蔽层 | DB9、插拔端子、圆形航空插头 | 时通时断、抗干扰差、接反 | 万用表、目视 |
| 软件接口 | 驱动向上层暴露的 API 与数据结构 | 驱动库、内核子系统 | 打开失败、发送阻塞、接收丢帧 | 日志、抓包 |
把这六层摆在桌面上之后,那个原始问题就有了一个干净的回答:**CAN 在严格意义上是协议,而且是同时覆盖数据链路层和物理层电气部分的一套规范;工程口语里的“CAN 接口”,指的是这套协议在物理世界的落地形态,包括收发器、连接器和线束。**两者不是二选一的关系,是同一件事在抽象层和物理层的两个名字。下面两章分别从协议和接口两个方向把这个结论撑起来。
2. 协议视角:CAN 的规则全都写在帧里
判断一样东西是不是协议,最朴素的标准是:它有没有规定“谁在什么时候可以说话、说的话长什么样、说错了怎么办”。CAN 这三条全占了,而且规定得相当细。它的帧结构、仲裁机制和错误处理构成了一个自洽的体系,任何一家厂商的控制器只要按这套规则实现,就能和另一家的节点在同一根线上共存——这种互操作性正是协议存在的意义。我经常跟新人说,你不需要背下每一个字段,但你必须理解三件事:帧怎么组织、冲突怎么解决、错误怎么被发现和隔离。这三件事理解了,剩下的都是查表。
2.1 四种帧类型撑起了协议的骨架
CAN 总线上跑的不止一种帧。数据帧负责携带实际内容,是绝大多数业务通信使用的那一种;远程帧用于请求对方发送指定 ID 的数据,实际项目里用得很少,因为它会引入额外的不确定性;错误帧由检测到错误的节点主动发出,用来通知全网“刚才那一帧有问题”;过载帧用于接收方还没准备好时请求延迟。
数据帧的字段排布本身就是协议的体现。开头是一位帧起始,把总线从空闲拉出来;接着是仲裁段,标准格式里是 11 位标识符加一位远程帧标志,扩展格式里是 29 位;然后是控制段,包含标识符扩展位、保留位和数据长度码;中间是数据段,经典格式最多 8 字节;后面是 15 位CRC 段加一位界定符;再往后是应答段,发送方发隐性位,任何正确接收的节点都会把它拉成显性,等于集体签字确认;最后是 7 位帧结束,把总线拉回隐性。
这套结构里有两个细节特别值得注意。第一个是数据长度码只有 4 位,所以经典格式的上限被卡在 8 字节——这不是随意定的,而是在当年总线速率有限、实时性要求高的背景下做的权衡,字节数越多,一帧占用的时间越长,高优先级消息的等待时间就越不可控。第二个是应答段的设计:不是指定某一个节点应答,而是所有正确接收的节点一起把这一位拉成显性。这带来一个副作用,发送方只知道“至少有一个节点收到了”,不知道是谁收到了。这个特性在很多现场故障里是关键线索——如果发送方报应答错误,说明总线上没有一个节点能正确接收,问题往往在物理层或者波特率;如果发送方一切正常,但某个特定节点没反应,那问题多半在接收端的滤波器、ID 配置或者应用层。
2.2 位仲裁:协议层最值得琢磨的一个设计
CAN 最有意思的地方在于,它允许多个节点同时开始发送,而且不会因此丢数据。这套机制叫非破坏性位仲裁,靠的是两个约定:总线上显性位压过隐性位;标识符数值越小优先级越高。
具体怎么运作的:所有想发数据的节点先监听总线,发现空闲后同时发出帧起始位,然后逐位往外发自己的标识符。每一位发出后,节点都会回读总线上的实际电平。如果自己发的是隐性位,但读回来是显性位,说明有别的节点正在发一个更小数值的 ID,自己输了,立刻停止发送、转为接收状态,等下一次总线空闲再重来。赢的那个节点完全感觉不到有人跟它竞争,帧继续往下发,一个位都不会丢。
举个例子:三个节点同时要发,标识符分别是 0x0F0、0x123、0x150。从最高位比起,第一个不同的位置就分出胜负,0x0F0 的高位更小,一路都是显性,会把另外两个都压下去。输的节点不会产生错误帧,也不会重传同一帧——它们只是退让,等这帧结束后按优先级重新竞争。
这个设计带来两个实践中必须知道的后果。**第一,高优先级帧会饿死低优先级帧。**如果总线上周期性发的高优先级帧足够多,低优先级帧可能永远抢不到总线。我遇到过一次,某个诊断报文要等十几秒才发出去,一算负载率已经到 70% 以上了,把几条非关键的周期性报文周期从 10 毫秒放宽到 100 毫秒,问题立刻消失。**第二,标识符分配是一门学问。**别图省事按设备顺序编号,要按消息的实时性要求来分:安全相关的、控制闭环的用小 ID,状态上报的、诊断的用大 ID。等到系统跑起来再想调整 ID,那就是牵一发动全身的活儿。
2.3 错误检测与故障界定:协议自带的免疫系统
CAN 在协议层内置了一整套错误检测机制,这是它能在电磁环境恶劣的场合活下来的重要原因。检测手段有五种:位错误,节点发出去的电平和回读的不一致;填充错误,位填充规则被破坏;CRC 错误,接收端算出的校验值和帧里带的对不上;格式错误,固定格式位出现了不该出现的电平;应答错误,发送方在应答位没等到任何人拉显性。
其中位填充这条规则经常被忽略,但它是协议层的一部分,和插头没有任何关系。规则是:从帧起始到 CRC 段结束,连续出现 5 个相同电平,发送方必须插入一个相反电平;接收方看到连续 5 个相同电平,就自动把下一位丢掉。这样做是为了保证总线上的跳变足够多,接收方能持续从跳变沿恢复时钟——如果没有这条规则,一长串相同电平会让接收端的位定时漂移,采样点落到错误的位置。
检测到错误之后的处理更能体现设计意图。每个节点维护两个计数器:发送错误计数和接收错误计数。计数正常时节点处于错误主动状态,发现问题就主动发错误帧把这一帧作废,让全网重来;发送错误计数超过 127 之后进入错误被动状态,只能被动标记错误,不再主动打断总线——这是为了防止一个本身有问题的节点把整条总线搞瘫痪;发送错误计数超过 255 时进入总线关闭状态,节点主动脱离总线,停止收发。恢复方式由软件决定:可以等一段冷却时间后自动重连,也可以要求上位机下发指令才恢复。
注意:总线关闭之后不做任何处理,是新手最容易留下的一类问题。表现是设备“突然就不通信了”,重启就恢复,过一阵又复发。一定要在驱动里加上总线关闭的回调处理,并记录发生次数和发生时的错误计数,这两个数字对定位物理层问题极有价值。
2.4 从经典格式到可变速率格式:变的是规则,插头几乎没动
后来演进出的可变速率格式,是理解“协议与接口分开”这件事最好的例子。它的核心改动有三处:数据段可以切换到时基更短的高速率,仲裁段还是用原来的速率保证兼容;数据长度码扩展,单帧最多能带 64 字节,把小包拼大包的开销省下来了;校验算法加固,加入了填充位计数和固定填充位,把原来残余的错误漏检概率又压低了一截。
这里的关键在于:这些改动全部发生在协议层。总线上还是那两根差分线,电平定义没变,终端电阻还是 120 欧姆,连接器还是那些连接器。真正需要换的是收发器——因为速率上去了,收发器的上升下降时间、环路延时必须跟得上,老型号在高速率下波形会明显变圆。所以你会看到一个很典型的场景:同一块板子,换一颗支持高速率的收发器,再改几行控制器配置,协议就升级完了,线束一根没动。如果 CAN 只是一根“接口”,这种升级是不可能发生的;正因为规则和物理形态是分离的,它才能这样平滑地演进。
3. 接口视角:电气和机械上的硬性约束
把视角切换到接口这一侧,逻辑就完全变了。这里没有“谁先说话”的问题,只有电压够不够、阻抗配不配、线长超没超、插头对不对。这一层的错误往往是确定性的——接反了就是不通,电阻少一个就是不稳,不用怀疑,测一下就知道。我个人的经验是:现场报“CAN 通信异常”,七成以上能在这一层找到原因,而且大部分用万用表和示波器十几分钟就能定位。可惜很多人第一反应是去翻代码。
3.1 控制器、收发器、总线:三个必须分开说的东西
这三个东西经常被混成一句“CAN 芯片”。控制器在单片机内部,是一个数字外设,它的工作是按协议规则组装和解析帧、算 CRC、做位填充、跑错误计数器、按滤波器决定收不收这一帧。它的引脚输出的是普通单端逻辑电平,也就是 0 和电源电压。收发器是一颗模拟为主的小芯片,输入端接控制器的收发引脚,输出端接总线,负责把单端逻辑转成差分电平、把总线上的差分电平转回单端,同时还承担总线故障保护、共模抑制这些活儿。总线就是那对特性阻抗 120 欧姆的双绞线。
为什么必须分清?因为“这块芯片不支持 CAN”这句话,指的可能是完全不同的三件事。可能是单片机的控制器外设数量不够,这要靠换型号或者外扩解决;可能是板上压根没焊收发器,很多核心板为了省成本只把控制器的引脚引到排针上,收发器留了空焊盘;也可能是收发器焊了但供电没接对,某些型号需要 5V,某些能宽压工作,混着用就会出现“逻辑能通、总线不通”的现象。我见过一次很典型的返工:一块板子怎么都不通信,示波器量控制器出来的收发引脚波形很漂亮,量总线却是一潭死水,最后发现收发器的使能脚被默认拉到了一个无效状态,飞线改了一个电阻就好了。
所以在原理图评审时,我坚持要看三个独立的数字:控制器外设几路、收发器几颗、连接器几个。这三个数字对不上,一定要当场问清楚。
3.2 差分电平与终端电阻:接口层的两条硬性规则
总线的电平定义很简洁。显性状态下,两条线的电平被分别拉高和拉低,差分电压大约 2 伏;隐性状态下,两条线都处于中间的偏置电压,差分接近 0 伏。接收端的判定阈值大致是:差分电压超过 0.9 伏判为显性,低于 0.5 伏判为隐性,中间是不确定区。这个设计的好处是,即使线上有相当程度的共模干扰,只要两条线一起漂,差分值基本不变,接收端照样能判对——这就是差分传输抗干扰的根本原因,也是为什么这两根线必须绞在一起走,绞距越密,共模干扰被抵消得越彻底。
终端电阻是另一个硬指标。高速总线的两端各要接一个 120 欧姆电阻,跨接在两条信号线之间。为什么是两端而不是一端、为什么是 120 而不是别的值?因为双绞线的特性阻抗大约是 120 欧姆,信号传到头如果没有匹配的负载,就会反射回来,和后续的信号叠加,在高速率、长线的情况下直接把波形搞花。两端各接一个 120 欧姆,从任意一点看进去,是两个 120 欧姆并联后与线路阻抗匹配,等效 60 欧姆。
所以有一个非常实用的现场判断方法:断电,用万用表电阻档量两条信号线之间,正常应该读到 60 欧姆左右。读到 120 欧姆,说明只接了一端;读到无穷大,说明两头都没接或者线断了;读到明显小于 60 欧姆,说明某处短路或者有人多接了一个。这个方法能在三十秒内排掉一大类故障,我基本上每次到现场第一件事就是做它。
注意:测量前一定要断开所有节点的供电,带电测电阻不但读数不准,还可能损坏万用表。另外某些节点的收发器内部集成了一部分终端功能,断电后可能影响读数,遇到读数奇怪的情况要先把节点逐个拔掉再测。
电阻的功率也有讲究。有人问要不要用 1 瓦的,其实没有必要——显性状态虽然电流不小,但单帧的显性时间很短,平均功耗远低于峰值,常规的 1/4 瓦贴片足够,只要注意别把两个电阻叠在一起贴着塑料件就行。
3.3 速率、线长、节点数:接口层的预算怎么算
接口层的所有约束,归根到底都指向一个物理事实:**信号在线上跑是有延时的,而且必须在一个位时间内跑完一个来回,才能完成仲裁和应答。**这就是为什么速率和线长是一对死绑的关系。下面这张表是行业里流传很广的经验值,我在实际项目里试过,基本吻合,可以当预算用:
| 波特率 | 单段最大线长(经验值) | 典型应用场景 |
|---|---|---|
| 1 Mbps | 约 40 米 | 短距离高实时性控制 |
| 500 kbps | 约 100 米 | 车载动力与底盘常见档位 |
| 250 kbps | 约 250 米 | 商用车、工程机械 |
| 125 kbps | 约 500 米 | 工业现场、楼宇 |
| 50 kbps | 约 1000 米 | 长距离低速采集 |
| 20 kbps | 约 2500 米 | 超长距离、极低速场合 |
这张表的用法不是“正好卡在边界上”,而是留出余量。我一般的做法是把实际线长控制在表内数值的 60% 到 70%,剩下的余量用来对付线材批次差异、接头接触电阻和温度变化。曾经有一个项目,500 kbps 跑了 95 米,实验室里一切正常,装到现场夏天中午就开始偶发错误帧,后来把速率降到 250 kbps 就彻底稳了。不是因为 95 米超过了 100 米的限值,而是因为余量太小,任何一点参数漂移都会把它推出安全区。
节点数量同样有个上限,但这个上限更多取决于收发器的输入阻抗而不是协议本身。每个节点挂在总线上都会带来一定的负载,节点越多,总的差分负载越重,显性时的差分电压就越低,低到一定程度接收端就判不出来了。保守的做法是单段不超过 32 个节点,如果需要更多,就用中继或者分段。还有个容易被忽略的点是支线长度:从主干线分出去到节点的这一段,在高速率下要尽量短,一般控制在 0.3 米以内。支线就是一段没有终端匹配的短线,它会把信号反射回主干,支线越长反射越明显。我见过一个机柜,所有节点都从一条主线上用长线并出来,每根支线接近 1 米,500 kbps 下根本通不了,改成分段加中继之后立刻正常。
3.4 五花八门的连接器:同一个协议,不同的插头
到了连接器这一层,可以说是百花齐放,同一个协议能长出十几种不同的物理形态,这也是“接口”这个词最容易被误解的地方——很多人说的“CAN 接口”,其实指的是某个特定形状的插头。
常见的几种:9 针 D 型连接器,在工业设备和调试口上很常见,信号定义基本上是 2 脚接负极性信号线、3 脚接地、7 脚接正极性信号线,但这套定义并不是强制标准,不同厂商的引脚分配存在差异,接线前必须查对方的手册。车载诊断口是一个 16 针的梯形接口,其中两针给一组总线、另两针给另一组,还有电源和地。插拔式接线端子在工业控制柜里最常见,通常标着正、负、地三个位。圆形航空插头用在高振动、需要防护的场合。还有一些设备会用网线接口的外形来跑这路总线,这种最容易让人误判,看到网口就以为是以太网。
线材也有讲究。要用特性阻抗 120 欧姆的双绞线,两根信号线对绞,有屏蔽层更好。屏蔽层的接地方式是个老话题:两端都接,在某些场合会形成地环流,反而把干扰引进来;一端接,抗干扰能力会打折。我自己的习惯是,短距离、单机柜内部,两端接地问题不大;跨机柜、长距离、接地电位差明显的场合,只在主控端接,另一端通过一个小电容接地。这个做法不是教条,具体还得看现场,但至少比“随手两头一拧”强得多。
4. 分不清会怎样:选型、配置、排错三处的实际影响
前面讲的是概念,这一章讲后果。概念上的模糊不会立刻出问题,它会在某个具体的节点上以某种具体的形式炸出来,而且往往是返工级别的。我把这些年遇到的案例归了三类:选型时把接口当协议、配置时把协议参数当接口参数、排错时从错误的层次入手。这三类问题的共同点是,只要事先把层次说清楚,全都可以避免。
4.1 选型时把接口当协议,买回来对不上
这是最常见也最贵的一类。某项目需求写的是“需要两路独立 CAN”,采购按“两个接口”理解,选了一块带两个连接器的板子。硬件工程师拿到手才发现,板子上只有一个控制器、一颗收发器,两个连接器是从同一对线并联引出来的。电气上它们是同一个通道,不可能一个跑 500 kbps 一个跑 250 kbps,也不可能做双通道冗余。返工方案要么换板,要么外挂一个控制器模块,工期直接推了两周。
还有个反向的例子:另一位同学要的是“两个连接器”,方便菊花链布线,结果供应商给了一块双控制器的板子,成本上去了不说,多出来的那一路还得在软件里屏蔽掉,白白增加复杂度。
我的处理办法是在需求阶段就把三个问题问死:**需要几个能独立配置速率的逻辑通道?需要几个物理连接器?这两个数字是不是必须相等?**如果需求方说“我就要两个插口,随便插哪个都行”,那就是并联引出,一路控制器足够;如果说“我要同时接两个不同速率的子系统”,那必须是两个独立控制器。这两种需求的成本差距可能是几倍。
4.2 位时序配置:协议参数配在控制器里
位时序是最能体现“协议参数落在硬件外设里”的地方。它不是接口参数,插头和线材怎么换都改不了它,但它配错了,表现却很像物理层故障——偶发错误帧、通信不稳定、长线尤其明显。
配置的核心是把一个位时间切成若干份,每份叫一个时间份额。整个位时间由四段组成:同步段、传播段、相位缓冲段一、相位缓冲段二。采样点就在相位缓冲段一结束的位置。举个具体例子,假设控制器时钟 8 MHz,目标速率 500 kbps。
第一步算位时间:1 除以 500000,等于 2 微秒。第二步选时间份额数,取 16 份,则每份 125 纳秒。第三步算分频:8 MHz 的周期是 125 纳秒,正好一份,所以分频系数取 1。第四步分配各段:同步段 1 份、传播段 5 份、相位缓冲段一 6 份、相位缓冲段二 4 份,加起来正好 16 份。采样点位置等于前三段之和除以总份数,也就是 12 除以 16,等于 75%。
如果想按行业常见推荐值把采样点提到 87.5%,就改成同步段 1 份、传播段 6 份、相位缓冲段一 7 份、相位缓冲段二 2 份,前三段之和 14,14 除以 16 正好 87.5%。同步跳转宽度一般取 1 到 2 份,用来吸收节点之间的时钟偏差。
注意:一条总线上所有节点的采样点必须尽量一致,差异最好不要超过几个百分点。我踩过一次坑:两个厂家的设备,一个默认 75%,一个默认 87.5%,短线测试完全正常,接到 60 米线束上就开始偶发错误帧,速率降到一半才稳。后来把两边都统一到 87.5%,问题消失。所以协议里说的“速率要一致”其实不够,采样点也要一致。
4.3 排错的顺序:从物理层往上,别一上来就翻代码
排错有一条我坚持了很多年的顺序,几乎没失手过:先量电阻,再量静态电平,再看波形,再确认速率和采样点,然后才是 ID 和周期,最后才是应用层信号定义。
为什么是这个顺序?因为下面几层的错误会以“上面几层出错”的形式表现出来,而下面的层次测量成本最低。终端电阻缺一个,表现可能是间歇的错误帧,看起来像协议问题;收发器没供电,表现是彻底收不到,看起来像驱动没起来;波特率差一点,表现是偶尔收到一堆错误帧,看起来像线束干扰。如果按相反的顺序查,你会在代码里找到一百个“可能的原因”,然后一个一个排除,花掉整整两天。
反过来,下面几层确认没问题之后,往上查就是顺藤摸瓜:电阻 60 欧姆正常、静态电平 2.5 伏左右正常、波形干净、速率和采样点都对,那问题一定在滤波器和报文配置上;如果连滤波器都确认放开了,那就只剩应用层的数据解析了。这个顺序不是理论,是我被坑出来的——有一次为了一个偶发丢帧,我在驱动里加了一堆日志,最后发现是接插件松动,插拔一下就好的事。
5. 常见问题与排查实录
这一章是纯经验,都是我在实验室和现场反复遇到的。我把它们整理成了一张速查表,再加上几个印象比较深的案例。速查表的用法是:先看现象,再看对应的层次,然后按那一列的动作去做,不要跳步。
5.1 现象与层次对照速查表
| 现象 | 最可能的层次 | 优先动作 |
|---|---|---|
| 完全不通信,所有节点都收不到 | 接口:供电、接线、收发器 | 测信号线电阻,测收发器供电,检查正负是否接反 |
| 断电测电阻读到 120 欧姆 | 接口:终端电阻 | 补齐缺失一端,注意节点内部是否已集成 |
| 断电测电阻读到无穷大 | 接口:断线或双端缺失 | 分段测量,逐段断开定位 |
| 发送方报应答错误 | 接口或速率 | 先查物理层,再核对两侧速率 |
| 短线上正常,长线上偶发错误帧 | 协议:采样点或速率余量 | 统一各节点采样点,降低速率验证 |
| 只有某个特定节点收不到 | 控制器:滤波器或 ID 配置 | 放开验收滤波,核对标识符 |
| 通信一阵后彻底停止,重启恢复 | 协议:错误计数与总线关闭 | 加总线关闭回调,记录错误计数 |
| 波形上升沿圆钝、幅值偏低 | 接口:收发器速率等级或负载过重 | 核对收发器速率等级,减少节点或分段 |
| 高优先级报文正常,某条报文长期发不出 | 协议:仲裁优先级与总线负载 | 算负载率,调整标识符分配与发送周期 |
| 换一个机柜就变差,同一套设备 | 接口:屏蔽与接地 | 检查屏蔽层接地方式与地电位差 |
5.2 几个印象比较深的坑
第一个坑是终端电阻只焊了一端。板子出厂时两个 120 欧姆电阻都焊了,但其中一块板子的电阻位置被误贴了 0 欧姆,等于短路。表现是这条支路一接上,整条总线就瘫,因为等效阻抗被拉得太低,显性差分电压被压下去了。这种故障用电阻档一量就露馅,量出来只有二十几欧姆。所以我现在量电阻不只是看“有没有 60”,还要看“是不是明显小于 60”。
第二个坑是两支线太长。一个控制柜里,主干线只有 1 米,但从主干上分了 6 根支线到各个模块,每根 80 厘米。250 kbps 下勉强能跑,升到 500 kbps 直接不通。后来把模块改成串接在主干上,支线压到 10 厘米以内,问题消失。这件事让我后来画任何总线拓扑,都先把支线长度标出来,超过 30 厘米就必须解释原因。
第三个坑是屏蔽层两端接地引进了干扰。一台设备单机测试干干净净,装到现场就偶发错误帧。查了整整一天,最后发现屏蔽层在两端都接了机柜地,而两端的地电位差有将近 2 伏,屏蔽层上跑起了环流,反而变成了干扰源。改成主控端单点接地之后,现场和实验室表现一致了。这个案例说明,接口层的问题有时候不是“没做防护”,而是“做过头了”。
第四个坑是总线关闭没处理。某设备的错误计数被打满,进入脱离状态,软件里没有任何回调,界面上看起来就是“设备在线但不刷新数据”。这种问题最难查,因为从外部看设备是活的。后来加了错误计数和总线关闭次数的上报,才发现是某个接插件在振动下间歇接触不良,导致反复出错。加上上报之后,这个硬件问题三天就定位了,而在之前它可能藏几个月。
5.3 手里那两件工具怎么用
万用表承担了八成的初步判断。断电测信号线之间电阻,判断终端和短路;上电测静态时两条线对地的电压,隐性状态下两条线都应该在 2.5 伏附近,如果一条明显偏高一条明显偏低,说明有节点在持续输出显性,或者有节点短路到电源或地;再测一下收发器供电脚,确认电压在器件要求范围内。
示波器负责看波形。最方便的做法是用两个通道分别接两条信号线,然后打开数学运算做差,直接看差分波形。正常情况下应该看到清晰的方波台阶:显性时差分约 2 伏,隐性时接近 0 伏,边沿干净,没有明显的过冲和振铃。如果看到台阶变圆、幅值只有 1 伏出头,多半是负载过重或者收发器速率等级不够;如果看到明显的振铃和台阶上的台阶,基本可以确定终端匹配有问题。
提示:探地线一定要短,最好用探头自带的短弹簧地针。用地线夹子夹一根长线去测,测出来的“振铃”很可能是探头地线引入的,容易误判。
6. 我自己的几条体会
写到这里,那个最初的问题其实已经有了完整答案:CAN 在规范层面是协议,而且是同时覆盖数据链路和物理电气的一整套规则;工程口语里的“CAN 接口”,是这套协议落地时的物理形态。两者不是对立选项,是同一件事的两个侧面。真正值得花时间的是那六个层次怎么分、分完之后各自该找谁、该用什么工具——这才是能省钱省时间的地方。
几条我自己的做法,随手记下来。写需求文档时,把“路”拆成控制器数量、收发器数量、连接器数量三个字段,这一条至少帮我省过两次返工。画原理图评审时,一定要把收发器的使能脚和供电范围单独过一遍,很多“莫名其妙不通信”都出在这两个地方。调试时先把万用表拿出来,量电阻量电平,五分钟能排掉一大半问题,比在代码里加日志高效得多。多节点项目在协议文档里明确写死采样点,不要指望各家的默认值一样。最后,任何产品化的设计都要处理总线关闭的恢复策略,并且把错误计数上报出来——这个数字是硬件健康的体温计,出事的时候它就是唯一的线索来源。