☰
CAN通信学习路径:从显性隐性到帧结构,嵌入式初学者入门指南
2026/10/21 2:21:30 网站建设 项目流程

1. 为什么CAN通信值得单独拎出来学

CAN通信这东西,第一次接触的人多半会觉得它有点“反直觉”。明明是个总线,却不像串口那样一问一答;明明只有两根线,却能挂几十个节点;明明速率不算高,却在汽车、工业控制这些对可靠性要求极高的场景里活了几十年。我刚开始学的时候,也是被“显性电平”“隐性电平”“位定时”“仲裁”这些词绕得头晕,后来真正上手调过几块板子、抓过几次波形,才慢慢摸到门道。

这篇内容就是把我自己学CAN的路径重新梳理一遍。它适合谁看?适合已经会点单片机、用过UART或I2C,但一碰到CAN就不知道从哪下手的嵌入式初学者;也适合工作中需要用到CAN、但只停留在“能通就行”阶段的工程师,想回头把底层逻辑补扎实。核心关键词就一个:CAN通信的学习路径。我会按“先建立直觉、再啃协议、然后动手、最后排错”的顺序来讲,每一步都告诉你为什么这么安排,以及我踩过的坑。

先说结论:CAN的学习不能一上来就抱着协议手册硬啃。它是一门“先有场景、再有规则”的技术。你得先知道它解决的是什么问题,才能理解那些规则为什么长这样。所以我的路径是:先搞懂它为什么存在,再理解帧结构,接着动手搭最小系统,最后在排错中反哺理论。下面按这个顺序展开。

2. 学习路径的整体设计与取舍逻辑

2.1 为什么不能从协议手册第一页开始读

很多人学CAN的第一反应是找一份官方协议文档,从“帧格式”那一章开始看。我试过,效果很差。因为协议手册是写给“已经懂的人”看的参考书,不是教程。它默认你知道为什么要分标准帧和扩展帧,默认你理解“位填充”是为了同步,默认你清楚“仲裁”发生在什么时刻。你如果直接读,就会陷入“每个字都认识,连起来不知道在说什么”的状态。

我的建议是反过来:先找一个真实的CAN应用场景,比如汽车里的车窗控制、电池管理,或者工业里的电机驱动。你不需要真的去修车,只需要知道“哦,原来这里有一堆设备挂在两根线上,它们要互相说话,还不能互相打架”。有了这个画面,再去理解“多主架构”“非破坏性仲裁”就顺理成章了。这就是我把它放在路径第一步的原因:先建立场景直觉,再学规则。

2.2 学习路径的三个阶段划分

我把整个学习过程分成三个阶段,每个阶段的目标和产出都不一样。

第一阶段叫“建立直觉”,目标是能用自己的话解释CAN为什么适合多节点、抗干扰强。产出是你能在白纸上画出总线拓扑,并说清楚显性位和隐性位谁“赢”。

第二阶段叫“啃协议”,目标是能看懂一帧CAN报文,知道每一段是干什么的。产出是你能手动解析一段抓包数据,说出ID、DLC、数据段分别是什么。

第三阶段叫“动手与排错”,目标是能自己搭一个最小CAN节点,发一帧收一帧,并且遇到不通的时候有排查思路。产出是一个能跑起来的小系统,以及一份你自己的排错清单。

这三个阶段不是严格线性的,但大方向不能乱。跳过第一阶段直接啃协议,你会很痛苦;跳过第三阶段只学理论,你永远不知道实际波形长什么样。

2.3 工具选型的取舍:为什么我推荐从独立CAN控制器入手

学CAN绕不开工具。市面上有几种选择:一是用带CAN控制器的单片机(比如很多ARM芯片内置CAN外设),二是用独立的CAN控制器芯片加收发器,三是用USB转CAN的分析仪。

我的建议是:初期用USB转CAN分析仪配合电脑软件来观察总线,同时用一块带CAN外设的开发板做发送端。为什么不推荐一上来就用复杂的车载网络?因为车载网络里节点太多、报文太杂,你分不清哪帧是你关心的。一个简单的双节点系统——一个发、一个收,或者一个分析仪加一个开发板——足够你理解所有基础概念。

独立CAN控制器芯片(比如经典的SJA1000系列)虽然老,但它的寄存器手册写得非常清楚,你能看到每一位是干什么的。相比之下,很多现代单片机把CAN外设封装得很好,你调个库函数就发出去了,反而看不到底层细节。所以我的路径里,会建议你在第二阶段后期,花点时间读一读独立控制器的寄存器说明,哪怕你不实际用它。

3. 核心细节解析:从显性隐性到帧结构

3.1 显性位与隐性位:CAN的“物理层语言”

CAN总线最底层的概念就是显性位和隐性位。你可以把它想象成一根绳子,显性位是“有人用力拉”,隐性位是“没人拉”。如果两个人同时拉,绳子还是被拉的状态,所以显性位会“覆盖”隐性位。这就是CAN仲裁的物理基础:谁发显性位,谁就继续发;谁发隐性位但总线上是显性,谁就退出。

这里有个容易混淆的点:显性位对应逻辑0,隐性位对应逻辑1。为什么?因为CAN收发器在显性时驱动总线到差分电压,隐性时释放总线。很多初学者记反了,导致看波形时判断错误。我的记法是:“显性”就是“明显有动作”,有动作就是0,因为0在数字电路里常表示有效。当然这只是助记,真正要记的是差分电压的极性。

在实际测量时,你会看到CAN_H和CAN_L两根线。显性时,CAN_H大约3.5V,CAN_L大约1.5V,差分约2V;隐性时,两根线都在2.5V左右,差分接近0V。这个差分信号就是CAN抗干扰强的原因——共模干扰会被差分接收器抵消掉。

3.2 位定时与采样点:为什么波特率不是随便设的

CAN的波特率不是简单分频出来的,它涉及“位时间”的划分。一个位时间被分成四段:同步段、传播段、相位缓冲段1、相位缓冲段2。采样点就在相位缓冲段1和相位缓冲段2之间。为什么要这么复杂?因为CAN总线上的信号传播有延迟,节点之间的时钟也有误差,必须留出足够的“容错窗口”来保证所有节点都能正确采样。

我见过很多人设波特率时只改一个分频系数,结果通信不稳定。正确的做法是:先确定总线长度和节点数,然后根据传播延迟计算传播段,再根据晶振误差计算相位缓冲段。对于初学者,我建议直接用芯片厂商提供的计算工具,或者参考常见配置表。比如500kbps下,如果总线长度小于100米,通常用16个时间份额(TQ),采样点设在75%左右。

这里有个实操心得:采样点位置比波特率数值更重要。两个节点如果采样点差太多,即使波特率标称一样,也会出现偶发错误。我遇到过两个节点都是250kbps,但一个采样点在87.5%,另一个在75%,短帧没事,长帧就偶尔出错。后来统一采样点后问题消失。

3.3 帧结构拆解:标准帧与扩展帧的区别

CAN帧分标准帧和扩展帧,区别在ID长度:标准帧11位,扩展帧29位。为什么要有扩展帧?因为标准帧的ID空间只有2048个,对于复杂系统不够用。扩展帧通过“IDE位”和“SRR位”来区分,结构上多了一段。

一帧标准数据帧的结构是:帧起始(SOF)、仲裁段(11位ID + RTR)、控制段(IDE + 保留位 + DLC)、数据段(0-8字节)、CRC段、ACK段、帧结束。每一段都有明确作用。比如RTR位区分数据帧和远程帧,DLC表示数据长度(0-8)。注意DLC是4位,所以最大是8,不是随便写的。

我建议你在学习时,拿一张纸,把每一段画出来,然后找一段真实的抓包数据,一个位一个位地对。比如抓到一个ID为0x123、数据为0x11 0x22的帧,你就去数:SOF是1位显性,接着11位ID,然后RTR是显性(数据帧),IDE是显性(标准帧),保留位是显性,DLC是0010(表示2字节),然后数据,然后CRC,然后ACK槽,然后7位隐性帧结束。这样过一遍,比看十遍手册都管用。

3.4 仲裁机制:为什么CAN不会“撞车”

CAN最精妙的地方就是非破坏性仲裁。当多个节点同时发送时,它们会逐位比较。谁发隐性位但总线上是显性,谁就失去仲裁,自动转为接收状态,而且不需要重发——因为它的数据还没发出去,等总线空闲再发就行。赢得仲裁的节点继续发,完全不受影响。

这个机制的关键在于:ID越小,优先级越高。因为显性位是0,隐性位是1,所以ID数值小的帧,前面有更多显性位,更容易赢。这就是为什么在系统设计时,紧急报文要分配小ID。比如刹车信号用0x100,车窗用0x300,这样刹车永远优先。

我踩过的一个坑是:两个节点用了一样的ID,结果一个发的时候另一个也发,仲裁虽然不会损坏总线,但接收方会收到两帧混在一起吗?不会,因为仲裁会淘汰一个,但问题是两个节点都认为自己是发送方,最后只有一个成功,另一个会重发。如果它们的数据不同,接收方就会收到两个不同数据的同ID帧,逻辑就乱了。所以ID必须唯一,这是设计铁律。

4. 实操过程:从零搭一个最小CAN节点

4.1 硬件准备与接线要点

要动手,先准备硬件。我建议的最小配置是:一块带CAN控制器的开发板(比如常见的STM32系列或类似芯片),一个CAN收发器模块(比如TJA1050或类似型号),一个USB转CAN分析仪,若干杜邦线,一个120欧姆终端电阻。

接线很简单:开发板的CAN_TX接收发器的TXD,CAN_RX接RXD,收发器的CAN_H接分析仪的CAN_H,CAN_L接CAN_L。终端电阻接在CAN_H和CAN_L之间。注意:终端电阻必须接,而且只在总线两端各接一个。我见过有人每个节点都接120欧姆,结果总线负载太重,通信距离骤减。正确做法是:如果总线只有两个节点,就在这两个节点各接一个;如果多个节点,只在最远两端接。

电源方面,收发器通常需要5V或3.3V,看型号。开发板和收发器共地,这点不能忘。我刚开始时忘了共地,波形完全不对,查了半天才发现。

4.2 软件配置:波特率与过滤器设置

软件部分,以常见的单片机CAN外设为例。首先配置波特率。假设晶振8MHz,目标500kbps,位时间16TQ,那么分频系数 = 8MHz / (500kbps * 16) = 1。所以预分频器设为1。然后分配各段:同步段1TQ,传播段2TQ,相位缓冲段1为7TQ,相位缓冲段2为6TQ,采样点在1+2+7=10TQ处,即62.5%。这个配置在大多数场景下够用。

接着配置过滤器。CAN外设通常有多个过滤器组,可以设置接收哪些ID。初学者可以先把过滤器设为“接收所有”,等通了再细化。我建议一开始用“掩码模式”,掩码全0表示不关心任何位,这样所有帧都收。

发送就简单了:填好ID、DLC、数据,然后请求发送。注意发送邮箱可能有好几个,选一个空的就行。接收用中断或轮询,中断更高效。

4.3 第一帧的发送与接收验证

配置好后,先发一帧最简单的:ID=0x123,DLC=2,数据=0x11 0x22。用分析仪看总线,应该能看到一帧标准数据帧。如果看不到,先查硬件:终端电阻、共地、收发器供电。如果能看到但开发板收不到,查过滤器配置和接收中断使能。

我建议你第一次成功时,把分析仪抓到的数据保存下来,然后手动解析一遍。比如看到ID=0x123,就去数二进制:0x123 = 0001 0010 0011,共11位,前面补0就是000 0001 0010 0011?不对,11位是0x123 = 1 0010 0011,即二进制100100011,共9位,前面补两个0就是00100100011。这样数一遍,你就彻底记住标准帧ID是11位了。

4.4 用示波器看波形:验证显性隐性

如果有示波器,一定要看看CAN_H和CAN_L的波形。你会看到一串差分信号,显性时两根线分开,隐性时合拢。测量差分电压,显性约2V,隐性约0V。你还可以测量位时间,比如500kbps下每位2微秒,看看示波器上的格子对不对。

这个步骤看起来简单,但能帮你建立“代码-寄存器-引脚-总线-波形”的完整链路。以后遇到通信问题,你就能判断是软件没发出去,还是硬件没驱动好。

5. 常见问题与排查技巧实录

5.1 通信完全不通:从电源到终端的排查顺序

通信不通是最常见的问题。我的排查顺序是:先查电源和地,再查终端电阻,再查收发器使能,再查波特率,最后查过滤器。为什么这个顺序?因为电源和地是最基础的,如果收发器没供电,后面全白搭。终端电阻如果缺失,短距离可能能通,但长距离或高速率就不行。收发器使能引脚如果没拉对,芯片不工作。波特率不匹配,连帧起始都识别不了。过滤器配错,帧收到了但被丢弃。

我遇到过一次,开发板和收发器都正常,但就是不通。后来发现收发器的使能引脚悬空了,芯片处于待机模式。所以使能引脚一定要明确拉高或拉低,不能悬空。

5.2 偶发错误:采样点与位填充的坑

偶发错误比完全不通更难查。常见原因有两个:采样点不一致和位填充错误。采样点前面说过,两个节点采样点差太多会导致偶发错误。位填充是CAN的同步机制:发送方在连续5个相同位后插入一个相反位,接收方自动删除。如果发送方和接收方的位填充逻辑不一致,或者总线干扰导致位填充错误,就会触发错误帧。

排查偶发错误,我建议用分析仪的错误计数器功能。如果错误计数器在涨,说明有错误帧。然后看错误类型:是位错误、填充错误还是CRC错误。位错误通常是采样点问题,填充错误通常是干扰或时钟偏差,CRC错误通常是数据被篡改。

5.3 总线负载过高:如何计算和优化

总线负载率是CAN设计的重要指标。计算公式是:负载率 = 所有帧的位数之和 / 总线带宽。比如500kbps下,一帧标准数据帧大约111位(含填充),如果每秒发1000帧,负载率 = 111 * 1000 / 500000 = 22.2%。一般建议负载率不超过50%,否则延迟会变大。

如果负载率过高,优化方法有:减少发送频率、合并数据、提高波特率、用扩展帧?不对,扩展帧更长,应该用标准帧。还可以用“事件触发”代替“周期发送”,只在变化时发。

我见过一个系统,负载率到了80%,结果紧急报文延迟超过100ms,这是很危险的。后来把非紧急报文的周期从10ms改成100ms,负载率降到30%,问题解决。

5.4 常见问题速查表

现象可能原因排查方法
完全不通电源/地/终端电阻/使能万用表测电压,示波器看波形
偶发错误采样点不一致/位填充分析仪看错误计数器,统一采样点
收不到特定ID过滤器配置错误改为接收所有,再逐步细化
发送失败总线忙/仲裁丢失/邮箱满查状态寄存器,增加重试
波形异常终端电阻过多/过少测量总线电阻,应为60欧姆左右

这个表是我自己排错时总结的,你可以打印出来贴在工位上。

6. 进阶方向:从会用到用好

6.1 CAN FD与经典CAN的区别

CAN FD是经典CAN的升级版,主要区别是数据段可以到64字节,速率可以更高。学习路径上,我建议先把经典CAN吃透,再看CAN FD。因为FD的仲裁段还是经典CAN,只是数据段变了。如果你经典CAN的仲裁、位定时都懂了,FD只是多了一个“速率切换”的概念。

6.2 用CAN分析仪做自动化测试

当你熟悉了基本收发,可以尝试用分析仪的脚本功能做自动化测试。比如周期发送一帧,然后监控另一帧的响应时间。这能帮你验证系统的实时性。很多分析仪支持Python或类似脚本,你可以写个简单的循环,记录每次响应的时间戳,然后算平均值和最大值。

6.3 从单节点到多节点网络

最后一步是搭一个多节点网络。你可以用三块开发板,分别模拟发动机、仪表、车门。给它们分配不同ID,设置不同发送周期,然后观察总线负载和仲裁情况。这时候你会真正体会到CAN的设计精髓:没有主从,谁有急事谁先发,但急事的ID小,所以永远优先。

我个人在实际操作中的体会是:CAN通信的学习,最难的不是协议本身,而是建立“总线思维”。你不能只盯着一个节点,要时刻想着总线上还有其他节点在听、在等、在仲裁。一旦你有了这个思维,再看那些帧结构、位定时、仲裁规则,就全都顺了。最后分享一个小技巧:每次调不通的时候,先别改代码,拿示波器看一眼波形,十有八九问题就在那两根线上。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询