在嵌入式系统领域,UDS(Unified Diagnostic Services)诊断协议被广泛应用于ECU诊断、汽车行业以及其他嵌入式设备中。
在嵌入式开发面试中,面试官经常会问关于UDS诊断的相关问题,以考察候选人在这方面的专业知识及实际应用能力。
以下是一些常见的UDS诊断问题以及详细的解答,文章设计上侧重于深入分析和实际应用。
1
UDS协议的层次结构
在开放系统互连(OSI)基本参考模型中规定了各类物理层通信对应部分的UDS诊断协议。
例如,CAN通信(ISO 11898-1、ISO 11898-2和ISO 11898-3)在应用层的UDS诊断协议是ISO 14229-1和ISO 14229-3。
2
UDS有哪些常用服务?
3
UDS 协议中的不同帧类型有哪些?
UDS 通信使用以下主要帧类型:
请求帧:由客户端发起,用于调用服务(格式:SID + 参数)。
响应帧:由服务器发送;可为正面(SID + 0x40 + 数据)或负面(0x7F + SID + NRC 码)。
负面响应帧:表示错误,例如 0x7F 0x22 0x12 表示“子函数不支持”,用于读取无效 DID。
正面响应帧:确认成功执行,通常包含请求数据。 这些帧确保可靠通信;例如,在多帧响应中,传输层使用流控制帧管理缓冲。
4
UDS报文结构与响应机制
以诊断和通信管理功能单元(Diagnostic and Communication Management functional unit )为例,服务请求和响应有两类:一类是具有Subfunction(子功能),另一类是不具有Subfunction(子功能)。
不具有Subfunction(子功能)的UDS诊断服务请求和响应机制如下图所示:
诊断方(Tester)向ECU发送指定的请求数据(Request),这条数据中需要包含SID,且SID处于该应用层数据的第一个字节。
ECU接收到请求数据(Request)后会返回响应,可返回肯定响应或者否定响应。
肯定响应(Positive Response)格式为:(SID+0X40)+数据。例如,请求0X10服务,肯定响应第1个字节为0X50;请求0X22服务,肯定响应第1个字节为0X62。
否定响应(Negative Response)格式为:0X7F+SID+NRC。例如,请求0X10服务,否定响应第1个字节为固定的0X7F,第2个字节为0X10,第3个字节为NRC。NRC是否定响应码,可以根据返回的NRC判断是什么原因导致的否定响应。
具有Subfunction(子功能)的UDS诊断服务请求和响应机制如下图所示:
诊断方(Tester)向ECU发送指定的请求数据(Request),这条数据中需要包含SID,且SID处于该应用层数据的第一个字节。
ECU接收到请求数据(Request)后会返回响应,可返回肯定响应或者否定响应。
肯定响应(Positive Response)格式为:(SID+0X40)+Subfunction(子功能)+数据。例如,请求0X10服务,Subfunction(子功能)为0X02,肯定响应第1个字节为0X50,第2个字节为0X02。
否定响应(Negative Response)格式为:0X7F+SID+NRC。例如,请求0X10服务,否定响应第1个字节为固定的0X7F,第2个字节为0X10,第3个字节为NRC。NRC是否定响应码,可以根据返回的NRC判断是什么原因导致的否定响应。
5
常见NRC代码
6
详细说明服务 0x27 (SecurityAccess) 的工作流程
服务 0x27 (安全访问) 是UDS中用于保护ECU关键功能(如刷写、修改标定参数等)的核心机制。它采用 “种子(Seed)-密钥(Key)”质询-响应 机制来验证客户端的合法性。
详细工作流程如下:
第一步:客户端请求种子 (Request Seed)
- 客户端向ECU发送请求,子功能为奇数,代表请求种子。例如,请求第一级安全访问的种子:27 01。
- ECU内部会生成一个随机或伪随机的“种子”(通常是2-16字节的随机数),并将其返回给客户端。
- ECU响应:67 01 [Seed_Bytes]。例如 67 01 A1 B2 C3 D4。同时,ECU内部启动一个定时器,等待客户端发送密钥。
第二步:客户端发送密钥 (Send Key)
- 客户端和ECU事先约定了一个相同的、保密的算法。客户端使用这个保密算法和接收到的种子 [A1 B2 C3 D4] 计算出一个“密钥”。
- 客户端将计算出的密钥发送给ECU。子功能为对应的偶数(请求子功能+1)。例如:27 02 [Key_Bytes]。
第三步:ECU验证密钥
- 0x35 (Invalid Key): 密钥错误。
- 0x36 (Exceeded Number Of Attempts): 尝试次数超限,ECU会锁定一段时间,防止暴力破解。
- 0x37 (Required Time Delay Not Expired): 两次尝试之间的时间间隔太短。
- ECU内部也使用同样的保密算法和之前发送的种子,计算一个期望的密钥。
- 比较自己计算的密钥与从客户端收到的密钥是否一致。
- 验证成功:ECU进入“已解锁”状态,并返回肯定响应 67 02。此时客户端就可以访问受保护的服务了。
- 验证失败:ECU返回否定响应,常见的NRC有:
7
假如ECU多次错误输入Key会发生什么?
ECU会进入安全锁定状态(Security Lock),需要冷启动或超时解除。
该机制防止暴力破解。
8
谈谈你对服务 0x19 (ReadDTCInformation) 的理解
服务 0x19 (读取DTC信息) 是诊断的灵魂功能,用于从ECU的故障存储器中读取诊断故障码(DTC)及其相关信息。它拥有非常多的子功能,用于实现灵活的故障查询。
常用子功能举例:
- 0x01 (reportNumberOfDTCByStatusMask):根据一个状态掩码,报告满足条件的DTC数量。
- 0x02 (reportDTCByStatusMask):根据一个状态掩码,报告所有满足条件的DTC及其状态字节。
- 0x0A (reportSupportedDTC):报告ECU支持的所有DTC列表。
- 0x06 (reportDTCSnapshotDataByIdentifier):读取指定DTC的冻结帧数据。
9
DTC的状态字节 (Status Byte) 是如何构成的?
DTC状态字节 (DTC Status Byte) 是精髓所在,它用一个字节的8个比特位来精确描述一个DTC的当前状态,是判断故障性质的关键。
其结构如下:
核心位解释:
- bit0: testFailed:当前状态,代表该故障的诊断测试在当前时刻是否失败。它是一个瞬时状态,非常灵敏。
- bit1: testFailedThisOperationCycle:本驾驶循环状态,代表在本驾驶循环中,该故障是否曾经发生过(testFailed 位是否曾经置1)。
- bit2: pendingDTC:“待定”故障。通常指故障在本驾驶循环中已经发生,但还未满足确认(confirmed)的条件(例如,需要连续多个驾驶循环都发生)。
- bit3: confirmedDTC:“已确认”故障。代表故障已经满足了所有恶化和老化的条件,被正式确认为一个“历史”或“当前”的存储故障。这是点亮仪表盘故障灯(MIL)的主要依据。
- bit6: testFailedSinceLastClear:自上次使用服务 0x14 (ClearDiagnosticInformation) 清除故障码以来,该故障是否曾经发生过。
10
UDS Bootloader的典型升级流程
以下是固件升级服务的典型顺序:
10 02 → 进入编程会话 27 01/27 02 → 安全认证 34 xx xx → 请求下载 36 ... → 分块传输数据 37 → 结束传输 31 01 FF00 → 校验程序 11 01 → 软复位
更详细的步骤可见下图。
11
Tester Present(0x3E)的作用
UDS协议要求诊断会话在超时TsessionTimeout(典型值5s)内保持活跃。
若测试仪无操作,ECU会自动返回默认会话。
因此,上位机需周期性发送:
023E 00 → TesterPresent
该命令本身无功能性意义,仅维持诊断连接。
12
写一段代码,解析UDS请求帧
typedef struct {
uint8_t SID;
uint8_t SubFunc;
uint8_t data[8];
uint8_t len;
} UDS_Msg_t;
void UDS_ParseRequest(uint8_t *rxBuf, uint8_t len)
{
UDS_Msg_t req;
req.len = rxBuf[0];
req.SID = rxBuf[1];
req.SubFunc = rxBuf[2];
switch(req.SID)
{
case 0x10:
if(req.SubFunc == 0x02)
UDS_SendResponse(0x50, 0x02); // 编程会话
break;
case 0x3E:
UDS_SendResponse(0x7E, 0x00); // TesterPresent响应
break;
default:
UDS_SendNegResponse(req.SID, 0x11); // 服务不支持
break;
}
}13
UDS 中的物理寻址和功能寻址有何区别?
物理寻址:使用唯一地址针对单一 ECU(例如,CAN ID 0x7A1 请求,0x7A9 响应)。适用于 ECU 特定任务如重编程。功能寻址:广播到组或功能(例如,CAN ID 0x7DF),允许多个 ECU 响应(如适用)。它高效用于全局查询,但风险碰撞,通过响应抑制缓解。 这种区别优化车辆网络带宽,物理寻址更适合敏感操作的安全性。14
UDS 中的诊断会话是什么,有哪些类型?
诊断会话定义 ECU 的操作模式,控制服务可用性。类型包括:
- 默认会话(0x01):基本访问,用于常规诊断。
- 编程会话(0x02):用于软件更新,通常重置 ECU。
- 扩展会话(0x03):高级测试,例如 I/O 控制。
15
当诊断请求的报文长度超过一帧CAN报文时,UDS是如何处理的?
当UDS报文(如包含长DID数据的62响应)超过7字节(单帧CAN网络,1字节PCI)时,就需要CAN-TP(也称ISO-TP)来进行分包和流控。
CAN-TP定义了四种帧类型 (PCI - Protocol Control Information):
单帧 (SF - Single Frame)
- 用于传输长度小于等于7字节的短报文。
- PCI字节高4位为0,低4位为报文长度。
- 示例:03 22 F1 90 (请求读取DID F190)。
首帧 (FF - First Frame)
- 用于长报文的第一帧,宣告一次多帧传输的开始。
- PCI字节高4位为1,后面12位表示整个长报文的总长度。
- 示例:10 1A 62 F1 90 ... (表示这是一个多帧响应,总长度为 0x1A = 26字节)。
连续帧 (CF - Consecutive Frame)
- 用于传输长报文的后续数据帧。
- PCI字节高4位为2,低4位是一个从1开始,模16循环的序列号(SN),用于接收方确认帧的顺序。
- 示例:21 ..., 22 ...
流控帧 (FC - Flow Control)
- FS (Flow Status):0=继续发送(CTS), 1=等待(Wait), 2=溢出(Overflow)。
- BS (Block Size):在收到下一个流控帧前,发送方可以连续发送多少个连续帧。BS=0表示可以无限制连续发送。
- STmin (Separation Time minimum):发送方发送两个连续帧之间的最小时间间隔。
- 由接收方发送给发送方,用于控制数据的发送速率和流量。
- PCI字节高4位为3。
- 关键参数:
16
请解释CAN-TP(ISO 15765-2)的多帧通信机制
多帧通信流程:
- 发送方发送一个首帧(FF)。
- 接收方收到首帧后,回复一个流控帧(FC),告知发送方自己已经准备好接收,并指定BS和STmin。
- 发送方根据FC的指示,开始发送连续帧(CF)。
- 如果BS不为0,发送方在发送完一个Block的CF后,会暂停并等待接收方的下一个FC。
- 重复步骤3和4,直到所有数据发送完毕。
这个机制确保了即使在总线负载较高或接收方处理能力有限的情况下,长数据也能被可靠、有序地传输,而不会导致数据丢失或接收方缓冲区溢出。
我要赚赏金
