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

UDS 0x3E 服务(Tester Present)详解及 C++ 代码示例

0
分享至


一、服务概述

在 UDS(ISO 14229-1)协议中,0x3E 服务(Tester Present)用于让诊断测试工具(Tester)告知 ECU:“我还在线,请不要自动切回默认会话状态”。
ECU 通常有一个会话超时定时器(S3 Server 定时器),如果在规定时间内未收到任何诊断请求,它会自动从非默认会话(如编程会话、扩展诊断会话)返回到默认会话(Default Session)。
0x3E 服务正是用来重置这个定时器,维持当前会话状态,防止因超时而丢失非默认会话中的功能(如解锁安全访问、写入数据等)。

简单来说:Tester 定期发送 0x3E 请求,ECU 收到后刷新会话保持计时器,从而保持在当前会话。

二、报文格式 2.1 请求报文

字节位置

参数名称

值(例)

0

SID

0x3E

服务标识符

1

SubFunction

0x00 或 0x80

子功能,决定 ECU 是否需要发送肯定响应


  • 子功能(SubFunction):

    • 0x00:suppressResponse= true,ECU不应发送肯定响应。

    • 0x80:suppressResponse= false,ECU必须发送肯定响应。

实际应用中,为了保证通信可靠性并确认 ECU 仍在线,通常使用 0x80(请求响应)。但很多简单实现也直接发送 3E 00,并不期待响应。ISO 14229-1 规定:若子功能为 0x00,ECU 不得发送任何肯定响应;若为 0x80,ECU 应回复 7E 80。

常见报文示例:

  • 3E 00—— 仅刷新定时器,ECU 不回复响应。

  • 3E 80—— 刷新定时器,并要求 ECU 回复肯定响应。

2.2 肯定响应报文

字节位置

参数名称

值(例)

0

SID

0x7E

肯定响应标识符(0x3E+0x40)

1

SubFunction

0x80

与请求中的子功能相同


  • 若请求为3E 80,则肯定响应为7E 80。

  • 若请求为3E 00,ECU不会发送肯定响应。

2.3 否定响应

当 ECU 无法处理该请求时,返回否定响应(格式:7F SID NRC)。常见的否定响应码(NRC)包括:

NRC

含义

原因

0x12

子功能不支持

子功能参数不是 0x00 或 0x80

0x13

请求报文长度错误

报文长度不为 2 字节

0x22

条件不满足

当前会话不允许执行该服务

0x78

请求正确,但响应延迟

ECU 忙,稍后重新请求


三、使用场景

  • 诊断会话保持:当 ECU 处于扩展诊断会话(0x03)或编程会话(0x02)时,Tester 需每隔 ≤ S3_Server 时间(通常为 5 秒)发送一次 0x3E 服务,否则 ECU 会自动切回默认会话(0x01)。

  • 安全访问保持:解锁安全访问后,若长时间无活动,ECU 会重新锁定,此时可通过 0x3E 维持解锁状态。

  • 写入操作保护:在进行多帧写入(如 0x34/0x36 服务)过程中,可穿插 0x3E 防止会话超时导致写入中断。

四、C++ 代码示例

下面提供一个简单的 C++ 类UdsClient,封装了发送 Tester Present 请求(支持响应)的功能。
假设:底层已实现 CAN 通信接口(例如 Linux SocketCAN),提供了CanSend()和CanReceive()函数。实际使用时需替换为真实的 CAN 驱动代码。

4.1 辅助函数定义(伪实现)

#include  

#include
#include
#include
#include

// 模拟 CAN 发送(实际应调用 SocketCAN 等接口)
bool CanSend(const std::vector& data, uint32_t can_id) {
std::cout << "[CAN TX] ID=0x" << std::hex << can_id << " Data: ";
for (auto byte : data) printf("%02X ", byte);
std::cout << std::dec << std::endl;
// 这里替换为真实的 write() 调用
return true;
}

// 模拟 CAN 接收(非阻塞,带超时)
bool CanReceive(std::vector& data, uint32_t& can_id, int timeout_ms) {
// 模拟接收数据(实际应从 socket 读取)
// 此示例中直接返回 false,演示超时场景
std::this_thread::sleep_for(std::chrono::milliseconds(timeout_ms));
return false; // 无数据
}
4.2 UdsClient 类实现

class UdsClient {
public:
UdsClient(uint32_t req_id, uint32_t resp_id)
: req_can_id_(req_id), resp_can_id_(resp_id) {}

// 发送 Tester Present 请求
// sub_func: 0x00(无响应) 或 0x80(期望响应)
// timeout_ms: 等待响应的超时时间(毫秒),仅当 sub_func==0x80 时有效
bool SendTesterPresent(uint8_t sub_func, int timeout_ms = 100) {
// 构造请求报文:2 字节
std::vector request = { 0x3E, sub_func };
if (!CanSend(request, req_can_id_)) {
std::cerr << "Send TesterPresent request failed" << std::endl;
return false;
}

// 如果不需要响应,直接返回成功
if (sub_func == 0x00) {
std::cout << "TesterPresent with suppressResponse, no ack expected." << std::endl;
return true;
}

// 等待肯定响应
std::vector response;
uint32_t rx_id;
if (!CanReceive(response, rx_id, timeout_ms)) {
std::cerr << "Timeout waiting for TesterPresent response" << std::endl;
return false;
}

// 检查 CAN ID 是否正确
if (rx_id != resp_can_id_) {
std::cerr << "Unexpected response CAN ID" << std::endl;
return false;
}

// 检查响应长度
if (response.size() < 2) {
std::cerr << "Response too short" << std::endl;
return false;
}

// 检查肯定响应 SID (0x7E)
if (response[0] == 0x7E && response[1] == sub_func) {
std::cout << "Received positive response: 7E " << std::hex << (int)sub_func << std::dec << std::endl;
return true;
}
// 检查否定响应 (0x7F)
else if (response[0] == 0x7F && response[1] == 0x3E) {
uint8_t nrc = response[2];
std::cerr << "Negative response, NRC = 0x" << std::hex << (int)nrc << std::dec << std::endl;
return false;
}
else {
std::cerr << "Unexpected response format" << std::endl;
return false;
}
}

private:
uint32_t req_can_id_; // 请求使用的 CAN ID(通常为 0x7DF 或物理寻址 ID)
uint32_t resp_can_id_; // 响应使用的 CAN ID(通常为 ECU 的物理响应 ID)
};
4.3 使用示例

int main() {
// 假设 ECU 物理请求 ID 为 0x701,响应 ID 为 0x702
UdsClient client(0x701, 0x702);

// 场景1:要求 ECU 回复肯定响应(推荐)
std::cout << "=== Send TesterPresent with response (subfunc=0x80) ===" << std::endl;
bool ok = client.SendTesterPresent(0x80, 200);
if (ok) {
std::cout << "ECU stays in current session." << std::endl;
} else {
std::cout << "Failed to refresh session timer." << std::endl;
}

// 场景2:不要求响应(仅刷新定时器)
std::cout << "\n=== Send TesterPresent without response (subfunc=0x00) ===" << std::endl;
ok = client.SendTesterPresent(0x00);
if (ok) {
std::cout << "TesterPresent sent (no response needed)." << std::endl;
}

// 模拟周期性发送(每 3 秒一次,假设会话超时为 5 秒)
std::cout << "\n=== Start periodic TesterPresent (every 3s) ===" << std::endl;
for (int i = 0; i < 5; ++i) {
std::this_thread::sleep_for(std::chrono::seconds(3));
if (!client.SendTesterPresent(0x80, 200)) {
std::cerr << "Periodic TesterPresent failed at iteration " << i << std::endl;
break;
}
}

return 0;
}
五、注意事项
  1. 发送周期:应小于 ECU 的 S3_Server 超时时间(通常为 5 秒)。建议周期为 2~3 秒,留有余量。

  2. 子功能选择:

  • 如果诊断流程需要确认 ECU 仍然在线,使用0x80并等待响应。

  • 如果仅需保持会话且不希望增加总线负载,可使用0x00(无响应)。

会话切换影响:如果 ECU 已经返回默认会话(例如因超时),则 0x3E 服务依然可以执行,但不会自动切换回之前的会话。此时应重新请求需要的会话(如 0x10 服务)。

错误处理:若收到 NRC 0x78(响应延迟),Tester 应稍后重发请求(但注意不要过于频繁)。

CAN ID 设置:示例中使用了物理寻址(点对点)。也可使用功能寻址(如 0x7DF),但需注意 ECU 是否支持功能寻址响应。

六、总结

UDS 0x3E 服务(Tester Present)是一个简单但至关重要的诊断服务,用于维持 ECU 的非默认会话状态。其报文格式简洁(仅 2 字节),通过子功能控制是否需要响应。
在实际嵌入式开发中,正确实现该服务可以避免因会话超时导致的诊断流程中断。本文提供的 C++ 代码演示了如何在客户端侧封装该服务,并可根据需要集成到真实的诊断工具中。

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

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-27 14:04:12
日乒男单全军覆没!日媒当场甩锅中国,张本智和这番话,彻底破防

日乒男单全军覆没!日媒当场甩锅中国,张本智和这番话,彻底破防

无意争春
2026-09-28 04:19:51
房价:大家不用等了,没出意外,房价将会重演历史

房价:大家不用等了,没出意外,房价将会重演历史

地球记
2026-09-27 17:16:13
中国3大禁地,个个重兵把守,无论哪一个被偷袭,都将视为宣战

中国3大禁地,个个重兵把守,无论哪一个被偷袭,都将视为宣战

文史道
2026-07-19 23:38:12
32岁女游客独游罗马,被骗至废弃建筑喂药轮奸囚禁72小时

32岁女游客独游罗马,被骗至废弃建筑喂药轮奸囚禁72小时

听心堂
2026-06-01 07:29:57
堪称最离谱的枕边翻车现场,清华学霸杨奇函被女友趁熟睡时蚂蚁搬家式转走百万

堪称最离谱的枕边翻车现场,清华学霸杨奇函被女友趁熟睡时蚂蚁搬家式转走百万

东方不败然多多
2026-08-22 04:34:50
贫穷能让一个人有多卑微?网友:给05年小富婆妹当过狗,还给130斤小富婆做了俩月男朋友

贫穷能让一个人有多卑微?网友:给05年小富婆妹当过狗,还给130斤小富婆做了俩月男朋友

带你感受人间冷暖
2026-09-15 00:05:19
两性心理学:如果一个女人能和一个婚内的男人,保持长久的关系,不是因为两个人之间真有感情,而是因为这个女人太傻

两性心理学:如果一个女人能和一个婚内的男人,保持长久的关系,不是因为两个人之间真有感情,而是因为这个女人太傻

心理观察局
2026-09-15 06:16:05
又曝出轨大瓜,男子自曝妻子出轨班长5个月,班长只给他妻子买过情趣内衣,还曝光俩人大尺度聊天内容

又曝出轨大瓜,男子自曝妻子出轨班长5个月,班长只给他妻子买过情趣内衣,还曝光俩人大尺度聊天内容

汉史趣闻
2026-09-10 18:28:47
《兰香如故》林绣茹戏台一笑!袁绍辉至死不知,他丢的不是妾是妻

《兰香如故》林绣茹戏台一笑!袁绍辉至死不知,他丢的不是妾是妻

东方不败然多多
2026-09-20 08:29:54
《兰香如故》林锦歧拼命护送回京的太子,只做了9个月的皇帝,却开启了大明王朝的“仁宣之治”!

《兰香如故》林锦歧拼命护送回京的太子,只做了9个月的皇帝,却开启了大明王朝的“仁宣之治”!

牛锅巴小钒
2026-09-27 11:03:55
50岁左右的成熟阿姨这样打扮,显得简单大方又有女人味

50岁左右的成熟阿姨这样打扮,显得简单大方又有女人味

美女穿搭分享
2026-09-26 18:25:27
吴艳妮预赛前检录处补妆涂口红 日媒:她凭出众外貌拥有200万粉丝

吴艳妮预赛前检录处补妆涂口红 日媒:她凭出众外貌拥有200万粉丝

劲爆体坛
2026-09-27 09:39:05
如果你存款高于这个数,恭喜你!已超过大多数人成为有钱人

如果你存款高于这个数,恭喜你!已超过大多数人成为有钱人

三农老历
2026-09-27 15:45:41
1961年《红岩》出版后在全国爆火,沈醉却说:提审江姐内容不真实

1961年《红岩》出版后在全国爆火,沈醉却说:提审江姐内容不真实

文史达观
2026-01-11 12:41:06
男女肢体接触的正确顺序:多数人第一步就做错,难怪总被拒绝

男女肢体接触的正确顺序:多数人第一步就做错,难怪总被拒绝

荷兰豆爱健康
2026-09-25 01:37:22
还打什么?41金中国拿30金,港台再拿3金,日韩抢8金抢到头破血流

还打什么?41金中国拿30金,港台再拿3金,日韩抢8金抢到头破血流

刘哥谈体育
2026-09-28 00:02:49
2027年将会是中华人民共和国全党、全军、全国各族人民重要的一年

2027年将会是中华人民共和国全党、全军、全国各族人民重要的一年

铁锤侃侃而谈
2026-09-12 00:54:59
生育大局已定!2026新生儿预估出炉,低生育率根本不是年轻人懒生

生育大局已定!2026新生儿预估出炉,低生育率根本不是年轻人懒生

瓦伦西亚月亮
2026-09-27 16:55:32
五芳斋,情况不妙?

五芳斋,情况不妙?

鱼眼观察
2026-09-27 11:00:02
2026-09-28 05:32:49
新能源自动驾驶 incentive-icons
新能源自动驾驶
专注于半导体行业资讯
1015文章数 348关注度
往期回顾 全部

科技要闻

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

头条要闻

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

头条要闻

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

体育要闻

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

娱乐要闻

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

财经要闻

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

汽车要闻

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

态度原创

旅游
本地
时尚
游戏
教育

旅游要闻

四百载风雨坚守,贵阳这座古阁,藏着贵州人的文运期许!

本地新闻

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

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

《宝可梦风/波》完整地图疑泄露 含澳大利亚北部

教育要闻

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

无障碍浏览 进入关怀版