多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

CAN总线从物理层到协议层的完整拆解:差分信号、仲裁机制与实战避坑

CAN总线从物理层到协议层的完整拆解:差分信号、仲裁机制与实战避坑 搞汽车电子或者嵌入式开发的人几乎没有人能绕开CAN总线。我第一块带CAN功能的板子是给某车载控制器做通信测试当时三个节点死活调不通示波器上全是乱糟糟的波形排查了两天才发现是终端电阻的位置放错了。这个教训让我意识到CAN总线协议看上去不复杂但物理层、协议层和实际布线之间的坑远比想象中多。这篇文章把我这些年调CAN总线的经验完整梳理一遍从差分电平到帧结构从RTR/SRR位到采样点计算再到节点电路设计和常见故障排查一次拆透。这篇内容适合刚接触CAN的工程师、汽车电子方向的学生也适合那些已经用过CAN但想补全底层原理的人。看完之后你至少能回答这几个问题CAN为什么用两根线就能可靠通信仲裁是怎么做到不冲突的RTR位和SRR位到底有什么用所谓分支线长度到底指哪一段还有拿示波器怎么快速定位总线故障。我会尽量用大白话讲复杂的地方配例子和现场经验。1. 物理层的本质差分信号和终端电阻1.1 为什么是两根线而不是一根线CAN总线的物理层不是普通的单端信号而是差分信号。CANH和CANL两根线平时都维持在2.5V左右这个状态叫隐性逻辑上表示1当某个节点要发送显性位时它会同时把CANH拉到约3.5V、把CANL拉到约1.5V两根线之间形成约2V的压差逻辑上表示0。接收端真正关心的是CANH减CANL的差值不是某根线对地的绝对电压。这个设计带来的好处非常实际。汽车发动机舱里电磁干扰极其严重点火线圈、电机、继电器开关哪个都是噪声源。如果信号是单端传输比如像UART那样靠一根线的高低电平表示数据外部电磁干扰叠加到线上接收端很容易误判。而差分传输用两根线外部干扰在两根线上产生的电压几乎相同相减之后就被抵消掉了。双绞线进一步强化这个特性绞得越密两根线受到的干扰越一致。所以CAN总线必须用双绞线你拿普通排线替代短距离低波特率勉强能通高速长距离就一定出问题。实际测量时用示波器看CANH和CANL静默状态下两条线都在2.5V附近波形重叠成一条线有数据时一条线往上跳、一条线往下跳拉开约2V。用示波器的数学通道A减B来看显性位就是约0V变成约2V的脉冲非常干净。1.2 终端电阻为什么必须焊在两端CAN总线的特性阻抗是120欧姆左右所以ISO 11898标准规定总线的物理两端必须各接一个120欧姆终端电阻。所谓终端电阻就是吸收信号到末端时的能量反射。你可以把它想象成水管末端的水锤效应水在管道里流动如果末端是堵死的水撞到墙会反弹回来形成冲击波如果末端是开放的水流出去反而没有反射。电信号在传输线上也是这个道理末端阻抗不匹配信号就会反射回来叠加到原信号上形成台阶和振铃。很多初学者会在每个节点上都放一个120欧姆电阻这是错的。如果三个节点都接等效阻抗是40欧姆显性电平会被拉低反射也没有被正确吸收总线负载过重轻则距离缩水重则波形直接畸变到没法通信。正确做法是只在总线的最两端各放一个。中间节点不焊终端电阻。还有一个非常容易踩的坑终端电阻不一定要在某个“主节点”上而必须在这个物理线缆的两个端点。如果总线上有三个节点布线方式是A到B到C串下来那终端就在A和C如果是星形布线两条支路末端各放一个中间汇聚点不放。判断标准永远是线缆的末端不是哪个节点更重要。1.3 并联分支的长度到底指哪一段热搜里有个问题问“CAN总线并联分支的长度是指哪个长度”这个确实是实际布线最容易含糊的地方。分支长度指的不是总线主干线的长度而是从主干线上某个连接点到节点收发器之间的那一段“T型引出线”业内叫stub也就是“总线干道”和“节点车位”之间的连接线。打个比方主干线就像一条双向六车道公路每个节点是从公路拐进停车场的匝道。匝道短车流进出顺畅匝道长了拐弯时车流会堵在主干道上。信号在主干线上传播时遇到支线末端那一段“死胡同”会产生反射反射回来的能量正好在采样点附近出现就会造成误码。支线越长反射回来得越晚对采样窗口的影响越大。实测情况是500K波特率下一个节点支线拉到5米左右总线上就会出现偶发错误帧把支线缩短到1米以内问题立刻消失。ISO 11898建议高速应用时支线不超过0.3米低速125K以下可以放宽到几米。注意支线长度是整个节点接入总线的那段物理引线不是两个总线接插件之间的距离。如果你在一个连接器处同时引出多个传感器每个传感器到连接器的线都是独立支线需要分别控制长度。所以在做CAN节点布局时我的习惯是先确定总线的物理走线路径所有节点贴着主干线布置能直接插在主干线上就不要额外拉线。如果实在避免不了长支线就得降波特率或者使用CAN中继、集线器设备把总线分段。2. 协议层的骨架仲裁、帧结构与RTR/SRR位2.1 非破坏性仲裁为什么ID越小越优先CAN总线是多主总线任何节点空闲时都可以发送。如果两个节点同时开始发谁说了算答案是靠非破坏性仲裁靠位逻辑的“显性覆盖隐性”来决胜。总线上如果同时出现显性0和隐性1最终呈现的是显性0每个发送节点都在发的同时监听总线一旦发现自己发的是隐性位但总线上读到的是显性位就知道自己仲裁输了立即停止发送转为接收状态。仲裁的实质是比较帧ID的每一位。ID从高位到低位逐位比较显性0赢过隐性1所以ID数值越小二进制里高位0出现得越早优先级越高。例如ID0x123二进制0001 0010 0011和ID0x4560100 0101 0110第一位ID为0的那个节点就会获胜。这个机制和以太网的CSMA/CD完全不同CSMA/CD是冲突后随机退避会浪费总线时间而CAN在仲裁过程中不破坏数据赢的一方继续发完整个帧输的一方下个总线空闲再重发。所以CAN总线在高负载下依然有确定性这是它能在汽车这种实时性要求高的场合长期占据主流的根本原因。2.2 五种帧类型一次说清CAN协议定义了五种帧数据帧、远程帧、错误帧、过载帧和帧间隔。日常用得最多的是数据帧。错误帧是节点发现错误时自动发出的由6个显性位和8个隐性位组成会把当前正在发的正常帧打断相当于“总线出了状况所有人都停一下”。过载帧是在接收端处理不过来时请求延迟下一个数据帧的实际项目里很少见到普通调试基本不用管。帧类型作用触发条件数据帧承载应用数据节点主动发送或响应请求远程帧请求对方发送数据某个节点需要数据但自己不主动发错误帧打断错误报文任何节点检测到错误过载帧延迟下一个帧接收端过载或间隙过小帧间隔帧与帧之间的分隔数据帧/远程帧之后2.3 标准数据帧逐位拆解先看标准数据帧它由这些字段组成SOF1个显性位→ 仲裁场11位ID 1位RTR→ 控制场IDE、r0、DLC共6位→ 数据场0到8字节按DLC决定→ CRC场15位CRC 1位CRC分隔符→ ACK场ACK槽 ACK分隔符共2位→ EOF7个隐性位→ IFS3个隐性位。SOF表示一帧开始所有节点通过它同步。ID就是报文标识符比如0x201代表“车速报文”0x123代表“发动机状态”。RTR位紧跟在ID后面它是最容易被问到的位置含义是Remote Transmit Request。RTR位为0表示这是数据帧携带数据RTR位为1表示这是远程帧不携带数据只是请求总线上对应ID的节点发送数据。控制场里的DLC四个位表示数据场长度范围是0到8。数据场就是真正要传的字节。CRC场是循环冗余校验用来检查传输过程中有没有位翻转。ACK场很有意思发送节点在ACK槽发送一个隐性位总线上任何一个节点只要正确收到了这一帧就会在这个位置拉一个显性位作为回应。如果发送节点发现ACK槽还是隐性说明总线上一帧都没人收到就会报ACK错误。这就是为什么只有两个节点调试时对端不供电你就发不出去——没人应答。2.4 扩展帧与SRR位为什么SRR要设计成隐性标准帧的ID只有11位最多2048个标识符。后来需求变多发展出扩展帧ID扩展到29位标准帧和扩展帧的格式必须区别开于是IDE位承担了这个角色。扩展帧里ID由11位基础ID加18位扩展ID组成仲裁场里的位顺序是基础ID → SRR → IDE → 扩展ID → RTR。SRR是Substitute Remote Request替代远程请求位。重点来了SRR这个位的位置正好对应标准帧里RTR的位置。当初设计扩展帧时为了尽量兼容标准帧的收发逻辑在这个位固定放一个隐性1。为什么必须是隐性因为如果扩展帧在这个位置放一个显性0当总线上同时出现一个基础ID相同的标准数据帧和扩展数据帧时扩展帧的SRR0会赢得仲裁这就会打破设计意图——协议原始定义希望标准帧当ID相同时优先生效。SRR固定为隐性再加上紧随其后的IDE也是隐性这样标准帧RTR位的显性0就能在仲裁中胜过扩展帧的SRR和IDE标准帧优先。顺便说一句扩展帧的RTR并不在这个位置它跑到扩展ID后面去了。所以同是RTR位标准帧在ID后第1位扩展帧在扩展ID后第1位千万别搞混。调试的时候很多报文解析软件显示RTR/SRR/IDE几个位时如果你只对着标准帧的理解去看扩展帧会一头雾水。远程帧在实际工程中其实用得不多。原因很简单第一远程帧本身不携带数据它要求目标节点立刻回复如果两个节点同时发出相同ID的远程帧目标节点要连续回应多个数据帧总线负担反而增加第二汽车行业的通信矩阵基本都是周期性主动发送很少用“请求-响应”模式。但考试或者面试经常问RTR位所以协议层面的理解一定要扎实。2.5 位填充连续五个相同位之后的反转CAN还有一个容易忽略但非常关键的机制位填充。从SOF到CRC场结束如果连续出现5个相同电平的位发送方会自动插入一个相反电平的位。为什么这么做一是给接收端提供更多电平跳变沿方便时钟同步二是避免长串相同电平导致总线长时间没有翻转进而引起电容积累和直流漂移。举个例子原始数据里连续发送0000000实际总线上会变成0000010000010插入的第6位和第12位是填充位。接收端收到后会自动把它剔除还原原始数据。CRC校验、ACK场、EOF这些区域不进行位填充这是协议明确的规则。所以抓波形时看到一位“多出来”的反转不要觉得是错误很可能是正常的填充位。3. 位时间、采样点与波特率配置3.1 一个位时间被切成了几段CAN协议里的一个bit并不是简单的一段电平而是一个时间轴被分成同步段、传播段、相位缓冲段1和相位缓冲段2。同步段固定为1个时间量子tq它用来让所有节点对齐位边界传播段用来补偿信号在线缆上的传输延迟相位缓冲段1和2用来微调采样点位置吸收各个节点时钟的微小偏差。采样的时刻就在相位缓冲段1结尾和相位缓冲段2开头之间。采样点的位置非常重要它决定你在一个bit的什么时刻去读取电平。如果采样点太靠前信号还没稳定容易受到反射和边沿毛刺影响如果太靠后留给相位缓冲段2的余量不足波特率误差容忍度就变差。我建议一般场合用75%到87.5%之间汽车高速CAN常用87.5%。设置完波特率之后一定要换算一下采样点别只盯着波特率对不对。3.2 一个可复用的500Kbps配置计算以STM32的bxCAN外设为例假设APB1时钟是36MHz目标是500Kbps。先计算每个位需要的时间1/500K等于2微秒。为了得到合理的采样点我通常先确定位时间由几个tq构成再反推预分频系数。我选择9个tq组成一个位时间其中同步段1tq、相位缓冲段1为7tq、相位缓冲段2为1tq这样采样点在(17)/9约等于88.9%。位时间2微秒除以9每个tq约222纳秒。那么CAN时钟频率应该是1/222纳秒约4.5MHzAPB1时钟36MHz除以4.5MHz等于8所以预分频系数是8。注意部分控制器寄存器里写入的分频值可能比实际系数小1具体看数据手册我在这里按实际分频系数说明配置时以参考手册为准。CAN_InitTypeDef CAN_InitStructure; CAN_InitStructure.CAN_SJW CAN_SJW_1TQ; CAN_InitStructure.CAN_BS1 CAN_BS1_7TQ; CAN_InitStructure.CAN_BS2 CAN_BS2_1TQ; CAN_InitStructure.CAN_Prescaler 8; // 实际分频系数8 CAN_InitStructure.CAN_Mode CAN_Mode_Normal; CAN_Init(CAN1, CAN_InitStructure);这里有一个通用公式波特率 CAN时钟频率 / 预分频 / (同步段 BS1 BS2)。改波特率的时候只要把目标位时间对半分先定采样点再反推预分频就行。很多人一上来就改预分频BS1和BS2保持默认结果波特率对了但采样点不对表现为短距离能通、长距离或多节点时偶发错误帧。总线越长传输延迟越大传播段不够就会出问题所以长距离应用建议适当增加BS1也就是把采样点往后推。3.3 总线长度与波特率的经验对照CAN总线的理论极限距离和波特率强相关因为信号在一公里线缆上的传播延迟接近5微秒位时间越短对延迟越敏感。参考ISO 11898-21Mbps时理论长度40米500Kbps大约100米250Kbps大约250米125Kbps可以到500米。这里说的都是保守值实际取决于线缆质量、节点数量、支线长度和终端情况。波特率理论最大总线长度参考实际工程建议1Mbps40m控制在30m以内支线尽量小于0.3m500Kbps100m控制在80m以内支线小于1m250Kbps250m控制在200m以内支线小于3m125Kbps500m控制在400m以内注意压降和共地20Kbps1000m以上长距离传输别忘共地必要时加网关超过这个距离一般不是完全不通而是错误帧率明显上升隐藏表现为三天两头丢一帧。排查的时候先降波特率试一下如果降速后问题消失八成是物理层时序裕量不足。4. 汽车CAN节点电路设计实战4.1 一个标准节点由哪些部分构成一个完整的CAN节点硬件基本包括主控MCU内部集成CAN控制器或者外部SPI接MCP2515、CAN收发器、终端电阻如果这个节点在总线端点、共模扼流圈、ESD防护器件、接口连接器其次是电源轨。汽车上如果是12V供电还需要DCDC或LDO把电压降到5V/3.3V。MCU内部有CAN控制器但它输出的是TXD和RXD这种逻辑电平不能直接驱动总线。CAN收发器才是连接控制器和物理总线的桥梁它负责把TXD的逻辑0/1转换成CANH/CANL的差分信号并把总线上的差分信号还原成RXD的串行数据。所以看原理图时先找收发器它两边一边接MCU的CAN_TX和CAN_RX一边接CANH和CANL。4.2 收发器选型对比与引脚细节市面上常见的CAN收发器有TJA1050、TJA1042、TJA1051、MCP2562和SN65HVD230。TJA1042是5V供电带待机模式应用非常广TJA1051T/3多一个VIO引脚可以直接对接3.3V MCU不用额外做电平转换MCP2562也是Microchip常见的低成本方案SN65HVD230是3.3V供电常用于工业设备能直接和3.3V MCU连接。型号供电待机/静默控制适合场景TJA10425VSTB引脚车载高速CAN最常见TJA1051T/35VSTB引脚带VIO车载3.3V MCU平台MCP25625VSTBY引脚低成本车载/工业SN65HVD2303.3VRS引脚控制静默3.3V设备、工业现场这里有一个非常容易被忽略的细节TXD引脚的电平逻辑和普通TTL相反。CAN控制器的TXD为高电平表示隐性为低电平表示显性。MCU刚上电时GPIO如果默认输出低电平总线会一直被拉成显性其他节点全都发不了数据。解决办法是MCU上电期间让TXD引脚保持高阻或上拉高电平有些板子直接在TXD上串一个10k电阻上拉到收发器VCC确保MCU进入正常程序之前总线处于隐性状态。另外收发器的STB或RS引脚不能悬空必须由MCU的GPIO控制或者直接接固定电平。悬空的控制引脚可能让收发器莫名进入待机模式表现为这个节点发不出去、也收不到。4.3 外围电路共模电感、TVS和终端电阻在收发器与总线连接器之间成熟的汽车节点设计通常会放一个共模扼流圈常见型号如ACT45B-510-2P这是一个共模电感对差分信号阻抗很小对共模噪声呈现高阻抗专门用来抑制汽车上来自电机、点火系统的共模干扰。不加它EMC测试往往很难过。共模电感靠总线连接器的外侧还要加TVS二极管。我常用的PESD1CAN是专门为CAN设计的ESD防护器件钳位电压低、电容小适合放在连接器引脚附近。TVS的作用是钳位静电放电和浪涌电压防止收发器被打坏。很多人省掉TVS短时间也不出问题但上车之后静电几次就可能把收发器打穿表现为主板上的CAN收发器RXD永远输出低电平总线被错误帧刷屏。终端电阻前面讲过了只焊在总线两端节点。如果板子设计时不确定自己是不是端节点可以预留三个电阻位两个120欧和一个0欧跳线。做最终端节点时装120欧中间节点就装0欧直通或干脆不装。千万别做成一上电就三个120欧并联。4.4 从MCU到总线的信号路径梳理我把一个端节点的信号路径完整列一下方便你画原理图时对号入座MCU的CAN_TX接到收发器TXDMCU的CAN_RX接收发器RXD。收发器的TXD和RXD之间有时会加串联电阻一般10到33欧用来抑制振铃但不要加太大否则边沿变缓。收发器STB脚由MCU的GPIO控制平时拉低进入正常模式。收发器的CANH/CANL经过共模电感再经过TVS管最后到达总线连接器。连接器内侧跨接120欧终端电阻。电源方面如果需要3.3V MCU和5V收发器混用注意TJA1042的RXD输出5V电平3.3V MCU引脚如果不是5V容忍需要串电阻分压或者用TJA1051T/3的VIO直接供电3.3V。画PCB时CANH和CANL尽可能走差分对等长布线离DC-DC开关节点远一点。TXD和RXD不要贴着晶振走。总线连接器外壳接参考地屏蔽线如果用了单端接地不要两端都接形成地环路。5. 通信协议实例从报文设计到代码收发5.1 报文ID和信号矩阵的设计思路协议层看起来是“收发字节”实际工程里更讲究“信号矩阵”也就是DBC文件背后的思维方式。一个CAN报文ID是一组信号容易被解析的载体信号定义包括起始字节、起始位、位长度、字节序、缩放因子和偏移量。物理值等于原始值乘以缩放因子再加偏移量。比如我要定义一帧车速报文ID0x201DLC8。Byte0是计数器每一帧加1溢出回0Byte1是状态字bit0表示上电自检通过bit1表示故障报警Byte2到Byte3组成无符号16位车速信号低字节在前缩放因子0.01也就是原始值500按公式换算成5.00km/hByte5到Byte6是电量百分比原始值按0.1缩放Byte7是校验和把前7个字节异或得到。这种设计的好处是上位机拿到整个报文后按照DBC定义就能自动解析出物理量不用关心字节怎么拼。你在项目里即使不引入DBC工具也应该照着这个思路设计报文ID代表“这是什么数据”数据场只放定义好的信号不要乱塞。5.2 发送端代码周期上报车速报文发送端以STM32 HAL库为例先配置好CAN外设然后周期调用发送函数。关键是填充CAN_TxHeaderTypeDef结构体包括标准帧ID、帧格式、帧类型和数据长度。发完之后检查返回值成功会返回邮箱索引失败说明总线忙或节点进入Bus-off。CAN_TxHeaderTypeDef txHeader; uint8_t txData[8]; uint32_t mailbox; uint8_t counter 0; txHeader.StdId 0x201; txHeader.IDE CAN_ID_STD; txHeader.RTR CAN_RTR_DATA; txHeader.DLC 8; uint16_t rawSpeed 500; // 500 * 0.01 5.00 km/h uint16_t rawSoc 920; // 920 * 0.1 92.0% txData[0] counter; txData[1] 0x03; // bit0 自检通过bit1 无故障 txData[2] rawSpeed 0xFF; txData[3] (rawSpeed 8) 0xFF; txData[4] 0; txData[5] rawSoc 0xFF; txData[6] (rawSoc 8) 0xFF; txData[7] 0; for (int i 0; i 7; i) { txData[7] ^ txData[i]; } if (HAL_CAN_AddTxMessage(hcan, txHeader, txData, mailbox) ! HAL_OK) { // 发送失败查询错误状态 }实际项目中发送节奏不要用delay死等应该在定时器中断或者RTOS任务里按周期触发。如果CAN邮箱已满说明上一帧还没发出去你的发送周期可能设置得太短或者总线波特率低于设计值。5.3 接收端过滤器配置只收需要的报文接收端如果不加过滤所有帧都会进FIFOMCU每帧都做中断处理CPU开销大而且高优先级帧的响应实时性会变差。CAN控制器的硬件过滤器可以帮你提前丢掉不关心的报文。以STM32的bxCAN为例我要精确匹配0x201这一帧标准数据帧配置如下CAN_FilterTypeDef sFilterConfig; sFilterConfig.FilterActivation ENABLE; sFilterConfig.FilterMode CAN_FILTERMODE_IDMASK; sFilterConfig.FilterScale CAN_FILTERSCALE_32BIT; sFilterConfig.FilterBank 0; sFilterConfig.FilterIdHigh (0x201 5) 0xFFFF; // 标准ID存在高16位的高位段 sFilterConfig.FilterIdLow 0; sFilterConfig.FilterMaskIdHigh (0x7FF 5) 0xFFFF; // mask全1必须逐位匹配 sFilterConfig.FilterMaskIdLow 0; HAL_CAN_ConfigFilter(hcan, sFilterConfig);屏蔽位的逻辑是屏蔽位为1的位必须匹配屏蔽位为0的位不关心。所以我要精确匹配ID 0x201时屏蔽寄存器的高11位全部置1。如果我想同时接收0x200到0x2FF这一段可以把掩码低8位清零高3位置1这样ID高3位固定001低8位任意。灵活运用掩码一个过滤器就能覆盖一组报文。接收中断回调里正常做法是把接收到的报文存入环形队列由主循环或任务去解析不要在中断里做复杂处理否则会频繁打断主程序导致总线上其他帧得不到及时处理。5.4 远程帧的软件处理如果你确实要用远程帧接收方要识别RTR位。当收到一个RTR1、ID0x201的远程帧时软件需要主动调用发送函数把对应ID的数据帧发出去。控制器硬件不会自动替你回数据帧这是很多人第一次调远程帧时发现不工作的原因。void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) { CAN_RxHeaderTypeDef rxHeader; uint8_t rxData[8]; HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, rxHeader, rxData); if (rxHeader.IDE CAN_ID_STD rxHeader.RTR CAN_RTR_REMOTE rxHeader.StdId 0x201) { // 向0x201发送数据帧响应 sendSpeedFrame(); } }实际车载网络几乎不用远程帧但在工控设备里偶尔会用到比如主站周期性请求从站上传状态。真要用的时候记住远程帧的DLC表示你期望对方回复的数据长度目标节点回的数据帧DLC应当与请求一致。6. 常见问题排查与实战避坑6.1 错误帧与Bus-off电路“罢工”的真相CAN节点内部有两个错误计数器发送错误计数器和接收错误计数器。每检测到一个错误相关计数器加8每正确收发一帧计数器减1。当错误计数超过127节点从主动错误状态降级为被动错误状态只能发隐性错误标志超过255节点直接进入Bus-off离线状态完全退出总线不再参与任何通信直到检测到128次连续11位隐性位并完成恢复流程。实际调试时如果你发现总线上错误帧刷屏先接上CAN分析仪看错误帧的类型。CRC错误说明数据被干扰但节点间时序可能还行位错误说明总线上有其他节点同时发送ID冲突或者终端问题ACK错误说明发送节点一帧都没被确认先检查对端是否开机、有没有接终端电阻。Bus-off节点通常表现为自己发不出去也不响应任何请求但其他节点看起来又很正常。这种“单节点消失”最隐蔽。有些收发器或控制器支持快速恢复有些则需要软件复位CAN外设。我建议在应用层做一个监控如果很长时间没有收到某个节点的心跳主节点可以尝试对该节点发一个复位指令让它主动重新初始化CAN控制器。6.2 示波器排查一抓一个准没有CAN分析仪时示波器也能做大量排查。把通道1接CANH通道2接CANL用数学通道做A减B。抓到的正常波形应该是空闲时差分电压0V帧开始后有规则脉冲显性位幅度约2V脉冲边沿陡峭没有台阶和振铃。如果显性电平明显偏低比如只有1.2V大概率是终端电阻位置不对或者节点数量远超收发器驱动能力又或者总线有轻微短路。如果波形边沿有台阶尤其是长总线上要么是终端电阻没接要么是支线过长。如果总线上静止时不是0V说明有节点在发错误帧或者某个节点TXD卡死逐一断开节点排查。还有一个土办法断电状态下用万用表量整条总线的CANH和CANL之间的直流电阻正常应该大约60欧就是两个120欧并联。如果量出来是120欧左右说明只有一端有终端电阻如果量出来接近0欧有一个节点短路了如果接近40欧说明有三个终端电阻并联。这个检查不需要上电特别适合现场快速判断。6.3 共地问题差分信号也怕参考电位漂移CAN用的是差分信号抗共模干扰能力强但这不意味着各节点可以不共地。收发器内部的差动输入级有共模输入范围比如TJA1042的范围内在-12V到12V但如果两个节点距离远地线上的电流造成两个节点GND之间有几十伏的电位差超出范围一样收不到数据。现场典型的故障是单独测试每个节点都正常两个节点一接总线就不通或者一天丢帧几次。量一下两个节点电源地的直流电压差如果超过1V就要留意超过5V基本必出问题。解决办法是总线节点之间要有共同的参考地用带屏蔽层的双绞线时屏蔽层单端接地或者在系统设计时把各节点的电源地统一。6.4 故障定位速查表现象可能原因优先排查总线上所有节点都发不出数据某节点TXD被拉低总线持续显性逐个断开节点量CANH/CANL差分电压发送失败错误帧计数器不断涨终端电阻缺失、支线过长、采样点不当万用表量CANH-CANL电阻示波器看波形ACK错误总线上没有其他正常节点或接收节点未上电至少接两个节点用CAN分析仪监听CRC错误频繁干扰、线缆质量差、共地不良检查双绞线、接地、屏蔽层处理单个节点消失其他节点正常该节点进入Bus-off复位该节点查找错误根源CANH和CANL对地电压异常收发器损坏或总线短路断电后量CANH和CANL对地电阻长距离通信偶发丢帧位时间裕量不足、传播段不够提高采样点检查终端和支线最后说一个我现在的职业习惯每次测试CAN节点前先断电用万用表量CANH和CANL之间的电阻确认是60欧左右再上电上电后先量CANH和CANL对地电压确认总线处于隐性状态再把节点接入。这两步加起来不到一分钟但能排除掉绝大多数物理层的低级问题。调CAN这些年真正复杂的协议问题很少大部分故障都是终端电阻、支线和共地这三个环节快准狠地把物理层确认清楚再谈协议层能省掉大量无意义的抓包时间。
返回列表