ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

CAN总线协议深度解析:从CAN 2.0到CAN FD,数据帧结构与排错实战

CAN总线协议深度解析:从CAN 2.0到CAN FD,数据帧结构与排错实战 干了这么多年嵌入式跟总线打交道最多的就是CAN。不管是做车载ECU、工业设备还是机器人通信CAN协议都是绕不开的基础。很多刚入行的朋友一上来就啃协议手册或者直接拿现成库调收发结果总线上出来一个错误帧都不知道怎么回事。我整理了这篇CAN协议基础的内容重点讲清楚CAN协议的种类CAN 2.0A、CAN 2.0B、CAN FD和CAN数据帧的完整结构以及我用分析仪抓帧、排错的一些实际操作经验。不管是刚开始学CAN还是正在调试手头设备这篇文章应该能帮你把底盘打牢。1. CAN协议家族图谱从CAN 2.0A到CAN FD1.1 标准帧与扩展帧的本质区别CAN协议最初由Bosch在1986年提出后来被ISO标准化。大家最常听到的CAN 2.0规范分为A和B两个部分它们的核心区别在于标识符Identifier简称ID的长度。CAN 2.0A定义的是标准帧标识符只有11位。11位意味着什么二进制范围是0x000到0x7FF一共2048个ID。在早期的汽车电控系统里发动机、ABS、变速箱、仪表盘这些ECU加起来也就几十个节点每个节点发几个报文2048个ID完全够用。所以早期设计就把ID长度定在了11位成本低、帧短、实时性也好。后来功能越来越复杂总线上的报文种类越来越多11位就不够用了。于是CAN 2.0B引入了扩展帧标识符扩展到29位也就是在11位基础ID后面再追加18位扩展ID。29位能提供的地址空间是2^29超过5亿个这在工程上基本等于无限了。要注意的是CAN 2.0B规范还区分了两种设备一种是只支持标准帧的被动兼容设备另一种是既能发也能收扩展帧的主动设备。实际项目里只要总线上有一个节点需要扩展帧那么所有节点的控制器最好都选支持扩展帧的型号否则会出现接收过滤配置不上的情况。我记得第一次做多ECU联调时某个节点用的老款芯片只支持CAN 2.0A结果扩展帧报文一上总线这个节点就直接报错。后来换了支持CAN 2.0B的控制器问题才消失。这个坑在新老设备混用的产线上尤其常见大家在选型时一定先确认清楚。1.2 CAN FD为什么我们会需要它CAN FDFlexible Data-rate是Bosch在2012年推出的增强版2015年被ISO 11898-1:2015收录。它解决的核心痛点是两个带宽不够和数据长度不够。传统CAN的数据段最长只有8字节波特率主流是500kbps或者250kbps。放在十年前的车载网络里足够但放到现在的OTA升级、ADAS传感器数据、多屏娱乐系统上传输固件动辄几十MB用CAN帧一包8字节地传能传到天荒地老。CAN FD做了两件事一是把数据场的最大长度从8字节提升到64字节。大家别小看这个提升64字节意味着一条报文可以承载一个完整的诊断故障码快照或者一段音频采样数据传输效率高了很多。二是引入可变速率传输。CAN FD允许在仲裁段用标准速率比如500kbps在数据段切换到一个更高的速率比如2Mbps或5Mbps。为什么这么做因为CAN总线在隐形位到显性位的切换过程中需要足够的上升/下降时间让所有节点采样一致。仲裁段要保持低速率是为了保证多个节点同时发帧时能可靠地进行位仲裁而数据段里只剩一个节点在发这时可以把速率提上去而不影响仲裁可靠性。这个设计非常巧妙既保留了CAN原有的仲裁机制又把数据吞吐量提了一个台阶。实测下来同样一条总线上多个节点都用CAN FD数据段的吞吐量能比传统CAN提升3到8倍。当然前提是总线布线质量和收发器必须跟得上否则高速率下沿变差误码率会直线上升。1.3 不同协议版本之间的兼容性很多人关心CAN 2.0和CAN FD能不能混用。答案是可以但有条件。CAN FD设计时就考虑了向后兼容FD帧的仲裁段仍然使用标准速率且帧格式里用一个FDF位Flexible Data-rate Format位来区分这是传统CAN帧还是FD帧。传统CAN控制器收到FD帧时如果它不认识FDF位就会把这一帧判定为错误帧然后总线上的错误计数器会增长。所以实际部署中有两种做法如果整个网络里的节点都升级为CAN FD控制器那就做纯FD通信如果只是部分节点升级那么传统节点必须挂在单独的网段上或者通过网关做协议转换不要让FD帧直接经过旧节点的收发器。这点在改造成本项目时一定要规划好。2. 深入拆解CAN数据帧的每一个字段2.1 帧起始与仲裁段先拿最常用的标准数据帧举例把帧从第一个bit到最后一个bit全部拆开看你会对整个协议有种豁然开朗的感觉。帧起始SOF只有1个bit固定为显性逻辑0。总线在空闲状态时是隐性的逻辑1当某个节点发送SOF时总线电平从隐性跳到显性这个下降沿就是所有节点同步的起点。说白了它就像一篇文章的开头标点告诉所有节点“我要开始发内容了”。紧跟着就是仲裁段。标准帧的仲裁段由12位组成11位ID加1位RTRRemote Transmission Request。扩展帧的仲裁段更复杂11位基础ID、1位SRRSubstitute Remote Request、1位IDEIdentifier Extension、18位扩展ID、最后是1位RTR。这里有个重点在CAN总线中ID不仅用来标识报文的来源和优先级还直接参与仲裁。多个节点同时发帧时总线会根据ID逐位仲裁显性位0优先于隐性位1。所以ID数值越小优先级越高这一点在划分报文优先级时必须慎重。想象一下如果某个关键的安全气囊报文不小心被分配了一个大ID值而在同一时刻有一个普通传感器报文也在发那么传感器反而会先发出去这在汽车这种对安全要求极高的场景里是不可接受的。2.2 控制段、数据段与CRC段仲裁段之后是控制段。标准帧的控制段由6位组成IDE位、保留位r0和4位DLC数据长度码。扩展帧则是保留位r1、r0和DLC。IDE位的作用是表示当前是不是扩展帧标准帧里IDE是显性扩展帧里是隐性。保留位留作以后扩展传统CAN里它们必须发显性但接收端一般不去检查所以很多设备实际发送时也是显性。DLC字段大家要重点记它用4位二进制表示数据段的字节数范围是0到8。在CAN FD里情况不一样了DLC不是线性对应字节数而是有跳变的编码表下面专门说。数据段就是真正要传的内容传统CAN最多8字节。数据段是唯一的和ID不同它不参与仲裁也就是说数据段的每个bit都按正常位时序发送不会因为其他节点的干扰而中断。数据段之后是CRC段。传统CAN的CRC是15位基于多项式x^15 x^14 x^10 x^8 x^7 x^4 x^3 1即CRC-15计算覆盖SOF、仲裁段、控制段、数据段的内容。别以为CRC只是随便加个校验在CAN的强电磁干扰环境下CRC是防止错误帧被误采纳的最后一道防线。接收节点会重新计算一遍CRC如果和发送方附带的不一致就会忽略这一帧并发出错误帧。CAN FD的CRC更复杂一点它除了要覆盖前面的字段还要额外处理数据段的高速位流。由于数据段存在位速率切换传统的一位一采样的CRC计算方式不适用所以CAN FD在CRC段里额外加入了“填充位计数”信息和“奇偶校验位”用于检测高速段的位填充是否正确。这也是为什么CAN FD帧的CRC字段长度是动态的可以是17位或21位取决于数据段长度是否超过16字节。2.3 ACK槽与帧结束CRC段后是ACK段总共2位一个ACK槽位加一个ACK分隔位。ACK槽位非常巧妙。发送方在发出ACK槽位时会主动发送一个隐性位然后释放总线。总线上其他所有正常接收该帧的节点如果在本帧过程中没有发现错误就会在这个槽位发送一个显性位来“确认”。也就是说发送节点通过采样到一个显性位就知道至少有一个节点成功接收了这帧。如果没有任何节点应答发送方会认为自己发出的帧没有被正确接收虽然它不会因此重发重发是上层协议的事但这会让发送节点的错误计数器增加。这个机制我第一次理解时觉得很巧妙——它把“点对点确认”变成了一种“总线级广播确认”。代价是没有节点能确认具体是哪个节点收到了但在广播式的CAN总线上这种设计已经足够高效。最后一小段是EOFEnd of Frame标准帧是7个隐性位扩展帧也是7个隐性位。EOF之后总线上就会恢复空闲状态允许下一帧开始。帧结束后面还可能有3个bit的ITMIntermission间隔也叫帧间隔让节点有时间处理接收缓存。3. 数据帧之外的帧类型与总线仲裁机制3.1 四种帧类型很多人以为CAN总线上只跑数据帧其实协议定义了四种帧第一是数据帧用来承载实际数据也就是上面拆解的那种。第二是远程帧节点可以主动请求总线上另一个节点发送某个特定ID的报文——远程帧没有数据段只有ID和DLC。第三是错误帧当节点检测到总线错误时会主动发一个由6个显性位加8个隐性位组成的错误帧用来打断当前正在传输的帧告诉所有节点“刚才这帧有问题”。第四是过载帧一个节点如果接收缓冲区满了可以发送过载帧来延迟下一帧的到达。我喜欢把这四种帧理解成日常沟通的场景数据帧是正常说话远程帧是点名“某某某你来说两句”错误帧是有人突然打断说“你刚才说错了”过载帧是“你慢点说我处理不过来”。这样记起来非常快。3.2 仲裁机制为什么不会发生冲突总线仲裁是CAN协议最具魅力的地方。在没有CAN的时代多设备共享一根总线通常都需要“令牌”或者“主从问答”来避免冲突。CAN的做法非常简单又优雅靠ID逐位仲裁。初始化时所有节点监听总线如果两个节点同时开始发送那么它们每个bit都会往总线上写数据同时回读总线电平。因为显性位能覆盖隐性位所以当某一bit出现一个节点发隐性1、另一个节点发显性0时总线呈现显性发隐性的那个节点会发现自己“写1读0”立刻退出仲裁转入接收模式。整个过程一直在比较直到剩下最后一个节点继续发完整个帧。这个机制真正厉害的地方在于仲裁过程不会中断正在进行的帧传输赢家从头到尾不需要重发整个总线带宽被充分利用。对比一些冲突检测需要重发的协议比如经典的以太网CSMA/CDCAN在这个方面的效率要高得多。当然仲裁的前提是所有节点对位的采样时机一致。如果两个节点波特率偏差过大或者采样点设置不合适就可能出现“前一个节点还在发低位后一个节点已经采到自己想要的电平”的情况导致仲裁失效。后面我专门讲采样点设置时再细说。3.3 位填充机制与同步CAN还有一个容易被忽视但极其关键的机制位填充Bit Stuffing。协议规定在SOF到CRC段之间如果连续出现5个相同的电平就会在第6个bit的位置自动插入一个相反电平的填充位。为什么要做位填充因为接收节点需要从总线的边沿变化中恢复出时钟信息。如果总线上长时间没有电平跳变接收端的PLL就会失去参考采样就会漂移。位填充保证了每个bit流里最多5个bit就会出现一次边沿这样接收节点就能持续从边沿中做重新同步。但同时也有一个坑位填充不是协议用户可控的它是控制器硬件自动完成的。在很多老手册里你会看到“最大帧长度”这种说法实际上算的是含填充位的最坏情况。CAN FD在高速数据段对位填充策略做了调整它是用固定的“每4个bit插入一个填充位”的方式来保证高速采样的稳定性所以CRC计算时也必须把这部分统计进去。理解位填充对排查问题很有帮助。比如你看到某帧数据非常长比理论算出来的最大长度还长那大概率是填充位导致的不是控制器异常。另外连续5个相同电平后的第6个bit如果仍是相同电平就会触发填充错误这通常说明总线上有节点时序异常是硬件问题的一个重要特征。4. 实操用分析仪抓帧与解析CAN数据4.1 工具准备与连接方式理论讲得再多不如自己抓一帧数据看看。实操需要的工具很简单一个CAN分析仪市面上常见的兼容周立功驱动或者PCAN的都可以、两个120欧终端电阻很多分析仪和开发板上已经内置了但外接时不要重复接、以及一个可以发CAN报文的上位机软件比如CANTest、PCAN-View、或者汽车电子常用的CANalyzer。接线方面CAN分析仪的CANH接总线的CANHCANL接总线的CANLGND要跟总线上的设备共地。这一步很多人忽略实际上CAN收发器虽然可以用差分信号抗共模干扰但如果各节点地电位差过大共模范围超限后一样会通信异常。接好线后把波特率设置为总线实际波特率。如果你不知道具体波特率可以用分析仪的“自动识别波特率”功能去扫描。最常用的候选波特率是125k、250k、500k、1M扫描时间一般几秒就能找到。4.2 一帧数据从波形到解析的完整过程假设我用分析仪抓到了一条标准数据帧原始数据显示为ID 0x123, DLC 8, Data 01 02 03 04 05 06 07 08这个只是上层软件简化后的显示硬件底层实际传输的是完整帧结构。如果我们把这条帧放到示波器上观察能看到的波形顺序是1个显性SOF11位ID0x123的二进制是0 0010 0011但要注意总线上是高位先发所以顺序是从第10位到第0位1位RTR数据帧里是显性01位IDE标准帧里是显性01位保留位显性04位DLC数值为8即1000也是高位先发8字节数据共64位逐字节高位先发15位CRC加上1位CRC分隔符隐性11位ACK槽发送方发隐性1接收方回一个显性0来覆盖1位ACK分隔符隐性17个EOF全为隐性1做嵌入式上位机开发时经常需要自己解析这个格式。我给你一个最简的计算方式在不考虑位填充的理想情况下标准数据帧的物理位长度可以用这个公式估算总位数 1SOF 11ID 1RTR 1IDE 1r0 4DLC 8*DLC字节数 15CRC 1CRC分隔 1ACK 1ACK分隔 7EOF代入DLC8就是111111464151117108位。实际线缆上的位流会因位填充变长标准帧理论上最长约130位左右。4.3 CAN FD帧的抓取与速率切换如果你用支持CAN FD的分析仪去抓CAN FD报文上面那个公式就要变了。CAN FD帧在仲裁段和数据段之间有一个速率切换点位于BRS位。波形上你会看到明显的一处“变密”现象也就是后面的bit宽度变窄。抓CAN FD帧时关键是正确配置仲裁段波特率和数据段波特率。比如仲裁段是500k数据段是2M那么分析仪软件里要在“FD设置”里分别填写这两个值。采样点位置也要针对两段分别调整。如果配置不对最常见的现象是能看到帧头ID但数据段全是乱码或者直接报“CRC错误”。我实测过一种情况用默认采样点70%去收一个数据速率2M的CAN FD网络误码率在1%左右把采样点调到75%后连续跑一小时零错误。所以做CAN FD项目时采样点设置不要照抄默认值一定要根据你的线缆长度和收发器规格去算。5. 常见问题与排查技巧实录5.1 常见问题速查表我在实验室和现场都排过不少CAN总线问题下面这个表是我自己的经验总结大部分场景都适用现象可能原因排查方向所有节点都收不到数据总线缺少终端电阻或终端电阻接错测CANH与CANL之间电阻正常应为60欧左右单个节点收不到该节点波特率配置错误或节点处于Bus Off状态断开该节点单独测试修改波特率后重新上电偶发错误帧采样点偏移、线缆过长、布线靠近干扰源调整采样点缩短分支线检查屏蔽和接地一上电就Bus Off控制器连续发错误帧检查收发器供电、CANH/CANL是否接反高速CAN FD数据乱码数据段波特率配置错误确认分析仪和被测设备的仲裁/数据两段速率均一致明明能收到但CRC报错收发器摆率不够或总线阻抗不匹配检查线缆特性阻抗尽量用120欧双绞屏蔽线5.2 排查经验先量电阻再抓波形很多朋友拿到设备就问“为什么CAN不通”我一般建议按这个顺序排查先量总线电阻。正常工作的CAN总线在任意节点上测CANH到CANL之间的直流电阻应该是60欧左右——这是两个120欧终端电阻并联的结果。如果测出来约120欧说明只有一端接了终端电阻如果接近0欧说明有短路如果是无穷大说明两端都没接或线断了。这个测试5秒钟就能做能排除一大半硬件问题。再抓波形。用示波器量CANH和CANL对地的波形。正常通信时显性位CANH约3.5V、CANL约1.5V差分约2V隐性位两者都在2.5V左右差分约0V。如果你看到差分电压偏小比如小于1.5V那大概率是终端电阻或者收发器驱动能力出了问题。偏大的话说明共模电压有问题或两个节点参考地不一致。最后才是用分析仪抓帧看错误类型。CAN控制器的错误寄存器会记录最近一次的错误类型比如位错误、填充错误、校验错误、ACK错误等。每种错误对应不同的排错方向位错误说明发送时总线电平跟预期不一致往往是有其他节点干扰或者收发器有问题填充错误说明位流格式不对通常是波特率不匹配ACK错误说明发出了但没人接收检查总线上是否只有发送方。5.3 独家避坑技巧最后分享几个常规文档里不太会写的细节第一总线分支线越短越好。CAN不是点对点的串行总线而是像一棵树一样挂很多节点每个节点出来的那根线叫“分支线”。分支线越长反射越大对高速传输的影响越明显。经验值是波特率1M时分支线要控制在30厘米以内500k时可以放宽到1米左右。现场实在避免不了长分支线时可以适当降低波特率或者用双绞线加磁环。第二采样点不要用默认80%一刀切。标准CAN推荐采样点一般在70%到80%之间但位数不同、速率不同、线缆长度不同最佳值都不一样。我的习惯是先算一下采样点同步段传播时间段相位缓冲段1/同步段传播时间段相位缓冲段1相位缓冲段2。比如你用1M波特率、8分频同步段1个Tq传播段3个Tq相位段1设为5个Tq相位段2设为3个Tq那么采样点就是(135)/(1353)69.2%。线缆短、波特率低时采样点可以稍微靠前线缆长、干扰大时稍微靠后这个需要实际抓波形调。第三终端电阻不要重复接。有些开发板内部已经焊了120欧电阻如果用外部分析仪又接了120欧并联后只有60欧终端阻抗失配会增加反射。接之前拿万用表量一下最靠谱。第四远程帧这玩意能不用就不用。它虽然协议里有但在实际项目中容易引发“广播风暴”——多个节点同时请求同一个ID导致总线上连续不断出现远程帧。现代开发更建议上层应用直接用数据帧周期发送安全性高得多。我个人在实际项目里的体会是CAN协议最核心的设计哲学就是“简单、健壮、不依赖主节点”。它的仲裁机制和错误处理机制让整个总线在没有中心管理器的情况下依然能稳定运转。无论你是刚接触CAN还是被某个棘手总线问题卡了一整天把帧结构、仲裁、位同步这三块彻底吃透绝大部分问题你都能自己找出答案。后面如果有机会我准备再写一篇CANopen和J1939这些上层协议的实战笔记那是另一片广阔的战场了。
返回列表