# STM_UDS **Repository Path**: minerals/stm_-uds ## Basic Information - **Project Name**: STM_UDS - **Description**: 在stm32f407vet6上实现uds服务,自动记录故障,生成故障码快照信息 - **Primary Language**: Unknown - **License**: GPL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2026-09-20 - **Last Updated**: 2026-10-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # STM_UDS #### 介绍 基于 **STM32F407VET6** 实现的 **UDS 诊断协议栈**,让一块开发板扮演一台真实的车用 ECU:诊断仪通过 USB-CAN 接上总线,即可按国际标准对它进行「切会话 / 读车架号 / 读故障码 / 写配置 / 复位」等在线问答。 无需真实车辆,完全可控、可复现。 - 协议:**ISO 14229(UDS)** + **ISO 15765-2(CAN TP)** + **ISO 15031-6(DTC 格式)** - 架构:参考 **AUTOSAR** 分层思想(MCAL / CanIf / CanTp / DCM)组织代码 - 已实现 **8 个诊断服务**:0x10、0x11、0x14、0x19、0x22、0x27、0x2E、0x3E - 支持诊断会话管理、安全访问(种子/密钥 + 失败锁定)、DTC 读取与故障码快照 - 已用 USB-CAN 分析仪(CANable)+ Cangaroo 完成单帧、多帧、否定响应全流程抓帧验证 **硬件与参数** | 项目 | 说明 | |------|------| | MCU | STM32F407VET6(Cortex-M4F @168MHz,512KB Flash) | | CAN 收发器 | TJA1050 / SN65HVD230 | | CAN 接口 | CAN1(PA11=RX,PA12=TX),**125 kbps**,Prescaler=56 / BS1=3 / BS2=2 / SJW=2 | | 调试串口 | USART1(PA9=TX,PA10=RX,115200-8N1) | | USB-CAN 工具 | CANable 2.0(SLCAN 协议) | | 报文 ID | 物理寻址 0x7E0 → 0x7E8;功能寻址 0x7DF | | 开发环境 | STM32CubeMX 6.18 + Keil MDK-ARM(ARMCC) | | RTOS | FreeRTOS V10.3.1(CMSIS-RTOS V2 封装) | #### 软件架构 **分层结构** ``` ┌───────────────────────────────────────────────────────────────────────┐ │ 应用层 My_Application/ │ │ DID 表(VIN/硬件版本/可写配置) · 会话状态 · 安全等级 · DTC 表与快照 │ ├───────────────────────────────────────────────────────────────────────┤ │ UDS 层 uds_service.c + UDSLogic/SIDxx_*.c │ │ 配置表驱动的服务分发引擎(会话/安全/长度校验 + NRC)· 8 个服务实现 │ ├───────────────────────────────────────────────────────────────────────┤ │ TP 层 My_Transport/can_tp.c │ │ ISO 15765-2:单帧/首帧/连续帧/流控帧 · 多帧拆包组包 · 4095B 缓冲 │ ├───────────────────────────────────────────────────────────────────────┤ │ 驱动层 My_Drivers/drv_can.c · drv_timer.c │ │ CAN 中断 + FreeRTOS 队列 · ID 验收滤波 · 统一软件定时器管理 │ ├───────────────────────────────────────────────────────────────────────┤ │ 基础层 Core/(CubeMX + HAL)· Middlewares/(FreeRTOS) │ │ MCAL 外设驱动 · 任务调度 · 时基(TIM6 给 HAL,SysTick 给 FreeRTOS) │ └───────────────────────────────────────────────────────────────────────┘ ``` **模块职责与 AUTOSAR 对应关系** | 目录 / 模块 | 职责 | AUTOSAR 对应层 | |---|---|---| | `Core/` | 外设初始化、时钟、中断向量(CubeMX 生成,用户代码隔离) | MCAL | | `My_Drivers/drv_can.c` | CAN 收发、32 位 ID 列表滤波(0x7E0/0x7DF)、中断→队列分发 | CanDrv + CanIf | | `My_Transport/can_tp.c` | ISO 15765-2 拆包组包、流控、序号校验 | **CanTp** | | `My_Application/uds_service.c` | 服务分发引擎:查表 → 会话 → 长度 → 安全 → 调用 handler | **DCM** | | `My_Application/UDSLogic/SIDxx_*.c` | 每个服务一个文件,含 `check_len()` 与 `service_xxx()` | DCM 服务实现 | | `My_Application/Src/service_cfg.c` | 服务配置表(函数指针表),新增服务只需加一行 | DCM 配置 | | `My_Application/Src/DID_Table.c` | DID 数据源(0xF190 / 0xF180 / 0xF1C0) | SWC / 应用层 | | `My_Drivers/drv_timer.c` | 统一超时管理(N_As…N_Cr、P2/P2\*/S3/S2 共 10 个实例) | OS / BswM 计时 | **目录结构** ``` STM_UDS/ ├── Core/ CubeMX 生成:main.c / can.c / usart.c / freertos.c / it.c ├── My_Drivers/ 用户驱动层 │ ├── Inc/ drv_can.h drv_timer.h │ └── Src/ drv_can.c drv_timer.c ├── My_Transport/ ISO 15765-2 传输层 │ ├── Inc/ can_tp.h │ └── Src/ can_tp.c ├── My_Application/ UDS 应用层 │ ├── Inc/ uds.h uds_service.h DID_Table.h service_cfg.h │ ├── Src/ uds_service.c DID_Table.c service_cfg.c │ └── UDSLogic/ SID10 / SID11 / SID14 / SID19 / SID22 / SID27 / SID2E / SID3E ├── Drivers/ STM32F4xx HAL 库 ├── Middlewares/ FreeRTOS 源码 ├── MDK-ARM/ Keil 工程(Fake_CarECU.uvprojx) ├── Fake_CarECU.ioc CubeMX 工程文件 ├── Fake_CarECU_PROJECT_DOC.md 详细设计文档(协议知识 + 模块详解) └── Fake_CarECU_测试流程_导师版.md 可复现测试流程(面向非专业评审) ``` **数据流** ``` 接收:CAN 总线 → drv_can(中断取帧 + 入队)→ CAN_Rx_Task(阻塞消费) → can_tp(SF 直取 / FF+CF 组包)→ UDS_Process(查表 + 校验) → SIDxx handler(读 DID 表 / 改会话 / 查 DTC)→ uds_positive_rsp / uds_negative_rsp 发送:响应报文 → can_tp(≤7B 走单帧;>7B 发 FF → 等 FC → 连续发 CF) → drv_can → CAN 总线 ``` #### 安装教程 **1. 硬件准备** | 物品 | 说明 | |------|------| | STM32F407VET6 开发板 | 核心板或最小系统板均可 | | CAN 收发器 | TJA1050 / SN65HVD230(板载则跳过) | | USB-CAN 分析仪 | CANable 2.0 或周立功等支持 SLCAN 的工具 | | USB-UART 模块 | CH340 / CP2102,用于串口调试输出 | | 120Ω 终端电阻 | 总线两端各一个(CANable 侧可用拨码开关) | **2. 接线(关键:必须共地)** ``` STM32 板 CANable 2.0 ┌─────────┐ ┌──────────┐ │ CAN_H ├──────────┤ CAN_H │ │ CAN_L ├──────────┤ CAN_L │ │ GND ├──────────┤ GND │ ← 不共地会完全不通! │ PA9/PA10├──────────┤ USB → PC │ └─────────┘ └──────────┘ 120Ω 拨码开关:ON ``` **3. 编译与下载** 1. 安装 Keil MDK-ARM 5.x,并确保已安装 `STM32F4xx_DFP` 器件支持包; 2. 打开 `MDK-ARM/Fake_CarECU.uvprojx`; 3. **Rebuild All**(不要只增量编译——曾因旧 obj 导致 HAL 时基未生效而卡死); 4. 编译下载到开发板,复位运行。 > 如需修改波特率/时钟等外设配置,用 STM32CubeMX 打开 `Fake_CarECU.ioc` 重新生成; > 用户代码全部隔离在 `My_*` 目录中,重新生成不会丢失。 #### 使用说明 **1. 上电检查** - LED 闪烁表示系统运行;USART1(115200-8N1)会输出 CAN TP 多帧发送完成等调试信息。 - 会话状态可用 LED 指示:默认会话 / 扩展会话 / 编程会话 闪烁频率不同。 **2. Cangaroo 配置** | 参数 | 值 | |------|-----| | Interface | CANable 对应的 COM 口(如 COM5) | | Bitrate | 125000 | | Listen only | **不勾**(需要 CANable 发 ACK) | | One-Shot | 不勾 | | Auto-Restart on bus off | 建议勾 | 操作:`Measurement → Start Measurement`,在 Transmit View 填 ID 与数据后 Send。 **每次拔插/复位硬件后需 Stop → Start 重新初始化。** **3. 常用测试帧(请求 → 期望响应)** | 用途 | 请求 ID | 请求数据 | 期望响应(0x7E8) | |------|---------|----------|------------------| | 进扩展会话 | 0x7E0 | `02 10 03 00 00 00 00 00` | `06 50 03 00 32 01 F4` | | 进编程会话 | 0x7E0 | `02 10 02 00 00 00 00 00` | `06 50 02 00 32 01 F4`(需先处于扩展会话,否则回 `7F 10 33`) | | 回默认会话 | 0x7E0 | `02 10 01 00 00 00 00 00` | `06 50 01 00 32 01 F4` | | 保持在线 | 0x7E0 | `02 3E 00 00 00 00 00 00` | `02 7E 00 00 00 00 00 00` | | 保持在线(抑制响应) | 0x7E0 | `02 3E 80 00 00 00 00 00` | 无响应(仅刷新 S3 定时器) | | 读 VIN | 0x7E0 | `03 22 F1 90 00 00 00 00` | 多帧:FF→FC→CF,共 20 字节 `62 F1 90` + 17B VIN | | 读硬件版本 | 0x7E0 | `03 22 F1 80 00 00 00 00` | 多帧:`62 F1 80` + `HW_1.0` | | 不存在的 DID | 0x7E0 | `03 22 12 34 00 00 00 00` | `03 7F 22 31` | | 安全访问-请求种子 | 0x7E0 | `02 27 01 00 00 00 00 00` | `06 67 01 11 22 33 44` | | 安全访问-发密钥 | 0x7E0 | `06 27 02 44 77 66 11 00` | `02 67 02`(密钥 = 种子 XOR 0x55) | | 写可写 DID(未解锁) | 0x7E0 | `07 2E F1 C0 01 02 03 04` | `03 7F 2E 33`(securityAccessDenied) | | 写可写 DID(已解锁) | 0x7E0 | `07 2E F1 C0 01 02 03 04` | `03 6E F1 C0` | | 读 DTC 数量 | 0x7E0 | `03 19 01 FF 00 00 00 00` | `06 59 01 FF 00 00 03`(共 3 个) | | 读 DTC 列表 | 0x7E0 | `03 19 02 FF 00 00 00 00` | 多帧 `59 02 FF` + 3×(DTC 3B + 状态 1B) | | 读 DTC 快照 | 0x7E0 | `06 19 04 05 56 01 01 00` | `59 04` + DTC + 状态 + 快照项(0xF120 转速 / 0xF121 车速 / 0xF122 电压) | | 清除全部 DTC | 0x7E0 | `04 14 FF FF FF 00 00 00` | `01 54` | | ECU 硬复位 | 0x7E0 | `02 11 01 00 00 00 00 00` | `02 51 01` 后复位重启 | | 不支持的服务 | 0x7E0 | `01 FF 00 00 00 00 00 00` | `03 7F FF 11` | > 注 1:请求帧首字节是 ISO 15765-2 的 PCI(低 4 位为 UDS 报文长度),不是 UDS 数据本身。 > 注 2:0x11 / 0x14 / 0x2E 需要先通过 0x27 解锁(安全等级 Level 1)。 > 注 3:DTC 示例为 P0562(电压过低)、B1000(车身 ECU)、U0100(通信丢失)。 **4. 多帧交互示例(读 VIN)** ``` 诊断仪 (0x7E0) ECU (0x7E8) │ 03 22 F1 90 ────────────────→ │ 单帧请求 │ │ │ ←──── 10 14 62 F1 90 ... │ 首帧 FF:总长 0x014 = 20 字节 │ 30 00 00 ... ────────────────→ │ 流控帧 FC:FS=0 继续,BS=0,STmin=0 │ ←──── 21 ... │ 连续帧 CF,SN=1 │ ←──── 22 ... │ 连续帧 CF,SN=2 │ ←──── 23 ... │ 连续帧 CF,SN=3(结束) ``` **5. 通信不通时的排查顺序** 1. CANable 与 STM32 **是否共地**(最容易漏,症状是 CAN_H/L 电压正常但完全不通); 2. CAN_H 接 CAN_H、CAN_L 接 CAN_L 是否接反; 3. 总线两端是否各有 1 个 120Ω 终端电阻; 4. 波特率是否都是 125 kbps,采样点是否接近(建议统一 87.5%); 5. Cangaroo 是否已 Stop → Start(每次硬件变动后都要)。 #### 参与贡献 1. Fork 本仓库 2. 新建 `Feat_xxx` 分支 3. 提交代码 4. 新建 Pull Request **代码约定** - 分层原则:每层只调用下一层接口,跨层调用请先补接口; - 中断里只做「取数据 + 入队」,耗时操作一律交给任务; - 函数注释使用 Doxygen 风格(`@brief` / `@param` / `@retval` / `@note`)。 **新增一个 UDS 服务的步骤** 1. 在 `My_Application/UDSLogic/` 新建 `SIDxx_服务名.c` 与 `.h`; 2. 实现两个函数:`service_xx_check_len(data, len)` 与 `service_xx_服务名(data, len)`; 3. 在 `My_Application/Src/service_cfg.c` 的 `uds_service_list[]` 配置表里加一行 (SID、处理函数、长度检查函数、会话支持位、所需安全等级); 4. 把 `My_Application/Inc/service_cfg.h` 里的 `SID_NUM` 加 1; 5. 把新文件加入 Keil 工程分组并编译。 **分发引擎本身不需要改动**——这正是配置表驱动的意义。 #### 特技 - **配置表驱动的服务分发**:函数指针表把「SID / 处理函数 / 长度检查 / 会话支持位 / 安全等级要求」 收敛成一张表,引擎只做查表与校验,加服务零侵入。 - **中断-任务彻底解耦**:CAN 中断回调仅 `xQueueSendToBackFromISR` + `portYIELD_FROM_ISR`, 由独立任务 `xQueueReceive(portMAX_DELAY)` 阻塞消费,既不在中断里打印也不丢帧。 - **完整的 ISO 15765-2 多帧状态机**:首帧 12 位长度解析、流控帧回发、连续帧 SN(模 16)校验、 4095 字节重组缓冲、发送侧 FF → 等 FC → CF 全流程。 - **会话与安全的联动保护**:切会话强制回锁安全等级;S3 超时(5s 无 TesterPresent)自动回退默认会话, 模拟真实 ECU 在诊断仪拔出后回到安全状态的行为。 - **故障码快照**:每个 DTC 关联转速 / 车速 / 电压三个 DID,按请求动态计算响应长度,还原故障现场数据。 - **踩坑记录已落文档**:FreeRTOS 中断优先级规则(`configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY`)、 HAL 时基与 RTOS 时基分离、大结构体放栈导致崩溃、CAN 未共地等问题均在 `Fake_CarECU_PROJECT_DOC.md` 中有完整的「现象 → 根因 → 修复」记录。 #### 已知限制与 Roadmap > 以下为**尚未实现**的部分,如实标注以避免误解,也便于协作认领。 | 项 | 现状 | 计划 | |---|---|---| | Flash / NVM 持久化 | 未实现,DID 写入仅存 RAM,断电丢失 | 片内 Flash 模拟 EEPROM,Magic + CRC 校验、双扇区磨损平衡 | | CAN TP 超时 | 10 个定时器实例已封装,仅 S3 真正接入 | 把 N_Ar / N_Br / N_Cs / N_Cr 接入 `can_tp.c` | | STmin / BS / WT | 回发流控帧固定 `30 00 00`,连续帧未按 STmin 间隔发送 | 解析并遵守诊断仪下发的流控参数 | | 故障自动记录 | DTC 表与快照目前为示例数据 | 由真实信号或故障注入触发,自动置位状态位并生成快照 | | 未实现的服务 | 0x28、0x31、0x34/0x36/0x37(刷写)、0x85 | 按优先级补充,刷写流程优先 | | 验证方式 | 手工 USB-CAN 抓帧,无单元测试 / HIL | 补 Python + CANable 自动化回归脚本 | | 其他 | 无 CAN FD、无 LIN、无网络管理(NM)、未使用扩展帧(29 位 ID) | 视需求扩展 |