资讯动态

CAN总线从入门到实践:STM32硬件配置与协议核心机制详解

发布时间:2026/10/18 1:08:36 来源:尧图企业网站定制
1. 为什么要写这篇 CAN 总线文章很多人第一次接触 CAN 总线是在做嵌入式比赛或者工业设备改造的时候。我自己的经历差不多拿到一块带 CAN 控制器的开发板手册翻了两页全是帧格式波特率采样点这些词直接把人看懵了。其实 CAN 本身不复杂但它的文档和资料习惯性地把协议层和硬件层混在一起讲初学者很容易卡在看起来每个字都认识连起来不知道在说什么的状态。这篇内容的目标只有一个把 CAN 总线从物理层到 STM32 应用层的完整链路拆开让你看完之后能自己搭一套双机通信的 Demo知道怎么配波特率、怎么发数据、怎么收数据也能处理掉最常见的几个坑。适合的人群有三类正在学 STM32准备用 CAN 做项目但找不到系统资料的人工作中需要和 CAN 设备对接想快速搞懂协议细节的人已经会用 CAN 但总是遇到通信不稳定想弄清楚底层原理的人。2. 先搞懂 CAN 总线到底是个什么东西2.1 CAN 产生的原因与优势CAN 全称是 Controller Area Network控制器局域网。它最早是汽车电子厂商为了解决车内线束过多、信号互相干扰的问题搞出来的。传统车载布线方式是一对一一个传感器接一根线到 ECU车上几十个传感器就要几十根线重、贵、难维护。CAN 的思路改成了一条总线挂多个节点所有设备共享两根线通过报文 ID 区分谁的数据。这套设计带来的核心优势有三点多主架构。总线上任何一个节点都可以主动发数据不需要主机轮询这对实时性要求高的场景非常关键。抗干扰能力强。物理层用的是差分信号两根线CAN_H 和 CAN_L上的电压相减得到逻辑电平外部共模噪声会被抵消。错误处理机制完善。协议层自带 CRC 校验、位填充检测、帧格式检查出错能自动重发硬件层面的可靠性远高于串口。所以 CAN 后来不只是用在汽车上工业控制、医疗设备、无人机、机器人、电梯、船舶都有大量应用。它的定位是可靠的中短距离多节点通信传输距离和节点数介于 I2C 和以太网之间但实时性和抗干扰能力比一般现场总线强很多。2.2 电平与传输介质CAN 物理层用的是两根线CAN_H 和 CAN_L。逻辑 1隐性位时两根线电压都在 2.5V 左右差分电压约 0V逻辑 0显性位时CAN_H 拉高到约 3.5VCAN_L 拉低到约 1.5V差分电压约 2V。这个差分的设计是 CAN 抗干扰的根本原因。外界噪声同时叠加到两根线上相减后噪声被消除而串口单线传输靠的是绝对电压噪声一上来就容易误码。传输介质用双绞线特性阻抗约 120Ω。总线两端必须接 120Ω 终端电阻防止信号反射。少了终端电阻波形会严重过冲和振铃通信距离和稳定性会大幅下降。这是我实际测试中踩过的第一个坑两根线都接好了插上就能收到乱码查了半天发现其中一个节点的终端电阻没焊。注意终端电阻是接在总线物理两端各一个 120Ω不是每个节点都接。如果是两个节点互联那就是各自接一个合计等效 60Ω。超过两个节点时只在最远两端接。2.3 OSI 模型视角下的 CANCAN 协议覆盖了 OSI 模型的数据链路层和物理层。物理层决定信号怎么变成电压、怎么传输数据链路层决定数据怎么封装、怎么仲裁、怎么校验。用户通常只接触应用层直接调用控制器硬件提供的收发接口。STM32 内部的 bxCAN 外设其实已经把数据链路层的大部分功能用硬件实现了。你要做的只是告诉它波特率多少、过滤器怎么设、消息 ID 是多少然后写发送数据等接收中断。3. CAN 协议核心机制解读3.1 报文帧的构成拆解CAN 报文帧有四种类型数据帧、远程帧、错误帧、过载帧。实际使用最多的就是数据帧带数据远程帧用来向总线请求数据现在用得少很多现代协议已经不用它了。错误帧和过载帧是总线自动维护用的普通开发者不需要手动构造。数据帧的标准格式11 位 ID结构如下段名长度作用帧起始1 bit显性位标记一帧开始仲裁段12 bitID11 RTR1控制段6 bitIDE1 DLC4 r01数据段0-64 bit最多 8 字节CRC 段16 bit校验帧内容ACK 段2 bit接收确认帧结束7 bit隐性位7 个连续的隐性位DLC 是 Data Length Code表示数据长度取值范围 0-8。超过 8 字节的帧在 CAN 2.0 协议里不存在这是很多新手第一眼看到会疑惑的地方为什么一个帧最多 8 个字节因为早期的汽车控制报文都短8 字节足够承载当时的传感器数据而且短帧有利于保证实时性和总线利用率。CAN FDFlexible Data协议扩展到了 64 字节但那是后话大部分 STM32 应用场景还用不到。CRC 段是 15 位 CRC 加 1 位 CRC 分隔符。CRC 覆盖的范围包括仲裁段、控制段、数据段但不包括填充位。接收方算出来的 CRC 和帧里带的 CRC 不一致时就会产生错误帧。3.2 标识符仲裁的原理CAN 是多主总线任意节点都可以在总线空闲时发数据。如果两个节点同时开始发怎么决定谁先发谁后发答案在仲裁段。仲裁规则一句话概括ID 数值越小优先级越高。总线上的显性位0优先级高于隐性位1。两个节点同时发送时每一位都做线与逻辑——只要有一个节点发出显性位总线就呈现显性状态。发送隐性位的节点发现总线上是显性电平就意识到自己输了立即停止发送转为接收状态。举个例子节点 A 发 ID0x123二进制 001 0001 0011节点 B 发 ID0x456二进制 100 0101 0110逐位比较的第一位A 发出 0显性B 发出 1隐性总线呈现显性B 检测到冲突后退出。所以 0x123 的优先级比 0x456 高先发。这个机制的妙处在于仲裁过程不浪费总线时间胜出的节点继续发完剩下的比特失败节点自动闭嘴完全不需要主机协调。在实际项目中设计报文 ID 时通常会预留优先级含义越紧急的数据用越小的 ID。标识符仲裁是 CAN 协议最优雅的设计之一。我特别想强调一个点仲裁只在两个节点同时开始发送时才发生不是任何时候都抢总线。总线空闲时任何节点随时可以启动发送。3.3 位填充机制CAN 协议规定发送端发送同一电平超过 5 个连续位时会强制插入 1 个相反电平的填充位。接收端收到 5 个连续相同电平和 1 个相反电平后会丢弃这个填充位恢复原始数据。为什么要干这件事两个原因保持时钟同步。CAN 接收端靠电平跳变来同步自己的位时钟长时间没有跳变采样时机就会漂移。填充位保证了每隔最多 5 个比特就有一次跳变。错误检测。如果接收端检测到连续 6 个相同电平说明总线出了稳定性问题或节点故障可以直接触发错误帧。位填充的范围覆盖仲裁段、控制段、数据段、CRC 段。帧起始到仲裁段起始以及 ACK、EOF 段没有填充。3.4 错误处理机制CAN 的错误处理是硬件自动完成的这也是它比串口可靠的关键原因。每个节点内部维护着发送错误计数TEC和接收错误计数REC每次出错都会根据规则加减分检测到自己发送出错TEC 8自己发送时收到 ACK 错误TEC 8接收出错REC 1成功发送或接收对应计数 -1计数超过 127 时节点进入离线状态不再参与总线通信。离线后要检测到总线空闲 128 次才会重新恢复。这套机制下单个节点故障不会拖垮整条总线。某个节点如果反复出错计数会迅速上升最后主动离线剩下的节点继续正常工作。这也是为什么 CAN 总线有硬件故障隔离特性的原因。4. 一步一步配置 STM32 的 bxCAN4.1 硬件连接与电路设计要让 STM32 的 CAN 控制器真正发数据到总线需要经过一个 CAN 收发器芯片。STM32 的 CAN 控制器输出的是 TTL 电平的 TX/RX 信号不能直接驱动差分总线必须外接收发器。常用型号有 TJA1050、TJA1040、VP230 等。典型接线方式STM32 CAN_TX 引脚如 PA12→ 收发器 TXDSTM32 CAN_RX 引脚如 PA11→ 收发器 RXD收发器 CANH 引脚 → 总线 CAN_H 线收发器 CANL 引脚 → 总线 CAN_L 线收发器 VCC 接 3.3V 或 5V根据芯片型号注意 STM32 的 io 引脚不是随便选的。CAN_TX 和 CAN_RX 必须映射到具有 CAN 复用功能的引脚具体引脚表在数据手册里有。选错引脚程序怎么调都不通。我测试用的板子是 STM32F103C8T6CAN 引脚默认复用为 PA11RX和 PA12TX波特率设置为 500kbps收发器用的 TJA1050总线两端接 120Ω 终端电阻实测通信稳定。4.2 开启时钟与引脚复用配置 CAN 外设的第一步是打开外设时钟。STM32F103 系列中CAN1 挂在 APB1 总线上时钟 APB1 通常是 36MHz注意是 36MHz 不是 72MHz。很多人直接按 72MHz 计算波特率导致参数完全错误。时钟和引脚配置代码基于标准外设库HAL 库逻辑类似void CAN_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); GPIO_InitStructure.GPIO_Pin GPIO_Pin_12; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; // TX 推挽复用 GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IPU; // RX 上拉输入 GPIO_Init(GPIOA, GPIO_InitStructure); }注意 RX 引脚不能配成推挽输出这点容易忽略。它是输入引脚要浮空输入或上拉输入。4.3 初始化结构体的关键参数CAN 初始化涉及几个核心参数波特率、工作模式、重同步跳跃宽度SJW、采样点位置。CAN_InitTypeDef CAN_InitStructure; CAN_InitStructure.CAN_TTCM DISABLE; // 时间触发模式一般关闭 CAN_InitStructure.CAN_ABOM ENABLE; // 自动离线恢复推荐打开 CAN_InitStructure.CAN_AWUM ENABLE; // 自动唤醒模式推荐打开 CAN_InitStructure.CAN_NART DISABLE; // 非自动重发关闭表示出错自动重发 CAN_InitStructure.CAN_RFLM DISABLE; // 接收 FIFO 锁定模式关闭 CAN_InitStructure.CAN_TXFP DISABLE; // 优先级由报文 ID 决定 CAN_InitStructure.CAN_Mode CAN_Mode_Normal; // 正常模式 CAN_InitStructure.CAN_SJW CAN_SJW_1tq; // 同步跳转宽度 CAN_InitStructure.CAN_BS1 CAN_BS1_4tq; // 相位缓冲段 1 CAN_InitStructure.CAN_BS2 CAN_BS2_3tq; // 相位缓冲段 2 CAN_InitStructure.CAN_Prescaler 9; // 波特率分频 CAN_Init(CAN1, CAN_InitStructure);这段配置对应波特率的计算过程APB1 时钟 36MHz经过 Prescaler 分频后得到 Tq时间量子。一个位时间由 SYNC_SEG1 tq BS14 tq BS23 tq组成共 8 tq。波特率 36MHz / (9 × 8) 500 kbps这个公式建议反复理解因为它是 CAN 配置里最容易出错的地方。不管寄存器直接计算非常容易多乘或少乘一个 2。4.4 过滤器配置详解bxCAN 的过滤器是新手入门最容易卡住的地方。STM32F103 有 14 个过滤器组0-13每组可以配置为 ID 列表模式或掩码模式宽度可配为 32 位或 16 位。过滤器的核心作用是接收时硬件先检查报文 ID符合过滤规则的报文进入接收 FIFO不符合的直接丢弃不占用 CPU。这样在总线报文很多时MCU 只需要处理自己关心的 ID。我的建议是只要项目需求不复杂先配置一个过滤器为掩码模式屏蔽全部比较位即接收所有报文。这样可以先保证通信跑通再逐步细化过滤规则。CAN_FilterInitTypeDef CAN_FilterInitStructure; CAN_FilterInitStructure.CAN_FilterNumber 0; CAN_FilterInitStructure.CAN_FilterMode CAN_FilterMode_IdMask; CAN_FilterInitStructure.CAN_FilterScale CAN_FilterScale_32bit; CAN_FilterInitStructure.CAN_FilterIdHigh 0x0000; CAN_FilterInitStructure.CAN_FilterIdLow 0x0000; CAN_FilterInitStructure.CAN_FilterMaskIdHigh 0x0000; CAN_FilterInitStructure.CAN_FilterMaskIdLow 0x0000; CAN_FilterInitStructure.CAN_FilterFIFOAssignment CAN_FIFO0; CAN_FilterInitStructure.CAN_FilterActivation ENABLE; CAN_FilterInit(CAN1, CAN_FilterInitStructure);掩码全是 0 表示不检查任何位。如果只想接收 ID 0x101 的报文掩码全部置 1ID 寄存器写入 0x101 对应的格式。过滤器配置的具体映射规则跟帧类型有关标准帧用 ID 高 11 位扩展帧用 29 位。实际调试时不要凭感觉写对照参考手册查清楚。5. 从发送到接收完整跑通 CAN 通信5.1 CAN 发送消息的详细流程发送 CAN 报文的核心操作填充消息数据配置消息 ID、DLC调用发送接口。typedef struct { uint32_t StdId; // 标准 ID uint32_t ExtId; // 扩展 ID标准帧时不用 uint8_t IDE; // 帧格式标准帧 / 扩展帧 uint8_t RTR; // 帧类型数据帧 / 远程帧 uint8_t DLC; // 数据长度0-8 uint8_t Data[8]; // 数据 } CanTxMsg;发送函数CanTxMsg TxMessage; TxMessage.StdId 0x101; TxMessage.IDE CAN_Id_Standard; TxMessage.RTR CAN_RTR_Data; TxMessage.DLC 4; TxMessage.Data[0] 0x01; TxMessage.Data[1] 0x02; TxMessage.Data[2] 0x03; TxMessage.Data[3] 0x04; uint8_t mailBox CAN_Transmit(CAN1, TxMessage);CAN_Transmit 返回的是请求发送的邮箱号0-2或者失败值。每次发送前要检查有没有空邮箱发送后要轮询状态直到确认发送完成if (CAN_Transmit(CAN1, TxMessage) ! CAN_TxStatus_Failed) { // 等待发送完成 while (CAN_TransmitStatus(CAN1, mailBox) ! CAN_TxStatus_Ok) { // 超时保护避免死等 } }如果不等待发送完成就立刻发下一帧会出现 FIFO 覆盖或邮箱占用冲突。实际调试时我遇到过一种情况代码里发送函数跑得飞快但总线上抓到的帧数量少原因就是没有等待发送完成状态还在挂起时下一帧的发送请求就被拒绝了。5.2 CAN 接收消息的两种方式接收 CAN 报文有两种方式查询和中断。查询方式适合简单测试中断方式适合生产项目。查询接收核心逻辑CanRxMsg RxMessage; if (CAN_Receive(CAN1, CAN_FIFO0, RxMessage) CAN_GetFlagStatus(CAN1, CAN_FLAG_FIFO0)) { // 这里判断 FIFO 是否有数据参考手册有更合适的写法 }需要注意 CAN_Receive 在 FIFO 为空时会被阻塞。如果只用查询方式必须先用标志位判断 FIFO 是否有数据。中断接收更常用。开启接收 FIFO0 中断CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE); NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel USB_LP_CAN1_RX0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority 0; NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; NVIC_Init(NVIC_InitStructure);中断服务函数void USB_LP_CAN1_RX0_IRQHandler(void) { CanRxMsg RxMessage; if (CAN_GetITStatus(CAN1, CAN_IT_FMP0) ! RESET) { CAN_Receive(CAN1, CAN_FIFO0, RxMessage); // 处理接收到的消息 ProcessCANMessage(RxMessage); CAN_ClearITPendingBit(CAN1, CAN_IT_FMP0); } }注意 CAN_GetITStatus 和 CAN_ClearITPendingBit 必须在同一个中断函数里配对使用否则标志位不被清除中断会反复触发。FIFO 溢出也是个问题。如果数据到得太快CPU 来不及取走FIFO 满了之后新数据会丢失。这时可以用 CAN_IT_FF0 和 CAN_IT_OVR0 中断做溢出标志。实际项目中溢出处理最简单的策略是在接收中断里只做数据拷贝不做长任务处理把处理任务丢给主循环或高优先级任务。5.3 一个最小的双机测试用例为了验证整个链路建议先做双板互联测试板 A 周期性发送板 B 接收打印。注意板 A 的 CAN_AA 引脚和板 B 的 CAN 引脚之间的连接CAN_A_H 接 CAN_B_HCAN_A_L 接 CAN_B_L两端各接 120Ω 到地。测试程序流程板 A 每 100ms 发送一帧 ID 0x101 数据内容为计数器的累加值。板 B 中断接收解析 ID 和 DLC把数据通过串口打印。确认板 B 收到的计数值连续递增说明无丢失、无错序。下面给出板 A 发送部分的完整伪代码直接集成到上一节的初始化之后即可int main(void) { CAN_GPIO_Init(); CAN_Init(); // 使用上面配置的参数 CAN_Filter_Init(); while (1) { CanTxMsg msg; msg.StdId 0x101; msg.IDE CAN_Id_Standard; msg.RTR CAN_RTR_Data; msg.DLC 4; msg.Data[0] counter; msg.Data[1] counter 8; msg.Data[2] counter 16; msg.Data[3] counter 24; if (CAN_Transmit(CAN1, msg) ! CAN_TxStatus_Failed) { while (CAN_TransmitStatus(CAN1, mailBox) ! CAN_TxStatus_Ok); } delay_ms(100); } }这个测试用例跑通后基本上就可以开始做正式项目了。6. 实际项目中的 BIT 时序与采样点配置6.1 位时序的底层推导CAN 的一个位时间由四个段组成同步段SYNC_SEG、传播段PROP_SEG、相位缓冲段 1BS1、相位缓冲段 2BS2。每个段的长度用 Tq 表示。SYNC_SEG固定 1 Tq用于同步总线上各节点。PROP_SEG补偿信号传播延迟长度取决于总线长度和收发器延时。BS1 和 BS2用于补偿时钟漂移采样点位于 BS1 结束处。STM32 bxCAN 把传播段和 BS1 合并所以你的寄存器里看到的是 BS1 和 BS2不像其他控制器有独立的 PROP_SEG。这个细节很关键——许多从其他平台转过来的人会找 PROP_SEG 寄存器找不到就乱猜参数。采样点位置 (SYNC_SEG BS1) / (SYNC_SEG BS1 BS2) × 100%上面的配置里采样点 (1 4) / 8 × 100% 62.5%6.2 不同波特率的常用配置表这里给一份实测过的常用配置表APB1 36MHz 时波特率PrescalerBS1BS2采样点实际误差1Mbps44466.7%0%500kbps94362.5%0%250kbps184466.7%0%125kbps364466.7%0%如果 APB1 时钟不是 36MHz必须依据公式换算配置表和实际硬件对不上时通信会完全失败或偶发错误。判断波特率是否配置正确的快速方法把两个节点接好后用逻辑分析仪看总线波形。一个正常的 CAN 帧帧起始的下降沿到仲裁段结束电平变化应该符合协议特征而不是一团乱码。6.3 采样点选择对稳定性的影响采样点太早或者太晚都会导致误码率上升。总线短、节点少时采样点在 70%-90% 之间都还能稳定总线长超过 100 米或者节点间晶振误差大时采样点偏差的影响会被放大。一般建议车载应用采样点设置在 87.5% 左右工业应用可以设置在 75%-80%。STM32F103 上把采样点调到 87.5% 的配置示例BS16BS21Prescaler 不变。我自己的经验是双机互联、线长不到 50 厘米时采样点漂移影响很小老老实实按推荐值配置就行。不要为了看起来更稳去乱调采样点改动后一定要做长时间压力测试。7. 调试工具与排查手段7.1 逻辑分析仪看波形调试 CAN 最有效率的办法是用逻辑分析仪抓波形然后软件解码。市面上常见的逻辑分析仪软件大多支持 CAN 协议解码。抓波形的步骤很简单逻辑分析仪通道接 CAN_RX 引脚或直接接总线 CAN_H 与 GND设置采样率建议至少 4 倍波特率500kbps 波特率用 2MS/s 以上触发条件设置为下降沿抓一段总线空闲到数据出现的完整波形。解码时如果看到 CRC 错误或者帧格式错误重点检查波特率配置和时钟源精度。如果波形正常但解码结果变乱码检查收发器的供电和终端电阻。7.2 波特率错误的现象与定位波特率不匹配的典型现象是接收方偶尔能收到数据大部分时间收到的是乱码或错误帧用示波器看 ACK 段波形明显看到 ACK 位没有正确的显性电平。波特率偏差的本质是 Tq 时间和实际位时间不匹配。发送方的位时间比接收方的短发送多个字节后误差累积接收方采样点逐步偏移到错误位置。定位步骤用频率计或示波器看总线波形手动测量一个位时间反推实际波特率。反过来检查代码里配置的 Prescaler 和 BS1/BS2 是否与 APB1 时钟匹配。检查两个节点的晶振频率偏差。如果总线上节点太多建议用一个 20ppm 精度的晶振做基准节点。7.3 终端电阻缺失的表现与验证终端电阻缺失时总线波形有明显振铃。用示波器看 CAN_H 到 GND 的波形在数据跳变的边沿会看到过冲和回振严重时逻辑电平会越过阈值导致接收端采样错误。验证终端电阻的方法断电状态下用万用表量 CAN_H 和 CAN_L 之间的阻值。两个终端电阻都正常时应该量到约 60Ω。只在一端接了电阻时量到约 120Ω。两端都没接量到无穷大或接近无穷大。我在一个项目中就遇到过终端电阻缺失的问题总线长度约 30 米三个节点只是因为一个节点换上了早期不带电阻的收发器板卡就成了间歇性通信故障。后来换了电路板阻值恢复 60Ω问题立刻消失。8. 常见问题与排查技巧实录8.1 CAN 发送超时或失败发送失败的表现是 CAN_Transmit 一直返回 Failed或者发送状态卡在挂起不变成成功。排查顺序确认总线空闲用逻辑分析仪看总线是否有持续电平变化。总线长期被某个节点占死会导致其他节点发不出去。确认 CAN_TX / CAN_RX 引脚配置正确TX 必须是复用推挽输出RX 必须是输入。确认收发器芯片供电正常TJA1050 需要 5V 供电有些板子是 3.3V选错芯片供电会导致输出电平不足。屏蔽过滤器测试把过滤器掩码全部清零如果这样能收到说明过滤规则配错了。8.2 接收中断频繁触发但数据不变看起来数据每次长度一样、内容一样实际是 FIFO 溢出后数据被覆盖或者读取缓冲区没有更新。建议在接收中断里加一个版本号字段或 CRC 字段发送端每帧改变接收端校验后打印。如果版本号不更新检查发送端是否真的在发新数据而不是发了缓存里同一份数据。8.3 波形的隐性电平异常如果总线空闲时 CAN_H 和 CAN_L 电压不是 2.5V而是接近 0V 或 5V说明收发器工作状态不对常见原因是收发器没有进入正常模式。部分收发器有 STBY 引脚需要在代码里拉高或拉低仔细看 datasheet。8.4 CAN 和 USB 共用一个中断向量STM32F103 的 CAN1 RX0 中断和 USB 中断共用向量名USB_LP_CAN1_RX0_IRQn。如果工程里同时用了 USB 和 CAN中断入口冲突。解决办法是改用 FIFO1 中断对应CAN1_RX1_IRQn或者统一在共用中断函数里做源判断。这个坑比较隐蔽很多人排查了半天时钟和过滤器结果是中断向量冲突。9. CAN 总线扩展方向与进阶建议如果这篇内容消化得差不多了下一步可以尝试几个方向CAN FD。CAN FD 是在 CAN 2.0 基础上的扩展数据段最长 64 字节波特率可切换适合传输大数据块。高层协议J1939、CANopen、UDS。这些是基于 CAN 物理层之上约定的应用层协议真正的车载诊断和工业控制会用到。协调多个节点在总线上挂 3 个以上节点设计一套简易的广播应答通信协议理解多节点情况下的冲突处理。用 STM32CubeMX 和 HAL 库做同样功能的工程对比标准库和 HAL 库的差异这在换芯片、做跨平台移植时会很有用。自己写一个逻辑分析仪 CAN 解码插件。如果正在用开源的逻辑分析仪软件写插件的过程能加深对整个协议栈的理解。我个人在实际操作中的体会是CAN 协议最重要的是理解仲裁和错误处理机制因为它们是硬件自动完成的很多功能透明到你看不到但一旦出问题又必须从原理层面去排查。比如你设置好波特率后总线通信大概率直接就通了但如果你要处理的是偶发性掉线、数据丢帧、多节点争抢这些疑难杂症没有协议层的完整认知就只能靠碰运气了。最后再分享一个小技巧调试 CAN 时可以故意让两个节点用不同的波特率开机然后观察错误计数。能读出来错误计数是多少、往上涨还是往下跌基本就能确认错误机制有没有正常运作。这个技巧我教过不少人排查速度比盲目改参数快得多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑