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

UDS诊断协议详解:ISO-15765传输层与C++代码实现

0
分享至


UDS(Unified Diagnostic Services,统一诊断服务)是汽车电子开发中的核心协议栈,广泛应用于ECU(电子控制单元)的故障读取、刷写、标定等场景。理解UDS,关键在于分清两层:应用层(ISO 14229)定义诊断服务接口,传输层(ISO 15765)负责在CAN/CAN FD总线上可靠地打包、传输和重组数据。

本文将聚焦ISO 15765-2:2004(又称DoCAN)传输层协议,详细拆解四种帧类型、多帧交互流程,并给出可直接使用的C++代码示例。

一、ISO 15765 四种帧类型

由于经典CAN数据场最多8字节,当诊断报文超过8字节时,必须采用多帧传输。ISO 15765定义了以下四种协议数据单元(N_PDU):

帧类型

N_PCI字节高4位

用途

单帧(SF)

0x0

传输≤7字节的用户数据

首帧(FF)

0x1

多帧传输的第一个帧,告知总数据长度

连续帧(CF)

0x2

多帧中的后续数据帧,顺序编号

流控帧(FC)

0x3

接收方控制发送方连续帧的速率和数量


1. 单帧(SF)

  • PCI字节 : 0x0 + 4位数据长度(Data Length),表示有效数据字节数。

  • 示例 : 02 10 01 00 00 00 00 00
    第一个字节 0x02 → 单帧 + 长度2,后续2字节 10 01 是诊断请求(UDS服务ID 0x10)。

2. 首帧(FF)
  • PCI字节 : 0x1 + 12位数据总长度(FF_DL),范围9~4095字节。

  • 示例 : 13 FF 22 F1 90 ...
    0x13FF → 首帧标志,总数据长度为 0x3FF=1023 字节,后续6字节承载数据开头。

3. 连续帧(CF)
  • PCI字节 : 0x2 + 4位序列号(SN),从1开始,每发一帧加1,模16循环(0x1~0xF,然后回到0x0)。

  • 示例 : 21 xx xx ... → 第一个连续帧(SN=1),后面7字节为有效数据。

4. 流控帧(FC)
  • PCI字节 : 0x3 + 流控状态(FS)+ 块大小(BS)+ 最小间隔时间(STmin)。

    • FS : 0x0 =继续发送, 0x1 =等待, 0x2 =溢出/取消。

    • BS :允许连续发送的CF数量(0=无限制)。

    • STmin :连续帧之间的最小间隔(毫秒或微秒编码)。

  • 示例 : 30 00 14 → 流控帧,FS=0(继续),BS=0(无限制),STmin=0x14(20ms)。

二、多帧交互流程(经典案例)

假设诊断仪(Tester)需要向ECU发送一个长请求(例如数据下载),总长度200字节。

Tester                                    ECU
| |
|------- [FF: 13 C8 + 前6字节数据] ----->| // 首帧,总数据0x1C8=456字节(假设)
| |
|<------- [FC: 30 0A 14] ----------------| // 流控:允许连续10个CF,间隔20ms
| |
|------- [CF: 21 + 数据块1] ------------->|
|------- [CF: 22 + 数据块2] ------------->|
| ... |
|------- [CF: 2A + 数据块10] ------------>| // 发完BS=10个CF
| |
|<------- [FC: 30 00 14] ----------------| // 再次流控,块大小无限制
| |
|------- [CF: 2B + 剩余数据] ------------>|
| ... |
|------- [CF: 2x + 最后数据] ------------>| // 所有帧发送完毕

关键规则:

  • 发送方收到FC后才可发出第一个CF。

  • 连续帧的SN必须与FC中的BS配合,达到BS数量后必须等待下一个FC。

  • 如果BS=0,表示无块限制,发送方可连续发送所有CF直到结束。

三、C++代码实现

以下代码实现了一个简化的ISO 15765传输层处理类,支持:

  • 将长数据分割为首帧+连续帧

  • 解析接收到的单帧、首帧、连续帧、流控帧

  • 多帧接收重组(状态机)

3.1 CAN帧结构定义

#include  
          
#include
#include

struct CanFrame {
uint32_t id; // CAN ID (11/29 bit)
uint8_t data[8]; // 数据场
uint8_t len; // 实际数据长度 (0-8)
};

enum class N_PCItype : uint8_t {
SF = 0x0,
FF = 0x1,
CF = 0x2,
FC = 0x3
};
3.2 发送端:数据打包器

class Iso15765Sender {
public:
// 输入: 完整诊断数据 (如UDS请求)
// 输出: 一组CAN帧 (首帧+连续帧)
std::vector packMultiFrame(const std::vector& data, uint32_t canId) {
std::vector frames;
if (data.size() <= 7) {
// 单帧
CanFrame sf{canId, {}, 8};
sf.data[0] = (static_cast(N_PCItype::SF) << 4) | static_cast(data.size());
std::copy(data.begin(), data.end(), sf.data + 1);
frames.push_back(sf);
return frames;
}

// 多帧:构造首帧
CanFrame ff{canId, {}, 8};
ff.data[0] = (static_cast(N_PCItype::FF) << 4) | ((data.size() >> 8) & 0x0F);
ff.data[1] = data.size() & 0xFF;
size_t copyLen = std::min(6, data.size());
std::copy(data.begin(), data.begin() + copyLen, ff.data + 2);
frames.push_back(ff);

// 构造连续帧
uint8_t seqNum = 1;
size_t offset = copyLen;
while (offset < data.size()) {
CanFrame cf{canId, {}, 8};
cf.data[0] = (static_cast(N_PCItype::CF) << 4) | (seqNum++ % 16);
size_t chunkSize = std::min(7, data.size() - offset);
std::copy(data.begin() + offset, data.begin() + offset + chunkSize, cf.data + 1);
frames.push_back(cf);
offset += chunkSize;
}
return frames;
}
};
3.3 接收端:多帧重组状态机

class Iso15765Receiver {
public:
enum class RxState { IDLE, RECEIVING };

// 输入一个CAN帧,输出完整诊断数据(如果已重组完成)
std::vector onReceive(const CanFrame& frame) {
if (frame.len < 1) return {};

uint8_t pci = frame.data[0];
N_PCItype type = static_cast (pci >> 4);

if (type == N_PCItype::SF) {
// 单帧直接返回数据
uint8_t sfLen = pci & 0x0F;
return std::vector(frame.data + 1, frame.data + 1 + sfLen);
}
else if (type == N_PCItype::FF) {
// 开始接收多帧
m_state = RxState::RECEIVING;
m_totalLen = ((pci & 0x0F) << 8) | frame.data[1];
m_buffer.clear();
m_buffer.reserve(m_totalLen);
// 拷贝首帧中的前6字节数据
size_t firstChunk = std::min(6, m_totalLen);
m_buffer.insert(m_buffer.end(), frame.data + 2, frame.data + 2 + firstChunk);
m_nextSeqNum = 1; // 期望的第一个CF序列号
// 如果总长度<=6,实际已收完?但规范要求>7才是多帧,此处安全处理
if (m_buffer.size() >= m_totalLen) {
return complete();
}
return {}; // 等待连续帧
}
else if (type == N_PCItype::CF) {
if (m_state != RxState::RECEIVING) return {};
uint8_t seq = pci & 0x0F;
if (seq != m_nextSeqNum) {
// 序列号错误,可触发错误处理
m_state = RxState::IDLE;
return {};
}
// 拷贝连续帧中7字节数据
size_t remaining = m_totalLen - m_buffer.size();
size_t copyLen = std::min(7, remaining);
m_buffer.insert(m_buffer.end(), frame.data + 1, frame.data + 1 + copyLen);
m_nextSeqNum = (m_nextSeqNum + 1) % 16;
if (m_buffer.size() >= m_totalLen) {
return complete();
}
return {};
}
else if (type == N_PCItype::FC) {
// 流控帧由发送方处理,接收方不需要在此类中实现
return {};
}
return {};
}

private:
std::vector complete() {
m_state = RxState::IDLE;
return std::move(m_buffer);
}

RxState m_state = RxState::IDLE;
uint16_t m_totalLen = 0;
std::vector m_buffer;
uint8_t m_nextSeqNum = 0;
};
3.4 简单测试

#include  
          

void printBytes(const std::vector& bytes) {
for (auto b : bytes) printf("%02X ", b);
printf("\n");
}

int main() {
// 构造一个长诊断请求: 22 F1 90 (读取DID) 加上填充数据到20字节
std::vector request = {0x22, 0xF1, 0x90, 0x01, 0x02, 0x03, 0x04, 0x05,
0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
0x0E, 0x0F, 0x10, 0x11};
Iso15765Sender sender;
auto frames = sender.packMultiFrame(request, 0x7DF);

std::cout << "Generated " << frames.size() << " CAN frames:\n";
for (size_t i = 0; i < frames.size(); ++i) {
printf("Frame %zu: ", i);
for (int j = 0; j < frames[i].len; ++j) printf("%02X ", frames[i].data[j]);
printf("\n");
}

// 模拟接收方重组
Iso15765Receiver receiver;
std::vector assembled;
for (auto& frame : frames) {
auto out = receiver.onReceive(frame);
if (!out.empty()) {
assembled = out;
}
}
std::cout << "Reassembled data: ";
printBytes(assembled);
return 0;
}

输出示例:

Generated 4 CAN frames:
Frame 0: 14 22 F1 90 01 02 03 04 // 首帧,总长度20,前6字节
Frame 1: 21 05 06 07 08 09 0A 0B // CF SN=1
Frame 2: 22 0C 0D 0E 0F 10 11 00 // CF SN=2
Reassembled data: 22 F1 90 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11
注:实际工程中还需处理流控帧的发送逻辑(响应FC、BS限流、STmin延时),上述代码侧重于单帧/多帧的组包与解包。
四、总结
  • ISO 15765-2 是UDS在CAN总线上的“搬运工”,定义了单帧、首帧、连续帧、流控帧四种协议帧。

  • 单帧 用于短数据(≤7字节), 多帧 通过首帧告知总长度、流控帧调节速率、连续帧按序发送。

  • C++实现 时,发送方需按规则拆包,接收方维护状态机重组;流控机制保证了总线负载可控与接收方缓冲安全。

  • 掌握这些底层传输细节,是进行UDS诊断开发、调试以及编写Bootloader刷写逻辑的基础。

当你理解了ISO 15765的“怎么传”,再去学习ISO 14229的“做什么”就会事半功倍。希望本文和代码能帮助你快速上手UDS诊断协议!

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

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-27 10:52:03
医院老护士含泪揭秘:人临终前的10个残酷真相,很多子女不懂

医院老护士含泪揭秘:人临终前的10个残酷真相,很多子女不懂

蝉吟槐蕊
2026-09-13 18:15:04
25岁女子吐槽河北婆婆做“糊弄饭”,老公不耐烦了:爱吃吃不吃滚

25岁女子吐槽河北婆婆做“糊弄饭”,老公不耐烦了:爱吃吃不吃滚

许三岁
2026-09-28 02:00:08
小布披露绝望输球内幕下周取代吴易昺,王左亚运血案含金量引热议

小布披露绝望输球内幕下周取代吴易昺,王左亚运血案含金量引热议

网球之家
2026-09-28 10:27:54
低价“0公里二手车”连环骗局爆雷,上千车主或面临钱车两空

低价“0公里二手车”连环骗局爆雷,上千车主或面临钱车两空

凤凰网财经
2026-09-27 22:01:48
4次扑救哈兰德+非常规手型!科斯塔9.4分,葡萄牙换代成功了

4次扑救哈兰德+非常规手型!科斯塔9.4分,葡萄牙换代成功了

赵或是个热血青年
2026-09-28 11:28:49
西方不服气,为何中国没发动任何战争,却成为世界一流经济强国

西方不服气,为何中国没发动任何战争,却成为世界一流经济强国

纪史行者
2026-09-28 08:33:10
刘欢临终细节被曝!含泪离世,老婆女儿都守在身旁,母女俩太痛苦

刘欢临终细节被曝!含泪离世,老婆女儿都守在身旁,母女俩太痛苦

观察鉴娱
2026-09-27 10:19:27
张杰谢娜一家五口出游,仨女儿都坐推车不带腿,有专属摄影师摄像

张杰谢娜一家五口出游,仨女儿都坐推车不带腿,有专属摄影师摄像

阿废冷眼观察所
2026-09-28 00:02:06
喜讯!U23国足进入亚运会四强之后,足协就可能跟多位强援完成续约

喜讯!U23国足进入亚运会四强之后,足协就可能跟多位强援完成续约

振刚说足球
2026-09-28 10:05:42
亚运会女单金牌得主诞生!王曼昱4-2险胜孙颖莎,摘得生涯第2冠

亚运会女单金牌得主诞生!王曼昱4-2险胜孙颖莎,摘得生涯第2冠

乒谈
2026-09-27 20:58:07
彻底崩盘!曼联 6000 万水货混日子!名宿怒喷卡里克赶紧清洗

彻底崩盘!曼联 6000 万水货混日子!名宿怒喷卡里克赶紧清洗

澜归序
2026-09-28 09:11:57
人无法共情以前自己买的那些东西。网友:三个垃圾桶1700。

人无法共情以前自己买的那些东西。网友:三个垃圾桶1700。

天气观察站
2026-09-27 16:03:26
气愤!刘翔师弟夺冠后怒斥:日本电视台没把我当回事 日本选手无视我

气愤!刘翔师弟夺冠后怒斥:日本电视台没把我当回事 日本选手无视我

念洲
2026-09-27 20:49:20
李谷一不再隐瞒,揭晓宋祖英走上高位的真相,观众:原来如此!

李谷一不再隐瞒,揭晓宋祖英走上高位的真相,观众:原来如此!

林轻吟
2026-07-02 19:19:19
中秋假期游客在秦皇岛乘坐海上索道被淋成落汤鸡,景区:下雨后暂停了一会索道,淋到雨的游客是在下雨前上去的

中秋假期游客在秦皇岛乘坐海上索道被淋成落汤鸡,景区:下雨后暂停了一会索道,淋到雨的游客是在下雨前上去的

台州交通广播
2026-09-27 19:31:25
一投提前下班!严子怡大幅提升赛会纪录,夺亚运会女子标枪金牌

一投提前下班!严子怡大幅提升赛会纪录,夺亚运会女子标枪金牌

全景体育V
2026-09-27 21:01:43
如果莉莉贝特真长这样!丝毫不输夏洛特公主,皮肤还更白嫩!

如果莉莉贝特真长这样!丝毫不输夏洛特公主,皮肤还更白嫩!

艺利森
2026-09-28 09:07:46
美方同意放行伊朗总统,专机起飞后怕生变故,全程未在第三国停靠

美方同意放行伊朗总统,专机起飞后怕生变故,全程未在第三国停靠

你是我心中最美星空
2026-09-27 20:36:09
案例:湖南女护士被执行死刑,行刑时回头质问武警,让他当场崩溃

案例:湖南女护士被执行死刑,行刑时回头质问武警,让他当场崩溃

星宇共鸣
2025-09-17 17:58:03
2026-09-28 12:08:49
新能源自动驾驶 incentive-icons
新能源自动驾驶
专注于半导体行业资讯
1015文章数 348关注度
往期回顾 全部

科技要闻

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

头条要闻

媒体:俄杜马选举普京获压倒性胜利 俄乌冲突有2大走向

头条要闻

媒体:俄杜马选举普京获压倒性胜利 俄乌冲突有2大走向

体育要闻

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

娱乐要闻

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

财经要闻

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

汽车要闻

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

态度原创

数码
亲子
本地
公开课
军事航空

数码要闻

满电青春集结古都 航嘉满电青年计划9月22日登陆西安电子科技大学

亲子要闻

监控拍下拖把在锅里涮,老师辞职后才敢发图,孩子吐了没人当回事

本地新闻

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

公开课

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

军事要闻

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

无障碍浏览 进入关怀版