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

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.

相关推荐
热点推荐
坐标上海!被裁失业后的生活,引炸评论区,大家同为天涯沦落人…

坐标上海!被裁失业后的生活,引炸评论区,大家同为天涯沦落人…

慧翔百科
2026-05-13 11:30:11
《大表哥2》全员转生《GTA6》?R星偷懒还是另有深意

《大表哥2》全员转生《GTA6》?R星偷懒还是另有深意

游民星空
2026-06-25 16:30:25
祸从口出!默茨提议中方签署广场协议,欧洲央行行长紧急出面降温

祸从口出!默茨提议中方签署广场协议,欧洲央行行长紧急出面降温

面包夹知识
2026-06-24 18:15:04
iPhone 20全面曝光: 苹果憋了十年的"iPhone X时刻",赌注大得多

iPhone 20全面曝光: 苹果憋了十年的"iPhone X时刻",赌注大得多

明美无限
2026-06-23 15:48:07
委内瑞拉突发7.5级大地震,伤亡恐破万,美国会见死不救么?

委内瑞拉突发7.5级大地震,伤亡恐破万,美国会见死不救么?

罗富强说
2026-06-25 16:43:24
顶级阴阳!韩国记者提问:你们食物中毒了吗

顶级阴阳!韩国记者提问:你们食物中毒了吗

观察者网
2026-06-25 15:25:40
中国网友的造梗能力能拿世界杯冠军

中国网友的造梗能力能拿世界杯冠军

雷斯林
2026-06-25 14:27:51
央视将播!谍战大剧《千里江山图》来了!我敢说:陈道明又赌对了

央视将播!谍战大剧《千里江山图》来了!我敢说:陈道明又赌对了

草本纪年
2026-06-25 16:57:46
包养10位情妇,睡觉靠翻牌,生下11个私生子,75岁仍在拼命生娃!

包养10位情妇,睡觉靠翻牌,生下11个私生子,75岁仍在拼命生娃!

云舟史策
2026-03-15 17:04:48
确认了,台风+冷空气影响杭州!明天记得开窗!大反转马上就到

确认了,台风+冷空气影响杭州!明天记得开窗!大反转马上就到

19楼
2026-06-25 15:22:00
霍启山被曝11月将举办婚礼仅1天,女方被扒底朝天,郭晶晶没说错

霍启山被曝11月将举办婚礼仅1天,女方被扒底朝天,郭晶晶没说错

娱瓜酱
2026-06-23 14:41:23
离婚又爆挪用上亿公款!「戏剧女王」黄正音面露憔悴暴瘦一圈

离婚又爆挪用上亿公款!「戏剧女王」黄正音面露憔悴暴瘦一圈

ETtoday星光云
2026-06-25 17:11:41
官方出手!涉事者下场大快人心,张桂梅终于能松口气,宋佳没说错

官方出手!涉事者下场大快人心,张桂梅终于能松口气,宋佳没说错

好贤观史记
2026-06-25 14:32:58
我隐瞒拳击金牌身份入伍,低调了4年,直到那天6个老兵群殴我班长

我隐瞒拳击金牌身份入伍,低调了4年,直到那天6个老兵群殴我班长

荔枝人物记
2026-03-13 21:30:07
两岸已签约成功,大陆重大让步?蒋万安开始行动,台当局公开道歉

两岸已签约成功,大陆重大让步?蒋万安开始行动,台当局公开道歉

丁丁鲤史纪
2026-06-24 15:48:50
全网热议的“弟弟要钱买800多的鼠标”事件,炸出多少精神贵族!

全网热议的“弟弟要钱买800多的鼠标”事件,炸出多少精神贵族!

北纬的咖啡豆
2026-06-09 09:35:13
一场65-60!验出中国男篮最大水货,郭士强弃用“拖油瓶”成定局

一场65-60!验出中国男篮最大水货,郭士强弃用“拖油瓶”成定局

刘哥谈体育
2026-06-25 16:42:29
二战士兵怎么解决生理需求的?德国最好笑,美国最实用

二战士兵怎么解决生理需求的?德国最好笑,美国最实用

月光作笺a
2026-06-02 00:10:43
俄乌战争如果继续下去,普京可能被斩首,那将是俄罗斯解体的结局

俄乌战争如果继续下去,普京可能被斩首,那将是俄罗斯解体的结局

荷兰豆爱健康
2026-06-24 17:43:19
指数狂欢,4200股陪跑 A股极致分化行情何时休?

指数狂欢,4200股陪跑 A股极致分化行情何时休?

金融投资报
2026-06-25 16:36:22
2026-06-25 18:00:49
新能源自动驾驶 incentive-icons
新能源自动驾驶
专注于半导体行业资讯
1003文章数 348关注度
往期回顾 全部

科技要闻

宇树机器人大降价

头条要闻

重卡司机称换不起85万的纯电重卡:追平45万差价要5年

头条要闻

重卡司机称换不起85万的纯电重卡:追平45万差价要5年

体育要闻

世界杯最动人一吻:我若离世 你就改嫁吧

娱乐要闻

这国产剧太装了,居然还热播第一?

财经要闻

净利润涨近15倍!美光再次引爆行情

汽车要闻

2027款星途ES 天马1:11:36背后的实力

态度原创

时尚
艺术
亲子
游戏
本地

最高级的夏季配色,来了!

艺术要闻

2026年第三届全国大学生美术作品展 油画选(一)

亲子要闻

广东发放托育券最高2000元,深圳有56家托育机构可用

比异兽更危险的是人心执念,《春秋异闻录》定档7月16日发售

本地新闻

2026世界杯全勤太难?这份保姆级攻略请收好

无障碍浏览 进入关怀版