ARTICLE DETAIL

资讯详情

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

第二章:CAN 总线硬件底层原理

第二章:CAN 总线硬件底层原理 导读实际项目调试中90% 的 CAN 通讯故障来源于硬件问题仅有小部分是代码配置错误。很多开发者直接上手写收发代码忽略硬件基础遇到通讯无响应、高速丢包、波形异常、总线离线等问题无从下手。本章完整讲解 CAN 三层硬件架构、差分电平原理、终端电阻的作用与坑点并提供可直接移植的硬件故障检测代码。2.1 CAN 总线三层硬件架构一套可以稳定运行的 CAN 通讯系统分为三层MCU‑CAN 控制器层、CAN 收发器层、CAN 总线传输线缆层三层缺一不可。2.1.1 MCU 内置 CAN 控制器协议逻辑层STM32、GD32、HC32 等工业 MCU 内部集成硬件 CAN 控制器不需要外接协议芯片。CAN 控制器负责协议层面全部逻辑工作由硬件自动完成CPU 只需要读写寄存器自动组装帧起始、仲裁段、DLC、CRC、应答位等帧结构硬件完成总线仲裁多节点同时发包时自动优先级竞争CRC 校验、错误统计、错误帧处理、报文自动重发提供发送邮箱、接收 FIFO 缓冲区存放报文。注意MCU 输出的是 3.3V 单端逻辑信号CAN_TX、CAN_RX 引脚驱动能力弱不能直接长距离走线必须外接 CAN 收发器芯片。工程实例STM32F103 的 CAN1对应引脚 PA11 (CAN_RX)、PA12 (CAN_TX)。MCU 的 CAN_TX 输出逻辑电平给到收发器收发器把差分信号送到总线上总线回来的差分信号经过收发器转换为单端信号送到 MCU 的 CAN_RX。2.1.2 CAN 收发器芯片电平转换层常见型号TJA1050、TJA1042、SN65HVD230。 收发器是 MCU 和总线之间的桥梁两大核心作用电平转换把 MCU 单端逻辑信号转换成 CAN_H / CAN_L 差分总线电平反过来把总线上差分信号转换成 MCU 识别的单端 RX 信号。总线驱动与保护提高总线驱动能力具备过压保护防止总线上高压浪涌击穿单片机 IO。典型接线关系收发器 TX 引脚 → MCU CAN_TX收发器 RX 引脚 → MCU CAN_RX收发器 CAN_H、CAN_L 引出到总线双绞线VCC 接 5VTJA1050或者 3.3VSN65HVD230实操坑点收发器电源不稳会出现偶发丢包收发器待机模式STB 引脚拉高芯片进入睡眠会完全无法收发报文很多新手踩这个坑。2.1.3 CAN 总线传输线缆层CAN 总线信号必须使用屏蔽双绞线两根线命名 CAN_H 和 CAN_L。双绞线互相缠绕可以抵消外界共模电磁干扰屏蔽层建议单点接地不要两端同时接地避免地环路引入干扰。禁止直接使用普通杜邦线平行走线做长距离 CAN 通讯。平行导线没有抵消干扰能力在 500K/1M 高速波特率下极易乱码、丢包。2.2 CAN 差分电平原理CAN 总线不看单根导线对地电压而是看 CAN_H 和 CAN_L 之间的电压差值分为隐性电平逻辑 1和显性电平逻辑 0。这是抗干扰和硬件仲裁的物理基础。2.2.1 隐性电平逻辑 1总线空闲总线空闲时收发器内部电路将 CAN_H、CAN_L 钳位在约 2.5V。CAN_H ≈ 2.5VCAN_L ≈ 2.5V差值 CAN_H - CAN_L ≈ 0V 代表逻辑 1总线处于空闲状态。隐性电平有一个关键特性只要任意一个节点输出显性电平总线就会被强制覆盖为显性电平。2.2.2 显性电平逻辑 0总线占用当节点发送逻辑 0 时收发器驱动CAN_H ≈ 3.5VCAN_L ≈ 1.5V差值 CAN_H - CAN_L ≈ 2V代表逻辑 0显性电平优先级高于隐性电平这就是 CAN 硬件仲裁的物理根源。2.2.3 硬件仲裁完整实例场景两个节点 A (ID0x200优先级低)、节点 B (ID0x100优先级高) 同时检测总线空闲同时启动发送报文。总线初始状态隐性电平空闲两个节点同时发送 SOF 帧起始位显性 0总线被拉到显性无冲突开始发送 ID 最高位节点 A 发出逻辑 1隐性节点 B 发出逻辑 0显性总线物理上变成显性电平。节点 A 一边发送一边监听总线电平发现自己发的是 1但总线实际是 0节点 A 立刻停止发送退出竞争等待总线下一次空闲节点 B 不受影响继续完整发送自己的报文。整个仲裁全部硬件自动完成微秒级软件完全不需要干预。面试考点为什么 CAN 可以实现无冲突通讯本质就是显性电平可以覆盖隐性电平发送方边发边回读总线电平进行比对。2.3 终端电阻深度解析2.3.1 终端电阻原理高频数字信号在线缆传输末端如果阻抗不匹配信号会发生信号反射。反射波叠加原始波形波形变形、抖动接收端识别出错出现乱码丢包。CAN 总线双绞线标称阻抗 120Ω因此需要在总线物理两端并联 120Ω 电阻实现阻抗匹配吸收反射信号还原干净波形。2.3.2 终端电阻硬性规则阻值固定为 120Ω不要随意用 100Ω、150Ω 替代只允许接在整条总线物理最两端设备的 CAN_H 和 CAN_L 之间总线中间挂载的设备禁止焊接 120Ω 终端电阻一条 CAN 总线最多只能有两个 120Ω 终端电阻。断电测量总线 CAN_H、CAN_L 之间电阻两端都接 120Ω 时并联后测量值约 60Ω这是判断电阻是否正确的简易手段。2.3.3 多场景案例场景 1点对点两个设备通讯。两个设备分别是总线两端各焊 120Ω 电阻测得总线约 60Ω通讯稳定。 场景 2多节点组网一共 5 个节点。1 号节点和 5 号节点在总线首尾接 120Ω2、3、4 中间节点不接。 场景 3临时调试只有两个设备手头只有一个 120Ω 电阻接任意一端也可以短暂通讯但是高速波特率抗干扰能力下降。2.3.4 典型故障现象故障现象125K 低速波特率通讯正常切换 500K、1M 波特率大量丢包、偶发通讯失败。 故障根因缺少终端电阻低速下信号反射影响小高速时波形畸变严重。 解决方案总线两端补上 120Ω 电阻。拓展坑接了三个或者四个 120Ω 电阻总线等效电阻过小收发器负载过重同样通讯异常。2.4 CAN 硬件状态检测完整代码STM32 HAL 库下面代码可以直接放进工程用于调试阶段实时获取总线错误状态快速定位硬件故障。#include can.h #include stdio.h //总线状态 0正常 1总线离线BusOff 2应答错误 3信号/时序错误 uint8_t g_can_bus_state 0; /** * brief CAN硬件故障检测循环调用 */ void CAN_Hardware_Detect(void) { uint32_t err_code HAL_CAN_GetError(hcan); HAL_CAN_ClearError(hcan); if(err_code HAL_CAN_ERROR_NONE) { g_can_bus_state 0; return; } if(err_code HAL_CAN_ERROR_BUSOFF) { g_can_bus_state 1; printf([CAN ERR] BusOff总线离线检查120Ω电阻、CAN_H/L接线、收发器供电\r\n); } else if(err_code HAL_CAN_ERROR_ACK) { g_can_bus_state 2; printf([CAN ERR] ACK应答错误总线上没有接收节点在线\r\n); } else if((err_code HAL_CAN_ERROR_BIT) || (err_code HAL_CAN_ERROR_TIMEOUT)) { g_can_bus_state 3; printf([CAN ERR]信号异常检查波特率匹配、线路接触、电磁干扰\r\n); } } /** * brief 判断CAN发送邮箱是否空闲 * retval 1空闲0繁忙 */ uint8_t CAN_Check_Bus_Idle(void) { if((hcan.State HAL_CAN_STATE_READY) (HAL_CAN_GetTxMailboxesFreeLevel(hcan) 0)) { return 1; } return 0; } /** * brief 安全发送封装发送前检测总线状态 * param id 标准ID * param buf 数据缓存 * param len 长度0~8 * retval 0成功1总线繁忙2总线异常 */ uint8_t CAN_Send_Safe(uint16_t id, uint8_t *buf, uint8_t len) { if(g_can_bus_state ! 0) { return 2; } if(!CAN_Check_Bus_Idle()) { return 1; } CAN_TxHeaderTypeDef tx_header; uint32_t tx_mailbox; tx_header.IDE CAN_ID_STD; tx_header.StdId id; tx_header.RTR CAN_RTR_DATA; tx_header.DLC len; tx_header.TransmitGlobalTime DISABLE; if(HAL_CAN_AddTxMessage(hcan, tx_header, buf, tx_mailbox) HAL_OK) { return 0; } return 1; }使用说明主循环周期调用CAN_Hardware_Detect()业务发送优先调用CAN_Send_Safe()避免总线异常状态下反复调用底层发送函数加重报错出现 BusOff 时硬件上优先排查接线、终端电阻、收发器供电。第二章到此结束。
返回列表