第2章:UDS协议基础——ISO 14229-1标准解读

各位同学,欢迎来到UDS诊断栈开发的第二讲。今天咱们聊聊UDS协议的基础,也就是ISO 14229-1这个标准到底在说什么。

说实话,我刚入行那会儿,看到14229-1这个编号就头大。几百页的文档,全是术语和表格。后来做项目做多了才发现,核心的东西其实就那么几个。今天我就把这些核心掰开了讲给你听。

2.1 ISO 14229-1到底规定了什么?

ISO 14229-1,全称是「道路车辆—统一诊断服务—第1部分:应用层」。说白了,它就是定义了ECU和诊断仪之间怎么「说话」的规则。

你想想看,不同厂家做的ECU,硬件不同、软件不同,但诊断仪得能跟它们通信。怎么办?那就得有个统一的标准。14229-1就是这个标准。

它主要规定了三件事:

  • 报文格式:诊断请求和响应长什么样
  • 服务定义:能做什么操作(比如读故障码、写数据)
  • 时序要求:什么时候该发、什么时候该回

核心要点:ISO 14229-1只定义了应用层,不涉及底层通信。底层用CAN、LIN还是以太网,那是ISO 15765、ISO 17987这些标准的事。

2.2 UDS报文结构——N_PDU与A_PDU

说到报文结构,很多初学者容易搞混。这里我给大家理清楚。

2.2.1 什么是N_PDU?

N_PDU是网络层协议数据单元。它负责把应用层的数据打包,加上地址信息,然后扔给底层去发。

N_PDU的结构很简单:

N_PDU = N_AI(地址信息) + N_PCI(协议控制信息) + N_DATA(用户数据)

举个例子,在CAN诊断中:

  • N_AI:就是CAN ID,比如0x7DF(功能寻址)或0x7E0(物理寻址)
  • N_PCI:单帧、多帧的控制字节
  • N_DATA:真正的诊断数据,比如0x10 0x01

我的经验:调试时经常遇到N_PDU解析错误。我建议你先把CAN ID和PCI字节搞清楚,这两个最容易出问题。

2.2.2 什么是A_PDU?

A_PDU是应用层协议数据单元。它才是我们真正关心的诊断数据。

A_PDU的结构:

A_PDU = A_SA(源地址) + A_TA(目标地址) + A_RA(响应地址) + A_Data(服务数据)

嗯,这里要注意,A_PDU里的地址和N_PDU里的地址不是一回事。A_PDU的地址是逻辑地址,N_PDU的地址是物理地址。

我刚开始做项目时,就因为这个搞混过。明明A_PDU里写的是0x10,结果CAN ID却是0x7E0。后来才明白,这两层是独立的。

2.3 服务标识符(SID)分类

SID是UDS的核心。每个诊断服务都有一个唯一的SID,就像每个人都有一个身份证号。

ISO 14229-1把SID分成了六大类:

类别 SID范围 典型服务 说明
诊断和通信管理 0x10 - 0x3E 0x10(诊断会话控制)、0x11(ECU复位) 管理诊断会话和通信
数据传输 0x22 - 0x2E 0x22(读取数据)、0x2E(写入数据) 读写ECU内部数据
存储数据传输 0x14 - 0x19 0x14(清除诊断信息)、0x19(读取DTC信息) 处理故障码
输入输出控制 0x2F - 0x3D 0x2F(输入输出控制) 控制ECU的输入输出
远程激活 0x31 - 0x3D 0x31(例程控制) 执行ECU内部例程
上传下载 0x34 - 0x37 0x34(请求下载)、0x36(传输数据) 刷写ECU软件

避坑指南:我曾经遇到过一个项目,工程师把0x22和0x2E搞混了。0x22是读数据,0x2E是写数据。写成了0x22去写数据,ECU直接返回NRC 0x12(不支持)。这种低级错误,调试时特别浪费时间。

2.4 诊断会话控制(0x10服务)

0x10服务,也就是诊断会话控制,是UDS里最重要的服务之一。为什么?因为它是所有诊断操作的前提。

ECU上电后,默认处于默认会话(Default Session)。在这个会话里,很多诊断服务是不支持的。你得先切换到其他会话,才能做更多操作。

0x10服务的请求格式:

请求:0x10 + 子功能(会话类型)
响应:0x50 + 子功能 + 响应参数

常见的会话类型:

  • 0x01:默认会话(Default Session)
  • 0x02:编程会话(Programming Session)——用于刷写
  • 0x03:扩展诊断会话(Extended Diagnostic Session)——用于高级诊断
  • 0x04:安全系统诊断会话(Safety System Diagnostic Session)——用于安全相关

举个例子,切换到扩展诊断会话:

请求:02 10 03
响应:02 50 03 00 32 00 C8

响应里的0x00 32表示P2Server_max(最大响应时间)为50ms,0x00 C8表示P2*Server_max(增强型响应时间)为200ms。

我的习惯:调试时,我一般先发一个0x10 0x01切回默认会话,再发0x10 0x03切到扩展会话。这样能确保ECU状态是干净的。有些ECU状态机设计得不好,直接切会话可能会卡住。

嗯,这里还要注意一点:会话切换是有超时机制的。如果ECU在P2*Server_max时间内没收到任何诊断请求,它会自动切回默认会话。这个机制是为了防止诊断会话一直占用资源。

我曾经在项目里遇到过一个问题:刷写过程中,刷写工具发完数据后等了一会儿才发下一个请求,结果ECU超时切回了默认会话。刷写工具再发请求时,ECU直接返回NRC 0x78(请求正确接收,但响应待定)。查了半天才发现是超时时间设置得太短。

所以,我建议你在设计诊断栈时,一定要处理好会话超时机制。特别是做刷写功能时,P2*Server_max要设置得合理一些。

2.5 小结

今天的内容就到这里。我们讲了ISO 14229-1的核心内容、N_PDU和A_PDU的区别、SID的分类,以及0x10服务的具体用法。

下一章,我们会深入讲解0x22和0x2E服务,也就是数据读写。这两个服务在实际项目中用得最多,也是很多问题的根源。到时候我会分享一些调试技巧,保证让你少走弯路。

好了,今天就到这里。有问题随时找我。