首页 / 资讯中心 / 文章详情

CAN总线技术选型与实战:从经典CAN到CAN FD的深度解析

CAN总线技术选型与实战:从经典CAN到CAN FD的深度解析 ★ FEATURED ARTICLE
聊CAN技术之前我想先抛一个问题你手里有一个项目要用总线把十几个节点串起来通信你第一个想到的方案是什么大概率是CAN对吧但真到了选型环节很多人会卡壳——经典CAN、CAN FD、CANopen、J1939甚至还有人在CAN和LIN、CAN和FlexRay之间反复横跳。我这些年折腾过车载ECU、机器人的伺服驱动、工控IO模块可以说每一种CAN技术都在实际项目里踩过坑、填过土也踩过不少“看着一样、用起来完全不是一回事”的坑。这篇东西就是把“不同CAN技术”拆开揉碎聊一遍从帧格式的底层差异到仲裁和错误处理的机制再到不同场景下到底该选谁最后附上我自己的排障实录和实测心得。不管你是刚接触CAN的新手还是已经在用CAN但想转向CAN FD、或者正在纠结上层协议栈怎么选的工程师这篇文章应该都能给你一个比较清晰的坐标系。1. 先弄明白CAN家族都有谁经典CAN、CAN FD和协议栈的关系1.1 经典CAN 2.0A/2.0B两种帧格式和它的20年CAN总线从1986年由Bosch正式提出到今天快四十年了但它依然是汽车和工业领域应用最广的现场总线。经典CANClassic CAN通常指CAN 2.0A和CAN 2.0B两个版本它们之间的核心差异就在帧格式上CAN 2.0A用11位标识符也就是标准帧最多能定义2048个不同报文ID实际使用还要去掉一些保留位CAN 2.0B支持29位标识符也就是扩展帧可用的报文ID空间大得多适合节点数量多、报文类型复杂的场合。很多初学者会忽略一个问题CAN 2.0B的控制器完全可以收发CAN 2.0A的帧只要配置成“扩展帧兼容模式”就行反过来却不行。比如你用STM32的bxCAN外设如果只开了标准帧接收那总线上的扩展帧就会被直接过滤掉表现为“明明总线上有数据我的节点却收不到”。这种问题特别隐蔽我当年调试时就因为忽略了这一条整整查了半天。经典CAN的数据场最长是8字节在波特率500kbps的场景下一个满载的8字节数据帧大概占用130us左右的总线时间。这个“8字节上限”在很长一段时间里够用因为早期ECU之间交换的无非是转速、温度、开关状态这类小数据。但随着汽车功能越来越复杂比如OTA升级、ADAS传感器原始数据传输、多轴伺服的位置和力矩同步8字节就显得非常局促了。于是就有了CAN FD。1.2 CAN FD数据段从8字节到64字节速率还能飙到8MbpsCAN FDCAN with Flexible Data-rate不是对经典CAN的彻底推翻而是向后兼容的升级。它保留了两者相同的仲裁机制和帧起始结构但做了两个关键改动一是数据场长度从8字节扩展到最多64字节这对大数据块传输是质的飞跃二是引入了“位速率切换”机制在仲裁段用标准速率比如500kbps进入数据段后自动切换成更高速度最高可达8Mbps实际常用2Mbps或5Mbps。这样兼容性和传输效率就同时保住了。这里有个很重要的概念叫“波特率切换点”。CAN FD帧里有一个BRS位Bit Rate Switch发送端置这个位为显性接收端就知道“接下来数据段要用高速率采样”。这意味着你的收发器和控制器的时钟精度必须足够高否则高速采样时采样点会飘导致CRC校验失败。实测下来CAN FD对晶振的要求比经典CAN苛刻不少经典CAN用精度±0.5%的晶振就能跑CAN FD在5Mbps数据段时最好用±0.1%甚至更高精度的时钟源。另外经典CAN的校验用15位CRCCAN FD由于数据段长、速度快改用了更强校验能力的17位或21位CRC取决于数据长度。这个设计细节经常被人忽略但它恰恰是CAN FD能在高带宽下保持可靠性的关键。还有一点ISO 11898-1:2015标准里定义了CAN FD的两种帧格式——CAN FD不带位速率切换即整个帧统一用一种速率和CAN FD带位速率切换。前者主要是给不支持和普通CAN共存的极端场景用的实际项目中几乎都用后者。1.3 CANopen、J1939、DeviceNet为什么协议栈比裸CAN更重要裸CAN只是定义了“怎么把一段数据从A送到B”它不关心数据本身代表什么含义。但真实项目里你总得规定“报文ID 0x231的第2个字节代表目标转速”这种约定就叫应用层协议。目前最常见的CAN高层协议有三个CANopen、J1939和DeviceNet。CANopen基于CAL协议广泛应用于运动控制、医疗设备、工业自动化。它把每个节点抽象成“对象字典”通过PDO过程数据对象和SDO服务数据对象两种机制通信。PDO用于周期性高优先级的数据交换SDO用于偶发性的配置读写比如启动时主站通过SDO把从站的PID参数写进去。它的最大优势是标准化程度高不同厂家的CANopen设备基本能即插即用这也是它能在工业领域活这么久的原因。J1939则是面向重型车辆和工程机械的协议比如卡车、拖拉机、柴油发电机。它在CAN 2.0B的29位扩展帧基础上定义了PGN参数组编号、SPN可疑参数编号和源地址/目的地址的概念。你去看一辆商用车的OBD诊断口物理层就是CAN上层大都是基于J1939的UDS或J1939诊断协议。这里有个记法J1939的报文优先级占3位所以优先级从0到70最高PGN占18位SPN是对具体参数的编号。比如发动机转速对应的SPN是190车速对应SPN是84。DeviceNet则是由Rockwell Automation主导的协议主要在美国市场的工厂自动化里用得多兼容电气层和CIP协议栈。说实话在国内的工控项目里DeviceNet的份额远不如CANopen和Modbus但如果你做出口美国的OEM设备绕不开它。它的物理层特色是支持24V供电和信号在同一对线缆上传输这对现场布线是个不小的便利。把这三个协议放在一起看你就能明白一个大原则底层的CAN收发器和控制器选型可能是通用的但上层协议直接决定了你的软件架构、设备兼容性和调试工具链。选错协议栈后面改软件的代价非常大。2. 拆开CAN最硬核的三个机制仲裁、错误处理与物理层2.1 CAN总线仲裁到底怎么工作为什么会出现仲裁失败CAN能在一对双绞线上挂几十个节点且不需要主机轮询靠的是分布式多主访问机制具体实现叫CSMA/CA也就是载波监听多路访问/冲突避免。很多人把CAN的仲裁和以太网的CSMA/CD搞混以太网是“冲突检测”发现冲突后随机退避重传CAN是“冲突避免”仲裁失败的节点自动转为接收模式等总线空闲再重发。这就是为什么CAN不会像以太网那样随着负载升高出现“碰撞风暴”导致吞吐量骤降。仲裁的底层原理是“线与”特性加上显性位优先。CAN总线上的电平分显性和隐性两种显性位对应逻辑0隐性位对应逻辑1。多个节点同时发送时只要有一个节点发出显性位总线电平就是显性。每个发送节点在发送仲裁段每一位的同时会回读总线电平如果自己发的是隐性位却读到显性位就说明有更高优先级的节点在竞争自己立即退出仲裁转为接收。那么“总线仲裁失败”是在什么场景下出现的我排查过几个项目最常见的原因有两个一是在不需要“多主”的场合里把多个节点都配成了发送者且没有合理分配ID优先级大家抢得不可开交二是波特率不一致。如果总线上存在两个节点波特率差得比较多它们的位时序采样点错位仲裁逻辑就会乱表现出来就是持续不断的仲裁失败和错误帧。还有一类仲裁失败值得单独说CAN FD帧和经典CAN帧混合的总线上如果经典CAN节点不知道何时跳过CAN FD的数据段它会在应该采样的地方读到“错误位”从而触发错误帧把整条总线拉崩。所以设计混合网络时必须保证所有节点要么都支持CAN FD要么用网关隔离不能天真地把两者直接挂一条线上。2.2 五种错误与三种状态CAN的“自我修复”能力CAN控制器内置了一整套错误检测和故障封禁机制这也是它能做到“单点失效不影响总线”的根本原因。错误分五种位错误、填充错误、CRC错误、格式错误、应答错误。位错误最直观——你发的位和回读到的位不一致就报错填充错误是因为CAN规定连续5个相同电平后必须插入一个反向填充位如果接收端发现填充规则被破坏就报错CRC错误就是校验失败格式错误和应答错误则分别涉及帧格式固定位和ACK时隙。控制器根据错误计数器TEC和REC的数值把自己关进三种状态之一主动错误、被动错误和总线关闭。错误计数小于127是主动错误出错时还能主动发错误帧计数在128到255之间是被动错误出错时只能发被动错误标志而且不能再主动发起发送计数超过255就进入总线关闭控制器完全脱离总线不再参与任何通信。这个机制的设计很巧妙它保证了偶发错误不会立即干掉一个节点但持续的故障节点会逐渐被“隔离”出去避免它拖垮整条总线。调试时有个实用技巧很多CAN分析仪或调试工具可以直接读TEC和REC计数。如果你看到某个节点持续处于被动错误状态排查思路就是“这个节点的发送质量有问题”优先检查它的终端电阻、接插件接触和CAN收发器的共模电压范围。如果多个节点同时出现大量错误帧那大概率是总线缺少终端电阻或者物理层被干扰了。2.3 物理层的门道终端电阻、双绞线以及“CAN线不够长”的解法CAN的物理层标准主要是ISO 11898-2也就是大家常说的“高速CAN”波特率范围从125kbps到1MbpsCAN FD可以更高用两根线CANH和CANL差分传输。差分信号的好处是抗共模干扰能力强所以CAN才能在汽车这种电磁环境极其恶劣的地方存活。但差分传输也对线缆阻抗有明确要求标准规定线缆的特征阻抗是120Ω所以总线两端各需要并联一个120Ω的终端电阻。没有正确端接时信号会在总线末端反射表现为波特率高时通信时好时坏波特率低时看起来又正常。关于“CAN线不够长”的问题前阵子还有人问我说大疆电调的CAN线不够长能不能自己接一截延长线。我的建议是能但要注意几个点。第一不要用普通跳线或长线直接绕接CAN线要使用双绞线而且绞距要尽量均匀这样才能保证差分信号的质量第二延长后的总长度不能超过该波特率下的极限总线长度经典CAN在500kbps下理论总长是130米左右在250kbps下可以到250米左右工程上建议留20%余量第三接头处要牢靠最好用焊接或压接端子不要用胶布缠。如果延长后出现偶发错误帧优先在靠近线缆延长处补一个终端电阻调整反射或者降一档波特率跑。另外补充一个冷门但实用的知识点高速CAN的低速容错版叫“容错CAN”它允许单根线对地短路时继续通信代价是最高速率只有125kbps。这种CAN在门窗、座椅等车身舒适域里用得多主要就是看重它的容错能力和更低的线束成本。如果你只是做实验或者学习用普通的USB-CAN分析仪加两个120Ω电阻和几根双绞线就能搭一套最基础的CAN网络完全不需要依赖任何专用硬件。3. 从选型到落地不同CAN技术的实战选择与一条龙实操3.1 场景决定技术机器人、汽车、工控到底该选谁选型这件事我的经验是先问自己三个问题网络上最多挂多少个节点单个报文最大需要传多少字节两个节点之间最远距离是多少这三个答案基本能把技术方向定得八九不离十。节点数少于32个、单包数据不超过8字节、速率要求不高经典CAN足够了。很多小型伺服驱动器和PLCIO扩展就是这么做的成本低、资料多、调起来快。如果你的节点数量到了30到50个且网络里有数据量大的节点比如64字节固件升级包、多轴联动的位置数据那就要考虑CAN FD。CAN FD在2Mbps数据段下的有效吞吐量大约是经典CAN的3到5倍而且向上的兼容路径很明确——所有的CAN FD控制器都能收发经典CAN帧。汽车行业目前处在一个过渡期法规和诊断层面还是以经典CAN为主比如UDS on CAN的请求和响应都是经典CAN帧但很多ADAS域控制器内部和传感器之间已经用上了CAN FD甚至车载以太网。如果你是做汽车电子Tier 1供应商的软件开发我的建议是直接把CAN FD支持做进底层驱动成本增加很小但后续扩展空间大得多。工控领域则相反CANopen的地位暂时很难撼动因为大量的驱动器、阀岛、传感器都已经在用它你贸然换协议栈反而会增加设备对接成本。所以结论很简单没有最好的CAN技术只有和场景最匹配的CAN技术。3.2 入门实操用STM32F429/F103跑通一个CAN通信STM32家族里的bxCAN外设是很多人学习CAN的第一站F103用的是第一代bxCANF429用的是改进版两者在寄存器层面有了些差别但CubeMX里的配置思路是基本一致的。先说几个新手最容易掉进去的坑。第一坑波特率算错。bxCAN挂在APB1总线上F103的APB1默认是36MHzF429的APB1默认是42MHz具体看时钟树配置。CAN波特率的计算公式是CAN波特率 APB1时钟 / (BRP预分频值 × (SJW BS1 BS2 1))。想配500kbps一个常见的组合是36MHz / (7 × (1 8 7 1)) 36MHz / (7 × 17) ≈ 302kbps这就不对了说明预分频或者时间段参数没匹配好。正确做法是先确定你想要的波特率再反推BRP和BS段。我建议用CubeMX的图形配置界面它会实时显示最终的CAN时钟频率省去大量手工计算。第二坑过滤器配置。bxCAN有28个F429或14个F103硬件过滤器可以按报文ID过滤也可以按掩码过滤。掩码模式下哪一位是1表示必须匹配哪一位是0表示不关心。很多新手把所有过滤器都关掉了导致收不到任何数据还有人是过滤器配得太松结果本不该接收的报文也进来了。一个实用的调试策略初始阶段把过滤器设为“接收所有ID”先确认物理链路通不通跑通后再收紧掩码规则。第三坑回环模式。CubeMX里有Normal、Loopback、Silent等模式。Loopback模式是内部把TX回环到RX不需要外部应答就能“自说自话”专门用于验证软件逻辑Silent模式是只收不发常用于监听总线。如果调试时不接外部收发器或者总线上只有一个单独节点Normal模式是发不出去的因为CAN协议要求每个帧都要有接收方回ACK。这个机制会让很多新手误以为自己的代码有问题其实只是总线上少了一个节点。实际跑通CAN的标准步骤是至少两个节点哪怕一个单片机一个CAN分析仪互相对发并各自通过串口打印收发结果。我在F429上跑通过CAN FD和经典CAN的混发只要在CubeMX里把“Protocol Mode”选成FD-CAN并把FD数据段速率设置为2Mbps其余配置和经典CAN大同小异。3.3 进阶实操S32K312的CAN时钟树与CAN FD使能S32K312是NXP针对汽车应用推出的MCU它的FlexCAN模块比STM32的bxCAN复杂不少但也更接近真实车载控制器的使用方式。要说最关键的配置绝对是CAN时钟树。S32K312内部的FIRC48MHz快速IRC和SIRC32kHz慢速IRC是两个常用时钟源但CAN外设通常需要时钟频率能被波特率整除。比如你想要500kbps经典CAN又想让CAN FD的数据段到2Mbps那就要求控制器时钟至少是2Mbps的整数倍并尽量选用能被精确分频的频率。我踩过的坑是直接用默认的FIRC 48MHz去分频结果经典CAN 500kbps能正常一旦使能CAN FD并且把数据段切成2Mbps总线就开始狂抱错误帧。后来查参考手册发现FlexCAN的时钟需要走PLL或者FIRC再经过分频而分频系数在某些组合下会产生很明显的采样点抖动。解决办法是把CAN时钟源切换成PLL输出配到80MHz然后经典CAN段设20分频得到4MHz的CAN时钟再除以8得到500kbps数据段再在控制器内部用2分频切到2Mbps。这样采样点稳定在80%跑几天压力测试都干净得很。FlexCAN还有一组很实用的寄存器用于调试ECR错误计数器、IMR中断屏蔽、IFLAG中断标志。当CAN FD帧报CRC错误你可以在中断服务函数里打印IFLAG的对应位和ECR的REC值。如果REC持续上涨而TEC没变化通常是接收端时钟精度不够或者物理层信号质量差如果TEC涨得快通常是发送端的数据段波特率和接收端不匹配。这两个方向一旦分清排查范围就小很多。3.4 上位机配合周立功CAN卡与LabVIEW二次开发做CAN项目基本离不开上位机不管是观察数据、模拟节点还是发送诊断命令。我常用的方案是周立功的USBCAN系列加上LabVIEW。周立功的CAN卡在国产工具里占有率非常高驱动稳定资料也比较全。它的API分两层底层是周立功自己的CAN接口函数库上层可以导出为DLL供LabVIEW调用。如果你不想自己封装复杂的结构体直接用他们提供的LabVIEW例子程序改一改能省不少时间。有一个细节必须提醒周立功CAN卡默认不启用CAN FD模式你如果用CAN FD节点发数据上位机解析出来全是错误帧。需要在初始化设备时单独调用CAN_FDInit接口并设置数据段波特率。另一个坑是PCAN或者周立功的USB-CAN卡的发送时间戳精度默认的发送流程如果不用“计划帧发送”模式每次发帧的间隔在Windows下会有1ms级别的抖動这对仿真某些严格周期报文来说是致命的。解决办法是用设备自带的硬件定时发送功能把所有要发送的帧预先配置到硬件内部发送缓冲区由CAN卡自己的时钟控制周期这样抖动可以压缩到几十微秒以内。LabVIEW程序的结构我一般会设计成三块初始化块打开设备、配置波特率、配置过滤器、循环读写块用While循环里跑一个CAN_Receive轮询数据队列化后用事件结构处理、退出清理块调用CAN_Close。这种结构既简单又稳定实时性也够大多数台架测试用。如果你想看波形或者对报文做触发记录周立功的ZCANPro软件本身就带报文回放和触发存储功能不用自己先从零造轮子。4. 高频问题与排查技巧实录这些坑我替你踩过了4.1 正响应0x40和负响应诊断帧里的“对”与“错”只要做汽车CAN诊断早晚会碰到“CAN里面40是正响应负响应是什么”这类问题。这里的“40”指的是UDS统一诊断服务协议里的正响应SID服务标识符规则很简单正响应SID 请求SID 0x40。举个例子请求SID为0x10诊断会话控制正响应就是0x50请求0x22按标识符读取数据正响应就是0x62。所以网络里看到0x40、0x50、0x62这些“奇怪”的高字节SID基本就能判定这是某个诊断请求的正响应。负响应则是另一种格式报文的第一字节是0x7F第二字节是被拒绝的请求SID第三字节是NRC负响应码。NRC是诊断排查的重中之重常见的NRC含义如下表NRC码含义常见原因0x10一般拒绝请求无法在当前状态下执行0x11不支持请求SID无效或未实现0x12子功能不支持子功能参数不合法0x13报文长度或格式错误字节数不对或数据格式错误0x14条件不满足前置条件未满足如未解锁0x22条件不满足安全访问未完成0x31请求超出范围参数值超上限或低于下限0x33安全访问被拒绝多次错误解锁导致锁定0x78请求已接收正在处理需要等待延后响应排查负响应最关键的思路是“先确认NRC码属于哪一类”。0x10到0x1F都是软件层拒绝检查ECU的应用逻辑和状态机0x20到0x2F是条件不满足检查安全访问和时序0x30到0x3F是请求参数无效检查你填的数据是否按规范编码。日常调试中0x22和0x31出现频率最高特别是误以为请求的DID数据标识符存在或者把十六进制数当成十进制数填了。4.2 仲裁失败、丢帧、波特率不匹配的定位思路当总线上出现大量错误帧或者仲裁失败我的常规排查步骤是这样的第一步用CAN分析仪以“只听模式”挂在总线上直接看错误帧的种类和来源。如果所有错误帧都指向同一个节点ID那问题大概率出在那个节点本身比如它的收发器损坏、供电异常、终端电阻脱落如果错误帧分布在各处且速率均匀则先怀疑物理层整体质量比如总线长度超了、线缆阻抗不对、终端电阻缺失或数量不对。第二步检查波特率一致性。很多人说“我两个板子都配置成500kbps”但查完发现一个用的是500kbps标准位时序另一个用的是500kbps但采样点相差很多。CAN的位时序涉及BRP、BS1、BS2和SJW不同的组合可能得到相同的波特率却导致不同的采样点位置。标准建议采样点尽量靠近位时间的75%到80%STM32的默认配置可能落在70%左右而另一个芯片可能是65%两者虽然都是500kbps但配合边缘节点时稳定性就差。统一采样点的办法是指定“采样点百分比”而不是只指定“波特率”。第三步丢帧问题要看“丢”的方式。是周期报文的某些周期没出现还是少量数据帧的CRC错误率很高如果CRC错误率高优先怀疑电磁干扰和线缆质量如果CRC错误正常但报文就是偶尔不上线需要检查发送节点是否因为发送缓冲区满而丢弃——很多CAN控制器的硬件发送队列只有3到8个槽位如果你在软件里一次性塞了太多帧超出槽位的帧可能被静默丢弃。解决办法是引入发送排队机制或者提高发送任务的优先级和缓冲深度。4.3 长线传输与节点扩展降速、加终端、换收发器怎么选总线长度不够或者要扩展节点时很多人的第一反应是“换个更强的收发器”但我要说的是先算物理层的极限和需求再动手。经典CAN的总线长度限制和波特率强相关计算公式是总线长度 最大传播延迟 × 信号速率。工程上有个近似经验值1Mbps下最大总线长度约40米500kbps约130米250kbps约250米125kbps约500米。如果你的场景是几个电调之间通信距离却拉到几十米首选方案是降波特率而不是加线缆粗度。如果降波特率影响性能再考虑换带信号增强的收发器或者加中继器。但要理解CAN是“线与”仲裁机制任何中继器都必须做到“转发的同时保持仲裁语义”也就是说它不能简单地把收到的报文重新发一遍因为它必须参与总线的瞬时仲裁。市场上大多数CAN中继器是“存储转发式”会引入明显延迟多个级联之后几乎无法做多主仲裁。真正可靠的做法是使用带CAN隔离和信号增强的网关把一个长总线拆成两段中间用不同CAN控制器芯片做桥接但桥梁本身要具备缓存和转发逻辑。对于节点扩展我发现很多人会忽略总线上的等效负载。一个CAN收发器的差分输入阻抗在隐性状态下约为20kΩ但收发器在显性状态下的负载会显著拉低总线阻抗。标准要求最多挂32个节点实际上超过20个节点时就要考虑链路裕量并在选型时选用低电流的CAN收发器或者带待机模式的型号。还有一个冷门技巧如果总线上节点数比较多可以用0.75倍波特率而不是1倍波特率比如把500kbps跑成375kbps给信号留出更多边沿斜率裕量——这在整车上很少用但在自制长线协议栈时很管用。5. 用了这么多年CAN我的一些个人体会写了这么多最后说点实在的感受。我自己的项目经验告诉我CAN技术本身的门槛不在协议层阅读而在“边界判断”。你首先要能在不同CAN技术之间做判断经典CAN够用的地方不要为了炫技上CAN FD平白增加时钟和PCB布局上的难度但也别因为习惯了经典CAN而不愿意升级多花一点代码量换来3到5倍的吞吐量提升在很多场合是完全值得的。还有一点是关于工具的。好的CAN分析仪能帮你省下大半调试时间但工具的价值取决于你会不会看它的统计数据。错误帧计数、总线负载率、TEC/REC数值、采样点分布这些才是真正能定位问题的高价值信息比盯着波形图“看半天”有效得多。如果条件允许尽量给自己配一台支持CAN FD的分析仪哪怕现在项目还用不到CAN FD后续升级时就不用重复采购了。最后分享一个小经验每次搭建CAN网络时把终端电阻做成可插拔的跳线把每个节点ID和波特率做成显式可配置的参数把上位机的过滤规则留成开放接口。做完这三件事你的CAN调试体验会完全不同——从“出问题到处量波形”变成“看一眼配置表就知道哪里不对”。这就是CAN这个老而弥坚的总线技术最迷人之处它的下限很低几根线加两个电阻就能跑起来但它的上限很高深入进去之后有太多细节值得研究。如果你正在做一个CAN相关的项目欢迎在调试过程中多记录异常现象的细节很多时候你排查到的“玄学问题”本质上都是某个物理层参数或者时序参数没有压到规定范围并不是协议本身的问题。先相信标准再怀疑代码最后才怀疑硬件这条排查顺序我用了十年都没变过。
阅读完成 · 觉得有帮助?
咨询建站