1. 从一条总线说起:为什么今天还要聊 CAN 和 CANFD
如果你拆过任何一台近十年的汽车、工业控制器或者储能设备,大概率会在电路板上看到两根拧在一起的线,旁边标着 CAN_H 和 CAN_L。这东西不显眼,但它是整个系统里最不能出问题的一环。我最早接触 CAN 是在一个车载数据采集项目上,当时觉得这协议简单得有点过分——就两根线,一帧最多 8 个字节,速率撑死 1 Mbps。但真正上手之后才发现,越是简单的东西,坑越隐蔽。
后来 CANFD 出来了,很多人第一反应是"不就是把速率提上去、把数据段拉长吗"。我一开始也这么想,直到在一个电机控制项目里被仲裁机制和数据段速率切换的问题折腾了整整两周,才意识到 CANFD 不是简单的"CAN 加速版",它在协议层面做了不少取舍和重新设计。这篇文章就把 CAN 和 CANFD 放在一起讲清楚:它们各自解决什么问题、底层机制差在哪、实际选型和调试时要注意什么。不管你是刚接触总线的嵌入式新手,还是已经用过几年 CAN 但没系统梳理过的老手,应该都能从里面找到点有用的东西。
需要先说明的是,本文涉及的参数和实测数据,一部分来自公开的协议规范和常见控制器手册,另一部分是我在实际项目里踩坑总结出来的经验值。不同厂家的收发器、不同拓扑的线束,结果会有出入,具体以你手上的硬件手册为准。
2. CAN 协议的底层逻辑:不只是"两根线传数据"
2.1 差分信号与显性隐性:CAN 的物理层根基
很多人学 CAN 直接从帧格式开始背,我觉得这是本末倒置。CAN 能在一堆电磁干扰里活下来,靠的是物理层的差分传输。CAN_H 和 CAN_L 两根线,逻辑 0 叫显性(Dominant),逻辑 1 叫隐性(Recessive)。显性状态下两根线电压差大约 2V,隐性状态下电压差接近 0。
这个设计的关键在于:显性会覆盖隐性。也就是说,如果总线上有一个节点发显性、另一个发隐性,最终总线呈现显性。这个"线与"特性是后面仲裁机制能成立的前提。你可以把它理解成一群人开会,只要有一个人举手(显性),这个议题就算通过,没人举手(隐性)才算否决。
差分传输带来的直接好处是抗共模干扰。车上电机、继电器一动作,整条线束上会叠加很大的共模噪声,但两根线同时被干扰,差值基本不变,接收端照样能判出逻辑。这也是为什么 CAN 线要双绞——绞距越均匀,两根线受到的干扰越一致,共模抑制效果越好。我见过有人图省事用普通排线走 CAN,短距离低速还能凑合,一旦上到 500 kbps 以上,误码率立刻飙升。
2.2 非破坏性仲裁:CAN 最精妙的设计
CAN 最让我佩服的地方是仲裁机制。多个节点同时想发数据时,不是谁先抢到谁发,而是靠 ID 逐位比较,ID 数值小的优先级高。每个节点在发送的同时也在监听总线,一旦发现自己发的位和总线上的不一致(自己发隐性、总线是显性),就立刻退出,转为接收。
这个过程不破坏任何数据,赢的那个节点继续发,输的节点等下一轮。这就是"非破坏性仲裁"。对比一下 RS485 那种主从轮询,或者以太网的 CSMA/CD 冲突后重发,CAN 的效率高得多,而且高优先级消息的延迟是确定的。
这里有个容易踩的坑:ID 不只是"地址",它同时决定了优先级。我见过有项目把节点地址直接当 ID 用,结果某个低地址节点疯狂发心跳,把高优先级的安全消息全堵在后面。正确的做法是按消息的实时性要求分配 ID,安全相关的、周期短的给低 ID,日志、诊断这类给高 ID。
2.3 帧格式与位填充:8 字节背后的约束
经典 CAN 一帧最多 8 字节数据,这个限制当年是权衡出来的结果。数据太长,仲裁和错误处理的实时性就保证不了。帧里除了数据,还有仲裁场、控制场、CRC 场、ACK 场等,标准帧和扩展帧的区别就在仲裁场——标准帧 11 位 ID,扩展帧 29 位 ID。
位填充是另一个细节。CAN 规定连续 5 个相同电平后必须插入一个相反电平,接收端再自动去掉。目的是保证总线有足够的跳变,让接收方能持续同步时钟。这个机制在调试时经常被忽略:如果你用示波器抓波形,看到偶尔多出来一位,别慌,那可能就是填充位。
提示:位填充是硬件自动完成的,软件层不用管。但如果你在写底层驱动或者做协议分析,必须把填充位算进去,否则解析出来的帧长会不对。
3. CANFD 到底改了什么:速率、长度与兼容性
3.1 数据段提速:从 1 Mbps 到 5 Mbps 以上的代价
CANFD 最直观的变化是速率。经典 CAN 最高 1 Mbps,CANFD 的仲裁段还是保持 1 Mbps 以内(为了兼容老节点和保证仲裁可靠),但数据段可以切到 2 Mbps、5 Mbps 甚至更高。这个"分段变速"是 CANFD 的核心设计。
为什么要分段?因为仲裁阶段需要所有节点逐位比较,速率太高的话,线束延迟、收发器延迟会让位采样出错。而数据段只有发送节点在发,其他节点在收,不涉及仲裁,速率可以拉高。实际项目里,我一般把仲裁段设 500 kbps,数据段设 2 Mbps,这个组合在大多数线束长度下比较稳。如果线束超过 10 米,数据段建议降到 1 Mbps 或者加中继。
速率切换点由 BRS 位(Bit Rate Switch)控制。BRS 为 1 时,从仲裁段末尾开始切到数据段速率,CRC 段再切回来。这个切换对收发器有要求,老式 CAN 收发器跟不上高速切换,必须用支持 CANFD 的收发器。我踩过一次坑:控制器配了 CANFD,收发器还是老型号,结果数据段一到 2 Mbps 就疯狂报错,换了收发器立刻正常。
3.2 数据长度扩展到 64 字节:效率提升的真相
CANFD 把数据场从 8 字节扩展到最多 64 字节。这个改动看起来只是"能装更多",但实际影响很大。经典 CAN 传 64 字节需要 8 帧,每帧都有仲裁、CRC、ACK 等开销,有效载荷占比很低。CANFD 一帧搞定,开销摊薄后总线利用率明显提升。
不过 64 字节不是随便设的,DLC 编码和经典 CAN 不同。经典 CAN 的 DLC 0-8 直接对应字节数,CANFD 的 DLC 9-15 分别对应 12、16、20、24、32、48、64 字节。这个非线性映射经常让人算错缓冲区大小。我在写驱动时第一次就按线性算,结果 64 字节的帧只分配了 15 字节缓冲,直接内存越界。
| DLC 值 | 经典 CAN 字节数 | CANFD 字节数 |
|---|---|---|
| 8 | 8 | 8 |
| 9 | 不支持 | 12 |
| 10 | 不支持 | 16 |
| 11 | 不支持 | 20 |
| 12 | 不支持 | 24 |
| 13 | 不支持 | 32 |
| 14 | 不支持 | 48 |
| 15 | 不支持 | 64 |
3.3 兼容性不是自动的:CANFD 与经典 CAN 共存的现实问题
很多人以为 CANFD 控制器能自动兼容经典 CAN 节点,其实没那么简单。CANFD 帧和经典 CAN 帧在格式上有区别,经典 CAN 控制器收到 CANFD 帧会当成错误帧处理,可能触发错误计数甚至总线关闭。
实际做法有两种:一是全网升级到 CANFD,二是用支持"CANFD 被动"的控制器,让它能识别但不参与 CANFD 通信。还有一种折中方案是网关隔离,CANFD 网段和经典 CAN 网段通过网关转发。我在一个混合网络项目里用过网关方案,配置起来麻烦,但胜在不用换掉所有老节点。
注意:如果你的总线上既有 CANFD 又有经典 CAN,务必确认经典 CAN 节点的错误处理策略。有些老控制器遇到不认识的帧会一直重发,把总线拖垮。
4. 位定时与采样点:调不通十有八九是这里的问题
4.1 位时间的四段划分与采样点位置
CAN 和 CANFD 的位定时都由四段组成:同步段、传播段、相位缓冲段 1、相位缓冲段 2。采样点就在相位缓冲段 1 和 2 之间。采样点位置用百分比表示,比如 75% 意味着在位时间的 75% 处采样。
采样点设在哪很讲究。设太靠前,信号还没稳定就采样,容易误判;设太靠后,留给相位缓冲的余量不够,时钟偏差累积后容易出错。经验值是:仲裁段采样点 75%-80%,数据段采样点 70%-75%。数据段速率高,位时间短,采样点要适当提前。
我调过一个 2 Mbps 数据段的 CANFD 网络,一开始采样点设 80%,短距离没问题,线束加到 8 米后误码率上升。后来把采样点降到 72%,同时调整了传播段,才稳定下来。所以采样点不是固定值,要结合线束长度和收发器延迟算。
4.2 波特率计算:从时钟源到实际位时间的完整推导
位定时参数不是拍脑袋定的,要从控制器时钟算起。假设控制器时钟 40 MHz,目标波特率 500 kbps,位时间就是 80 个时钟周期。这 80 个周期要分配到四段里,同时满足采样点要求。
具体步骤:先定同步段为 1 个周期,然后根据采样点百分比分配剩余周期。比如采样点 75%,相位缓冲段 1 加传播段占 60 个周期,相位缓冲段 2 占 19 个周期。再根据线束延迟调整传播段,收发器延迟一般 100-200 ns,按 500 kbps 算,一个位时间 2 微秒,传播段至少要覆盖往返延迟。
CANFD 的数据段要单独算一套参数。仲裁段和数据段可以用不同的时钟分频,这也是为什么 CANFD 控制器通常有两组位定时寄存器。我建议在配置工具里先把两组参数都算好,再写进代码,避免运行时切换出错。
4.3 实测中的采样点调整:示波器与错误计数器的配合
光算不够,必须实测。我的做法是:先用示波器抓总线波形,看位宽是否均匀、跳变沿是否干净。然后读控制器的错误计数器,如果 REC 或 TEC 持续增长,说明采样点或速率有问题。
调整时一次只改一个参数,改完观察一段时间。我一般先调数据段采样点,从 75% 开始,每次降 2%-3%,看错误计数是否下降。如果降到 65% 还不行,可能是线束或终端电阻的问题,别再死磕采样点。
终端电阻也常被忽略。CAN 总线两端各要一个 120 欧姆电阻,总线上其他节点不能再加。我见过有人在每个节点都焊了 120 欧姆,结果总线负载太重,波形幅度掉到 1V 以下,通信时好时坏。用万用表量一下 CAN_H 和 CAN_L 之间的电阻,正常应该是 60 欧姆左右(两个 120 欧姆并联)。
5. 错误处理与总线健康:那些让你半夜爬起来的问题
5.1 错误帧与错误计数器:CAN 的自我诊断机制
CAN 有一套很完善的错误检测机制:位错误、填充错误、CRC 错误、格式错误、ACK 错误。任何节点检测到错误就发错误帧,让全网知道这帧废了。同时每个节点维护两个计数器:发送错误计数器 TEC 和接收错误计数器 REC。
计数器不是随便加的,有明确的加减规则。发错误帧加 8,成功发送减 1,接收错误加 1 等。当 TEC 或 REC 超过 127,节点进入错误被动状态;超过 255,进入总线关闭状态,自动脱离总线。这个机制的好处是能自动隔离故障节点,避免一个坏节点拖垮全网。
我在一个项目里遇到过某个节点周期性总线关闭,查了半天发现是它的晶振偏差太大,导致采样点漂移。换晶振后问题消失。所以错误计数器不只是看热闹,它能帮你定位硬件问题。
5.2 总线关闭的恢复策略:自动还是手动
总线关闭后怎么恢复,是个策略问题。协议允许自动恢复,条件是检测到 128 次连续 11 个隐性位。但自动恢复有风险:如果故障没排除,节点会反复进出总线关闭,影响全网。
我的做法是:关键节点用自动恢复,但加恢复次数限制,超过阈值就上报故障;非关键节点可以手动恢复,由上层决定何时重新接入。CANFD 在这方面和经典 CAN 基本一致,但数据段速率高,出错概率大,恢复策略要更保守。
5.3 常见故障排查链路:从波形到代码的完整思路
通信出问题,我一般按这个顺序查:
- 量终端电阻,确认 60 欧姆左右。
- 示波器看波形,确认幅度、位宽、跳变沿。
- 读错误计数器,判断是发送还是接收问题。
- 检查位定时参数,特别是采样点。
- 确认收发器型号是否匹配速率。
- 最后才怀疑代码,比如缓冲区溢出、中断优先级冲突。
这个顺序能解决八成以上的问题。我见过太多人一上来就改代码,改了半天发现是终端电阻没接。硬件问题永远优先于软件问题,这是总线调试的铁律。
6. 选型与落地:什么时候用 CAN,什么时候上 CANFD
6.1 带宽需求评估:算清楚再决定
选 CAN 还是 CANFD,先算带宽。把所有周期消息的字节数乘以发送频率,加上事件消息的估算值,得到总负载。经典 CAN 在 500 kbps 下,建议负载不超过 50%,留余量给突发和错误重传。如果算下来超过 40%,就该考虑 CANFD 了。
举个例子:20 个节点,每个节点每 10 ms 发 8 字节,总负载就是 20×8×100=16000 字节/秒。500 kbps 理论极限约 62500 字节/秒,负载 25.6%,经典 CAN 够用。如果每个节点发 16 字节,负载翻倍到 51%,就必须上 CANFD 或者提高速率。
6.2 节点兼容性与升级成本:别只看芯片价格
CANFD 控制器和收发器比经典 CAN 贵,但真正的成本在升级和验证。老节点能不能换、线束要不要改、测试用例要不要重写,这些都要算进去。我参与过一个项目,为了省成本只把主控换成 CANFD,结果和老传感器通信时频繁出错,最后不得不加网关,反而更贵。
如果系统里大部分节点是新的,直接上 CANFD 更省事。如果老节点多、生命周期还长,建议先用网关过渡,等老节点自然淘汰再全网升级。
6.3 典型应用场景对照:汽车、工业与储能
汽车领域,动力和底盘早就用 CANFD 了,车身网络还在用经典 CAN 的也不少。工业控制里,CANopen 基于经典 CAN,迁移到 CANFD 需要协议栈支持。储能设备这几年上 CANFD 很快,因为电池管理需要传大量电压温度数据,经典 CAN 带宽不够。
| 场景 | 推荐协议 | 理由 |
|---|---|---|
| 车身灯光控制 | 经典 CAN | 数据量小,节点多,成本敏感 |
| 电机控制 | CANFD | 需要高频传电流、位置数据 |
| 电池管理 | CANFD | 电芯数量多,数据量大 |
| 工业传感器 | 经典 CAN | 协议栈成熟,节点便宜 |
7. 调试工具与实战技巧:少走弯路的经验
7.1 分析仪选型:别只盯着价格
CAN 分析仪从几百到几万都有。入门级能抓报文、发报文,但做 CANFD 分析时要注意是否支持数据段速率切换。我买过一台便宜的分析仪,标称支持 CANFD,实际只能抓仲裁段,数据段全是错的。后来换了支持双速率采样的型号才正常。
选型时重点看:是否支持 CANFD、最大数据速率、时间戳精度、是否支持触发和过滤。时间戳精度对分析时序问题很关键,低于 1 微秒的基本不够用。
7.2 报文过滤与触发:抓重点而不是抓全部
总线上报文多的时候,全抓下来根本看不过来。我一般先按 ID 过滤,只看关心的几个。分析偶发问题时用触发,比如某个 ID 出现特定数据时开始抓,或者错误帧出现时触发。这样抓到的数据量小,分析效率高。
CANFD 的过滤要注意 DLC 字段,因为 DLC 和实际字节数不是线性关系,过滤条件写错会漏报文。
7.3 代码层面的注意事项:缓冲区与中断
写 CAN 驱动时,缓冲区管理是重灾区。CANFD 一帧 64 字节,如果按经典 CAN 的 8 字节缓冲设计,必然溢出。我建议接收缓冲按最大帧长分配,并且用环形缓冲加 DMA,减少中断频率。
中断优先级也要注意。CAN 中断如果被其他高优先级中断长时间阻塞,接收 FIFO 会溢出。我在一个项目里把 CAN 中断设成最低优先级,结果高速通信时丢帧严重,调高优先级后解决。
提示:CANFD 数据段速率高,对控制器内存带宽也有要求。如果控制器主频低,DMA 搬运 64 字节可能成为瓶颈,选型时要确认。
8. 写在最后:一些个人体会
CAN 和 CANFD 这东西,入门容易精通难。协议本身不复杂,但实际项目里遇到的问题,往往不在协议本身,而在硬件设计、线束布局、参数配置这些细节上。我这些年最大的体会是:遇到通信问题,先怀疑硬件,再怀疑配置,最后才怀疑代码。这个顺序能帮你省下大量时间。
另外,CANFD 不是万能药。速率提上去了,但线束、收发器、控制器都要跟上,任何一个环节拖后腿,整体性能就上不去。选型时别只看芯片手册上的最高速率,要按实际线束长度和节点数量打折扣。
最后分享一个小技巧:调试新网络时,先只接两个节点,用最低速率跑通,再逐步加节点、提速率。这样出问题时容易定位,比一上来就全接上、高速率跑要高效得多。