CAN&诊断
| 通信矩阵设计 | 定义哪些信号走 CAN、周期、初始值 |
| DBC 文件编写 | CAN 数据库文件,定义报文/信号的物理值换算 |
| 接口规格书 | 底盘 ECU ↔ VCU/MCU/BMS 的接口定义 |
| CAN 故障处理策略 | 通信丢失/超时/错误时的安全动作 |
| CAN 工具链 | CANoe / PCAN / 周立功 的使用 |
| EMC 相关 | CAN 走线、终端电阻、共模干扰 |
1. CAN 协议基础(帧结构 + 仲裁 + 错误处理)
| 数据帧 | 携带数据(最常用) |
| 远程帧 | 请求别的节点发数据 |
| 错误帧 | 通知总线上出了错 |
| 过载帧 | 请求延迟发送(接收方还没准备好) |
| 帧间空间 | 帧与帧之间的间隔 |
身份—类型—大小—内容—校验—确认—结束
| SOF | 1 bit | “喂?” | 告诉所有人:我要开始说了 |
| ID | 11 bit | “我是谁” | 报文身份标识(0x100~0x7FF) |
| RTR | 1 bit | “要东西还是给东西” | 0=数据帧,1=远程帧(请求别人发数据) |
| IDE | 1 bit | “我说的是标准语还是扩展语” | 0=标准帧,1=扩展帧 |
| r0 | 1 bit | 保留 | 留给你以后扩展用 |
| DLC | 4 bit | “我带了几个字” | 数据长度 0~8(字节) |
| Data | 0~64 bit | “具体内容” | 最多 8 字节的有效载荷 |
| CRC | 15+1 bit | “你验一下对不对” | 校验码 + 分隔符 |
| ACK | 1+1 bit | “听到了就说一声” | 接收方确认 + 分隔符 |
| EOF | 7 bit | “说完了” | 帧结束标志 |
CSMA/CA(载波监听多路访问/碰撞避免)
💡
发送前先听总线(载波监听)
├── 总线空闲 → 可以发
├── 总线忙 → 等当前帧结束
└── 总线空闲 → 多个节点同时发 → 进入仲裁
优先级高(ID 小):
0x100 — 转向扭矩指令(10ms 周期) ← 安全关键
0x101 — 车速信号(10ms 周期) ← 安全关键
0x110 — 电机状态(20ms 周期) ← 功能重要
优先级中(ID 中):
0x200 — 电池状态(100ms 周期) ← 功能重要
0x210 — 仪表显示刷新(100ms 周期) ← 舒适相关
优先级低(ID 大):
0x300 — 诊断响应(事件触发) ← 售后
0x3F0 — OTA 数据块(事件触发) ← 维护
3.错误处理
| 位错误(Bit Error) | 发送方自己 | 发出去的位 ≠ 回读到的位 | 错误帧 |
| 填充错误(Stuff Error) | 接收方 | 连续 6 个相同极性位(违反了 5 位填充规则) | 错误帧 |
| CRC 错误(CRC Error) | 接收方 | 收到的 CRC ≠ 自己算的 CRC | 错误帧 |
| 格式错误(Form Error) | 接收方 | 固定隐性位区域出现了显性位(如 EOF/ACK Delimiter 区域) | 错误帧 |
| ACK 错误(ACK Error) | 发送方 | 发完数据后没有节点给 ACK | 错误帧 |
总共 14~20 bit,比数据帧短得多——错误帧的目的不是传数据,而是喊一嗓子"出事了"。
💡
| 错误标志(Error Flag) | 错误分隔符(Error Delimiter) |
| 6~12 bit | 8 bit |
| 显性 或 隐性(取决于状态) | 全部隐性(11111111) |
两种错误标志
显性错误标志(Active Error Flag)
发出信号:6 个连续的显性位(000000)
效果: 强行打断总线上的任何传输
隐性错误标志(Passive Error Flag)
发出信号:6 个连续的隐性位(111111)
效果: 不打断总线,只默默记录
错误叠加机制(Error Cascade)
- 每个 Error Active 节点发 6 个显性位
- 多个节点的显性位叠加 → 总线上看到的显性位更长
- 上限 12 bit(硬件设计保证)
- 超过 6 bit 后,硬件自动开始递减 → 到达某个时刻所有节点同时停止发送
- 然后进入错误分隔符(8 个隐性位)
错误帧的发送时机
| 位错误 | 发送方 | 发完出错位的那个 bit time 之后立刻发 |
| 填充错误 | 检测到违规的接收方 | 第 6 个相同位出现时立刻发 |
| CRC 错误 | 接收方 | CRC 分隔符结束后发 |
| 格式错误 | 检测到违规的接收方 | 违规 bit 出现时立刻发 |
| ACK 错误 | 发送方 | ACK 分隔符结束后发 |
位错误 / 格式错误 → 在出错位的那个 bit time 内发出错误标志
(当前帧被直接破坏,需要重发)
CRC 错误 / ACK 错误 → 在帧尾才发出错误标志
(当前帧已经传完了,只是接收方告诉发送方"你传的有问题")
错误帧触发后的完整流程
步骤1:节点 A 发完数据帧(含 CRC)
步骤2:节点 B 收到数据帧,自己算 CRC ≠ 收到的 CRC
步骤3:CRC 分隔符结束 → 节点 B 开始发显性错误标志(6 个 0)
步骤4:其他节点如果也检测到错误 → 叠加
步骤5:错误标志结束 → 进入错误分隔符(8 个隐性位 11111111)
步骤6:所有节点在分隔符期间同步 → TEC/REC 各自更新
步骤7:IFS(帧间空间 3 bit)→ 总线空闲
步骤8:节点 A 发现 ACK 失败 / 自己的错误计数器增加
步骤9:节点 A 重发数据帧(TEC += 8)
步骤10:如果节点 B 的 REC 超过阈值 → 可能进入 Error Passive
和FailSafe的关联
FLT_CAN_INP 检知逻辑,对应的就是错误帧机制的上层应用
物理层/数据链路层(CAN 协议本身):
位错误 / CRC 错误 → 错误帧 → 自动重发
应用层(EPS 软件):
连续 N 帧没收到 → 超时检知 → FLT_CAN_INP
Counter 不递增 → 丢帧检知 → FLT_CAN_INP
Signal 值越界 → 合理性检知 → FLT_BAS_FUN / FLT_INTG
💡
为什么6个连续隐性位不会打断
线与(Wired-AND)机制:只要有一个节点在驱动显性位(0),总线上就是 0
假设节点 X 有间歇性故障,它频繁犯错,一个快死的节点会拖垮整个网络;节点 X 持续犯错 → TEC 增加 → 进入 Error Passive,相当于一个坏节点被逐步隔离,不影响健康节点
TEC = Transmit Error Counter,发送错误计数器
发送错误 +8:你说的话别人听不懂 → 问题大概率在你 → 重罚
接收错误 +1:你听别人说话听不懂 → 可能是别人问题 → 轻罚
偶发干扰(EMC) → TEC 偶尔 +8,然后 -1 减回来 → 没事
2. CAN 信号打包/DBC 文件的实际写法
一、信号打包(Signal Packing)
CAN 一帧最多 8 字节 = 64 bit。
信号打包:把多个信号塞进这 64 个 bit 里。
信号要素
| 起始位(Start Bit) | 信号在 64 bit 中的起始位置 | Byte 0, Bit 0 → start_bit = 0 |
| 长度(Length) | 信号占几个 bit | 12 bit |
| 字节序(Byte Order) | Motorola(大端)还是 Intel(小端) | Intel = 低位在前 |
小端 = 小头先走(低字节放低地址)反着写电话号码
大端 = 大头先走(高字节放低地址)写电话号码
0x1234 用 CAN 发出去
小端(Intel):先发 0x34,再发 0x12
大端(Motorola):先发 0x12,再发 0x34
信号在 CAN 里传的是原始值(Raw Value),接收方需要换算成物理值(Physical Value)
二、DBC 文件实际写法
| 起始位 | 信号在 64 bit 中的起始 bit 位置 | 0~63 |
| 长度 | 信号占几个 bit | 1~64 |
| @字节序 | 1=Intel(小端),0=Motorola(大端) | 0 或 1 |
| 符号 | +=无符号,-=有符号 | + 或 – |
| Factor | 缩放因子 | 浮点数 |
| Offset | 偏移量 | 浮点数 |
| 最小值 | 物理值范围下限 | 浮点数 |
| 最大值 | 物理值范围上限 | 浮点数 |
| 单位 | 物理单位 | 字符串 |
| 接收节点 | 哪些节点接收这个信号 | 逗号分隔 |
3. 两轮电动车常见的 CAN 拓扑(VCU-MCU-BMS-仪表)
关键报文:
VCU → 底盘ECU:车速、档位、骑行模式、制动状态
底盘ECU → VCU:转向状态、故障码、助力状态
底盘ECU → MCU:(可能不直接通信,通过 VCU 转发)
BMS → VCU:SOC、电压、温度、充放电限制
MCU → VCU:电机转速、扭矩、温度、故障码
4. 二轮诊断框架
- 车载诊断(OBD) :DTC读写,冻结帧,实时数据流
- 离线诊断(售后):诊断仪连接,EOL 产线检测,维修后清除
- 远程诊断(OTA/云端):远程读取诊断码,固件升级,参数标定
诊断服务
| DiagSessionControl | 0x10 | 切换诊断会话(默认/扩展/编程) | 产线刷写、维修诊断 | |
| ReadDTCInformation | 0x19 | 读取故障码 + 状态 | 仪表显示"系统故障"、售后维修 | |
| ReadDataByIdentifier | 0x22 | 读取实时数据(PID) | 仪表显示 SOC/车速/电机温度 | |
| WriteDataByIdentifier | 0x2E | 写入参数/配置 | 售后标定、 VIN 写入 |
| ECUReset | 0x11 | 重启 ECU | 软复位排障、OTA 后重启 |
| SecurityAccess | 0x27 | 安全访问(种子/密钥) | 保护刷写和标定权限 |
| CommunicationControl | 0x28 | 控制 CAN 通信开关 | 刷写时暂停正常通信 |
| RoutineControl | 0x31 | 执行例程(如自检) | 产线 EOL 测试、电机学习 |
| ClearDTCInformation | 0x14 | 清除故障码 | 维修后清除历史故障 |
| RequestDownload | 0x34 | 请求下载(接收固件) | OTA 固件更新 |
| TransferData | 0x36 | 传输数据块 | 分块传输固件文件 |
| RequestTransferExit | 0x37 | 传输结束 | 固件接收完毕 |
| RequestUpload | 0x35 | 请求上传(导出数据) | 远程提取日志 |
![[LangChain] 学习笔记(02):LCEL 链式调用与动态模型配置实战-171主机测评](https://www.171host.com/wp-content/uploads/2026/10/20261030203301-6ae4fefdb54f3-220x150.png)

![[LangChain] 学习笔记(02):LCEL 链式调用与动态模型配置实战-171主机测评](https://www.171host.com/wp-content/uploads/2026/10/20261030202745-6ae4fdc1556bf-220x150.png)


