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

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.

相关推荐
热点推荐
差严子怡8米!日本奥运冠军痛哭:不甘心让她一枝独秀 明年要赢她

差严子怡8米!日本奥运冠军痛哭:不甘心让她一枝独秀 明年要赢她

风过乡
2026-09-28 09:06:08
洛夫顿离开上海得不偿失!发文开启勿扰模式,重返大鲨鱼障碍重重

洛夫顿离开上海得不偿失!发文开启勿扰模式,重返大鲨鱼障碍重重

体育见习官
2026-09-28 07:58:50
时隔两年半冲突视频曝光!斯图尔特挥拳尤班克斯 曾因此被禁赛3场

时隔两年半冲突视频曝光!斯图尔特挥拳尤班克斯 曾因此被禁赛3场

罗说NBA
2026-09-28 06:21:57
曼联无意让卡里克下课,重用拉什福德起作用!聘拉爵心仪主帅需1500万

曼联无意让卡里克下课,重用拉什福德起作用!聘拉爵心仪主帅需1500万

罗米的曼联博客
2026-09-28 10:14:03
CBA速递,上海大鲨鱼锁定麦基,六十万美元非常平价,三剑客浮现

CBA速递,上海大鲨鱼锁定麦基,六十万美元非常平价,三剑客浮现

体坛小快灵
2026-09-28 08:43:41
“升糖直接爆了”,家长晒儿子上学早餐,网友:吃完了倒头就睡

“升糖直接爆了”,家长晒儿子上学早餐,网友:吃完了倒头就睡

泽泽先生
2026-09-21 13:37:01
刘欢病逝2天,别墅、版权收入等资产曝光,遗产分配成焦点

刘欢病逝2天,别墅、版权收入等资产曝光,遗产分配成焦点

往史过眼云烟
2026-09-27 16:40:27
儿子作文里写:“我爸爸妈妈从来不吵架,但他们也不怎么说话”

儿子作文里写:“我爸爸妈妈从来不吵架,但他们也不怎么说话”

自由心向往之
2026-09-25 08:30:13
拒绝网红脸!央视秋晚四美火出圈,观众:这才是真审美

拒绝网红脸!央视秋晚四美火出圈,观众:这才是真审美

阿废冷眼观察所
2026-09-27 12:56:52
国家统计局:2026年1—8月份全国规模以上工业企业利润增长15.7%

国家统计局:2026年1—8月份全国规模以上工业企业利润增长15.7%

界面新闻
2026-09-28 09:31:49
台湾提出和统条件:一国三制,“外交权”和拥有军队?是痴心妄想

台湾提出和统条件:一国三制,“外交权”和拥有军队?是痴心妄想

老头的传奇色彩
2026-08-06 17:59:31
广州一工人误踩8层自建房楼顶绿色帆布坠入电梯井,连破两道安全网跌至一楼,调查报告披露:承包人无资质冒用他人名义,未设警示标志

广州一工人误踩8层自建房楼顶绿色帆布坠入电梯井,连破两道安全网跌至一楼,调查报告披露:承包人无资质冒用他人名义,未设警示标志

扬子晚报
2026-09-28 10:35:00
红薯正大量上市!研究发现:糖尿病吃一次红薯,等于给血糖添堵?

红薯正大量上市!研究发现:糖尿病吃一次红薯,等于给血糖添堵?

老李讲健康
2026-09-28 07:30:07
“磨膝大户”被揪出,是跑步的20倍,医生:不想软骨磨光,早扔掉

“磨膝大户”被揪出,是跑步的20倍,医生:不想软骨磨光,早扔掉

看世界的人
2026-09-20 22:04:47
王思聪坐香奈儿VIP贵宾室,懒懒旁边试包,消费降级传闻又被打脸

王思聪坐香奈儿VIP贵宾室,懒懒旁边试包,消费降级传闻又被打脸

梦醉为红颜一笑
2026-09-27 14:27:39
骁龙8EE6+11000mAh!荣耀新机官宣,9月28日发布

骁龙8EE6+11000mAh!荣耀新机官宣,9月28日发布

科技堡垒
2026-09-28 10:19:38
“抱歉,我们不喜欢肥头大耳的”,女孩公开追求体制内男,面相输了

“抱歉,我们不喜欢肥头大耳的”,女孩公开追求体制内男,面相输了

世界圈
2026-08-15 10:29:14
新央企首任董事长,未公布被调查就直接“双开”

新央企首任董事长,未公布被调查就直接“双开”

评论员岳连
2026-09-27 20:54:46
一个国家能蠢到什么程度?看看法国就明白了:法国黑人接近800万,巴黎新生儿里70%是黑人

一个国家能蠢到什么程度?看看法国就明白了:法国黑人接近800万,巴黎新生儿里70%是黑人

怪味历史连连看
2026-09-08 01:55:32
越老越妖,梅西30岁后罚进43粒直接任意球,比30岁前多10粒

越老越妖,梅西30岁后罚进43粒直接任意球,比30岁前多10粒

懂球帝
2026-09-28 10:05:05
2026-09-28 11:35:00
新能源自动驾驶 incentive-icons
新能源自动驾驶
专注于半导体行业资讯
1015文章数 348关注度
往期回顾 全部

科技要闻

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

头条要闻

牛弹琴:内塔尼亚胡有大麻烦了 不是命硬就能扛过去的

头条要闻

牛弹琴:内塔尼亚胡有大麻烦了 不是命硬就能扛过去的

体育要闻

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

娱乐要闻

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

财经要闻

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

汽车要闻

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

态度原创

本地
教育
亲子
手机
军事航空

本地新闻

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

教育要闻

欧洲名校也缺钱修楼?柏林高校开始发愁“楼太破”!

亲子要闻

江苏产妇产下5斤9两男宝,脐带刚剪断,宝宝突然刺耳尖叫

手机要闻

涨价了照样买 iPhone 18 Pro系列国内销量上涨

军事要闻

特朗普"罕见"提二战中美同盟 日本慌了

无障碍浏览 进入关怀版