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

UDS 0x85和0x22服务原理及代码示例

0
分享至


1. 诊断故障码设置控制服务 (ControlDTCSetting, 0x85) 1.1 服务概述

诊断故障码设置控制服务(0x85)用于动态地启用或禁用ECU内部诊断故障码(DTC)的记录功能。该服务通常用于维修或测试场景,避免在特定操作(如刷写、标定)期间因非真实故障产生误报。

根据ISO 14229-1标准,本服务具备以下关键行为:

  • 抑制/恢复记录:通过子函数参数指示ECU停止或重新开始记录DTC。

  • 会话层时序影响:若当前会话模式下抑制了DTC记录,当会话层时序参数(如P2Server_max)超时导致ECU自动返回默认会话(Default Session,0x01),DTC记录应自动恢复。

  • 复位影响:ECU执行任何硬件复位(上电复位、外部复位等)后,DTC记录功能恢复为默认允许状态。

  • 与清除服务联动:当诊断仪发送ClearDiagnosticInformation(0x14)服务清除DTC时,ECU必须重新开启DTC记录(即使之前处于抑制状态)。

1.2 报文格式 1.2.1 请求报文

字节序号

参数名称

值(hex)

0

SID

0x85

服务标识符

1

sub-function

0x01–0x02

DTC设置类型:
0x01 = off(停止记录)
0x02 = on(开始记录)

2…n

可选参数(保留)

标准中通常无额外参数,部分OEM扩展使用


注意:子函数字节的高四位为suppressPosRspMsgIndicationBit(0x00表示需要正响应),低四位为实际控制类型。
1.2.2 正响应报文

字节序号

参数名称

值(hex)

0

SID + 0x40

0xC5

服务正响应标识符

1

sub-function

0x01或0x02

回显请求中的控制类型

2…n

可选参数

标准无后续数据


1.2.3 负响应报文

字节序号

参数名称

值(hex)

0

0x7F

0x7F

负响应标识符

1

SID

0x85

原始服务标识符

2

NRC

见下表

负响应码(Negative Response Code)

常用NRC:

NRC

含义

0x12

子函数不支持(sub-function无效)

0x13

请求报文长度错误

0x22

条件不满足(例如在非扩展会话下请求)

0x31

请求超出范围(参数错误)


2. 通过标识符读取数据服务 (ReadDataByIdentifier, 0x22) 2.1 服务概述

通过数据标识符(DID,Data Identifier)读取数据服务允许诊断仪从ECU的存储器中读取一个或多个指定DID对应的数据记录。DID为两个字节(0x0000–0xFFFF),由车厂定义。

标准支持单请求多DID,但多数实现仅支持单个DID。下文以单DID为例说明。

2.2 报文格式 2.2.1 请求报文

字节序号

参数名称

值(hex)

0

SID

0x22

服务标识符

1

DID 高字节

0x00–0xFF

数据标识符高位

2

DID 低字节

0x00–0xFF

数据标识符低位

3…n

后续DID(可选)

多DID时重复字节1-2


2.2.2 正响应报文

字节序号

参数名称

值(hex)

0

SID + 0x40

0x62

服务正响应标识符

1

DID 高字节

0x00–0xFF

回显请求中的DID高位

2

DID 低字节

0x00–0xFF

回显请求中的DID低位

3…m

数据记录

可变

该DID对应的数据值

m+1…n

下一个DID+数据

无(多DID时重复)

仅当请求多个DID时存在


2.2.3 负响应报文

字节序号

参数名称

值(hex)

0

0x7F

0x7F

负响应标识符

1

SID

0x22

原始服务标识符

2

NRC

见下表

负响应码

常用NRC:

NRC

含义

0x13

请求报文长度错误

0x14

数据标识符不支持

0x22

条件不满足

0x31

请求超出范围(DID有效但无法读取)


3. C++代码实现示例

以下代码模拟一个简化但符合UDS行为规范的ECU,实现了:

  • ControlDTCSetting(0x85) 服务。

  • ReadDataByIdentifier(0x22) 服务。

  • 与ClearDiagnosticInformation(0x14) 的联动。

  • 会话超时与复位后自动恢复DTC记录的逻辑(通过定时器和复位标志模拟)。

#include  

#include
#include
#include
#include
#include
#include

// ---------- 辅助工具函数 ----------
// 将字节向量打印为十六进制
void printHex(const std::vector& data, const std::string& prefix = "") {
std::cout << prefix;
for (uint8_t b : data) {
printf("%02X ", b);
}
std::cout << std::endl;
}

// ---------- UDS 服务定义 ----------
const uint8_t SID_CONTROL_DTC_SETTING = 0x85;
const uint8_t SID_READ_DATA_BY_IDENTIFIER = 0x22;
const uint8_t SID_CLEAR_DIAG_INFO = 0x14;

// 子函数定义 (ControlDTCSetting)
const uint8_t DTC_SETTING_OFF = 0x01;
const uint8_t DTC_SETTING_ON = 0x02;

// DID 定义(示例)
const uint16_t DID_VIN = 0xF190;
const uint16_t DID_SW_VERSION = 0xF187;
const uint16_t DID_ECU_SERIAL = 0xF1A0;

// 负响应码 (NRC)
const uint8_t NRC_SUB_FUNCTION_NOT_SUPPORTED = 0x12;
const uint8_t NRC_INCORRECT_MESSAGE_LEN = 0x13;
const uint8_t NRC_REQUEST_OUT_OF_RANGE = 0x31;
const uint8_t NRC_CONDITIONS_NOT_CORRECT = 0x22;
const uint8_t NRC_DATA_IDENTIFIER_NOT_SUPP = 0x14;

// 简单模拟ECU环境
class EcuSimulator {
public:
EcuSimulator() : dtcRecordingEnabled_(true), currentSession_(0x01) // 默认会话
{
// 初始化模拟数据
vin_ = "1HGCM82633A123456";
swVersion_ = "2.1.0";
ecuSerial_ = "ECU_ABC123";
}

// 接收诊断请求(完整CAN帧数据域),返回响应数据
std::vector handleRequest(const std::vector& request) {
if (request.empty()) return buildNegativeResponse(0x00, NRC_INCORRECT_MESSAGE_LEN);

uint8_t sid = request[0];
switch (sid) {
case SID_CONTROL_DTC_SETTING:
return handleControlDTCSetting(request);
case SID_READ_DATA_BY_IDENTIFIER:
return handleReadDataByIdentifier(request);
case SID_CLEAR_DIAG_INFO:
return handleClearDiagnosticInfo(request);
default:
return buildNegativeResponse(sid, NRC_REQUEST_OUT_OF_RANGE);
}
}

// 模拟ECU复位(例如调用此函数后恢复DTC记录)
void performReset() {
std::cout << "[ECU] Performing reset...\n";
dtcRecordingEnabled_ = true; // 复位后恢复DTC记录
// 可选:切换到默认会话
currentSession_ = 0x01;
}

// 模拟会话超时(例如长时间无请求自动调用此函数)
void sessionTimeout() {
if (currentSession_ != 0x01) {
std::cout << "[ECU] Session timeout, switching to default session (0x01)\n";
currentSession_ = 0x01;
dtcRecordingEnabled_ = true; // 根据标准,会话超时返回默认会话后应恢复DTC记录
}
}

// 获取当前DTC记录状态(供外部监控)
bool isDtcRecordingEnabled() const { return dtcRecordingEnabled_; }

private:
bool dtcRecordingEnabled_; // DTC记录使能标志
uint8_t currentSession_; // 当前会话(0x01=默认, 0x02=编程等)
// 模拟数据
std::string vin_;
std::string swVersion_;
std::string ecuSerial_;

// 构建负响应
std::vector buildNegativeResponse(uint8_t sid, uint8_t nrc) const {
return {0x7F, sid, nrc};
}

// 处理 0x85 ControlDTCSetting
std::vector handleControlDTCSetting(const std::vector& req) {
// 最小长度:SID(1) + sub-function(1) = 2
if (req.size() < 2) {
return buildNegativeResponse(SID_CONTROL_DTC_SETTING, NRC_INCORRECT_MESSAGE_LEN);
}

uint8_t subFunc = req[1];
// 低四位为控制类型,高四位为抑制正响应标志(本例忽略抑制标志)
uint8_t controlType = subFunc & 0x0F;

// 可选:检查会话条件(例如只在扩展会话下允许)
if (currentSession_ != 0x02) { // 假设0x02为扩展诊断会话
return buildNegativeResponse(SID_CONTROL_DTC_SETTING, NRC_CONDITIONS_NOT_CORRECT);
}

bool newState;
switch (controlType) {
case DTC_SETTING_OFF:
newState = false;
break;
case DTC_SETTING_ON:
newState = true;
break;
default:
return buildNegativeResponse(SID_CONTROL_DTC_SETTING, NRC_SUB_FUNCTION_NOT_SUPPORTED);
}

dtcRecordingEnabled_ = newState;
std::cout << "[ECU] DTC recording has been " << (dtcRecordingEnabled_ ? "ENABLED" : "DISABLED")
<< " via 0x85 service.\n";

// 正响应:0xC5 + sub-function(原样返回)
return {static_cast(SID_CONTROL_DTC_SETTING + 0x40), subFunc};
}

// 处理 0x22 ReadDataByIdentifier
std::vector handleReadDataByIdentifier(const std::vector& req) {
// 最小长度:SID(1) + DID(2) = 3
if (req.size() < 3) {
return buildNegativeResponse(SID_READ_DATA_BY_IDENTIFIER, NRC_INCORRECT_MESSAGE_LEN);
}

uint16_t did = (static_cast(req[1]) << 8) | req[2];
std::vector data;

// 根据DID获取数据
if (did == DID_VIN) {
data.assign(vin_.begin(), vin_.end());
} else if (did == DID_SW_VERSION) {
data.assign(swVersion_.begin(), swVersion_.end());
} else if (did == DID_ECU_SERIAL) {
data.assign(ecuSerial_.begin(), ecuSerial_.end());
} else {
return buildNegativeResponse(SID_READ_DATA_BY_IDENTIFIER, NRC_DATA_IDENTIFIER_NOT_SUPP);
}

// 正响应:0x62 + DID + 数据
std::vector response;
response.push_back(SID_READ_DATA_BY_IDENTIFIER + 0x40);
response.push_back(req[1]); // DID高字节
response.push_back(req[2]); // DID低字节
response.insert(response.end(), data.begin(), data.end());
return response;
}

// 处理 0x14 ClearDiagnosticInformation
std::vector handleClearDiagnosticInfo(const std::vector& req) {
// 标准中0x14可能携带清除范围参数,此处简化:清除所有DTC并重新开启记录
// 实际实现中应真正清除存储的DTC列表
std::cout << "[ECU] Clearing all DTCs and re-enabling DTC recording.\n";
dtcRecordingEnabled_ = true; // 清除后必须恢复记录
// 正响应:0x54 (SID+0x40)
return {static_cast(SID_CLEAR_DIAG_INFO + 0x40)};
}
};

// ---------- 演示示例 ----------
int main() {
EcuSimulator ecu;

// 初始化:DTC记录默认开启
std::cout << "Initial DTC recording state: " << (ecu.isDtcRecordingEnabled() ? "Enabled" : "Disabled") << "\n\n";

// 模拟诊断仪发送 0x85 请求(停止记录)
std::vector req85_off = {0x85, 0x01}; // sub-function 0x01 = off
std::cout << "Request 0x85 (stop DTC recording): ";
printHex(req85_off);
auto resp85_off = ecu.handleRequest(req85_off);
printHex(resp85_off, "Response: ");
std::cout << "DTC recording state after request: " << (ecu.isDtcRecordingEnabled() ? "Enabled" : "Disabled") << "\n\n";

// 尝试读取一个DID(VIN)
std::vector req22_vin = {0x22, 0xF1, 0x90};
std::cout << "Request 0x22 (read VIN): ";
printHex(req22_vin);
auto resp22_vin = ecu.handleRequest(req22_vin);
printHex(resp22_vin, "Response: ");
std::string vinStr(resp22_vin.begin() + 3, resp22_vin.end());
std::cout << "VIN: " << vinStr << "\n\n";

// 模拟会话超时(应自动恢复DTC记录)
std::cout << "Simulating session timeout...\n";
ecu.sessionTimeout();
std::cout << "DTC recording state after timeout: " << (ecu.isDtcRecordingEnabled() ? "Enabled" : "Disabled") << "\n\n";

// 模拟ECU复位
std::cout << "Simulating ECU reset...\n";
ecu.performReset();
std::cout << "DTC recording state after reset: " << (ecu.isDtcRecordingEnabled() ? "Enabled" : "Disabled") << "\n\n";

// 模拟发送 0x14 清除诊断信息
std::vector req14 = {0x14, 0xFF, 0xFF}; // 简化的清除所有DTC
std::cout << "Request 0x14 (clear DTCs): ";
printHex(req14);
auto resp14 = ecu.handleRequest(req14);
printHex(resp14, "Response: ");
std::cout << "DTC recording state after clear: " << (ecu.isDtcRecordingEnabled() ? "Enabled" : "Disabled") << "\n\n";

return 0;
}
3.1 代码说明
  1. EcuSimulator类:

  • dtcRecordingEnabled_标志位模拟DTC记录状态。

  • handleControlDTCSetting:检查会话条件(要求扩展会话0x02),修改标志位,返回0xC5+子函数。

  • handleReadDataByIdentifier:支持三个示例DID,返回ASCII字符串数据。

  • handleClearDiagnosticInfo:模拟清除所有DTC,并将dtcRecordingEnabled_强制置为true。

会话超时与复位:

  • sessionTimeout():将当前会话切回默认会话(0x01),同时恢复DTC记录。

  • performReset():模拟硬件复位,恢复DTC记录。

符合标准的行为:

  • 0x85请求中若子函数无效返回NRC 0x12。

  • 非扩展会话下执行0x85返回NRC 0x22(条件不满足)。

  • 0x14服务后自动使能记录。

3.2 运行输出示例

Initial DTC recording state: Enabled

Request 0x85 (stop DTC recording): 85 01
[ECU] DTC recording has been DISABLED via 0x85 service.
Response: C5 01
DTC recording state after request: Disabled

Request 0x22 (read VIN): 22 F1 90
Response: 62 F1 90 31 48 47 43 4D 38 32 36 33 33 41 31 32 33 34 35 36
VIN: 1HGCM82633A123456

Simulating session timeout...
[ECU] Session timeout, switching to default session (0x01)
DTC recording state after timeout: Enabled

Simulating ECU reset...
[ECU] Performing reset...
DTC recording state after reset: Enabled

Request 0x14 (clear DTCs): 14 FF FF
[ECU] Clearing all DTCs and re-enabling DTC recording.
Response: 54
DTC recording state after clear: Enabled
4. 总结

本文详细解析了UDS服务ControlDTCSetting(0x85) 和ReadDataByIdentifier(0x22) 的协议格式、行为约束,并通过C++代码给出了符合ISO 14229-1规范的实现示例。实际量产ECU中还需考虑多DID读取、安全访问、DTC存储管理等额外功能,但上述代码清晰展示了核心流程与标准要求的关键交互行为。

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

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.

相关推荐
热点推荐
湖南一男子拾荒21年后领得42万养老金:当过国企工人,下岗后一直未缴费以为领不到

湖南一男子拾荒21年后领得42万养老金:当过国企工人,下岗后一直未缴费以为领不到

潇湘晨报
2026-09-27 20:04:27
2-1!世界第9征服客场,新帅哈维收获首胜,23岁天才梅开二度

2-1!世界第9征服客场,新帅哈维收获首胜,23岁天才梅开二度

足球狗说
2026-09-28 01:52:53
叶一茜携女儿九寨沟出游,森碟亭亭玉立,优秀家教令人赞叹

叶一茜携女儿九寨沟出游,森碟亭亭玉立,优秀家教令人赞叹

娱你同欢
2026-09-27 17:47:39
其实很多人活不过70岁

其实很多人活不过70岁

A活着
2026-09-27 09:05:25
北口榛花绝望大哭!严子怡难以逾越,日本网友:怪物必破世界纪录

北口榛花绝望大哭!严子怡难以逾越,日本网友:怪物必破世界纪录

杨华评论
2026-09-28 02:22:51
“刘欢被去世官方紧急辟谣”,自媒体造谣还有没有底线?

“刘欢被去世官方紧急辟谣”,自媒体造谣还有没有底线?

评底郭
2026-09-27 15:56:37
确认了!她系台湾间谍情报机关人员

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

焦作日报
2026-09-27 15:33:27
日媒:严子怡一枪砸穿日本纪录 日本网友:她去参加男子比赛也会赢

日媒:严子怡一枪砸穿日本纪录 日本网友:她去参加男子比赛也会赢

劲爆体坛
2026-09-27 23:15:02
塞尔维亚总统武契奇宣布辞职

塞尔维亚总统武契奇宣布辞职

澎湃新闻
2026-09-28 02:47:02
西贝又上热搜了,不是罗永浩,是俩探店博主线下吃出来的热度。

西贝又上热搜了,不是罗永浩,是俩探店博主线下吃出来的热度。

荆楚寰宇文枢
2026-09-27 20:53:44
全民化债的时代已经来了。

全民化债的时代已经来了。

老陆不老
2026-09-27 20:06:06
陈妤颉:100米金牌是成年礼,200米银牌是教训

陈妤颉:100米金牌是成年礼,200米银牌是教训

澎湃新闻
2026-09-27 19:53:17
全世界感叹:新的世界秩序已经形成,两个超级大国时代开启

全世界感叹:新的世界秩序已经形成,两个超级大国时代开启

农夫史记
2026-09-27 19:57:36
妻子曝刘欢真正死因!独女是诱因,错过5年抢救期,一度恶化致死

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

风月得自难寻
2026-09-27 18:01:52
亚运会女单金牌得主诞生!王曼昱4-2险胜孙颖莎,摘得生涯第2冠

亚运会女单金牌得主诞生!王曼昱4-2险胜孙颖莎,摘得生涯第2冠

乒谈
2026-09-27 20:58:07
宫鲁鸣是否下课悬念揭晓,赛后发言惹众怒,郑薇一针见血太厉害

宫鲁鸣是否下课悬念揭晓,赛后发言惹众怒,郑薇一针见血太厉害

宗介说体育
2026-09-27 19:13:06
刘欢临终细节被曝!含泪离世,老婆女儿都守在身旁,母女俩太痛苦

刘欢临终细节被曝!含泪离世,老婆女儿都守在身旁,母女俩太痛苦

观察鉴娱
2026-09-27 10:19:27
惊天警报!久明派急速夺权,克里姆林宫权力更迭已进入最后倒计时

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

军情观察家
2026-09-27 22:34:40
豹纹比基尼照刷屏后,这位韩国女演员的新剧也定了

豹纹比基尼照刷屏后,这位韩国女演员的新剧也定了

浅遇时光
2026-09-27 02:25:32
吴艳妮获铜牌!媒体人:这项目在亚洲已不领先,差距非常可怕

吴艳妮获铜牌!媒体人:这项目在亚洲已不领先,差距非常可怕

奥拜尔
2026-09-27 19:45:37
2026-09-28 04:51:00
新能源自动驾驶 incentive-icons
新能源自动驾驶
专注于半导体行业资讯
1015文章数 348关注度
往期回顾 全部

科技要闻

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

头条要闻

孙颖莎2比4不敌王曼昱摘银 称可能等不到下届亚运会了

头条要闻

孙颖莎2比4不敌王曼昱摘银 称可能等不到下届亚运会了

体育要闻

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

娱乐要闻

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

财经要闻

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

汽车要闻

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

态度原创

本地
家居
时尚
教育
艺术

本地新闻

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

家居要闻

2026建博会(广州) 公装联探展交流活动

兰香如故:谁为打工人的情绪工伤买单?

教育要闻

成绩靠后的老师,就该“强制”自费培训20周吗?

艺术要闻

千年松树开花,百年难遇!第一眼就惊艳了

无障碍浏览 进入关怀版