资讯详情

资讯详情

CAN总线基础详解:从差分信号到非破坏性仲裁,嵌入式必学

做嵌入式的尤其是跟汽车电子沾边的几乎没人能绕开CAN这门课。不管你是刚拿着开发板点灯的新手还是被总线上一堆莫名其妙的Error Frame折磨过的老手CAN基础都是必须夯实的地基。这篇是“CAN基础内容详解”系列的第一篇我会把物理层差分信号、帧结构、非破坏性仲裁、位时序还有错误处理这些最核心的东西挨个拆开讲清楚。看完这篇你至少能回答这几个平时经常被问懵的问题为什么CAN要用双绞线差分传输而不是单端一帧标准CAN报文到底由哪些bit组成、各字段是干嘛的总线上两个节点同时抢着发数据凭什么不会撞车还有那该死的120欧姆电阻到底非得接在哪。这套内容适合所有正在做嵌入式通信、想进汽车电子行业、或者只是被CAN协议栈绕得头晕的人。我不会只丢概念定义更多会结合我在实际项目里踩过的坑来说尽量让你看完能直接用。1. CAN这个协议到底为谁而生搞懂它解决的问题比背帧格式重要得多1.1 没有CAN之前汽车电子是怎么被线束逼疯的要理解CAN为什么设计成这个样子得先回到它的诞生背景。上世纪八十年代汽车上的电子功能开始爆发发动机电喷、ABS防抱死、自动变速箱、安全气囊接踵而来。传统做法是每个ECU之间点对点拉一根线每增加一个新功能就要从仪表台往车门、发动机舱拉一整捆新增的线束。一辆高端轿车的线束总长度轻松超过几公里接头数量上千个重量大、成本高、故障率还高。更要命的是功能之间需要共享数据。车速信号发动机要、仪表盘要、ABS要你不能让每个ECU都单独接一个车速传感器那样线束直接爆炸。所以业界需要一种能把所有节点挂在一对共享线路上的通信方式让每个节点都能收发数据这就是CAN出现的原因。CAN的核心理念因此非常明确所有节点共享一条串行总线任何一个节点都能主动发起通信优先级通过报文ID仲裁解决物理层则必须要有足够强的抗干扰能力来应对车内恶劣的电磁环境。1.2 从实际应用场景看CAN的技术取舍理解了动机再来看CAN的技术特点就顺了。它是多主总线这点和传统的UART点对点、I2C必须以主机为中心的架构有本质区别。在多主架构下任何一个节点都可以抢占总线发起通信不需要等待主机轮询因此实时性天然就好事件驱动的报文能在毫秒级发出。它的帧有效数据最多8字节这在今天看来小得可怜但在当时是精心考虑过的车辆状态信号大多是传感器瞬时值和控制指令单个信号往往只需要几个bit或一个字节8字节已经能覆盖绝大多数控制场景还能保证短小精悍的帧结构占用尽量短的总线时间让高优先级报文能更频繁地抢到总线。带宽方面经典CAN最高1Mbps对发动机转速、转向角度这类周期性小幅数据完全够用但对视频流这类大吞吐量的东西就没辙了那是车载以太网的地盘。CAN的技术定位基本就是“中等速率、极强抗干扰、极高可靠性、成本很低”的组合而这个组合在工业自动化、医疗器械、商用车辆、工程机械这些同样电磁环境恶劣、实时性要求高的领域里今天依然找不到性价比更高的替代方案。1.3 CAN和同类总线的对比帮你确定选型边界有不少新手会问既然有以太网、有LIN、有FlexRay为什么偏偏是CAN我用一张表说清楚它们的差异你心里就有数了。总线类型典型速率拓扑结构成本可靠性典型用途UART常用115.2kbps点对点极低一般板级两个器件通信LIN最高20kbps单主多从低一般车窗、座椅、后视镜等CAN最高1Mbps多主共享总线低很高动力、车身、工业控制FlexRay最高10Mbps多主共享/星型高极高线控转向、刹车冗余车载以太网100Mbps以上星型高协议栈复杂影音、摄像头、OTA从表能看出来LIN从CAN手里把低速车身控制分了出去以太网从CAN手里把高带宽应用分了出去但真正的实时控制域大到发动机变速箱小到工业机器人仍然是CAN的腹地。你如果在做嵌入式掌握CAN的收益非常明确。至于CAN FD和CAN XL那是后面几篇要讲的事先把经典CAN的地基打牢。2. 物理层决定总线性格差分信号、显性隐性电平与120欧姆的真相2.1 为什么CAN必须用差分信号而不是单端物理层设计是整个CAN可靠性的起点。如果CAN像UART那样用单端信号一根信号线对地传输电压车里遍布点火线圈、电机、继电器这些强干扰源会在信号线上感应出几十伏甚至上百伏的瞬态共模电压你发一个3.3V的高电平到接收端可能就变成噪声的一部分数据全毁。CAN改用差分传输信号不拿对地电压表达而是拿两条线之间的电压差值表达。发送端同时驱动CAN_H和CAN_L两根线接收端只关心两者之差。车内的电磁干扰属于共模干扰干扰同时叠加在两根线上你涨我也涨差值基本不变。这就好比两个人站在一起唱歌周围环境特别吵但听众只判断两个人音量的差值外界的齐声噪声就被抵消掉了。当年的汽车电子巨头在设计CAN时选择差分信号这条路本质上就是为恶劣电磁环境量身定制的。今天你在工业现场用CAN依然会为这个决定省下大量EMC设计的功夫。当然差分只是基础后面还有位填充、CRC、错误处理这些层层加固的防护。2.2 显性、隐性到底是谁覆盖谁CAN物理层只有两种电平状态显性和隐性。这个必须记牢因为仲裁机制完全建立在这两种状态的“覆盖关系”上。隐性状态时总线收发器不主动驱动总线CAN_H和CAN_L通过终端电阻都被拉到2.5V附近两者压差趋近于0对应逻辑1。显性状态时收发器把CAN_H拉到约3.5V把CAN_L拉到约1.5V两者之间存在约2V的压差对应逻辑0。关键特性在于显性能覆盖隐性。多个节点同时向总线发送数据时只要有一个节点发送显性位总线整体就表现为显性只有所有节点都发送隐性位总线才表现为隐性。这就是俗称的“线与”逻辑。这个特性直接导向一个结果CAN的仲裁是在通信过程中逐位进行的且不会破坏正在传输的数据。我在后面第4章讲仲裁时会详细展开。实际测量时有个经验可以记一下总线空闲时你用示波器量CAN_H或CAN_L对地都应该是2.5V左右两者压差为0通信期间差模信号会以约2V的幅度跳变。如果静默电压严重偏离2.5V比如变成0V或者4.5V说明收发器供电、终端电阻或者线路连接有问题这是一个非常快速的物理层健康检查法。2.3 120欧姆终端电阻两个且必须在两端只要用过CAN肯定被120欧姆折腾过。它的作用我用大白话说就是消除信号反射。双绞线的特征阻抗大约为120欧姆当信号在线上传播到末端时如果末端阻抗不匹配一部分能量就会反射回来和后续信号叠加产生过冲、振铃轻则影响边沿质量重则导致采样点误判。所以标准做法是在总线物理两端各并联一个120欧姆电阻使得总线上从任何一点看进去的阻抗都是60欧姆实现阻抗匹配。注意关键词是“两端”和“各一个”。很多人只在一端接了一个或者干脆认为一个电阻挂在哪都行这在短距离低速通信时可能问题不明显但距离一拉长、波特率一提高反射立刻让你知道什么叫“偶发数据错乱”。调试阶段你可以用万用表直接量CAN_H和CAN_L之间的电阻正常总线上应该测到约60欧姆这是两个120欧姆并联的结果。如果量到约120欧姆说明只接了一端的终端电阻。如果量到接近0那就短路了极有可能CAN_H和CAN_L碰线。这三组读数基本能快速定位物理层的三个常见故障。2.4 波特率、线缆长度和布线拓扑的实操参考CAN的通信距离和波特率不是任意组合的它们之间有个工程约束信号在双绞线里传播速度约为真空中光速的2/3大约每纳秒0.2米。波特率越高位时间越短而信号从总线一端传到另一端、再从远端反射或应答回来需要时间。如果这个往返时延接近甚至超过位时间的采样点余量节点就采不到有效电平。工程上常用的一组参考数据1Mbps时总线长度约40米500kbps约130米250kbps约270米125kbps约530米50kbps约1300米。我提醒一句实际项目里总线长度包括支线长度而且连接器压降、线缆材质、环境干扰都会让有效距离打折我一般按保守值的50%-70%来设计。例如250kbps的线缆理论上能到270米我最多按150米左右使用。布线拓扑上CAN最推荐的是直线型干线所有节点像路灯一样挂在主干线上。星型拓扑、T型长支线都是大忌因为支线末端如果没有终端电阻就会反射信号。支线的建议长度在1Mbps时不超过0.3米在低速时可以稍微长一些但越短越好。3. 帧结构把一帧CAN报文从第一位解剖到最后一位3.1 四种帧类型先把数据帧、远程帧、错误帧、过载帧分清CAN总线上跑的基本报文类型有四种。数据帧用于节点之间传递实际数据远程帧用于向其他节点请求数据错误帧用于总线节点向全网通报检测到错误过载帧则用于延迟下一帧的发送。其中数据帧是讨论核心远程帧在实际工程项目里用得相对少错误帧则是排查问题时经常在示波器上看到的“坏事信号”。注意一点远程帧的数据场长度通常为0它本身不携带数据而是通过在仲裁场中设置RTR位为隐性来表明“这是一个远程请求”。收到远程帧的节点如果恰好是数据源就会紧接着发送相应的数据帧。但在可靠性和实时性的权衡下很多工程师干脆不用远程帧而是让数据源节点周期性地主动发送数据帧这样能避免请求过程中数据更新延迟的问题。3.2 标准帧的每个字段逐位拆解不留盲区标准数据帧从第一个位开始依次是帧起始SOF、仲裁场、控制场、数据场、CRC场、ACK场、帧结束EOF、帧间空间IFS。我用一个字段表把它列清楚。字段位长度逻辑/内容作用SOF1位显性0同步所有节点标志一帧开始仲裁场12位11位ID 1位RTR决定报文优先级RTR区分数据/远程帧控制场6位IDE1位 r0保留1位 DLC4位标识数据长度扩展帧标志数据场0-8字节用户数据实际有效载荷CRC场16位15位CRC 1位定界符隐性校验传输错误ACK场2位ACK槽1位 1位定界符隐性接收节点应答确认EOF7位全隐性帧结束标志IFS3位全隐性帧间最小间距SOF这一位是隐含着重要的同步作用。CAN没有独立的时钟线节点如何知道一帧从哪里开始就靠SOF这个下降沿总线从隐性的2.5V变成显性的1.5V/3.5V差分跳变来硬同步所有节点以这个边沿为基准对齐位时间。所以你可以理解为什么终端电阻和边沿质量那么重要——边沿斜率差、振铃多SOF的同步点就容易乱。仲裁场里的ID严格说是用来表达优先级和报文身份的而不是传统意义上的“目标地址”。CAN是一种广播式总线一帧报文发送到总线上所有节点都会收每个节点根据自己的验收滤波器决定要不要保留这帧数据。这点和UART点对点的思路完全不同。控制场里的DLC用4位表示数据长度取值0到8对应0到8字节。注意DLC的值不能超过8如果你在软件里把DLC配成大于8很多CAN控制器会直接拒绝发送或者按8字节处理。CRC场是数据完整性校验的关键15位CRC对从SOF到数据场结束的所有位做校验计算。这里有个容易忽略的冷知识CRC序列本身不进行位填充而CRC之前的字段从SOF到数据场都按每连续5个相同位插入1个反相位的规则做位填充。这么做的原因是防止CRC段出现连续的相同位影响接收端的位同步。很多资料不写这个细节但理解它对你用示波器数一帧波形时长、或者写底层驱动时计算帧长度都很有用。3.3 扩展帧和标准帧的区别以及ID优先级背后的学问扩展帧诞生是因为标准帧的11位ID只能提供2048个不同标识符对越来越复杂的车载网络来说不够用了。扩展帧把ID扩展到29位实际报文容量大幅增加。结构区别在于扩展帧在仲裁场里用SRR位替代了标准帧的RTR位SRR是隐性紧接着标准帧控制场的IDE位在标准帧里是显性0在扩展帧里是隐性1用来告诉其他节点后面还有18位扩展ID。所以在扩展帧里仲裁场被拉长为32位控制场跟在后面。这里有个容易混淆的优先级细节。标准帧的IDE位是显性0扩展帧的IDE位是隐性1。当总线上同时出现一个标准帧和一个扩展帧且它们的前11位ID相同那么标准帧会在IDE位输出显性扩展帧输出隐性标准帧获胜。也就是说其他条件相同的情况下标准帧比扩展帧拥有更高优先级。29位ID同时带来了报文设计的哲学问题ID数字越小二进制里高位越早出现0也就是越早输出显性越容易在仲裁中获胜。所以真正需要低延迟的高实时性报文比如发动机扭矩指令、制动请求必须分配很小的ID而车窗状态这类不敏感的报文可以用比较大的ID。这个设计直接影响整车网络里报文优先级的规划千万别随便拍脑袋分配ID。3.4 手工估算一帧报文占用的总线时间做实时系统设计时经常需要估算最坏情况下一帧报文占多少时间。我给你列一个标准帧、8字节数据、无位填充时的位数量SOF1位、仲裁场12位、控制场6位、数据场64位、CRC场16位、ACK场2位、EOF7位、IFS3位合计111位。算上最坏情况的位填充标准帧最长大约能达到130位左右扩展帧因仲裁场更长最长约150位。举个例子总线波特率500kbps那么一位时间是1/500000秒约2微秒。一帧普通8字节标准帧不含填充的111位大约222微秒含最坏填充不到300微秒。如果你的应用要求某个报文每毫秒发送一次那么一帧最多占用总线约30%的时间这就是负载率。多个节点都往1ms周期的总线上灌报文时负载率很容易超过70%一旦峰值超过80%-90%错误帧和仲裁延迟就会明显增加这是设计网络时必须要核算的账。4. 仲裁和位时序CAN并发控制与时钟同步的巧妙设计4.1 非破坏性仲裁为什么总线上同时发数据不会撞坏报文这个是我认为是整个CAN协议里最优雅的部分。以太网遇到两个节点同时发数据会检测到冲突然后双方退避重传效率很低CAN则完全不同它利用显性覆盖隐性的线和特性在传输过程中自动完成仲裁输掉的节点立刻停止赢的节点继续完整发送整个过程数据没有被破坏不需要重传。我把原理用一场会议类比几个参会者同时开始抢话但每个人开口时先报自己的“编号”编号规则是数字最小的有最高话语权。他们报编号是逐位进行的一旦某个人发现自己报的这个位和别人冲突了且对方报的是“更有话语权”的0自己报的是1他就立即闭嘴。其他所有人也会同步识别出该闭嘴剩下的那个人继续把话说完。具体到CAN里ID是以二进制逐位输出的。三个节点同时要发送ID分别为0x540、0x555、0x700的报文先转成二进制0x540是0101 0100 00000x555是0101 0101 01010x700是0111 0000 0000。从高位开始逐位比较0x540和0x555前面几位完全相同直到第7位出现分岔0x540该位是0显性0x555该位是1隐性于是0x555在那一刻检测到自己发送隐性但总线实际是显性立刻退出仲裁转为接收0x700则在更靠前的第2位就分出了胜负。最终总线完整发送0x540这帧数据另外两个节点像没事人一样安静接收。这个机制对实时系统是决定性的高优先级报文不会因为低优先级报文正在发送而被迫等待超过“最长低优先级帧时间”而且一旦赢了整帧数据毫无损伤时间确定性非常好。4.2 位时序、采样点、同步和重同步CAN所有节点之间没有专门的时钟线只通过数据信号里的边沿来对齐位时间。每个位时间被分成四段同步段SYNC_SEG、传播段PROP_SEG、相位缓冲段1 PS1、相位缓冲段2 PS2。同步段固定占1个时间量子用于检测边沿传播段用于补偿总线上的物理传输延迟PS1和PS2是吸收时钟偏差和信号沿抖动的缓冲段采样点就固定在PS1结束、PS2开始的交界处。为什么这么复杂的位时序因为每个节点用的晶振不可能完全一致就算都是20MHz的晶振实际频率可能差千分之几。如果没有同步机制节点A发了1000个位节点B的采样点会因为时钟差逐渐偏移最终采到完全错误的电平。CAN靠的是每个总线边沿不断调整自己的位时间相位把误差控制在采样点能容忍的范围内。调整分硬同步和重同步。帧起始SOF边沿触发硬同步把所有节点的位时间强行对齐其余边沿触发重同步根据边沿比预期早还是晚往PS1或PS2里借时间。借时间的上限由同步跳转宽度SJW控制SJW配置越大容忍相位偏移的能力越强但太大也会降低采样精度。4.3 一个具体配置例子教你把采样点算得明明白白假设CAN外设输入时钟频率8MHz目标波特率500kbps。8MHz对应每位时钟周期125ns而500kbps对应位时间2微秒所以一个位时间需要16个时间量子即16TQ。参考常见的采样点设置推荐在75%到80%之间。我按75%分配SYNC_SEG固定1TQPROP_SEG设为2TQPS1设为9TQ那么采样点位置是(129)/1675%PS2就取剩余4TQSJW保留为2TQ。这样配置后相位缓冲段的容错能力足够应对大多数晶振精度和线缆传播延迟。实际中会有个坑有些入门者把PS2设置成1TQ甚至0TQ这样相位缓冲段形同虚设晶振稍有温度漂移就出现偶发错误帧。协议规定PS2最小为2TQ有些严格的控制器还会要求PS1必须大于等于传播段。我的建议是采样点宁可配置得保守一点留足相位余量也别为了追求高采样点而牺牲容错性。5. 错误处理不只是查Bug的工具它是CAN可靠性体系的一部分5.1 五类错误它们各自如何被检测到我平时排查问题最常打交道的就是错误帧。CAN规范定义了五种错误类型。位错误是最直观的发送节点在发送某一位的同时也在监听总线如果它发送的是隐性位但采到显性电平或者发送显性位采到隐性电平在仲裁期间除外就会被判定为位错误。这个机制保证了发送节点是第一个知道自己出错的人。填充错误则是连续6个相同电平出现在总线上破坏了位填充规则说明线路或采样出了问题。CRC错误发生在接收节点它本地重新计算CRC后与报文里的CRC值比对不一致表明传输过程发生了位翻转。格式错误指固定隐性或显性的位比如EOF、CRC定界符电平不符合预期。应答错误则是发送节点在ACK槽没有收到任何显性应答电平它认为总线上没有任何节点成功接收了这帧数据。了解这些错误类型对排查非常有价值。你在评估板上看到Error Frame疯狂刷用总线分析仪查看错误码就能反推出是哪一段链路的毛病。比如总报CRC错误多半是物理层干扰或终端电阻缺失总报ACK错误则基本可以锁定波特率不匹配或者对端没有在正常监听。5.2 错误计数和Bus-Off状态机看懂总线节点的“三级惩罚”CAN宁可错杀不可放过它用两个计数器TEC和REC来管理节点的“信用分”。发送错误会使TEC加8接收错误会使REC加1到8不等成功发送或接收一帧则相应减1。当TEC和REC都小于128时节点处于主动错误状态它发现错误时可以主动发出6位显性错误标志总线上的其他节点都会看到这个错误信号。当任一计数器超过127节点进入被动错误状态。这时候它只能发6位隐性错误标志不能主动打断总线上的错误帧。最严重的情况是TEC超过255节点直接进入Bus-Off状态彻底与总线隔离既不发送也不接收。这个机制的设计初衷是如果一个节点因为自身软硬件问题疯狂破坏总线必须在它能拖垮整个网络之前把它隔离出去。现实中遇到Bus-Off的排查思路是先用示波器量总线的差分波形和静态电平确认物理层没问题再检查是否有两个节点配置了相同ID且反复发送造成持续的仲裁失败和错误累计最后排查软件里是否存在异常占用、死循环发包或波特率配置被意外修改的情况。Bus-Off退出也不是立刻就能恢复的协议要求节点检测到128次总线空闲后才回到主动错误状态这是防止故障节点刚从错误中恢复又立刻扰乱网络。6. 新手学CAN最容易遇到的5个坑和排查方法很多人在CAN上花掉大量调试时间其实翻来覆去就那几个坑。我整理成速查表遇到问题直接对号入座。现象可能原因排查动作示波器看不到任何波形总线静默电压正常控制器未初始化、收发器供电异常、波特率配置错先做控制器Loopback回环自测再量收发器供电和CAN_H/CAN_L静默电平发送节点持续报ACK错误波特率不匹配、接收方验收滤波把帧丢弃、接收方没上电用总线分析仪确认两端波特率检查接收方是否正常在线总线上偶现CRC错误或位错误终端电阻缺失、支线过长、线缆经过干扰源量CAN_H与CAN_L间电阻确认两端终端检查布线和屏蔽层接法节点频繁进入Bus-Off供电抖动、总线负载过高、ID冲突造成持续竞价检查节点电源纹波计算总线负载率检查报文ID是否重复低速短距离正常、拉长距离就乱码传播延迟超过位时间余量、采样点配置过偏检查实际总线长度重算采样点必要时降低波特率这里我要重点强调一下自查工具的使用。CAN调试阶段一定要善用控制器的Loopback回环模式它能在不走物理总线的状态下验证MCU的CAN控制器、收发器焊接和底层初始化是否正确。我在实际项目中凡是遇到“发不出”“收不到”这类问题第一步肯定是把速率配好、发个固定ID的报文看能不能在Loopback模式下自己收回来。这一步能通过就说明MCU侧链路没问题然后把回路模式关掉直接接总线测。这套“先隔离软件再排查物理”的流程能帮你至少省一半的排查时间。另外还有一个很隐蔽的工程坑不能用万用表在报文中实时量总线差分电压因为万用表的采样率太低看到的都是平均值明明通信正常表上却可能显示一个很奇怪的电压。看波形必须用示波器抓错误帧也必须用带CAN触发的总线分析仪。这是工具选型上最容易犯的错误。调试阶段的软件开销也要算进总线负载率。有些人做Demo板时随意一个定时器中断里发好几帧报文总线毫无压力到了真实项目里几十个节点都在发一个100kbps的低速网络很可能被几帧异常报文直接塞爆。我一般会在设计初期把网络上每个节点的报文周期和长度拉一张表汇总算出总线的平均负载率和峰值负载率超过50%到60%的就得提醒自己这个方案要加带宽或优化报文合并了。在收发器选型方面第一优先看它是否符合ISO 11898-2标准其次看它支持的速率是否覆盖你的需求再次看它的ESD和EMC防护等级。车规项目里还必须考虑待机电流有些节点在车熄火后仍需在低功耗模式下监听网络收发器选型不合适就会造成蓄电池亏电。这些都是手册参数里直接能查到的下单前花十分钟确认一下能省掉后面整车的噩梦。这篇先写到这里CAN基础的地基部分已经铺完了物理层为什么用差分帧结构怎么拆仲裁怎么赢采样点怎么配错误怎么管踩坑怎么查。后面第二篇我会接着讲诊断协议、网络管理、CAN FD这些更贴工程实战的内容那部分才是真正帮你把理论知识转成排查疑难杂症能力的关键。如果你在项目里也遇到过什么奇葩CAN问题欢迎评论区把现象丢出来一起分析。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →