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

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.

相关推荐
热点推荐
湖南一男子拾荒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万元起

态度原创

本地
数码
旅游
时尚
公开课

本地新闻

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

数码要闻

10499元 微星Claw 8 EX AI+上新:搭载Arc G3处理器、睿频可达4.6GHz

旅游要闻

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

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

公开课

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

无障碍浏览 进入关怀版