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

UDS协议中的DID(Data Identifier)详解与C++代码示例

0
分享至


目录

  • 一、DID是什么?

    • 1.1 定义与本质

    • 1.2 DID的格式与范围

    • 1.3 C++中的DID表示

  • 二、DID主要作用

    • 2.1 开发阶段

    • 2.2 生产阶段

    • 2.3 售后与诊断阶段

    • 2.4 C++示例:DID在ECU状态监控中的应用

  • 三、涉及DID的诊断服务

    • 3.1 ReadDataByIdentifier (0x22) 服务

    • 3.2 WriteDataByIdentifier (0x2E) 服务

    • 3.3 其他相关服务

    • 3.4 C++完整示例:DID管理器实现

一、DID是什么? 1.1 定义与本质

在ISO 14229-1 (UDS协议) 中,DID (Data Identifier)是一个2字节的数值(0x0000 – 0xFFFF),用于唯一标识ECU内部的一个特定数据记录。可以将其类比为:

  • 编程语言中的键(Key):如std::map > 中的键。

  • 数据库中的主键:通过DID索引对应的数据内容。

  • 书目的索引号:查到编号即可翻到对应内容页。

核心特点:

  1. DID本身不是数据,而是数据的“门牌号”。

  2. 数据长度可变:DID指向的内容可以是1字节、4字节、甚至上百字节(如VIN码)。

  3. 标准化且预定义:DID在软件开发阶段由诊断规范确定,并非动态生成;不同供应商的ECU若支持相同DID(如0xF190),则读取的数据格式一致。

  4. 存储位置:指向的数据通常保存在非易失性存储器(如EEPROM、Flash)中,用于保存标定参数、序列号、故障阈值等。

1.2 DID的格式与范围

DID占16位,分为两大区域:

区域

范围

标准DID

0x0000 – 0xEFFF

协议预留及ISO定义的标准标识符,例如:
- 0xF190:VIN码
- 0xF18C:ECU硬件版本号
- 0xF187:系统供应商名称

自定义DID

0xF000 – 0xFFFF

留给主机厂或供应商自定义使用,如:
- 0xF100:发动机目标怠速转速
- 0xF200:电池健康度(SOH)

实际开发中,需严格遵循项目《诊断规范》文档,其中会明确每个DID的编号、数据类型、长度、访问权限(读/写/只读)。

1.3 C++中的DID表示

在C++代码中(如ECU固件或诊断工具),可以使用枚举或常量定义所有支持的DID:

// DID定义示例
enum class DataIdentifier : uint16_t {
VIN_CODE = 0xF190, // 17字节 ASCII string
ECU_SOFTWARE_VERSION = 0xF187, // 12字节
ENGINE_IDLE_RPM = 0xF100, // 2字节 uint16_t, 单位 rpm
BATTERY_SOH = 0xF200, // 1字节 uint8_t, 0-100%
MAX_ENGINE_TEMP = 0xF210 // 2字节 uint16_t, 0.1°C 单位
};


// 存储DID数据的简单结构
struct DidEntry {
uint16_t id;
std::vector data; // 原始字节数据
bool isReadOnly;
};
二、DID主要作用

DID在整个汽车电子生命周期中扮演关键角色:

2.1 开发阶段

  • 参数标定:工程师通过写入DID(如0xF100:目标怠速转速)在线调整控制参数,无需重新编译固件。

  • 功能测试:读取特定DID(如0xF200:电池SOH)验证控制算法输出是否正确。

2.2 生产阶段
  • 下线配置:车辆下线时,通过诊断工具写入VIN码(0xF190)、车辆配置字等DID。

  • 传感器校准:将单个ECU的传感器偏置值写入对应的DID中。

2.3 售后与诊断阶段
  • 快速故障定位:读取冻结帧中记录的DID(如故障发生时的车速、发动机转速),重现故障场景。

  • 软件升级后验证:读取软件版本号DID,确认刷写成功。

  • 数据监控:实时读取动态DID(如当前冷却液温度、油门开度),辅助诊断。

2.4 C++示例:DID在ECU状态监控中的应用

以下代码模拟ECU内部周期性更新某个DID对应的数据(如实时冷却液温度):

#include  

#include
#include
#include

class EcuRealTimeMonitor {
private:
std::map> dynamicDIDStorage;
// 模拟传感器读取
uint8_t readCoolantTemp() {
// 实际项目中会调用硬件驱动
return 95; // 95°C
}
public:
EcuRealTimeMonitor() {
// 注册动态DID,初始值为0
dynamicDIDStorage[0xF300] = {0}; // 0xF300 -> 冷却液温度
}
void updateDynamicDIDs() {
uint8_t temp = readCoolantTemp();
dynamicDIDStorage[0xF300] = {temp};
}
std::vector getDidData(uint16_t did) {
auto it = dynamicDIDStorage.find(did);
if (it != dynamicDIDStorage.end()) {
return it->second;
}
return {};
}
void printDynamicData() {
std::cout << "Current coolant temperature: "
<< (int)dynamicDIDStorage[0xF300][0] << " °C" << std::endl;
}
};

int main() {
EcuRealTimeMonitor monitor;
monitor.updateDynamicDIDs();
monitor.printDynamicData();
return 0;
}
三、涉及DID的诊断服务

UDS协议中,最核心使用DID的服务是通过标识符读取数据(0x22)和通过标识符写入数据(0x2E)。此外还包括通过标识符周期性读取(0x2A)等。

3.1 ReadDataByIdentifier (0x22) 服务

  • 请求格式:[0x22] [DID_High] [DID_Low]

  • 肯定响应:[0x62] [DID_High] [DID_Low] [Data_byte_1 … Data_byte_n]

  • 功能:读取一个或多个DID指向的数据(通常一次请求一个DID,部分实现支持多个)。

示例:读取VIN码

请求: 22 F1 90
响应: 62 F1 90 31 47 4E 31 46 45 58 41 32 33 34 35 36 37 38 39 (假设VIN为"GN1FEXA23456789")
3.2 WriteDataByIdentifier (0x2E) 服务
  • 请求格式:[0x2E] [DID_High] [DID_Low] [Data_byte_1 … Data_byte_n]

  • 肯定响应:[0x6E] [DID_High] [DID_Low]

  • 功能:将数据写入指定的DID(通常要求该DID具有可写属性,且ECU处于允许写入的会话状态)。

示例:写入发动机目标怠速转速 (0xF100, 2字节, 大端序)

请求: 2E F1 00 03 20   // 800 rpm (0x0320)
响应: 6E F1 00
3.3 其他相关服务
  • 0x2A - ReadDataByPeriodicIdentifier:建立周期性传输DID数据的会话,ECU按设定时间间隔自动发送DID数据。

  • 0x14 - ClearDiagnosticInformation:清除DTC时,可能同时重置某些与故障相关的DID(如故障计数器)。

  • 0x19 子服务0x06:读取DTC扩展数据记录,其中包含关联的DID值(如故障发生时的环境数据DID)。

3.4 C++完整示例:DID管理器实现

以下实现一个简单的DID管理器,支持读取(0x22)和写入(0x2E)服务,并模拟ECU内部的存储与权限检查。

#include  

#include
#include
#include
#include

class DidManager {
private:
struct DidAttribute {
std::vector data;
bool readOnly;
size_t maxLength; // 0 表示长度可变但受实际数据限制
};
std::unordered_map didDatabase;
public:
// 注册一个DID
void registerDid(uint16_t did, const std::vector& initialData, bool readOnly, size_t maxLen = 0) {
DidAttribute attr;
attr.data = initialData;
attr.readOnly = readOnly;
attr.maxLength = maxLen;
didDatabase[did] = attr;
}
// 模拟处理0x22请求:读取DID
// 返回pair <是否成功, 响应数据(包含响应id+did+数据)>
std::pair> handleReadRequest(uint16_t did) {
auto it = didDatabase.find(did);
if (it == didDatabase.end()) {
std::cout << "[ERROR] DID 0x" << std::hex << did << " not found" << std::endl;
return {false, {}};
}
std::vector response;
response.push_back(0x62); // 肯定响应ID
response.push_back((did >> 8) & 0xFF); // DID High
response.push_back(did & 0xFF); // DID Low
response.insert(response.end(), it->second.data.begin(), it->second.data.end());
return {true, response};
}
// 模拟处理0x2E请求:写入DID
std::pair> handleWriteRequest(uint16_t did, const std::vector& writeData) {
auto it = didDatabase.find(did);
if (it == didDatabase.end()) {
std::cout << "[ERROR] DID 0x" << std::hex << did << " not found" << std::endl;
return {false, {}};
}
if (it->second.readOnly) {
std::cout << "[ERROR] DID 0x" << std::hex << did << " is read-only, write denied" << std::endl;
return {false, {}};
}
if (it->second.maxLength > 0 && writeData.size() > it->second.maxLength) {
std::cout << "[ERROR] DID 0x" << std::hex << did << " write data exceeds max length" << std::endl;
return {false, {}};
}
// 执行写入
it->second.data = writeData;
std::cout << "[INFO] DID 0x" << std::hex << did << " written successfully" << std::endl;
std::vector response;
response.push_back(0x6E);
response.push_back((did >> 8) & 0xFF);
response.push_back(did & 0xFF);
return {true, response};
}
// 调试:打印所有DID
void printAllDIDs() {
for (const auto& entry : didDatabase) {
std::cout << "DID: 0x" << std::hex << entry.first
<< ", data length: " << std::dec << entry.second.data.size()
<< ", readOnly: " << (entry.second.readOnly ? "yes" : "no")
<< std::endl;
}
}
};

// 辅助函数:将大端字节序转换为整数(用于演示)
uint16_t bytesToUint16(const std::vector& bytes, size_t offset) {
return (bytes[offset] << 8) | bytes[offset + 1];
}

int main() {
DidManager ecuDid;
// 注册DID(模拟诊断规范定义)
// VIN码 0xF190: 17字节,只读
std::vector vin = {'L','F','V','3','A','2','1','9','L','0','0','1','2','3','4','5','6'};
ecuDid.registerDid(0xF190, vin, true);
// 发动机怠速转速 0xF100: 2字节,可读写
std::vector idleRpm = {0x03, 0x20}; // 800 rpm
ecuDid.registerDid(0xF100, idleRpm, false, 2);
// 电池SOH 0xF200: 1字节,可读写
std::vector batterySoh = {98}; // 98%
ecuDid.registerDid(0xF200, batterySoh, false, 1);
std::cout << "=== Initial DID Registration ===" << std::endl;
ecuDid.printAllDIDs();
// 模拟诊断工具发送0x22读取请求
std::cout << "\n=== Read VIN (0xF190) ===" << std::endl;
auto [ok, resp] = ecuDid.handleReadRequest(0xF190);
if (ok) {
std::cout << "Response: ";
for (uint8_t b : resp) printf("%02X ", b);
std::cout << std::endl;
// 解析VIN字符串
std::string vinStr(resp.begin() + 3, resp.end());
std::cout << "VIN: " << vinStr << std::endl;
}
// 模拟写入新的怠速转速 (1000 rpm = 0x03E8)
std::cout << "\n=== Write Engine Idle RPM (0xF100) to 1000 rpm ===" << std::endl;
std::vector newRpm = {0x03, 0xE8};
auto [ok2, resp2] = ecuDid.handleWriteRequest(0xF100, newRpm);
if (ok2) {
std::cout << "Write success, response: ";
for (uint8_t b : resp2) printf("%02X ", b);
std::cout << std::endl;
}
// 验证读取更新后的RPM
std::cout << "\n=== Read Engine Idle RPM again ===" << std::endl;
auto [ok3, resp3] = ecuDid.handleReadRequest(0xF100);
if (ok3) {
uint16_t rpm = bytesToUint16(resp3, 3);
std::cout << "Current idle RPM: " << rpm << std::endl;
}
// 尝试写入只读DID(应失败)
std::cout << "\n=== Try to write read-only DID (0xF190) ===" << std::endl;
std::vector fakeVin = {'X','X','X','X'};
ecuDid.handleWriteRequest(0xF190, fakeVin);
return 0;
}

程序输出示例:

=== Initial DID Registration ===
DID: 0xf100, data length: 2, readOnly: no
DID: 0xf190, data length: 17, readOnly: yes
DID: 0xf200, data length: 1, readOnly: no

=== Read VIN (0xF190) ===
Response: 62 F1 90 4C 46 56 33 41 32 31 39 4C 30 30 31 32 33 34 35 36
VIN: LFV3A219L00123456

=== Write Engine Idle RPM (0xF100) to 1000 rpm ===
[INFO] DID 0xf100 written successfully
Write success, response: 6E F1 00

=== Read Engine Idle RPM again ===
Current idle RPM: 1000

=== Try to write read-only DID (0xF190) ===
[ERROR] DID 0xf190 is read-only, write denied
总结

DID是UDS协议中访问ECU内部数据的核心索引机制。通过标准化的0x22和0x2E服务,诊断工具可以方便地读取或修改ECU的配置、状态和标定参数。在实际工程中,需要根据《诊断规范》准确实现DID的注册、访问控制和数据格式转换。上述C++代码展示了从DID定义到请求处理的全流程,可作为ECU诊断栈或离线诊断工具开发的参考基础。

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

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-28 12:32:49
刘青云携妻子郭蔼明现身卡定沟游玩,模样越来越像萨达姆,一个黑脸一个笑脸对比鲜明

刘青云携妻子郭蔼明现身卡定沟游玩,模样越来越像萨达姆,一个黑脸一个笑脸对比鲜明

裕丰娱间说
2026-09-27 13:57:53
涉案金额过亿 刘应成(原法名释永信)一审被判有期徒刑24年

涉案金额过亿 刘应成(原法名释永信)一审被判有期徒刑24年

每日经济新闻
2026-05-30 00:42:59
权贵们绕开高考走捷径:北理工裴轶和协会 4+4 一个路数

权贵们绕开高考走捷径:北理工裴轶和协会 4+4 一个路数

放开他让wo来
2026-09-27 13:45:46
亚运会最新奖牌榜:日本157枚,韩国83枚,中国健儿太让国人自豪

亚运会最新奖牌榜:日本157枚,韩国83枚,中国健儿太让国人自豪

锅锅爱历史
2026-09-28 06:23:47
被质疑放水输球!混双丢冠,孙颖莎王楚钦开心互动,谁注意王楚钦表态

被质疑放水输球!混双丢冠,孙颖莎王楚钦开心互动,谁注意王楚钦表态

懂球社
2026-09-27 11:25:19
日本:引进中国人,韩国人,甚至越南人都可以,但绝对不引进印度人和穆斯林!

日本:引进中国人,韩国人,甚至越南人都可以,但绝对不引进印度人和穆斯林!

步论天下事
2026-09-28 10:50:23
“没想到一枪就‘下班’了”,18岁严子怡只投了一枪,拿下金牌,大比分碾压日本名将!她曾放话:未来,开启一个属于我的新时代吧

“没想到一枪就‘下班’了”,18岁严子怡只投了一枪,拿下金牌,大比分碾压日本名将!她曾放话:未来,开启一个属于我的新时代吧

南方都市报
2026-09-28 11:58:41
天彻底塌了!亚运全线溃败零金收官,中国篮球已跌至谷底!

天彻底塌了!亚运全线溃败零金收官,中国篮球已跌至谷底!

田先生篮球
2026-09-25 17:24:52
女友在亚马尔社媒评论:我还是觉得你也太帅了,太不真实了

女友在亚马尔社媒评论:我还是觉得你也太帅了,太不真实了

懂球帝
2026-09-27 21:29:20
金卡戴珊全家逛上海野生动物园,紧身裤配高跟鞋,这打扮真够精致

金卡戴珊全家逛上海野生动物园,紧身裤配高跟鞋,这打扮真够精致

悦君兮君不知
2026-09-28 11:21:46
三毛说我去非洲是为了帮助黑人,李敖反问:你为什么不帮助黄人?

三毛说我去非洲是为了帮助黑人,李敖反问:你为什么不帮助黄人?

言过于诚
2026-09-27 22:31:29
骗走50亿!用小鲜肉的血抗衰,被央视曝光的“捞金女王”,真栽了

骗走50亿!用小鲜肉的血抗衰,被央视曝光的“捞金女王”,真栽了

深析古今
2026-04-08 10:09:38
张本智和:阿拉米扬以往发球就算不上完全合规,现在又肆无忌惮

张本智和:阿拉米扬以往发球就算不上完全合规,现在又肆无忌惮

懂球帝
2026-09-27 15:40:00
“反华妖女”许可馨,回国后曾叫嚣没人敢动她,六年后下场如何?

“反华妖女”许可馨,回国后曾叫嚣没人敢动她,六年后下场如何?

锅锅爱历史
2026-07-26 08:50:12
你做过最龌龊,最下流的事是什么?

你做过最龌龊,最下流的事是什么?

那年秋天
2026-08-16 11:50:09
仔细看,这张拍于2016年的合影照,当时樊振东19岁,那时的樊振东确实还满是青涩感!就不知左边的美女是谁?

仔细看,这张拍于2016年的合影照,当时樊振东19岁,那时的樊振东确实还满是青涩感!就不知左边的美女是谁?

小琦聊生活
2026-09-25 13:24:02
《繁花》里最狠的一条生意经:嘴甜是下等人的本事,忠心是中等人的筹码,能被大人物拉上桌的分蛋糕者,手里攥着这两种教人离不开的硬通货

《繁花》里最狠的一条生意经:嘴甜是下等人的本事,忠心是中等人的筹码,能被大人物拉上桌的分蛋糕者,手里攥着这两种教人离不开的硬通货

心理观察局
2026-08-04 06:38:04
河南一技校101名毕业生入职北大,所涉专业系全国唯一,该校曾入职北大的毕业生:有和北大人才中心签约的,也有劳务派遣

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

极目新闻
2026-09-27 19:00:11
微信上基本不发朋友圈的人,未必低调,十有八九是这三种人:1、生活过于丰富,不便展示;2、看透人性,藏锋守拙;3、自给自足,太充实

微信上基本不发朋友圈的人,未必低调,十有八九是这三种人:1、生活过于丰富,不便展示;2、看透人性,藏锋守拙;3、自给自足,太充实

品读时刻
2026-09-12 09:06:58
2026-09-28 13:11:00
新能源自动驾驶 incentive-icons
新能源自动驾驶
专注于半导体行业资讯
1015文章数 348关注度
往期回顾 全部

科技要闻

智能体惹了多少祸,OpenAI自己没查清!

头条要闻

供销社职工以46600元参与拐卖外籍妇女 获刑5年9个月

头条要闻

供销社职工以46600元参与拐卖外籍妇女 获刑5年9个月

体育要闻

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

娱乐要闻

好汉刘欢:一副好嗓子,一颗赤子心

财经要闻

标价298元核桃油, 实为大豆油冒充

汽车要闻

神龙科技与Momenta达成全球战略合作 2027年起推新车

态度原创

教育
数码
房产
手机
艺术

教育要闻

一个家庭,父母越“尊重”孩子,孩子脾气越大……

数码要闻

单卷能存100TB!富士推出LTO-10磁带:寿命30年售价3300+元

房产要闻

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

手机要闻

首批搭载第六代骁龙8超级至尊版!荣耀Magic9 Pro Max安兔兔跑分超552万

艺术要闻

12张效果图,抖音深圳第二总部显真容

无障碍浏览 进入关怀版