ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

第三章:CAN2.0 协议帧结构精讲

第三章:CAN2.0 协议帧结构精讲 导读CAN 总线所有交互都是依靠不同类型的帧完成很多初学者只会调用库函数收发报文看不懂原始帧每一位代表什么遇到抓包报文时无法定位问题。本章完整讲解 CAN2.0A / CAN2.0B五种帧类型逐位拆解报文结构配合真实报文样例最后给出报文解析示例代码。CAN2.0 分为两个版本CAN2.0A标准帧ID 长度 11 位日常车载、工业设备最常用。CAN2.0B扩展帧ID 长度 29 位适合大量设备组网、ID 资源紧张的场景。注意控制器支持 CAN2.0B 的硬件可以兼容接收 CAN2.0A 标准帧但是只支持 2.0A 的控制器不能解析扩展帧。3.1 CAN 的 5 种帧类型总览CAN 协议一共定义 5 种帧各自用途完全不同数据帧最常用节点向外发送有效业务数据。远程帧 (RTR)请求别的节点返回对应 ID 的数据不带数据段。错误帧任意节点检测通讯错误时主动发出通知全网发生错误。过载帧接收节点来不及处理报文通知发送方暂缓发送下一帧。帧间隔两帧报文之间的分隔段不属于报文本体。日常开发 95% 场景只使用数据帧和远程帧错误帧、过载帧由硬件控制器自动产生软件一般不需要手动构造。3.2 标准数据帧完整逐位拆解CAN2.0A11‑bit ID一帧标准数据帧从左到右传输顺序分为 7 个段帧起始SOF → 仲裁段 → 控制段 → 数据段 → CRC段 → ACK应答段 → 帧结束EOF3.2.1 帧起始 SOF1 bit显性 01 位显性电平标记一帧报文的开始。 总线处于空闲隐性 1时发送节点拉低总线发出 SOF通知所有节点即将开始传输一帧报文。3.2.2 仲裁段12bit标准帧仲裁段组成11 位 ID RTR 位11 位 ID报文标识符决定报文优先级ID 数值越小优先级越高。RTR 位0 代表数据帧1 代表远程帧。仲裁就发生在这个段。多个节点同时发包硬件对比每一位 ID遇到显性 0 和隐性 1 冲突发 1 的节点退出发送。实例标准 ID0x123二进制 ID0001 0010 0011一共 11bit。ID 越小在总线竞争中抢占能力越强。3.2.3 控制段6 bitIDE 位标识符扩展位。标准帧 IDE0扩展帧 IDE1。用来区分当前是标准帧还是扩展帧。r0保留位硬件置 0。DLC4 位数据长度码取值范围0~8。代表后面数据段有多少字节。重点CAN2.0 数据段最大只能 8 字节DLC 写 9‑15 属于非法硬件不支持。3.2.4 数据段0‑8 字节业务有效载荷DLC 规定多少字节就传输多少字节。 DLC 可以等于 0也就是不带任何数据的数据帧工程上可以用来做心跳包。示例DLC3数据为0x11 0x22 0x33那么这一帧携带 3 个字节业务数据。3.2.5 CRC 校验段16bit包含 15 位 CRC 校验值 1 位 CRC 界定符隐性 1。 发送端根据 SOF 到数据段所有 bit 计算 CRC接收端本地重新计算 CRC 对比。不一致则判定报文损坏触发错误处理。CRC 全部硬件运算软件不需要手动计算。3.2.6 ACK 应答段2bitACK 槽1 位。发送节点输出隐性 1如果有至少一个节点正确收到本帧接收节点会把 ACK 槽拉为显性 0。ACK 界定符隐性 1。非常重要故障点如果发送完成 ACK 槽仍然保持隐性 1代表没有任何节点接收到该报文产生 ACK 错误。常见原因对方设备没上电、CAN_H CAN_L 接反、波特率不一致。3.2.7 EOF 帧结束7 bit全部隐性 17 个连续隐性位标志本帧传输结束。之后总线回到空闲状态允许其它节点发送报文。3.3 扩展数据帧简要讲解CAN2.0B29bit ID扩展帧仲裁段变长基础 ID 11bit SRR 位 IDE 位 扩展 ID 18bit RTR 位总 ID 29 位。IDE 位此时为 1用来告诉控制器这是扩展帧。扩展帧 ID 空间极大适合大量传感器设备。工程注意抓包工具看到 StdId 和 ExtId不要混淆STM32 HAL 库中IDE CAN_ID_STD代表标准帧IDE CAN_ID_EXT代表扩展帧。3.4 远程帧 RTR 详解远程帧用来请求其他节点上报数据没有数据段DLC 可以为 0。RTR 位置 1数据段不存在。 举例节点 A 发送远程帧 ID0x200RTR1总线上 ID0x200 对应的节点 B 收到远程请求回复一条 ID0x200 的数据帧携带业务数据。现实项目中远程帧使用较少绝大多数项目直接使用定时主动上报数据帧。很多新设备厂商甚至不实现远程帧响应逻辑。远程帧常见坑写代码时误把 RTR 置 1明明想发数据帧结果发出远程帧接收端收不到有效数据调试很久找不到原因。3.5 错误帧、过载帧错误帧当任意节点检测 CRC 错误、位错误、填充错误、格式错误立刻发送错误帧。 错误帧由 6 个显性错误标志 错误界定符组成。全网节点收到错误帧知道当前报文传输出错发送方会硬件自动重发报文。节点内部维护两个计数器发送错误计数器 TEC、接收错误计数器 REC。TEC/REC 0‑99正常工作100‑127错误警告128‑255错误主动大于 255进入 Bus‑Off 总线离线状态断开总线不再参与通讯必须软件恢复。BusOff 就是第二章代码检测的总线离线是 CAN 调试高频故障。过载帧接收控制器内部缓冲区满来不及接收新报文发出过载帧通知发送设备暂缓发送。硬件自动处理软件不用干预。3.6 真实报文实例拆解标准帧抓包工具拿到报文ID:0x100 STDDLC4DATA:0x01 0x02 0x03 0x04逐段解析SOF显性 0帧起始。仲裁段ID0x100二进制0001 0000 0000RTR0 → 数据帧。控制段IDE0标准帧DLC4代表 4 字节数据。数据段0x01,0x02,0x03,0x04。CRC硬件自动计算校验。ACK 槽接收设备拉低应答。EOF7 位隐性帧结束。业务含义举例ID0x100 定义为电机状态报文字节 0 电机状态、字节 1 转速高 8 位、字节 2 转速低 8 位、字节 3 故障码。3.7 CAN 报文解析示例代码HAL 库接收回调STM32 HAL 库 CAN 接收中断回调把收到原始报文拆解打印方便对接 CAN 抓包日志。#include can.h #include stdio.h /** * brief CAN接收回调函数中断中触发 */ void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) { CAN_RxHeaderTypeDef rx_header; uint8_t rx_data[8] {0}; if(HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, rx_header, rx_data) ! HAL_OK) { return; } // 判断标准帧/扩展帧 if(rx_header.IDE CAN_ID_STD) { printf([CAN RX STD] ID:0x%03X , rx_header.StdId); } else if(rx_header.IDE CAN_ID_EXT) { printf([CAN RX EXT] ID:0x%08X , rx_header.ExtId); } // 判断远程帧还是数据帧 if(rx_header.RTR CAN_RTR_REMOTE) { printf(Remote Frame DLC:%d\r\n,rx_header.DLC); } else { printf(Data Frame DLC:%d Data:,rx_header.DLC); for(uint8_t i 0; i rx_header.DLC; i) { printf(0x%02X , rx_data[i]); } printf(\r\n); } }打印输出示例[CAN RX STD] ID:0x100 Data Frame DLC:4 Data:0x01 0x02 0x03 0x04开发提示中断回调函数中不要做复杂业务运算只做报文拷贝解析逻辑放到主循环处理避免中断阻塞。拓展远程帧发送示例代码片段uint8_t CAN_Send_RemoteFrame(uint16_t std_id) { CAN_TxHeaderTypeDef tx_header; uint32_t tx_mailbox; tx_header.StdId std_id; tx_header.IDE CAN_ID_STD; tx_header.RTR CAN_RTR_REMOTE; // RTR置1远程帧 tx_header.DLC 0; tx_header.TransmitGlobalTime DISABLE; //远程帧无数据缓冲区 if(HAL_CAN_AddTxMessage(hcan, tx_header, NULL, tx_mailbox) HAL_OK) { return 0; } return 1; }3.8 本章工程易错点汇总DLC 最大为 8超过 8 字节不能直接发送需要自己做分包。CAN2.0 本身不支持大于 8 字节单帧传输。RTR 位写反想发数据帧却设置远程帧对方收不到数据。IDE 设置错误发送扩展帧却配置 CAN_ID_STDID 错乱。ACK 错误发送成功但是没有应答优先排查硬件不是协议问题。Bus‑OffTEC/REC 计数器溢出硬件故障居多需要软件主动恢复总线。第三章到此结束。
返回列表