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

UDS 在 LIN 协议上的实现(UDSonLIN)

0
分享至


UDS 在 LIN 协议上的实现(UDSonLIN) 核心结论

UDSonLIN 是 ISO 14229-7 定义的标准,将 UDS 诊断服务映射到 LIN 总线上,实现主节点通过 LIN 网络对从节点进行标准化诊断和固件升级。 诊断请求通过 LIN 的 ID=0x3C 帧发送,响应通过 ID=0x3D 帧返回,使用 NAD(节点地址)标识目标从节点,传输层基于 ISO 15765-2 的帧格式(单帧/多帧)适配 LIN 的 8 字节数据场限制。

一、UDSonLIN 的协议架构 1.1 与 UDSonCAN 的关键差异

特性

UDSonCAN

UDSonLIN

数据链路

CAN 帧(最多 8 字节)

LIN 帧(固定 8 字节数据场)

诊断请求帧

标准 CAN ID

LIN ID = 0x3C(主请求帧)

诊断响应帧

标准 CAN ID

LIN ID = 0x3D(从响应帧)

节点寻址

通过 CAN ID 隐含

通过 NAD(首字节)显式指定

物理层速率

500 kbps ~ 1 Mbps

10 ~ 20 kbps

诊断通信始终由主节点发起:主节点通过 ID=0x3C 发送请求,目标从节点通过 ID=0x3D 返回响应。主节点本身不直接响应诊断请求,而是充当诊断仪与 LIN 从节点之间的网关。

1.2 LIN 诊断帧的数据结构

使用传输层协议时,LIN 数据场的 8 个字节按如下格式排列:

字节 0: NAD (Node Address) — 目标从节点地址,0x7E 为功能寻址
字节 1: PCI (Protocol Control Information) — 高4位帧类型,低4位数据长度
字节 2~6: 数据 (SID + 参数 或 RSID + 参数)
字节 7: 填充 0xFF(未使用字节)

PCI 高 4 位定义帧类型:

  • 0x0X :单帧(Single Frame),数据长度 1~6 字节

  • 0x1X :首帧(First Frame),后续有连续帧

  • 0x2X :连续帧(Consecutive Frame)

二、C++ 代码实现

以下代码模拟主节点通过 LIN 总线发送 UDS 诊断请求的完整流程,涵盖单帧传输和多帧传输两种场景。

// udsonlin_demo.cpp
#include
#include
#include
#include

// ---------- LIN 诊断帧常量 ----------
constexpr uint8_t LIN_DIAG_REQUEST_ID = 0x3C; // 主请求帧 ID
constexpr uint8_t LIN_DIAG_RESPONSE_ID = 0x3D; // 从响应帧 ID
constexpr uint8_t NAD_FUNCTIONAL = 0x7E; // 功能寻址
constexpr uint8_t PAD_BYTE = 0xFF; // 填充字节

// ---------- UDS 服务 ID ----------
enum UdsSid : uint8_t {
SID_DIAGNOSTIC_SESSION_CONTROL = 0x10,
SID_ECU_RESET = 0x11,
SID_READ_DATA_BY_IDENTIFIER = 0x22,
SID_SECURITY_ACCESS = 0x27,
SID_WRITE_DATA_BY_IDENTIFIER = 0x2E,
SID_ROUTINE_CONTROL = 0x31,
SID_REQUEST_DOWNLOAD = 0x34,
SID_TRANSFER_DATA = 0x36,
SID_REQUEST_TRANSFER_EXIT = 0x37
};

// ---------- PCI 帧类型 ----------
enum PciType : uint8_t {
PCI_SINGLE_FRAME = 0x00,
PCI_FIRST_FRAME = 0x10,
PCI_CONSEC_FRAME = 0x20
};

// ---------- LIN 帧结构(数据场固定 8 字节)----------
struct LinFrame {
uint8_t id; // LIN ID (0x3C / 0x3D)
uint8_t data[8];
};

// 构建单帧诊断请求
// 单帧数据最大 6 字节(NAD + PCI + 最多 6 字节 UDS 负载)
LinFrame buildSingleFrameRequest(uint8_t nad, const std::vector& udsPayload) {
LinFrame frame;
frame.id = LIN_DIAG_REQUEST_ID;
// 字节 0: NAD
frame.data[0] = nad;
// 字节 1: PCI — 单帧,低4位为数据长度
frame.data[1] = PCI_SINGLE_FRAME | (udsPayload.size() & 0x0F);
// 字节 2~: UDS 负载
for (size_t i = 0; i < udsPayload.size() && i < 6; ++i) {
frame.data[2 + i] = udsPayload[i];
}
// 填充 0xFF
for (size_t i = 2 + udsPayload.size(); i < 8; ++i) {
frame.data[i] = PAD_BYTE;
}
return frame;
}

// 构建多帧诊断请求(首帧 + 连续帧序列)
std::vector buildMultiFrameRequest(uint8_t nad,
const std::vector& udsPayload) {
std::vector frames;
// --- 首帧 (FF) ---
LinFrame ff;
ff.id = LIN_DIAG_REQUEST_ID;
ff.data[0] = nad;
// PCI 首帧: 高4位 0x1,低4位为总长度高 4 位
uint16_t totalLen = static_cast(udsPayload.size());
ff.data[1] = PCI_FIRST_FRAME | ((totalLen >> 8) & 0x0F);
ff.data[2] = totalLen & 0xFF; // 长度低 8 位
// 首帧数据最多 5 字节 UDS 负载(字节 3~7)
size_t offset = 0;
for (size_t i = 3; i < 8 && offset < udsPayload.size(); ++i, ++offset) {
ff.data[i] = udsPayload[offset];
}
frames.push_back(ff);
// --- 连续帧 (CF) ---
uint8_t seqNum = 1; // 连续帧序列号从 1 开始
while (offset < udsPayload.size()) {
LinFrame cf;
cf.id = LIN_DIAG_REQUEST_ID;
cf.data[0] = nad;
cf.data[1] = PCI_CONSEC_FRAME | (seqNum & 0x0F);
// 每帧最多 6 字节 UDS 负载(字节 2~7)
for (size_t i = 2; i < 8 && offset < udsPayload.size(); ++i, ++offset) {
cf.data[i] = udsPayload[offset];
}
// 填充
for (size_t i = 2 + (udsPayload.size() % 6 == 0 ? 6 : udsPayload.size() % 6); i < 8; ++i) {
cf.data[i] = PAD_BYTE;
}
frames.push_back(cf);
seqNum = (seqNum + 1) & 0x0F;
}
return frames;
}

// 解析单帧诊断响应
// 返回 RSID 及数据;若为否定响应(0x7F),返回 NRC
bool parseResponse(const LinFrame& frame, uint8_t& outRsid,
std::vector& outData, uint8_t& outNrc) {
if (frame.id != LIN_DIAG_RESPONSE_ID) return false;
// 字节 0: NAD(回显请求的 NAD)
// 字节 1: PCI
uint8_t pciType = frame.data[1] >> 4;
uint8_t dataLen = frame.data[1] & 0x0F;
if (pciType != PCI_SINGLE_FRAME) return false; // 简化:仅处理单帧响应
// 字节 2: RSID 或 0x7F
if (frame.data[2] == 0x7F) {
// 否定响应: [0x7F] [原 SID] [NRC]
outNrc = frame.data[4];
outRsid = 0x7F;
outData.clear();
return true;
}
outRsid = frame.data[2];
outData.assign(frame.data + 3, frame.data + 2 + dataLen);
return true;
}

// 打印 LIN 帧用于调试
void printFrame(const LinFrame& f, const std::string& tag) {
std::cout << tag << " [ID=0x" << std::hex << (int)f.id << "]: ";
for (int i = 0; i < 8; ++i) {
std::cout << std::setw(2) << std::setfill('0')
<< (int)f.data[i] << " ";
}
std::cout << std::dec << std::endl;
}
使用示例

int main() {
// --- 示例 1: 诊断会话控制(单帧)---
// 请求编程会话: SID=0x10, Sub=0x02
// 预期 LIN 数据: NAD=0x83, PCI=0x02, SID=0x10, Sub=0x02
{
uint8_t nad = 0x83;
std::vector payload = {
SID_DIAGNOSTIC_SESSION_CONTROL, 0x02
};
LinFrame req = buildSingleFrameRequest(nad, payload);
printFrame(req, "诊断会话请求");
// 模拟从节点响应: RSID=0x50, 会话参数
LinFrame resp;
resp.id = LIN_DIAG_RESPONSE_ID;
resp.data[0] = nad;
resp.data[1] = 0x02; // 单帧,2字节有效数据
resp.data[2] = 0x50; // RSID = SID + 0x40
resp.data[3] = 0x02; // 已进入编程会话
for (int i = 4; i < 8; ++i) resp.data[i] = PAD_BYTE;
printFrame(resp, "诊断会话响应");
uint8_t rsid, nrc;
std::vector data;
if (parseResponse(resp, rsid, data, nrc)) {
std::cout << "RSID: 0x" << std::hex << (int)rsid << std::dec << std::endl;
}
}
// --- 示例 2: 写入数据(多帧,超过 6 字节)---
// WriteDataByIdentifier: SID=0x2E, DID=0xF190, 写入 VIN 码 17 字节
{
uint8_t nad = 0x83;
std::vector payload = { SID_WRITE_DATA_BY_IDENTIFIER };
payload.push_back(0xF1); // DID 高字节
payload.push_back(0x90); // DID 低字节
// VIN 码 17 字节
const char* vin = "1HGCM82633A004352";
for (int i = 0; i < 17; ++i) payload.push_back(vin[i]);
std::cout << "\nUDS 负载总长度: " << payload.size() << " 字节" << std::endl;
auto frames = buildMultiFrameRequest(nad, payload);
for (size_t i = 0; i < frames.size(); ++i) {
std::string tag = (i == 0) ? "首帧" : ("连续帧 " + std::to_string(i));
printFrame(frames[i], tag);
}
}
return 0;
}
代码输出解释

示例 1 输出:

诊断会话请求 [ID=0x3c]: 83 02 10 02 ff ff ff ff
诊断会话响应 [ID=0x3d]: 83 02 50 02 ff ff ff ff
RSID: 0x50

数据帧 83 02 10 02 的含义:NAD=0x83(目标从节点),PCI=0x02(单帧,2 字节有效数据),SID=0x10(诊断会话控制),Sub=0x02(编程会话)。

示例 2 输出: 17 字节 VIN + SID + DID = 20 字节负载,超过单帧 6 字节上限,因此拆分为首帧 + 3 个连续帧。首帧的 PCI 格式为 0x1X 0xYY,其中 XXY 表示总长度(20 = 0x014),后续连续帧的 PCI 为 0x21、0x22、0x23。

三、传输层的关键设计考量 3.1 超时处理

LIN 诊断通信中,主节点发送请求后需等待从节点响应。如果在 P2Server 超时时间内未收到响应,主节点会重发请求(使用 ID=0x3C),直到超时计数器耗尽。功能寻址(NAD=0x7E)下,多个从节点可能同时响应,主节点需要处理仲裁或冲突检测。

3.2 诊断类别

ISO 14229-7 定义了三种诊断类别:

  • Class I :最小诊断,仅支持基础服务(如读取 DTC)

  • Class II :中等诊断,支持会话控制和数据读写

  • Class III :完整诊断,支持编程/刷写

从节点的诊断能力通过 LIN 节点的配置服务(SID B016~B816)声明。

四、工程实践中的注意事项

NAD 分配规则:NAD 范围 0x01~0x7F,其中 0x7E 为功能寻址地址,0x80~0xFF 保留给特定应用或历史兼容性使用。从节点的 NAD 通常在 LIN 描述文件(LDF)中配置。

Bootloader 场景:OTA 升级时,诊断流程通常为:进入扩展会话(0x10 0x03)→ 安全访问(0x27)→ 进入编程会话(0x10 0x02)→ 请求下载(0x34)→ 传输数据(0x36)→ 退出传输(0x37)→ ECU 复位(0x11)。LIN 总线上实测传输速率约 3.7 包/秒,128KB 固件升级约需 15 分钟。

实时性限制:LIN 的低波特率(通常 19.2 kbps)意味着 UDSonLIN 不适合对时间敏感的交互。诊断通信必须与其他 LIN 调度帧共享带宽,主节点需要合理分配调度表中的诊断时隙。

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

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-10-15 16:33:15
网传李嘉诚“去世”,这事透露着一股诡异……

网传李嘉诚“去世”,这事透露着一股诡异……

麦杰逊
2026-10-15 17:41:44
著名女星发声:不想再拍大尺度戏

著名女星发声:不想再拍大尺度戏

中国新闻周刊
2026-10-15 21:48:16
特斯拉Roadster“飞”起来了!中国官网开放预订,意向金33.2万元,将于2028年量产

特斯拉Roadster“飞”起来了!中国官网开放预订,意向金33.2万元,将于2028年量产

每日经济新闻
2026-10-16 10:19:06
余承东就三部门调查刹车踏板问题表态:正义可能会迟到,但永远不会缺席

余承东就三部门调查刹车踏板问题表态:正义可能会迟到,但永远不会缺席

金融界
2026-10-16 08:08:12
全网都在转这条动态:我们这一代完了,文凭没用房价飞涨,AI抢活心理崩溃,还被问你为什么焦虑

全网都在转这条动态:我们这一代完了,文凭没用房价飞涨,AI抢活心理崩溃,还被问你为什么焦虑

不掉线电波
2026-10-15 14:34:59
特朗普承诺不再对伊朗高层下手:我可能是做得太过火了,现在都不知该和谁打交道;美军被曝将用“炸弹之母”空袭伊朗 “威力仅次于核弹”

特朗普承诺不再对伊朗高层下手:我可能是做得太过火了,现在都不知该和谁打交道;美军被曝将用“炸弹之母”空袭伊朗 “威力仅次于核弹”

大风新闻
2026-10-15 19:16:05
仅4599元!苹果官宣:10月20日,新iPhone全面降价

仅4599元!苹果官宣:10月20日,新iPhone全面降价

搞机小帝
2026-10-15 15:14:39
火箭轰20-0大胜雷霆:申京14+7+5杜兰特11分 亚历山大17分

火箭轰20-0大胜雷霆:申京14+7+5杜兰特11分 亚历山大17分

醉卧浮生
2026-10-16 10:40:39
多所高校宣布:共同一作、共同通讯,不认了!高校职称评审全面收紧,“人均一作”的时代正在落幕!

多所高校宣布:共同一作、共同通讯,不认了!高校职称评审全面收紧,“人均一作”的时代正在落幕!

学术眺望
2026-10-16 09:40:03
10天后有望首夺金球奖!曝33岁凯恩与拜仁续约3年 加盟3年已夺6冠

10天后有望首夺金球奖!曝33岁凯恩与拜仁续约3年 加盟3年已夺6冠

风过乡
2026-10-16 06:35:21
重磅:高盛关于中国经济的最新报告

重磅:高盛关于中国经济的最新报告

格上基金
2026-10-15 23:12:36
悲催!心脏三院院士在西安参会猝死,满屋同行无力施救,网友:这是自己刀,削不了自己把儿吗

悲催!心脏三院院士在西安参会猝死,满屋同行无力施救,网友:这是自己刀,削不了自己把儿吗

火山詩话
2026-10-14 20:21:36
全球市场遭遇超级寒流

全球市场遭遇超级寒流

第一财经资讯
2026-10-16 00:47:22
李嘉诚去世真相大白!遗产分配曝光,难怪早对两个儿子安排好后路

李嘉诚去世真相大白!遗产分配曝光,难怪早对两个儿子安排好后路

墨印斋
2026-10-16 05:25:57
孙宏斌真“扛造”:贾跃亭坑走165亿,王健林套走700多亿,融创亏掉1100亿,如今再“翻盘”?

孙宏斌真“扛造”:贾跃亭坑走165亿,王健林套走700多亿,融创亏掉1100亿,如今再“翻盘”?

大厂财经社
2026-10-16 01:15:36
尊界刹车断裂反转?懂车帝遭到三重质疑!

尊界刹车断裂反转?懂车帝遭到三重质疑!

燕梳楼频道
2026-10-15 21:36:17
尼克斯险胜猛龙!布伦森20+7唐斯准三双,伦纳德6+1,巴恩斯23+4

尼克斯险胜猛龙!布伦森20+7唐斯准三双,伦纳德6+1,巴恩斯23+4

鱼崖大话篮球
2026-10-16 10:21:33
一把U型锁毁半生!成都打人宝妈后续残酷:3大恶果,没一个能扛住

一把U型锁毁半生!成都打人宝妈后续残酷:3大恶果,没一个能扛住

游古史
2026-10-16 05:07:03
前国乒球员暗讽张继科后续,张继科回应:他段位不行上不了台面,让他来找我也不敢

前国乒球员暗讽张继科后续,张继科回应:他段位不行上不了台面,让他来找我也不敢

尘语者
2026-10-16 08:34:40
2026-10-16 12:23:00
新能源自动驾驶 incentive-icons
新能源自动驾驶
专注于半导体行业资讯
1024文章数 348关注度
往期回顾 全部

科技要闻

杨天若院士:AI是中国弯道超车的机会

头条要闻

莎拉弹劾案突然转向 菲总统和副总统的"战争"加速了

头条要闻

莎拉弹劾案突然转向 菲总统和副总统的"战争"加速了

体育要闻

工资一分不要,曼联名将想把母队带回西甲

娱乐要闻

徐艺洋官宣生子,完全看不出生过宝宝

财经要闻

特斯拉“飞”起来了!意向金33.2万元

汽车要闻

年轻人专属的大五座 小鹏MONA L05预售16.98万起

态度原创

数码
房产
艺术
游戏
军事航空

数码要闻

高频打印、需要自动双面,打印质量好首选惠普连供670系列

房产要闻

整片大征收!三亚,又一座千亿新城来了!

艺术要闻

徐明 风景油画选

第一人称心理恐怖游戏《加密》公布 类似《寂静岭》

军事要闻

知情人士:乌克兰"爱国者"拦截弹库存耗尽

无障碍浏览 进入关怀版