尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

CAN协议种类与数据帧结构详解:从标准帧到扩展帧的实战解析

CAN协议种类与数据帧结构详解:从标准帧到扩展帧的实战解析 做嵌入式这些年几乎每个搞汽车电子、工业控制、甚至机器人调试的工程师都会在某个项目节点上被CAN协议磕一下。最近后台也有不少人问我CAN协议到底分成几种、数据帧又该怎么看尤其是刚入门的学生或者从单片机转过来做CAN开发的同事经常被标准帧、扩展帧、远程帧这些术语绕晕。这篇文章我用比较接地气的方式把CAN协议种类和CAN数据帧一次性讲清楚看完基本能读懂示波器或CAN分析仪上抓到的报文也能自己在板子上动手解析。这篇文章不会只讲理论我会把协议设计背后的“为什么”也拆开聊聊比如为什么标准帧优先级高、为什么CAN帧里要做位填充、为什么远程帧在实际项目中用得少。最后再分享一些调试CAN总线时踩过的坑和排查思路希望能帮你在真实项目里少走弯路。1. 先把CAN协议的种类盘清楚1.1 标准帧与扩展帧CAN 2.0A和CAN 2.0B的关系很多新手第一次接触CAN协议时最先听到的就是“标准帧”和“扩展帧”。这两个概念其实是跟着CAN协议版本走的。CAN协议最早由Bosch在1986年提出第一版定义了11位标识符也就是只支持标准帧这一版后来被称为CAN 2.0A。标准帧的ID范围是0x000到0x7FF最多2048个ID看起来不少但汽车电子发展太快车内ECU数量越来越多诊断、标定、多网段路由都需要更多的报文寻址空间11位ID很快就不够用了。Bosch在1991年发布了CAN 2.0B核心变化就是增加了29位标识符的扩展帧。29位ID由11位基础ID加18位扩展ID组成寻址空间大幅提升。但要注意CAN 2.0B向下兼容也要看具体实现规范里把支持扩展帧的节点又分成两种CAN 2.0B passive节点只能接收扩展帧、不能发送扩展帧CAN 2.0B active节点既能接收也能发送扩展帧。很多MCU的CAN控制器默认都支持active模式但不代表每一个挂在总线上的老节点都支持这一点在混合网络里非常容易踩坑。我还经常被人问“CAN 2.0A和CAN 2.0B是不是两套完全不同的协议”不是。它们的帧格式、仲裁机制、错误处理、位时序几乎一样区别只集中在标识符长度和帧结构里的几个控制位。所以从软件角度看一个控制器想同时收发标准帧和扩展帧主要就是配置掩码和解析ID时多判断一个IDE位硬件层面基本不用大改。1.2 按帧类型来分数据帧、远程帧、错误帧、过载帧除了按标准帧和扩展帧区分CAN协议在数据链路层还定义了四种帧类型数据帧、远程帧、错误帧、过载帧。这个分类和“标准/扩展”是两个维度很多文章把维度混在一起讲读者自然就糊涂了。数据帧最常用就是节点把实际数据发给总线远程帧用来向其他节点请求数据结构长得像数据帧但没有数据段错误帧是总线检测到通信错误时由出错节点自动发出的特殊序列用来通知全网“刚才那帧有问题”过载帧则用于接收节点还没准备好、请求发送方稍等片刻。后两种帧平时不太会被业务代码直接感知因为它们大多由CAN控制器的硬件自动生成除非你用分析仪抓总线波形否则很难看到。我觉得理解这个分类的意义在于调试。比如你抓到一个报文的帧类型是“远程帧”但你的应用层代码里压根没写过远程帧发送逻辑那就要考虑是不是其他节点在用远程帧请求数据或者哪里的配置出了问题。再比如总线上出现大量错误帧这不是某一个节点“发错数据”那么简单而是链路层已经出了状况优先查物理层和节点兼容性。1.3 高层协议不算CAN种类但建议提前了解CAN协议本身只定义了物理层和数据链路层帧里传的8字节数据具体是什么意思协议不管。所以工程上每个行业又各自封装了应用层协议比如工业自动化里常见的CANopen、DeviceNet商用车和农机上常用的J1939汽车诊断用的UDS on CAN标定用的CCP/XCP等。这些不属于“CAN协议种类”但初学者很容易把它们和CAN基础协议搞混所以提前说一下本文讲的是底层帧结构理解完这些再看高层协议会轻松很多。2. CAN数据帧结构逐位拆解2.1 帧起始SOF与总线同步每一帧CAN报文无论是标准帧还是扩展帧都是从帧起始SOF开始的。SOF只有一个显性位逻辑0组成它的作用有两个一是宣告一个节点要开始发送报文二是给总线上所有节点提供一个同步基准。这里有个有意思的细节。CAN总线是差分信号显性位对应CAN_H和CAN_L之间的电压差显性电平会把总线拉低所以总线上只要有一个节点发送显性位整条总线都会呈现显性状态。这也是CAN仲裁机制能成立的基础多个节点同时发送时谁先发显性位谁就能“压过”别人的隐性位。在解析帧结构时只要看到波形从空闲电平跳变到显性电平就说明一帧开始了。总线上的所有节点通过SOF的下降沿重新同步各自的时间片。实际项目中如果总线上某个节点的时钟偏差太大即使波特率配置一样也会在后续位采样时出现位错误所以CAN控制器会不断通过SOF和帧内的同步段做重同步。说句题外话示波器看波形时如果发现SOF之后不久就出现错误帧大概率是波特率有细微偏差而不是帧格式写错了。2.2 仲裁段标准帧的ID和扩展帧的ID仲裁段是CAN帧里最直接影响协议行为的部分。标准帧的仲裁段包含11位ID、1位RTRRemote Transmission Request远程发送请求位。扩展帧的仲裁段则更长11位基础ID、1位SRRSubstitute Remote Request替代远程请求位、1位IDEIdentifier Extension标识符扩展位、18位扩展ID、1位RTR。RTR位是区分数据帧和远程帧的关键。标准帧里RTR为显性0表示数据帧隐性1表示远程帧。扩展帧里原来RTR的位置先被SRR和IDE占用最后才轮到真正的RTR位但判断逻辑一样RTR为0是数据帧为1是远程帧。仲裁的原理值得仔细说说。CAN总线规定显性位0优先于隐性位1所以ID数值越小的报文优先级越高。多个节点同时发送时每个节点一位一位地往外发同时在总线上读回实际电平如果自己发的是隐性位但读到显性位就说明有别的节点在发更优先的报文自己立刻退出仲裁转为接收状态。这个机制不需要额外的仲裁报文也不破坏数据效率非常高。还有一个很多新手不知道的规则标准帧和扩展帧混用时如果基础ID相同标准帧的IDE位是显性0扩展帧的IDE位是隐性1所以在仲裁过程中标准帧会获胜。换句话说标准帧在同等ID前缀下优先级高于扩展帧。这个特征在混合网络里很关键后面我会再讲实践中的坑。2.3 控制段IDE位、DLC数据长度码控制段在仲裁段之后主要负责告诉接收方“这一帧是什么格式、带多少数据”。标准帧的控制段包含IDE位、保留位r0、4位DLCData Length Code数据长度码扩展帧的控制段包含保留位r1、r0、4位DLC。IDE位用来区分标准帧和扩展帧。标准帧的IDE位是显性0扩展帧的IDE位是隐性1。这个位对解析软件极其重要因为你在程序里拿到硬件寄存器时通常需要先判断帧格式再根据格式解析ID。如果用标准帧的解析方式去读扩展帧29位ID会被截成11位数据完全对不上。DLC是4位取值0到15但经典CAN的数据段最多8字节所以DLC超过8的值在经典CAN里是无效的只有CAN FD等新协议才重新定义了更大范围的DLC映射。标准CAN里接收节点会根据DLC决定接收几个字节如果发送方的DLC和实际数据字节数不一致接收方可能接收多余或缺失的字节这在应用层解析时会导致数据错位。另外控制段里还有FDF位和BRS位这两个位是CAN FD时代引入的。经典CAN帧里FDF位是显性0CAN FD帧里FDF位是隐性1。如果你用经典CAN的分析工具去解析CAN FD报文会看到奇怪的错误帧所以抓包前先确认总线上的报文是经典CAN还是CAN FD。2.4 数据段与CRC校验段数据段是真正传输业务数据的地方。经典CAN最多8字节CAN FD最多64字节。很多人疑惑为什么CAN一帧只有8个字节够用吗原因和CAN的总线仲裁机制有关。CAN是实时性很强的总线单帧太长会导致总线被占用的时间过长高优先级报文等不起另外CAN错误率和使用环境有关帧短一点万一出错重传的成本也低。实际工程里如果数据超过8字节要么拆成多帧发送要么使用ISO-TP等传输层协议做分包重组。CRC校验段包括15位CRC序列和1位CRC界定符。CRC的校验范围覆盖从SOF到数据段的所有位接收节点重新计算CRC并与发送方附带的CRC序列比较不一致就认为帧出错。这里有个严苛的地方CAN协议在SOF到CRC序列之间如果连续出现5个相同电平的位发送硬件会自动插入一个反向填充位。接收端收到后会把填充位去掉再计算CRC如果发现连续6个相同电平则认定填充错误。这个机制保证了总线上有足够的电平跳变方便接收节点提取时钟信息。我在自己写CAN解析程序时最初踩过一个坑直接把CAN控制器寄存器里的DLC和Data拿出来用没考虑数据段的字节序问题。CAN协议本身不规定字节序但整车厂和工控行业通常有约定比如Motorola格式还是Intel格式。跨团队联调时一定要先确认对方用的是大端还是小端否则解析出来的数值会完全颠倒。2.5 ACK段、EOF结束位和帧间隔ACK段是CAN协议保障可靠通信的重要设计由ACK槽和ACK界定符组成。发送节点在ACK槽发送一个隐性位而所有正确接收到这一帧的节点无论是不是该帧的目标节点都会在ACK槽主动发送一个显性位来应答。因为显性优先所以发送节点只要在ACK槽读到显性电平就知道“总线上至少有节点收到了”。如果总线上只有发送节点自己没有其他节点应答发送节点就会一直重发这也是单节点自测时经常看到发送失败的原因。EOF由7个隐性位组成表示一帧结束。帧与帧之间还有一个帧间隔IFS至少3个隐性位用来让总线从繁忙状态恢复到空闲状态。很多人在计算总线负载率时容易漏掉IFS导致算出来的负载偏高。实际用CAN分析仪抓包时同一报文ID的连续发送周期里时间差是包含IFS的计算时要留意。ACK机制在生产环境中经常成为问题根源。比如总线用了错误终端电阻波形反射严重某个节点在ACK槽读到的电平不确定就会导致ACK错误。尤其在低波特率长线缆场景下终端电阻和线缆长度会造成信号劣化这时不要只盯报文内容先量波形更靠谱。3. 标准帧和扩展帧如何选择3.1 一张表看懂两种帧的差异标准帧和扩展帧不是简单地“一个短一个长”它们在优先级、数据开销、兼容性上都有区别。我用一张表把关键差异列出来方便你对照选择对比项标准帧CAN 2.0A扩展帧CAN 2.0BID长度11位29位11位基础ID 18位扩展ID单帧总长度不含填充最短约47位最短约67位数据段最多8字节最多8字节经典CAN寻址能力2048个ID5亿多个ID同前缀ID仲裁优先于扩展帧被标准帧抢占典型应用实时控制、简单网络诊断、标定、多ECU复杂网络这张表里最容易被忽略的是“同前缀ID仲裁”那一行。标准帧在混合网络中拥有天然的优先级优势所以如果你有非常关键的控制报文如扭矩、转速、刹车可以考虑把它设计为标准帧并在ID分配时让它的ID值更小确保它在总线上随时可以抢到发送权。3.2 实际项目里怎么选类型我接触过的项目里选择标准帧还是扩展帧通常会看三个方面。第一是网络规模。如果整条总线上只有几个节点、几十条报文标准帧足够了。比如常见的BMS与VCU之间通信、简单的电机控制器控制标准帧简单直接解析效率高。第二是应用层需求。如果涉及UDS诊断、Bootloader刷写、CCP标定通常建议用扩展帧因为这类应用需要大量的会话控制和地址扩展11位ID不够用而且诊断规范本身也推荐扩展寻址。第三是兼容性约束。如果网络里已经有老节点只支持CAN 2.0A新设计就必须考虑要么全部用标准帧兼容要么用网关隔离开。有个容易被忽略的问题是帧长度对总线负载的影响。扩展帧比标准帧长20位左右相同字节数的数据扩展帧占用的总线时间更长。在波特率固定、总线负载率接近上限的项目里把大量报文改成扩展帧可能直接导致报文周期波动。所以不是“扩展帧功能强就一定要用”而是够用就好。3.3 混用标准帧和扩展帧时踩过的坑去年我调试过一个车载T-Box项目网关配置了29位扩展ID可总线上挂了一个很老的传感器节点只支持CAN 2.0A。结果传感器每次收到扩展帧都判断为格式错误随后总线上错误帧大量出现其他正常控制报文也被干扰整个网络出现间歇性丢帧。当时排查了很久才发现问题理论上CAN 2.0A节点遇到扩展帧应该报错并产生错误帧但它不会主动“学习”新格式所以只要扩展帧还在发错误帧就持续存在。解决方式也很直接把网关的报文类型改成标准帧或者给老节点前面加一个协议转换网关。这里要提醒一句CAN 2.0A节点收到扩展帧报错不是节点坏了而是协议支持不到位升级老节点或替换成2.0B active节点才是根本办法。4. 远程帧、错误帧、过载帧的工作机制4.1 远程帧请求别人发数据但自身不带数据远程帧的结构和数据帧几乎一样区别在于RTR位是隐性1而且没有数据段。它的作用是某个节点发一个远程帧请求总线上对应ID的节点尽快发送该ID的数据帧。这个机制在多主通信场景里看起来很方便比如主站需要采集从站数据发一个远程帧就够了。但在实际工程里远程帧用得并不频繁。原因有几个多主总线上远程帧请求和数据帧回复之间存在时间差如果被请求节点优先级低可能很久才响应另外如果有多个节点同时监听同一个ID远程帧可能引发多个节点同时回复造成总线冲突。很多CAN控制器虽然支持接收远程帧并自动回复数据帧但配置起来并不一致不同MCU的行为有细微差别联调时反而容易出问题。我看到有些团队为了省事直接用周期性数据帧代替远程帧请求主站要数据就从缓存里取最新值从站自己按周期发数据。这种“生产-消费”模型虽然没有远程帧那么“智能”但胜在简单可靠总线行为可预测排查问题也容易。4.2 错误帧总线自我修复的关键机制CAN协议对错误处理非常激进。任何一个节点在发送或接收过程中检测到错误都会立即发出错误帧让所有节点知道这一帧作废然后发送节点根据错误计数器决定是否重发。错误帧由错误标志和错误界定符组成主动错误状态的节点发送6个显性位被动错误状态的节点发送6个隐性位后面的错误界定符是8个隐性位。错误计数器的规则是发送错误加8接收错误加1成功发送或接收则减1。节点状态分三种错误计数器小于128时是主动错误介于128到255之间是被动错误大于255进入总线关闭。进入总线关闭后控制器会断开与总线的连接不再参与通信直到检测到128次总线空闲相当于连续收到128个空闲帧间隙才自动恢复。在实际调试中遇到错误帧风暴时第一步不是改软件而是看错误帧的规律。如果错误帧间隔均匀大概率是某个节点在持续发错误标志可以用排除法逐节点断电定位。如果错误帧伴随在特定报文ID后面通常是该报文发送节点的位时序、波特率或终端电阻出了问题。记得有一次一个节点用内部RC时钟替代了外部晶振结果波特率偏差超过5%总线上频繁出现CRC错误和填充错误换回晶振后问题立刻消失。4.3 过载帧接收端忙不过来的“请稍等”过载帧的作用是请求发送方延迟下一帧的发送。结构上它和错误帧很相似由6个显性位加8个隐性界定符组成但触发条件完全不同。过载帧是在帧间隔期间发送的意思是“我还没准备好接收请暂停一下”。实际项目中过载帧比较少见。CAN控制器的接收FIFO通常能缓存多帧只有在接收中断处理不及时、FIFO快满时控制器硬件才会自动插入过载帧。如果总线上频繁出现过载帧优先检查接收端的软件处理速度比如中断是否被高优先级任务长时间阻塞、是否在中断里做了耗时操作、FIFO深度是否配置得太小。另一个容易误判的地方是过载帧和主动错误帧在波形上都是连续显性位很多分析工具显示也不友好。区分方法主要看触发时机过载帧只出现在帧间隔期间错误帧则在数据帧或远程帧正常传输过程中出现。你要是看到某段总线上过载帧多先优化接收端再排查总线干扰不要在发送端死磕。5. 实操用CAN分析仪抓帧、解析与常见问题排查5.1 一套低成本调试环境就这么搭做CAN开发调试环境不一定要很贵。最低成本方案是买一个USB转CAN分析仪价格从几十到几百不等常见的品牌有周立功、创芯、PEAK等也可以直接拿一块带CAN控制器的开发板比如STM32F405、GD32、NXP的S32K自己写收发程序。软件方面Windows上可以用PCAN-View、周立功CANTestLinux下可以用SocketCAN配candump都能实时显示帧ID、帧格式、DLC和数据。接线时要注意三点CAN_H接CAN_HCAN_L接CAN_LGND最好也共地总线的两端各接一个120欧终端电阻波特率必须与总线保持一致。很多新手第一次抓不到数据百分之八十都是这三个原因。还有一个容易忽略的点分析仪供电不稳定会导致波形畸变如果发现数据时好时坏先换根USB线或换个供电口试试。波特率怎么判断最靠谱的办法是用示波器看一个显性位的时长然后算波特率。比如量出来一位的时间是2微秒波特率就是500kbps是4微秒就是250kbps。这一步比盲猜配置效率高得多。5.2 看懂抓包数据里的标准帧和扩展帧用CAN分析仪抓包后界面里通常会显示一系列报文。每一行常见的信息包括帧ID、帧格式标准帧/扩展帧、帧类型数据帧/远程帧、DLC、数据字节以及时间戳。解析的一瞬间你要能立刻判断这个ID是11位还是29位这个帧带不带数据DLC写的字节数和数据区实际数量是否一致以一段常见报文为例ID0x18FF50E3格式为扩展帧DLC8Data64 2A 00 00 FF 01 00 00。看到0x18开头很多做过商用车的人会联想到J1939协议下的专有报文但那是上层解析从底层看0x18FF50E3是一个29位扩展ID对应的11位基础ID是0x18扩展ID是0xFF50E3。如果你用只支持11位ID的工具去解析会把它错误截断成0x18数据完全对不上。如果你需要自己写报文解析代码建议先按帧格式分流再按DLC校验长度最后才按ID查表映射业务含义。示波器能看波形分析仪能看帧两者结合才完整。有人问我能不能直接用分析仪定位波形劣化我的建议是分析仪适合看协议层波形质量还是用示波器量差分电压、位时间、采样点这些信息分析仪是给不了你的。5.3 CAN调试常见问题排查速查表故障现象可能原因建议处理完全抓不到报文终端电阻缺失、CAN_H/L接反、波特率错误检查接线和终端电阻用示波器量波形确认猜测波特率错误帧频繁出现节点版本不兼容、位时序偏差、总线干扰排除法定位错误帧来源检查干扰源和接地情况偶发丢帧总线负载过高、接收FIFO溢出、中断处理不及时降低负载率优化中断响应提高接收缓冲区深度发送重试失败ACK无应答单节点、ACK槽被干扰确保总线上有至少两个节点检查终端电阻和线缆长度两个节点抢答ID分配冲突数据源不明确重新规划ID映射给不同节点分配不同ID波特率标称一致但仍错误某个节点用内部RC时钟偏差过大换外部晶振或用示波器逐个节点对比位时间这张表是我这几年做CAN调试时总结的高频问题基本覆盖七八成现场故障。遇到问题优先从物理层开始排查不要一上来就怀疑报文解析逻辑物理层不稳再好的解析也白搭。5.4 几个难得的调试小技巧第一用示波器测量CAN_H和CAN_L之间的差分电压。显性位通常在1.5V到3.5V之间隐性位在0V附近如果电平明显异常终端电阻和收发器嫌疑最大。第二用CAN分析仪的“只接收不发送”模式观察总线不加任何干扰就能看到当前总线上的全部报文这是排查自己节点是否被踢出总线最快的方式。第三遇到间歇性故障时开启分析仪的定时记录和触发功能把错误帧前后的完整波形逻辑导出比肉眼盯屏幕高效得多。还要提醒一句进入总线关闭Bus Off的节点不会自动发数据但并不会从终端断开如果你发现某节点收不到任何报文先看它的错误计数器状态再决定是重启还是查硬件。6. 一点个人经验备忘按我的经验学CAN协议最直接的办法不是死记文档而是找一块开发板、一个几十块的USB-CAN分析仪自己抓几个标准帧和扩展帧对照本文把SOF、仲裁段、控制段、数据段、CRC、ACK逐一画出来。等你亲手把一个报文的ID、DLC、数据、CRC都拆明白后面再看CAN FD、CANopen、J1939这些内容会轻松得多。最后再送个小技巧联调之前先和对方确认帧格式、字节序和DLC规则这三样只要有一处不一致后面所有数据都会对不上早确认早省事。
返回列表