UDS 诊断服务 实战解析

UDS 诊断服务 实战解析 1. UDS诊断服务基础概念第一次接触UDS诊断协议时我完全被各种服务ID和报文格式搞晕了。直到后来在实际项目中调试ECU才真正理解这套协议的精妙之处。简单来说UDS就像汽车ECU的普通话让不同厂商的诊断仪和ECU能够顺畅交流。UDS全称Unified Diagnostic Services统一诊断服务是ISO 14229标准定义的应用层协议。它位于OSI模型的第七层底层可以跑在CAN、LIN、FlexRay甚至以太网上。最常用的是基于CAN总线的实现也就是ISO 15765-2DoCAN。诊断通信的基本流程就像医生问诊诊断仪客户端发送请求RequestECU服务端返回响应Response每个请求都有对应的服务IDSID比如0x10代表会话控制我在实际项目中最常用的几个核心服务包括0x10 Diagnostic Session Control诊断会话控制0x19 ReadDTCInformation读取故障码0x22 ReadDataByIdentifier按ID读取数据0x27 SecurityAccess安全访问0x2E WriteDataByIdentifier按ID写入数据2. 诊断报文格式详解2.1 请求报文结构刚开始分析CAN报文时我经常分不清哪个字节是服务ID哪个是子功能。后来发现UDS请求报文其实有固定套路[服务ID] [子功能] [参数...]举个例子要进入扩展会话0x0310 03第一个字节0x10是服务ID第二个字节0x03是子功能扩展会话带抑制正响应标志的请求 有时候为了节省总线资源可以设置子功能最高位为1来抑制正响应。比如10 83这个请求的0x83就是0x03 | 0x80ECU收到后不会回复正响应。2.2 响应报文格式ECU的响应分为两种正响应Positive Response服务ID 0x40负响应Negative Response0x7F 原服务ID NRC正响应示例50 03这是对0x10服务的正响应0x50 0x10 0x40负响应示例7F 10 12表示0x10服务执行失败NRC 0x12代表子功能不支持2.3 多帧传输处理当数据量超过单帧限制CAN通常7字节时要用到ISO-TP的多帧传输。我调试刷写功能时就遇到过这个问题首帧First Frame以0x1开头包含数据长度1A 00 00 00 00 00 000x1A表示后续还有26字节数据连续帧Consecutive Frame以0x2开头21 23 45 67 89 AB CD3. 核心诊断服务实战解析3.1 10服务诊断会话控制ECU上电默认进入默认会话0x01但很多高级服务需要切换到其他会话# 进入编程会话的CAN报文示例 req [0x02, 0x10, 0x02] # CAN ID 10服务 编程会话 resp [0x02, 0x50, 0x02] # 正响应会话类型对比会话类型子功能典型用途默认会话0x01基础诊断编程会话0x02刷写ECU扩展会话0x03高级诊断3.2 19服务读取DTC信息排查车辆故障时19服务是我的得力助手。最常用的子功能是0x02读取快照信息请求19 02 FF 响应59 02 [DTC列表]DTC格式解析 一个完整的DTC占3字节例如0xC12345第一个字节0xC1高两位表示系统P/C/B/U后6位是故障码后两个字节具体故障细节3.3 22/2E服务数据读写读取ECU数据就像查字典每个数据都有唯一的DIDData Identifier读取DID 0xF110的请求 22 F1 10 响应 62 F1 10 [数据...]写入数据时需要先通过27服务解锁# 写入流程示例 1. 发送2701获取种子 2. 用算法计算密钥 3. 发送2702密钥 4. 验证通过后发送2E服务写入数据4. 安全访问机制剖析第一次做安全访问时我被种子密钥搞得头大。后来明白这其实就是个挑战-应答机制请求种子子功能0x01请求27 01 响应67 01 12 34 56最后三个字节是随机种子发送密钥子功能0x02请求27 02 78 9A BC 响应67 02密钥需要用特定算法计算常见安全等级0x01基础访问读取数据0x03编程访问刷写权限0x05厂商特殊功能5. 典型NRC代码处理遇到负响应不要慌关键看NRCNegative Response Code。我整理了几个常见错误NRC含义解决方案0x11服务不支持检查当前会话是否支持该服务0x12子功能不支持确认子功能值是否正确0x22条件不满足比如车速不在允许范围0x33安全访问拒绝检查安全等级和密钥算法0x31请求超出范围检查DID是否存在上周我就遇到个案例读取DID时一直返回0x31最后发现是DID列表版本不匹配更新DID定义后问题解决。6. 实战案例分析6.1 故障码读取完整流程以读取当前和历史故障码为例进入扩展会话发送10 03 接收50 03读取当前故障码发送19 02 接收59 02 [DTC列表]读取历史故障码发送19 0A 接收59 0A [DTC列表]6.2 ECU刷写关键步骤给ECU刷写新软件时标准流程是这样的进入编程会话10 02安全访问27 01/02通信控制28 01关闭非诊断报文请求下载34 00 00 00 00 [文件大小]传输数据36 [块数据]退出传输37ECU复位11 01记得有次刷写失败就是因为忘了第3步关闭常规通信导致总线负载过高超时。7. 开发调试技巧7.1 常用工具链CANalyzer/CANoe专业但昂贵PCAN-View轻量级CAN监视工具candump/cansendLinux下的CAN工具Python-can自己写脚本的好选择7.2 自制诊断工具要点用Python写简易诊断工具时关键要注意import can bus can.interface.Bus(channelcan0, bustypesocketcan) def send_uds_request(arb_id, service, subfNone, dataNone): msg [service] if subf is not None: msg.append(subf) if data is not None: msg.extend(data) message can.Message(arbitration_idarb_id, datamsg, is_extended_idFalse) bus.send(message)7.3 典型问题排查无响应检查物理连接确认CAN ID是否正确验证是否在正确会话模式负响应频繁检查NRC代码确认前置条件如安全访问验证参数格式数据异常检查字节序大端/小端确认数据缩放系数验证DID定义版本记得保存完整的通信日志这对后期分析非常有用。我习惯用Wireshark抓包配合自定义插件解析UDS报文。