UDS协议介绍
汽车诊断分为两种:
OBD:法规强制要求的,也就是经常听到的OBD(On Board Diagnostic)诊断,主要用于在车辆运行阶段能够及时的通告故障信息,给驾驶员以警告或提示,通过仔细阅读车辆手册可以获取相关问题的解决措施,来有效避免更严重的后果。OBD出现的更早,那么它主要针对传统燃油车,并且OBD主要是用于排放相关的诊断。
UDS:也叫增强型诊断或者离线诊断(Off Board Diagnostic),除报告故障之外,还拥有很多其他的功能。诊断仪通过UDS协议可以对车辆进行一系列的操作,通过查询数据或者控制变量的方法对车辆进行诊断,确认是否有问题或者发生了什么问题,从而指导维修。UDS是统一诊断系统,适用性则更广,它囊括了非排放相关的车身上所有ECU的诊断。
可以简单的理解OBD就是用于排放相关的ECU,如发送机控制单元,减速器控制器等;而UDS则包含了车身上几乎所有ECU的诊断,例如VCU BCM DCDC等等。
传统燃油或混动车中与排放相关的ECU既要支持OBD也要支持UDS,而其他的ECU一般仅仅需要支持UDS。
UDS诊断服务概念
基本概念
首先列举并解释一下下面的基本概念。
客户端、服务端:在UDS的规则里面,有两个角色是大家一定要知道的,就是客户端(client)和服务端(server),客户端按照UDS协议的规定可以向服务器请求某些服务,来实现数据的交互。在汽车上,客户端指诊断仪或具备诊断仪功能(发送诊断请求)的设备和ECU,服务端指实际执行请求命令的ECU。
请求、响应:客户端和服务端,通过请求和响应来实现的交互,客户端可以通过请求来向服务端索要数据,也可以通过请求来向服务端发送数据,服务端收到请求后,需要按照规则来给客户端响应,来实现具体的服务功能。响应分为肯定响应和否定响应,即请求的事务被正确处理时服务端给出肯定响应,请求的事务无法处理或处理时发生错误时服务端给出否定响应。否定响应包含被否定的服务ID和否定响应码(NRC)。
地址:每个服务端都有一组请求地址和响应地址,其中请求地址又分为物理寻址和功能寻址,也就是说每个服务端至少都有三个地址:功能请求地址、物理请求地址和响应地址。每个地址里面包含了目标地址和源地址,即不管是请求地址还是响应地址,地址信息里都包含了发送方和接收方的信息。有关地址格式的说明,在ISO15765系列里详细说明。
物理请求地址:一对一请求地址,即该地址指向的是单一服务器,可以理解为打电话,请求是由客户端发送给指定的服务端的,只有指定的服务端能对此请求进行响应,且如无特殊要求,必须响应。
功能请求地址:一对多请求地址,即该地址指向的是一组服务器,可以理解为电话会议,请求是由客户端发送给指定的多个服务端的,被请求的服务端都能够对请求进行响应,例如一般车上的功能寻址都是请求所有的控制器的。但是功能寻址所请求的内容如果不支持,是可以不响应的,具体细节在响应规则章节会说明。
响应地址:响应地址不区分物理还是功能,因为响应的发送方和接收方是唯一的,即只有一对一的场景。
服务ID:UDS是以诊断服务来划分功能的,每个服务分配一个特定的ID,占用一个字节长度,每个服务根据功能的不同会有不同的格式,但基本上有带子功能和不带子功能之分,这个在讲格式的时候会详细进行说明。
子功能:一些服务如10会话模式服务,会有不同的会话模式,19服务会包含读取故障码和快照等其他信息的功能,所以这些功能会用子功能进行区分,表示同类功能下的细分类别。子功能同样也占一个字节。
数据参数:大部分服务都需要数据参数才能确认请求的具体内容,例如22服务需要DID参数才能够确定要读取哪个数据,19服务需要指定参数才能确定读取的是哪一类或者哪个故障的数据等。
抑制肯定响应位:子功能的最高位,用来表示对该请求的响应要求,如果该位置1,则当前请求的肯定响应是不需要响应的,反之则需要响应。
否定响应码(NRC):当服务端处理请求出现问题时,需要给出的问题原因。ISO14229-1的附录A有一张否定响应码的表格,里面有每个码所代表的含义,同时在通用响应规则和每个服务的响应规则里也会指出具体在哪些步骤进行响应。
响应规则
UDS中,一般由客户端发起诊断请求,服务端进行响应,每次对话都是一问一答的形式,但是有些情况下,一些特定的请求是可以不响应,按照14229-1的四张表格,分别描述响应的具体规则。
物理寻址
对于带子功能参数的请求消息响应,对于物理寻址的客户端请求消息:NRC为:11表示不支持服务标识符,12表示不支持这个子功能。
对不带子功能参数的请求响应(物理寻址):如果支持服务标识符但是发生了某些错误,NRC=xx;如果不支持该参数,回复0x31,如果不支持服务标识符,NRC=0x11。
功能寻址
对于带子功能参数的请求消息响应(功能寻址):
对于不带子功能参数的请求消息响应(功能寻址):
UDS服务整体描述
首先来看服务请求和响应格式,“请求”由Tester端发送给ECU,请求报文里带有SID,根据具体的服务内容后面加具体的数据。肯定响应格式由“(SID+40)+具体的数据”。否定响应格式是一个固定的格式“7F+请求报文里的SID+1个字节的NRC”。
Subfunction,1个字节,UDS服务支持Subfunction的请求和响应格式:
“请求”为“SID+1个字节Subfunction+具体的数据”,肯定响应为“(SID+40)+Subfunction+具体的数据”。
然而,有的UDS服务里面是不支持Subfunction,但是支持DID的,DID是“数据ID”的意思,那么它的请求格式:
“请求”为“SID+具体的DID+数据内容”,肯定响应“(SID+40)+DID+具体的数据”。
肯定响应抑制位: 是在Subfunction里的这个字节的最高位,我们把它叫做肯定响应抑制位。只有这个服务支持Subfunction的时候,才有可能支持肯定响应抑制位,当肯定响应抑制位置1的时候,要求所有的肯定响应的抑制将不再发送。当肯定响应抑制位为0的时候,肯定响应是不被抑制的。这里要注意的是它只是抑制肯定响应,而否定响应是不被抑制的。
Tester发送的请求报文格式错误,或者请求发送的条件处于错误,ECU将发送否定响应,否定响应的格式是“7F+SID+NRC”,常用到的NRC如下:
- 11表示服务不支持;
- 12 subfunction不支持;
- 13 请求的长度不正确,或者格式不正确
- 31 是请求超出范围;
- 7E 是在当前会话下subfunction不支持
- 7F 是在当前会话下服务不支持
两个时间参数:P2Sever,P2Sever*。
当Tester给ECU发送请求过后,ECU需要在P2Sever时间内给出相应的响应,如果ECU当前正在处理别的任务,处理别的事情,而不能在P2Sever的时间内给出相应的响应,那么它先在P2Sever时间内给出一个NRC为78的Pending报文,告诉Tester“ECU正在忙”,之后会在P2Sever*的时间内给出其它的响应报文,如果P2Sever*的时间内还是不能给出相应的肯定响应和否定响应,将继续给出Pending报文,直到能够正确处理请求报文之后,会给出正确的响应报文。
UDS诊断服务模块
UDS诊断包括6大类,26种服务,每种服务都有自己独立的ID,即SID(Service Identifier)。
UDS的完整服务列表
SID | 服务 | 简介 |
---|---|---|
0x10 | DiagnosticSessionControl | 诊断会话控制 |
0x11 | EcuReset | ECU复位 |
0x27 | SecurityAccess | 安全访问 |
0x28 | CommunicationControl | 通信控制 |
0x3E | TesterPresent | 待机握手 |
0x83 | AccessTimingParameter | 访问时间参数 |
0x84 | SecuredDataTransmission | 安全数据传输 |
0x85 | ControlDTCSetting | 控制DTC设置 |
0x86 | ResponseOnEvent | 事件响应 |
0x87 | LinkControl | 链路控制 |
SID | 服务 | 简介 |
---|---|---|
0x22 | ReadDataByIdentifier | 通过id读数据 |
0x23 | ReadMemoryByAddress | 通过地址读内存 |
0x24 | ReadScalingDataByIdentifier | 通过id读比例数据 |
0x2A | ReadDataByPeriodicIdentifier | 通过周期id读数据 |
0x2C | DynamicallyDefineDataIdentifier | 动态定义标识符 |
0x2E | WriteDataByIdentifier | 通过id写数据 |
0x3D | WriteMemoryByAddress | 通过地址写内存 |
SID | 服务 | 简介 |
---|---|---|
0x14 | ClearDiagnosticInformation | 清楚诊断信息 |
0x19 | ReadDTCInformation | 读取故障码信息 |
SID | 服务 | 简介 |
---|---|---|
0x2F | InputOutputControlByIdentifier | 通过id控制输入输出 |
SID | 服务 | 简介 |
---|---|---|
0x31 | RoutineControl | 例行程序控制 |
SID | 服务 | 简介 |
---|---|---|
0x34 | RequestDownload | 请求下载 |
0x35 | RequestUpload | 请求上传 |
0x36 | TransferData | 传输数据 |
0x37 | RequestTransferExit | 请求退出传输 |
0x38 | RequestTransferFile | 请求传输文件 |
诊断和通信管理服务
- 处理诊断过程中的模式、状态跳转和保持,如控制会话模式
- 处理通信状态、内部存储状态、安全状态,如控制总线报文的收发
数据传输服务
- 处理对内部存储器的数据读取和写入,如读取和写入VIN信息
存储的数据传输服务
- 处理运行过程中所保存的故障和相关数据的读取和擦除
输入输出控制服务
- 处理对输入和输出引脚信号的控制,如控制车窗上升或下降
例程功能服务
- 处理内部功能的调用,如调用一些检查数据的机制
上传下载服务
- 处理控制器的软件更新或上传
诊断和通信管理功能单元
DiagnosticSessionControl(0x10)
10用于控制ECU在不同的session之间进行转换,session可以看作是ECU所处的一种软件状态,在不同的session中诊断服务执行的权限不同。其Request请求格式如下所示:
DiagnosticSessionControl的诊断request的格式
第一部分是SID,1个字节,值为0x10。
第二部分是sub-function,1个字节,子功能列表如下所示:
功能 | 会话模式 | 描述 |
---|---|---|
01 | 默认会话模式 | ECU在刚启动时保持的状态,当ECU复位的时候也是会返回默认会话,不需要超时处理。 |
02 | 编程会话模式 | 刷写程序时用的,超时或者刷写失败时会跳转回默认会话,即ECU从底层软件跳转到应用软件。 |
03 | 扩展会话模式 | 通常诊断用的大部分功能以及特殊功能都在这个会话模式下进行。主要是用来写入一些信息如VIN和序列号等,以及控制ECU执行一些特殊请求如控制应用通信和故障信息的更新等 |
ECU上电时,进入的是默认会话0x01(Default)。如果进入了一个非默认会话的状态,一个定时器会运转,如果一段时间(S3)内没有请求,那么到时间后,诊断退回到默认会话01。当然,我们有一个3E的服务,可以使诊断保持在非默认的状态。
ECU上电之后,由于默认处在0x01 默认会话模式中,而在这个会话中很多诊断服务不可以执行,导致很多诊断相关的数据不能读取或写入。
一般的诊断仪启动之后,会给ECU发送10 03,即让ECU进入0x03扩展会话模式中,在这个会话中可执行的诊断服务就很多了。
而如果要让ECU保持在非默认会话模式中,则需要诊断仪每隔固定的时间发送0x3E服务,ECU才会知道诊断仪有和自己通信的需求,从而保持在非默认会话模式中。
另一个常用的会话模式是0x02 编程会话模式,在这个会话模式中可以进行软件刷写的一系列诊断服务。
0x40 – 0x5F 这个范围中的会话模式由整车厂自定义使用,比如,某些诊断服务或诊断数据的操作需要在生产线上执行,即所谓的End-Of-Line,整车厂可以从这个范围中选择一个值来表示EOL会话模式;又或者在开发阶段需要某种“超级”会话模式,则也可以从这里选一个值用来使ECU进入开发模式的会话模式中。
DiagnosticSessionControl这个服务非常简单,但是它却是ECU和诊断通信的第一条诊断命令。
ECUReset(0x11)
ECUReset 这条指令的用途是通过诊断请求使ECU重启。
ECUReset 诊断request的格式
第一部分是SID,1个字节,值为0x11。
第二部分是sub-function,1个字节,其低7bit是sub-function,用于指示ECU将模拟哪种方式进行重启。 常用的sub-function包括(只举2个例子,UDS还定义了很多其他的值)
- 0x01 hardReset 模拟KL30的重启
- 0x02 keyOffOnReset 模拟KL15的重启
当我们通过诊断命令改写了ECU的某些数据,或者对ECU进行了某些设置,只有将ECU重启才能将这些配置生效,所以就有了这个诊断命令。在ECUReset 执行之后,ECU会从非默认会话模式回退到默认会话模式中。
SecurityAccess(0x27)
厂家可能会为ECU定义某些安全级别稍微高一些的诊断服务,在执行此类服务之前,就需要执行SecurityAccess 这个诊断命令,进行一个简单的身份验证。
完成SecurityAccess 有以下步骤:
根据UDS对$27服务的定义:
0x03, 0x05, 0x07– 0x41 这个范围留给用于requestSeed的sub-function;
0x04, 0x06, 0x08– 0x42 这个范围留给用于sendKey的sub-function。
具体选择哪对值,由整车厂自己定义。整车厂也可以选择多对sub-function,用于不同等级的安全访问。
举例来说:
假设0x05用于requestSeed,0x06用于sendKey。
- 诊断仪发送 27 05;
- ECU响应 67 05 01 0101(seed是 01 01 01);
- 诊断仪发送 27 06 02 03 04(key值是02 03 04,seed是 01 01 01,假设本地密码为01 02 03,而算法就是将密码与seed相加);
- ECU验证成功 67 06;
此时ECU就处于unlocked的状态了,那些被保护起来的诊断服务和诊断数据可以被操作了。通常来说,如果ECU重启,或者回到了默认会话模式,unlocked状态就失效了,如果要执行相关诊断服务,则需要再次执行上面描述的过程。
CommunicationControl(0x28)
该服务用于打开/关闭某些类别的报文的发送/接收。它通常在刷写软件或大量数据的时候使用,因为在刷软件或参数的时候并不需要ECU进行与通信相关的功能,将通信关闭之后可以把所有通信资源都留给软件或参数的下载,当下载过程完成之后再利用该服务将通信恢复即可。
0x28服务的格式如下图所示
第一部分是SID,1个字节,值为0x28;
第二部分是sub-function,1个字节,即对ECU的通信进行哪种控制,具体包括 :
第三部分是communicationType,1个字节,表明这条诊断请求要对哪种报文进行控制,定义如下表所示:
这个字节中最常用的就是低2 bit:
- 0x1代表普通应用报文,
- 0x2代表网络管理报文,
- 0x3代表普通应用报文和网络管理报文。
第四部分是optional的,只有当sub-functional等于0x04或0x05时才需要使用。
举例来说:
28 01 01 表示激活应用报文的接收并关闭应用报文的发送(网络管理报文不受影响)。
28 00 01 表示激活应用报文的接收和发送(网络管理报文不受影响)。
TesterPresent(0x3E)
这个诊断服务的用处可以通过它的名字很明显地得知,即告知ECU诊断仪还在连接着。在0x10中提到了关于会话模式的部分,如果没有诊断命令的发送和接收,ECU将从非默认会话模式中回退到默认会话魔兽, 0x3E就是用于使ECU保持在当前会话模式。
这应该是UDS中最简单的一个诊断服务了,它永远只有2个字节,格式如下:
第一个字节是SID,1个字节,值为0x3E。
第二部分是sub-function,1个字节,
当sub-function是0x00时,ECU要给出response;
当sub-function是0x80时,ECU不需要给出response。
一般来说主机厂会为这个服务定义两个时间参数,一个参数用于规定自己的诊断仪发送0x3E服务的间隔,另一个参数用于定义ECU收不到0x3E服务的timeout时间。
ControlDTCSetting(0x85)
该服务用于控制ECU的DTC(diagnostic trouble code,故障诊断码)存储,这个服务常常和前面提到的28服务一起使用,比如,在开始写参数之前,为了获得更快的传输速度,我们用28服务把所有ECU的通信关闭了,但此时因为收到不到相关的报文,ECU会没有必要地存储很多DTC,这时如果我们使用85服务把ECU存储DTC的功能暂时性地禁止掉,则不会造成这种麻烦。
0x85服务请求的格式
第一部分是SID,1个字节,值为0x85;
第二部分是sub-function,1个字节,即是打开还是关闭ECU的DTC存储,包括 :
- 0x01 on
- 0x02 off
第三部分是optional的,由各家自己定义,比如,可以用FF FF FF 来表示这条诊断命令针对所有的DTC。
ResponseOnEvent(0x86)
尽管诊断通信过程是问答式的,诊断仪发请求,ECU给响应。0x86服务算是一个例外,在ECU收到这条0x86服务之后,当DTC产生时,它会自动地上报DTC及相关环境数据,直到用另一条0x86服务来关闭ECU的这个行为。
该功能主要用于ECU的前期开发阶段,在售后和生产中是不会用到的,而且该服务的格式复杂(即可变的参数很多),执行它还分为好几个步骤,在这里就不过多叙述。
LinkControl(0x87)
这个服务用于转化ECU数据链路层和物理层的状态,比如,在高速CAN上的ECU正常通信速率是500kbit/s,但它同时也支持1M bit/s的波特率,如果需要刷写大量数据,便可以利用这条诊断服务让ECU以1M bit/s的波特率进行通信。
这个诊断服务的执行分为两个步骤:
- 验证ECU是否支持要调整到的目标波特率
- 让ECU的数据链路层和物理层转到目标波特率的通信状态
只有当第一个步骤验证通过了,第二个步骤才可以成功执行。
数据传输功能单元
在数据传输类服务,0x22和0x2E成对使用,0x23和0x3D成对使用,这几个服务用于诊断数据的基本读写操作。0x24,0x2A,0x2C是一些特殊操作。
ReadDataByIdentifier(0x22)
第一部分是SID,1个字节,值为0x22。
第二部分是DID,2个字节(通常),
l Request(请求):22+DID(Data Identifier,通常是两个字节)
l Response(响应):62+DID+Data
DID有一部分已经被ISO 14229-1规定了。比如0xF186就是当前诊断会话数据标识符,0xF187就是车厂零件号数据标识符,0xF188就是车厂ECU软件号码数据ID,0xF189就是车厂ECU软件版本号数据标识符。
举例来说:
22 F1 87 (读取零件号,DID=F1 87)
62 F1 87 XX YYZZ KK MM NN(给出零件号)
WriteDataByIdentifier(0x2E)
第一部分是SID,1个字节,值为0x2E。
第二部分是DID,2个字节(通常),
l Request(请求):2E+DID+Data
l Response(响应):6E+DID
注意,比如0xF186这个DID不支持直接写入数据,需要用$10来进行会话转换。也就是说,对于写数据的请求,一般来说需要在一个非默认会话,和解锁的状态下才能进行。
举例来说:
2E F1 87 XX YY ZZ KK MM NN(写入零件号)
6E F1 87(给出positive response)
ReadMemoryByAddress(0x23)
0x23服务的请求格式
第一部分是SID,1个字节,值为0x23。
第二部分是格式信息,长度为1个byte,高4 bits用于指示memorySize的长度(字节数),低4 bits用于指示memoryAddress的长度(字节数)。比如,如果这个值为0x46,则后面的memorySize为6个byte,memoryAddress为4个byte。
第三部分是memoryAddress信息,它的长度由第二部分的AddressAndLengthFormatIdentifier指示。
第四部分是memorySize信息,它的长度由第二部分的AddressAndLengthFormatIdentifier指示。
如果这条命令的格式是 23 22 xx yy aa bb,则它的含义就是,读取xx yy地址的长度为aa bb的数据。
WriteMemoryByAddress(0x3D)
了解了0x23的用法,0x3D的用法就很好理解了,它标识memoryAddress和memorySize的方法与0x23相同,只是在诊断命令最后再加上一段需要写入的数据。
存储数据传输功能单元
存储数据传输服务,用于操作DTC(diagnostic trouble code,故障诊断码)
在 ISO15031-6 中对 DTC 的格式有明确的定义,该规范中定义了 DTC 共由三个字节组成,如下图所示
DTC格式
字节1 | 字节2 | 字节3 |
诊断故障代码高字节 | 诊断故障代码低字节 | 诊断故障代码失效类型字节 |
在 ISO15031-6 中对 DTC 格式中的字节 1 与字节 2 也做了具体的定义,通过这个定义可以很方便确定记录的 DTC 属于车上的那种类型。
至此,DTC故障码的概念解释完毕,下面将展开关于存储传输类服务的解读:
这类服务主要涉及到两条诊断命令,分别是:
0x14:ClearDiagnosticInformation
0x19:ReadDTCInformation
这两条服务用于操作存储在ECU中的DTC,使用频率很高,而且它们比较好地体现了“诊断”两个字的含义。
ClearDiagnosticInformation(0x14)
这条诊断命令的格式比较简单,用法也很好理解,即删除存储在ECU中的DTC。
第一部分是SID,1个字节,值为0x14。
第二部分是DTC,3个字节,用于标识将要被删除的DTC种类,UDS规定用FF FF FF表示所有种类的DTC,由厂家自定义代表Powertrain、Chassis、Body、NetworkCommunication等种类DTC的值。
举例来说
Request:14+FF+FF+FF;(删除掉ECU中的所有DTC)
Response:54 ;
ReadDTCInformation(0x19)
这条指令用于读取存储在ECU中的DTC。
第一部分是SID,1个字节,值为0x19。
第二部分是sub-function,1个字节,代表了各式各样读取DTC的方法,UDS给19服务的sub-function从0x00到0x19进行了明确定义,这里介绍其中常见4种。
- sub-function = 0x01(reportNumberOfDTCByStatusMask)
用于读取符合DTC状态掩码的DTC的数量,此时parameter为一个byte的Mask掩码,用于与DTC的Status进行“与”运算,而ECU返回的则是"与"运算之后结果不为0的DTC的数量。
DTC的Status用一个byte表示,其中的8个bit分别代表DTC的不同状态,比如,bit0 表示这个DTC是active的还是passive的,bit 4表示这个DTC是否已经被confirm了,如果DTC的状态是confirm,则说明该DTC已经被ECU存储下来了。
比如:19 01 08这个命令的用途,就是读取所有状态为confirm的DTC的数量。
- sub-function = 0x02(reportDTCByStatusMask)
用于读取符合特定条件的DTC列表,此时parameter仍然为一个byte的Mask,用于与DTC的Status进行“与”运算,而ECU返回的则是"与"运算之后结果不为0的DTC列表。
比如19 02 01这个命令的用途,就是读取所有状态为active的DTC的数量。此时ECU返回的格式应该是59 02 01 XX XX XX 01 YY YY YY 09......。返回的DTC列表中的每个条目为4个字节,前三个字节用于标识DTC,比如 XX XX XX,最后一个字节用于标识DTC状态,比如01,表示DTC是active的,09表示DTC是active且confirm的。
- sub-function = 0x06(reportDTCExtDataRecordByDTCNumber)
用于读取某个DTC及其相关的环境数据,此时parameter为4个byte,前三个byte用于标识我们要读取的DTC,第四个byte用于标识要读取的环境数据的范围,UDS规定使用FF来表示读取所有的环境数据,各厂家可以要根据自己的需求定义其他的值来代表要读取的环境数据的范围。环境数据包括DTC状态,优先级,发生次数,老化计数器,时间戳,里程等,厂家还可以根据自己的需求定义一些此DTC产生时的测量数据。
比如 19 06 XX XX XX FF就表示读取 XX XXXX这个DTC的所有环境数据,ECU的返回值应该是59 06 XX XX XX AA BB CC DD.....,其中AA BB CCDD...代表的就是XX XX XX这个DTC产生时所一起存储的环境数据。
- sub-function = 0x0E(reportMostRecentConfirmedDTC)
sub-function = 0x0E时,不需要parameter。0x0E表示,要求ECU上报最近的一条被置为confirm的DTC。上文介绍过0x86服务,sub-function = 0x0E的19服务通常被作为参数传递给86指令,要求ECU在发生DTC存储的时候进行自动上报,即19 0E这两个字节的指令被嵌入到86服务的命令中。这条命令在开发阶段会用到,比如验证某个故障路径是否生效。
输入输出控制功能单元
InputOutputControlByIdentifier (0x2F)
2F这个服务即利用ID对ECU的输入输出进行控制,经常会在生产线上使用来验证零部件的功能。比如,在总装阶段,工人需要验证车上的各种功能是否正常,例如四个车窗的升降是否正常,如果挨个开关去按,那效率很低,如果通过一个诊断命令就能够观察到车窗升降的情况,效率则高得多。
比如,ECU接收一个输入信号A,我们就可以利用2F给这个A赋个我们需要的值;ECU对某个执行器B进行控制,我们就可以利用2F服务再配上某些特定的参数来实现对B的控制,例如门控对车窗升降、后视镜折叠等的控制。
2F服务的request由4部分组成
第一部分是SID,1个字节,值为0x2F。
第二部分是DID,2个字节,用于标识被控制的IO对象,例如下文举例0x9B00(进气口门位置)。
第三部分是controlOptionRecord,1个字节,用于标识控制类型,以及若干byte由厂家自定义使用的controlState。UDS明确定义了四种控制类型:
- 0x00 将控制权还给ECU,即结束控制
- 0x01 将DID标识的对象的输入信号、内部参数、输出信号等设为默认值
- 0x02 将DID标识的对象的的输入信号、内部参数、输出信号等冻结住
- 0x03 将DID标识的对象的的输入信号、内部参数、输出信号进行设置,其实就相当于开始了对ECU的控制,这种控制类型其后会跟着第五个字节,可以表示控制对象的数字量或模拟量。
举例来说:
使用2F控制Air Inlet Door Position (进气口门位置),用DID(标识符)=0x9B00来标识进气口门的位置。
Air Inlet Door Position [%] = decimal(Hex) * 1 [%] ,即用一个百分比来表示这个位置。
step1:
tester 发送22 9B 00读取当前进气口门的位置,这里22即SID,0x9B00即第二三字节DID。
ECU返回62 9B 00 0A ,这里 0x0A = 10(dec),即表示当前位置是10%
(UDS定义可以用22服务读取2F服务中使用的dataIdentifier,返回值是状态信息,具体的状态信息是什么,则由使用者自定义了。)
step2:
tester 发送2F 9B 00 03 3C ,表示要将进气口门的位置调整到60%,0x3C = 60(dec)表示要将控制对象的模拟量设定为60%。
ECU返回6F 9B 00 03 0C,表示接受控制,当前进气口门的位置为12%。因为ECU收到请求后是立刻响应的,而门的位置调节需要时间,所以还没有达到60%。
step3:
过一段时间后tester 发送22 9B 00读取当前进气口门的位置
ECU返回62 9B 00 3C , 0x3C = 60(dec),表示当前位置已经到了60%
step4:
tester 发送2F 9B 00 00,将控制权交还给ECU
ECU返回6F 9B 00 00 3A,表示接受请求,当前位置为58%
step5:
tester 发送2F 9B 00 02,冻结9B 00这个ID所代表的进气口门位置这个状态
ECU返回6F 9B 00 02 32,表示接受请求,当前位置保持在50%
此外,2F服务存在一个问题(引自知乎作者“心灵之花”),如果通过2F服务修改了某个值,后续也不把控制权还给ECU,那么这个修改的有效时间是一直持续下去?正确的做法是如果扩展会话超时,即切回默认会话,此时控制权应还给ECU,毕竟 2F的03子功能是"暂时接管控制权"。
例行程序控制功能单元
RoutineControl (0x31)
31服务是调用ECU内置的一些操作序列的接口,这个服务的应用很灵活,因为厂家可以根据自己的需要为ECU定义各种各样的内部操作,而要执行这些操作只需要调用31服务就好了。典型的用途包括检查边界条件、清除闪存、对数据进行较验、对软硬件依赖性进行校验等,甚至有需要的话可以进行恢复出厂设置的操作,还有很多与ECU自身逻辑功能相关的操作也可以定义。
31服务的request由4部分组成:
第一部分是SID,1个字节,值为0x31。
第二部分是sub-function,1个字节,启动(0x01)、停止(0x02)、查询结果(0x03)。
第三部分是routineIdentifier,2字节,任务ID,用于标识要执行的routine。
第四部分是routineControlOptionRecord,这是一个可选参数,用于标识routine执行时所需要的参数,由各家自定义它的内容。
举个例子:
假设用0x0809这个ID来代表检查ECU是否满足软件刷写条件(比如车速、转速为0,KL15接通等)的routine。
tester发送31 01 08 09来启动0x0809这个routine
如果所有条件都满足,则ECU返回71 01 08 09作为echo即可,如果条件不满足,则ECU返回7F 71 01 08 09 XX YY ZZ,后边的XX YY ZZ则表明哪些条件不满足,具体的内容就由厂家自己定义了。
上传与下载功能单元
关于ECU升级数据的传输,是通过34(请求下载)、36(传输数据)、37(请求退出传输)等服务来完成的。由于汽车ECU中用于缓存诊断服务数据的buffer大小有限,所以当我们需要读取或写入超过buffer大小的数据时,就无法简单地使用2E和22服务了,因此UDS据此定义了几个将大块数据写入或读出的服务,即数据下载和上传。
Upload Download functional unit总共定义了5个诊断服务,分别是:
RequestDownload (0x34):诊断仪向ECU请求下载数据
RequestUpload (0x35)诊断仪向ECU请求上传数据
TransferData(0x36) 诊断仪向ECU传数据(下载),或者服务器向客户端传数据(上传)
RequestTransferExit(0x37)数据传输完成,请求退出
RequestFileTransfer(0x38) 传输文件的操作,可以用于替代上传下载的服务。
下图是数据下载的简略过程,用到了34,36,37这三个服务,如果是上传的话,34服务被35服务替换,数据传输方向变一下,就可以了。
RequestDownload(0x34)
0x34服务用于启动下载传输,作用是告知ECU准备接受数据,ECU则通过0x74 response告诉诊断仪自己是否允许传输,以及自己的接受能力是多大。
0x34服务的请求格式包括5个部分
第一部分是SID,1个字节,值为0x34。
第二部分是dataFormatIdentifier,1个字节,用于指示数据压缩和加密的方法。其中,第7-4位定义了压缩方法;第3-0位定义了加密方法。该字节为0x00时则表示既没有使用压缩方法也没有使用加密方法。0x00外的其他值的定义是由车产自行规定的。
第三部分是addressAndLengthFormatIdentifier,1个字节,用于指示后面两个部分所占用的字节数,高4bit表示memorySize所占的字节长度,低4bit表示memoryAddress所占的字节长度。在这个例子中我将这两个值分别设置为n和m。
第四部分是memoryAddress,m个字节,由addressAndLengthFormatIdentifier中的低4bit指示。含义是要写入数据在ECU中的逻辑地址。
第五部分是memorySize,n个字节,由addressAndLengthFormatIdentifier中的高4bit指示。含义是要写入数据的字节数。
ECU收到请求之后,如果允许传输的话,会给出如下response
第一部分是Response SID=0x74
第二部分是1个byte的dataFormatIdentifier作为echo
第三部分是maxNumberOfBlockLength,长度不定,表示可以通过0x36服务一次传输的最大数据量。
TransferData(0x36)
如果34服务得到了正确响应,tester就要启动数据传输过程了,使用的就是36服务。36服务的格式如下。
第一部分是SID,1个字节,值为0x36。
第二部分是blockSequenceCounter,1个字节,标识当前传输的是第几个数据块,即帧序号,或者简单地说就是第几次调用36服务。
第三部分是transferRequestParameterRecord,传输的数据。第次传输数据量的上限就是34服务响应中的maxNumberOfBlockLength。
举例:如果ECU告知tester,maxNumberOfBlockLength = 20(来自$34服务的echo),也就是说tester每次通过36服务只能发送最多20个字节,其中还包括了SID和blockSequenceCounter,所以实际上每次可传的数据信息只有18个字节。如果tester要传的数据为50个字节,则需要传输三次,每次分别传输18,18,14个字节,即调用3次36服务。
36的响应很简单,就是一个字节的Response SID再加一个字节的blockSequenceCounter作为echo。
RequestTransferExit(0x37)
37服务用于退出上传下载,如果之前的34和36服务都顺利执行完成,那么37服务就可以得到ECU的positive response。
格式很简单,请求就是37,正确响应就是77,都是一个字节。
如果前面的36服务没有执行完成,以我前面举的例子来说,比如这个数据块有50个字节,但是tester只发了两次36服务传了36个字节,那么这次传输对于ECU来说是失败的,所以ECU应该给出NRC 0x7F 37 24,表示诊断序列执行有错误。
参考文档:
UDS诊断系列之一 汽车诊断简介_ChenglimK的博客-CSDN博客
关于汽车诊断OBD的理解(ISO15031-5)_obd诊断_AgingMoon的博客-CSDN博客
UDS诊断系列之二 ISO14229协议介绍(上)_ChenglimK的博客-CSDN博客