1. UDS协议基础:OSI模型与汽车诊断、UDS协议栈概述、诊断会话控制(0x10)、ECU复位(0x11)
1.1 OSI模型与汽车诊断——别被七层吓到
很多刚入行的朋友,一听到OSI七层模型就头大。说实话,我当年也是。但做汽车诊断这行,你不需要背下每一层,关键是理解数据怎么从你的上位机,一路跑到ECU里。
OSI模型分七层:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。在UDS里,我们最关心的是下面几层:
- 物理层:说白了就是线束和接口。CAN总线用双绞线,DoIP用网线。我在项目里遇到过,某次台架测试死活连不上ECU,最后发现是CAN收发器的地线没接好——物理层出问题,上层再牛也白搭。
- 数据链路层:负责把数据打包成帧。CAN协议里就是CAN帧,带ID、数据长度、CRC校验这些。嗯,这里要注意,CAN ID的分配经常是整车厂的机密,你拿到的诊断文档里一般会写。
- 网络层:在UDS里,这一层叫ISO 15765-2(CAN总线)或者ISO 13400(以太网)。它负责把长报文拆包、重组。比如你要发一个超过8字节的诊断请求,网络层会自动帮你分包发送。
- 应用层:这就是UDS协议本身了。0x10、0x11这些诊断服务,都在这一层定义。
我的经验:做上位机开发,你至少要把应用层和网络层搞透。物理层和数据链路层,交给硬件工程师和底层驱动去操心。但如果你能懂一点,排查问题时会快很多。
1.2 UDS协议栈概述——从请求到响应的旅程
UDS协议栈,说白了就是一套规则。它规定了:
- 上位机怎么发请求(Request)
- ECU怎么回响应(Response)
- 出错时怎么报错(Negative Response)
一个典型的UDS请求长这样:
请求:02 10 03 00 00 00 00 00
响应:06 50 03 00 32 01 F4 00
我来拆解一下:
- 02:数据长度,表示后面有2个有效字节
- 10:服务ID,0x10就是诊断会话控制
- 03:子功能,0x03表示扩展诊断会话
- 后面补的00是填充字节,CAN报文固定8字节
响应里的50,是0x10 + 0x40的结果。UDS规定,肯定响应(Positive Response)的服务ID = 请求ID + 0x40。这是规矩,记住就行。
小技巧:我习惯在代码里把服务ID和响应ID定义成宏,比如:
#define UDS_SID_DIAG_SESSION_CONTROL 0x10
#define UDS_RES_SID_DIAG_SESSION_CONTROL 0x50
这样写代码时一眼就能看出是请求还是响应,不容易搞混。
1.3 诊断会话控制(0x10)——ECU的"工作模式"开关
0x10服务,是用来切换ECU工作模式的。ECU平时在跑车,你不能随便动它的内部参数,否则出事了谁负责?所以UDS定义了三种会话:
| 子功能 | 会话名称 | 说明 |
|---|---|---|
| 0x01 | 默认会话 (Default Session) | 上电后的初始状态,只能做基本诊断 |
| 0x02 | 编程会话 (Programming Session) | 用于刷写ECU固件,权限最高 |
| 0x03 | 扩展诊断会话 (Extended Diagnostic Session) | 可以读写参数、执行例程,日常诊断最常用 |
你想想看,为什么要有这三种?
我举个例子。有一次我在做产线终检工具,需要读取ECU的VIN码。默认会话下,ECU只允许你读几个基本ID。想读VIN?必须切到扩展会话。我当时没注意,直接发了0x22读VIN,结果ECU回了否定响应——0x7F 22 0x7F(服务不支持)。查了半天才发现,原来是会话没切。
避坑指南:我曾经在量产项目上犯过一个低级错误——切到编程会话后忘了切回默认会话。结果ECU一直处于可刷写状态,整车下电后静态电流超标。后来我养成了习惯:每次诊断操作结束后,主动发一条0x10 0x01切回默认会话。
0x10服务的响应里,还带两个重要参数:
- P2_Server_max:ECU处理单个请求的最大时间(单位ms)。比如0x0032就是50ms。
- P2*_Server_max:当ECU需要额外时间处理时的扩展超时时间。比如0x01F4就是500ms。
这两个参数,直接决定了你的上位机超时设置。我一般会把超时设成P2_Server_max的2倍,留点余量。
1.4 ECU复位(0x11)——让ECU"重启一下"
0x11服务,就是让ECU复位。听起来简单,但这里面的门道不少。
子功能有三种:
| 子功能 | 复位类型 | 说明 |
|---|---|---|
| 0x01 | 硬复位 (Hard Reset) | 相当于断电重启,ECU所有RAM数据丢失 |
| 0x02 | 钥匙通断复位 (Key Off/On Reset) | 模拟点火开关通断,部分ECU会保留一些数据 |
| 0x03 | 软复位 (Soft Reset) | 只复位应用层,底层驱动不动,速度最快 |
我个人习惯,在开发调试阶段用软复位最多。为什么呢?因为硬复位后ECU要重新初始化CAN控制器,有时候会丢几帧报文,上位机那边容易报超时。软复位快,而且稳定。
但要注意,量产测试时一定要用硬复位。为什么?因为软复位可能残留一些诊断状态,影响下一轮测试的准确性。我曾经吃过这个亏——某次产线测试,用软复位后ECU还保留着之前的诊断会话,导致下一台车的测试用例跑错了分支。
关键点:ECU复位后,会自动切回默认会话。所以如果你复位后还想做诊断操作,记得重新发0x10切会话。
0x11的响应比较简单,就是0x51 + 子功能。但有个细节:ECU在复位前,会先发响应,然后再执行复位。所以你的上位机收到响应后,不要立刻发下一条指令,要等ECU重启完成。等多久?一般建议等500ms以上,具体看ECU的启动时间。
嗯,说到这我想起一个坑。有一次我写上位机,收到0x11的响应后立刻发了0x10切会话,结果ECU还在重启中,CAN控制器都没初始化好,报文直接丢了。后来我在代码里加了个延时:
# 发送复位请求
send_uds_request(0x11, 0x01)
# 等待响应
response = recv_uds_response()
if response[0] == 0x51:
# 关键:等ECU重启完成
time.sleep(1.0) # 等1秒,保守一点
# 再切会话
send_uds_request(0x10, 0x03)
这个1秒的延时,看起来笨,但稳。你想想看,ECU启动慢一点的车,500ms可能不够。我宁愿多等一会儿,也不愿意报文丢了重试。
小结
这一章我们聊了:
- OSI模型在汽车诊断里怎么用——重点在应用层和网络层
- UDS协议栈的基本结构——请求、响应、否定响应
- 0x10诊断会话控制——三种会话的切换,以及P2超时参数
- 0x11ECU复位——三种复位方式的区别,以及复位后的注意事项
下一章,我们会聊安全访问(0x27)和通信控制(0x28)。这两个服务,一个管权限,一个管通信,都是实战中的高频服务。到时候我会分享一些我在安全访问"种子-密钥"算法上踩过的坑,敬请期待。