网易首页 > 网易号 > 正文 申请入驻

UDS(统一诊断服务)详解与C++代码示例

0
分享至


1. UDS概述

统一诊断服务(Unified Diagnostic Services,UDS)是ISO 14229标准定义的汽车电子诊断通信协议,广泛应用于ECU(电子控制单元)的故障检测、参数配置、软件升级等场景。UDS基于客户端-服务器模型,通常运行在CAN、LIN、以太网等物理总线上。其核心是一组预定义的服务标识符(Service Identifier,SID),每个SID对应一个特定的诊断功能。

UDS报文结构简单:一个字节的SID(请求)或响应SID(通常为SID+0x40),后跟可变长度的参数。若服务器无法处理请求,则返回0x7F(负响应码)加一个否定响应代码(NRC)。

本文将对UDS常用服务进行分类讲解,并给出C++实现的构建与解析示例。

2. UDS服务标识符(SIDs)及分类

下表整理了典型UDS服务的请求SID、响应SID(正响应时使用)及功能描述。响应SID通常由请求SID加上0x40得到,如0x10 -> 0x50,0x27 -> 0x67。

2.1 诊断和通信管理

请求SID

响应SID

服务名称

功能简述

0x10

0x50

诊断会话控制

切换ECU的会话模式(默认、编程、扩展)

0x11

0x51

ECU重置

请求ECU执行复位

0x27

0x67

安全访问

解锁受保护的服务(需种子密钥验证)

0x28

0x68

通信控制

启用/禁用ECU的消息收发

0x29

0x69

身份验证

基于PKI的高级身份验证

0x3E

0x7E

存活测试(Tester Present)

维持当前会话,防止自动退出

0x83

0xC3

访问定时参数

读取/修改通信计时参数

0x84

0xC4

安全数据传输

加密传输诊断数据(ISO 15764)

0x85

0xC5

控制DTC设置

暂时禁用/恢复故障码存储

0x86

0xC6

对事件的响应

ECU在特定事件时主动发送数据

0x87

0xC7

连接控制

设置诊断访问的波特率等参数


2.2 数据传输功能单元

请求SID

响应SID

服务名称

功能简述

0x22

0x62

按标识符读数据

读取由DID标识的数据(如VIN)

0x23

0x63

按地址读取内存

直接读取物理内存

0x24

0x64

按标识符读取标定数据

读取标定/缩放信息

0x2A

0x6A

按标识符定期读取数据

周期广播传感器数据

0x2E

0x6E

按标识符写数据

写入DID对应的数据

0x3D

0x7D

按地址写入内存

直接写物理内存

0x20

0x60

动态定义数据标识符

动态组合多个DID


2.3 存储数据传输功能单元

请求SID

响应SID

服务名称

功能简述

0x14

0x54

清除诊断信息

清除存储的DTC

0x19

0x59

读取DTC信息

读取故障码及其状态


2.4 输入输出控制功能单元

请求SID

响应SID

服务名称

功能简述

0x2F

0x6F

按标识符对输入输出进行控制

控制ECU的模拟/数字输入输出


2.5 例程控制功能单元

请求SID

响应SID

服务名称

功能简述

0x31

0x71

例程控制

启动/停止例程(如自检、擦除)


2.6 上传下载功能单元

请求SID

响应SID

服务名称

功能简述

0x34

0x74

请求下载

准备向ECU写入数据

0x35

0x75

请求上传

准备从ECU读取数据

0x36

0x76

传输数据

实际数据传输

0x37

0x77

请求传输退出

终止上传/下载过程

0x38

0x78

请求文件传输

文件级别的上传/下载


2.7 其他(负响应)

响应SID

含义

用法

0x7F

负响应

服务器无法处理请求,后跟一个字节的NRC

常见否定响应代码(NRC)例如:

  • 0x10 :不支持请求的SID

  • 0x11 :不支持子功能

  • 0x12 :子功能在本次会话无效

  • 0x13 :报文长度错误

  • 0x22 :条件不满足

  • 0x31 :请求超出范围

  • 0x33 :安全访问未解锁

3. 重要服务详解(附带场景) 3.1 诊断会话控制(0x10)
  • 作用 :切换ECU的诊断会话模式(默认会话、编程会话、扩展会话)。不同会话下可用的服务集合不同,例如刷写软件通常在编程会话中完成。

  • 请求格式 : [0x10] [子函数] ,子函数如 0x01 =默认会话, 0x02 =编程会话, 0x03 =扩展会话。

  • 响应格式 : [0x50] [子函数] [会话参数] ,会话参数包括P2ServerMax、P2*ServerMax等定时值。

3.2 安全访问(0x27)
  • 作用 :防止未授权操作。步骤:客户端发送“请求种子”子功能(如 0x01 ),ECU返回种子;客户端基于种子计算密钥并发送“发送密钥”子功能(如 0x02 );若匹配则解锁受保护的服务。

  • 子功能 :奇数请求种子,偶数发送密钥。同一组内奇偶对应(0x01/0x02,0x03/0x04…)。

3.3 存活测试(0x3E)
  • 作用 :客户端定期发送此服务告知ECU自己仍在线,ECU则保持当前会话不自动退回默认会话。子功能 0x00 或 0x80 (带标志位)。

3.4 读取数据(0x22)与写入数据(0x2E)
  • 数据标识符(DID) :两个字节,如 0xF190 表示VIN码。请求 [0x22] [DID_H] [DID_L] ,响应 [0x62] [DID_H] [DID_L] [数据…] 。写入类似,携带待写数据。

3.5 例程控制(0x31)
  • 子函数 : 0x01 启动, 0x02 停止, 0x03 请求结果。例程ID两字节,例如 0x0200 表示自检例程。请求 [0x31] [子函数] [例程ID_H] [例程ID_L] [可选参数] 。

3.6 上传下载(0x34/0x35/0x36/0x37)
  • 典型流程 :

    1. 客户端发送 0x34 (请求下载),描述地址、大小等。

    2. 服务器回复 0x74 ,确认最大块长度。

    3. 客户端循环发送 0x36 (传输数据)。

    4. 最后发送 0x37 (请求退出)。

3.7 负响应(0x7F)

当服务器无法执行请求时,返回[0x7F] [请求SID] [NRC]。例如,若未解锁安全访问就尝试写数据,可能返回0x7F 0x2E 0x33。

4. C++代码示例

以下代码演示如何构建常见的UDS请求,解析响应,并模拟一个简单的诊断会话控制服务。为简化,假设使用单帧传输(不超过CAN帧8字节)。

4.1 基础数据结构与工具函数

#include  
          
#include
#include
#include

// UDS报文结构
struct UdsMessage {
uint8_t sid; // 服务标识符
std::vector data; // 参数(不含SID)
};

// 打印字节数组
void printBytes(const std::vector& bytes, const std::string& prefix) {
std::cout << prefix << ": ";
for (auto b : bytes) {
std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)b << " ";
}
std::cout << std::dec << std::endl;
}

// 构建请求消息(SID + 参数)
UdsMessage buildRequest(uint8_t sid, const std::vector& params) {
return {sid, params};
}

// 将UdsMessage序列化为字节流
std::vector serialize(const UdsMessage& msg) {
std::vector result;
result.push_back(msg.sid);
result.insert(result.end(), msg.data.begin(), msg.data.end());
return result;
}
4.2 构建常用服务请求

// 诊断会话控制:子函数 (0x01默认, 0x02编程, 0x03扩展)
UdsMessage createDiagnosticSessionControl(uint8_t subFunction) {
return buildRequest(0x10, {subFunction});
}

// 安全访问:请求种子 (seedKeyId: 0x01, 0x03等)
UdsMessage createSecurityAccessRequestSeed(uint8_t seedKeyId) {
return buildRequest(0x27, {seedKeyId});
}

// 安全访问:发送密钥
UdsMessage createSecurityAccessSendKey(uint8_t seedKeyId, const std::vector& key) {
std::vector params;
params.push_back(seedKeyId); // 对应请求种子的子函数+1
params.insert(params.end(), key.begin(), key.end());
return buildRequest(0x27, params);
}

// 存活测试
UdsMessage createTesterPresent() {
return buildRequest(0x3E, {0x00}); // 子函数0x00常见
}

// 按标识符读数据 (DID两字节)
UdsMessage createReadDataByIdentifier(uint16_t did) {
return buildRequest(0x22, {static_cast(did >> 8), static_cast(did & 0xFF)});
}

// 例程控制启动 (例程ID两字节)
UdsMessage createRoutineControlStart(uint16_t routineId) {
return buildRequest(0x31, {0x01, static_cast(routineId >> 8), static_cast(routineId & 0xFF)});
}

// 请求下载 (address, size)
UdsMessage createRequestDownload(uint32_t address, uint32_t size) {
// 简化:地址长度4字节,大小4字节,不包含内存标识符
std::vector params;
params.push_back(0x00); // 内存标识符,此处简单填0
params.push_back(0x04); // 地址长度4字节
params.push_back(0x04); // 大小长度4字节
for (int i = 24; i >= 0; i -= 8) params.push_back((address >> i) & 0xFF);
for (int i = 24; i >= 0; i -= 8) params.push_back((size >> i) & 0xFF);
return buildRequest(0x34, params);
}
4.3 解析响应

// 解析正响应(检查是否为请求SID+0x40,并提取参数)
bool parsePositiveResponse(const std::vector& response, uint8_t requestSid, std::vector& outData) {
if (response.empty()) return false;
uint8_t expectedRespSid = requestSid + 0x40;
if (response[0] == 0x7F) { // 负响应
std::cout << "Negative response: NRC=" << std::hex << (int)response[2] << std::dec << std::endl;
return false;
}
if (response[0] != expectedRespSid) {
std::cout << "Unexpected response SID: " << std::hex << (int)response[0] << std::endl;
return false;
}
outData.assign(response.begin() + 1, response.end());
return true;
}


// 模拟ECU内部处理(演示)
std::vector simulateEcu(const UdsMessage& request) {
// 简单模拟:根据请求SID生成响应
std::vector resp;
switch (request.sid) {
case 0x10: { // 诊断会话控制
if (request.data.empty()) {
resp = {0x7F, 0x10, 0x13}; // 报文长度错误
} else {
uint8_t sub = request.data[0];
// 假设支持默认(0x01)和扩展(0x03)会话
if (sub == 0x01 || sub == 0x03) {
resp.push_back(0x50); // 正响应SID
resp.push_back(sub); // 回显子函数
resp.push_back(0x50); // P2ServerMax = 80ms(例)
resp.push_back(0x64); // P2*ServerMax = 100ms
} else {
resp = {0x7F, 0x10, 0x12}; // NRC: 子功能不支持
}
}
break;
}
case 0x22: { // 读数据
if (request.data.size() == 2) {
uint16_t did = (request.data[0] << 8) | request.data[1];
if (did == 0xF190) { // VIN模拟
resp.push_back(0x62);
resp.push_back(request.data[0]); resp.push_back(request.data[1]);
const char vin[] = "1HGCM82633A123456";
for (size_t i = 0; i < 17; ++i) resp.push_back(vin[i]);
} else {
resp = {0x7F, 0x22, 0x31}; // 请求超出范围
}
} else {
resp = {0x7F, 0x22, 0x13};
}
break;
}
case 0x3E: { // 存活测试
resp = {0x7E, 0x00}; // 正响应
break;
}
default:
resp = {0x7F, request.sid, 0x10}; // 不支持服务
break;
}
return resp;
}
4.4 主程序示例

int main() {
// 1. 发送诊断会话控制(扩展会话)
auto req = createDiagnosticSessionControl(0x03);
auto rawReq = serialize(req);
printBytes(rawReq, "Request: 0x10 (Extended Session)");
auto rawResp = simulateEcu(req);
printBytes(rawResp, "Response");
std::vector respData;
if (parsePositiveResponse(rawResp, 0x10, respData)) {
std::cout << "Session control success. SubFunction=0x" << std::hex << (int)respData[0] << std::endl;
}

// 2. 存活测试
req = createTesterPresent();
rawReq = serialize(req);
printBytes(rawReq, "Request: TesterPresent");
rawResp = simulateEcu(req);
printBytes(rawResp, "Response");
parsePositiveResponse(rawResp, 0x3E, respData); // 忽略数据

// 3. 按标识符读VIN
req = createReadDataByIdentifier(0xF190);
rawReq = serialize(req);
printBytes(rawReq, "Request: Read DID 0xF190");
rawResp = simulateEcu(req);
if (parsePositiveResponse(rawResp, 0x22, respData)) {
uint16_t did = (respData[0] << 8) | respData[1];
std::string vin(respData.begin()+2, respData.end());
std::cout << "Read DID 0x" << std::hex << did << " -> VIN: " << vin << std::endl;
}

// 4. 尝试不支持的服务 (0x31 例程控制)
req = createRoutineControlStart(0x0200);
rawReq = serialize(req);
printBytes(rawReq, "Request: Routine 0x0200 start");
rawResp = simulateEcu(req);
parsePositiveResponse(rawResp, 0x31, respData); // 会输出负响应

return 0;
}

输出示例:

Request: 0x10 (Extended Session): 10 03 
Response: 50 03 50 64
Session control success. SubFunction=0x3
Request: TesterPresent: 3e 00
Response: 7e 00
Request: Read DID 0xF190: 22 f1 90
Response: 62 f1 90 31 48 47 43 4d 38 32 36 33 33 41 31 32 33 34 35 36
Read DID 0xf190 -> VIN: 1HGCM82633A123456
Request: Routine 0x0200 start: 31 01 02 00
Response: 7f 31 10
Negative response: NRC=10
5. 总结

UDS为汽车诊断提供了标准化、可扩展的通信框架。本文介绍了核心服务标识符及其分类,详细阐述了诊断会话控制、安全访问、数据传输、上传下载等关键服务的用途和报文格式。通过C++代码示例,展示了如何构建常见UDS请求、模拟ECU响应并解析结果。实际开发中,UDS往往运行在CAN总线上,需要处理多帧传输(ISO 15765-2)、定时参数及安全算法,但本文的基本模式可应用于大多数诊断工具或ECU固件的实现。

掌握UDS服务是理解现代汽车电子架构的基础,开发者可根据ISO 14229标准进一步深入学习每个服务的完整参数和NRC定义。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
事态已经全面升级!赖清德有可能成为新中国历史上,唯一一位在任台湾地区领导人中出现重大变故的人物

事态已经全面升级!赖清德有可能成为新中国历史上,唯一一位在任台湾地区领导人中出现重大变故的人物

人生录
2026-09-11 00:05:21
严子怡创雨战世界历史第一好成绩,日本电视台:不知道怎么解说了

严子怡创雨战世界历史第一好成绩,日本电视台:不知道怎么解说了

杨华评论
2026-09-28 04:29:40
确认了!她系台湾间谍情报机关人员

确认了!她系台湾间谍情报机关人员

焦作日报
2026-09-27 15:33:27
53岁知名科普作家吴京平告别仪式在上海举办,挚友汪诘:未来或用技术让他继续陪伴听众

53岁知名科普作家吴京平告别仪式在上海举办,挚友汪诘:未来或用技术让他继续陪伴听众

极目新闻
2026-09-27 17:40:22
惊天警报!久明派急速夺权,克里姆林宫权力更迭已进入最后倒计时

惊天警报!久明派急速夺权,克里姆林宫权力更迭已进入最后倒计时

军情观察家
2026-09-27 22:34:40
深夜,突然跳水!特朗普,最新发声

深夜,突然跳水!特朗普,最新发声

中国基金报
2026-09-28 00:11:40
“第一次感觉离死亡这么近!”男子称喝了几口隔夜鱼汤差点窒息,孩子哭着喊“爸爸不要死”……医疗专家解析

“第一次感觉离死亡这么近!”男子称喝了几口隔夜鱼汤差点窒息,孩子哭着喊“爸爸不要死”……医疗专家解析

都市快报橙柿互动
2026-09-28 00:14:52
青年男女疑高铁上不雅举动引热议 女方还有腹肌 网友:肯定练过

青年男女疑高铁上不雅举动引热议 女方还有腹肌 网友:肯定练过

环球趣闻分享
2026-09-27 13:36:44
妻子曝刘欢真正死因!独女是诱因,错过5年抢救期,一度恶化致死

妻子曝刘欢真正死因!独女是诱因,错过5年抢救期,一度恶化致死

风月得自难寻
2026-09-27 18:01:52
这个中秋,三四线相亲市场崩了?

这个中秋,三四线相亲市场崩了?

魔都囡
2026-09-27 11:01:54
孙颖莎:我可能等不到下届亚运会了 王曼昱:莎莎有很多地方值得我学习

孙颖莎:我可能等不到下届亚运会了 王曼昱:莎莎有很多地方值得我学习

中国青年报
2026-09-27 21:38:09
“45秒,全没了!”柏林宣布退出,奥运会从顶级IP沦为财政噩梦

“45秒,全没了!”柏林宣布退出,奥运会从顶级IP沦为财政噩梦

史智文道
2026-09-27 19:19:01
冷门炸裂!0-4,两大名将黯然离场,王楚钦张本智和成最大遗憾!

冷门炸裂!0-4,两大名将黯然离场,王楚钦张本智和成最大遗憾!

军科零零
2026-09-27 11:06:05
耿同学又出手!揭《Nature》一论文造假,24个原始值完全一致,通讯作者已承认并撤稿

耿同学又出手!揭《Nature》一论文造假,24个原始值完全一致,通讯作者已承认并撤稿

材料科学与工程
2026-09-24 11:48:39
震惊!网传杭州商K整治引发连锁反应:大批高奢包急售,二奢市场震动,美女扎堆申硕或相亲

震惊!网传杭州商K整治引发连锁反应:大批高奢包急售,二奢市场震动,美女扎堆申硕或相亲

火山詩话
2026-09-27 17:34:05
河南一技校101名毕业生入职北大,所涉专业系全国唯一,该校曾入职北大的毕业生:有和北大人才中心签约的,也有劳务派遣

河南一技校101名毕业生入职北大,所涉专业系全国唯一,该校曾入职北大的毕业生:有和北大人才中心签约的,也有劳务派遣

极目新闻
2026-09-27 19:00:11
预赛给自己打0分的吴艳妮,在名古屋亚运会收获一枚铜牌

预赛给自己打0分的吴艳妮,在名古屋亚运会收获一枚铜牌

封面新闻
2026-09-27 21:09:39
邓亚萍谈日本男单全军覆没:男团夺冠后兴奋过了头,能战胜国乒出乎他们的意料;张本智和对中国队做了充分的准备,单打他的心态不一样了

邓亚萍谈日本男单全军覆没:男团夺冠后兴奋过了头,能战胜国乒出乎他们的意料;张本智和对中国队做了充分的准备,单打他的心态不一样了

极目新闻
2026-09-27 09:04:26
李克勤演唱会迟到,救场歌手连唱近20首,本人表示:“3万人的演出这还是第一次,之前最多是五六千人”

李克勤演唱会迟到,救场歌手连唱近20首,本人表示:“3万人的演出这还是第一次,之前最多是五六千人”

韩小娱
2026-09-27 16:58:06
20名“双一流”大学生、研究生"翻墙"被处分 ,网传被举报:“一个姐们差一名保研,拿翻墙这事把前面所有人全举报了”

20名“双一流”大学生、研究生"翻墙"被处分 ,网传被举报:“一个姐们差一名保研,拿翻墙这事把前面所有人全举报了”

双一流高校
2026-09-28 00:09:38
2026-09-28 08:36:49
新能源自动驾驶 incentive-icons
新能源自动驾驶
专注于半导体行业资讯
1015文章数 348关注度
往期回顾 全部

科技要闻

星舰第14飞,为什么准备绕地球六圈?

头条要闻

小伙汽车电瓶被偷刚报完案车又被砸 强忍蚊虫蹲守一宿

头条要闻

小伙汽车电瓶被偷刚报完案车又被砸 强忍蚊虫蹲守一宿

体育要闻

114项指控成立,曼城已经完蛋了吗?

娱乐要闻

刘欢去世后谣言四起,韩磊被翻旧账

财经要闻

“为了看短剧,我妈两年花了22万 ”

汽车要闻

MAZDA EZ-60激光版上市 焕新全系11.39万元起

态度原创

旅游
本地
亲子
房产
公开课

旅游要闻

打开草原天路的四种方式

本地新闻

中秋逛白塔寺,体验国医妙荟雅集

亲子要闻

深度长文:2.5 亿精子闯关,奔赴 10 厘米外的卵子,最终赢家只有 1 个

房产要闻

全年霸榜TOP1!南海・叁號院周年官宣:新作即将登场

公开课

李玫瑾:为什么性格比能力更重要?

无障碍浏览 进入关怀版