从ISO 15765传输层到ECU诊断服务的完整技术解析,涵盖OBD接口、CAN帧结构、网络层时序、核心服务消息格式与否定响应代码
基于ISO 14229与ISO 15765-2的CAN总线UDS诊断协议,必须在物理层、数据链路层、网络层、会话层、应用层五个层级上精确实现,才能通过OEM认证。本文从OEM工程规范出发,系统解析各层帧格式、时序参数、CAN ID分配策略及核心诊断服务的消息结构,为汽车ECU与工业控制设备的诊断系统开发提供可直接落地的技术参考。实测数据表明,严格遵循N_As=1000ms、P2CAN_ECU=50ms等时序约束,可使诊断通信兼容率达到99%以上。
UDS(Unified Diagnostic Services,统一诊断服务)在CAN总线上的实现并非单一协议,而是依赖完整的标准栈。根据ISO参考标准,诊断通信的分层架构如下:
| OSI层级 | 标准 | 核心内容 | Flash占用 |
|---|---|---|---|
| 应用层(Layer 7) | ISO 14229-1 | 诊断服务定义(SID、DID、RID、DTC) | 8~12KB |
| 表示层(Layer 6) | — | 数据格式标识、地址与长度格式标识 | — |
| 会话层(Layer 5) | ISO 15765-3 | 诊断会话管理、会话保持时序(S3) | 1~2KB |
| 传输层/网络层(Layer 4/3) | ISO 15765-2 | CAN帧分段传输(SF/FF/CF/FC)、流控制 | 4~6KB |
| 数据链路层(Layer 2) | ISO 15765-4 | CAN帧格式、DLC=8、填充字节00h | 硬件实现 |
| 物理层(Layer 1) | ISO 15765-4 / SAE J1962 | OBD-II连接器、CAN_H/CAN_L、终端电阻 | 硬件实现 |
在嵌入式ECU开发中,应用层与会话层由MCU固件实现,传输层通常集成在CAN协议栈中,而物理层与数据链路层由CAN收发器(如TJA1043)和控制器(如STM32 bxCAN)硬件完成。OEM要求所有诊断CAN帧的DLC必须固定为8,未使用的数据字节填充00h,以确保总线负载的一致性。
诊断测试仪通过符合SAE J1962/ISO 15031-3标准的16针OBD-II连接器与车辆网络对接。在排放相关ECU(如发动机管理系统EMS)的诊断实现中,以下引脚为必用引脚:
| 引脚 | 信号名称 | 功能描述 | OEM要求 |
|---|---|---|---|
| 4 | 车辆接地 | 车身地线 | 必须 |
| 5 | 信号地 | 诊断信号参考地 | 必须 |
| 6 | CAN_High1 | 高速CAN1正(ISO 15765-4) | 必须 |
| 14 | CAN_Low1 | 高速CAN1负(ISO 15765-4) | 必须 |
| 16 | 电池+(+12V) | 诊断仪供电 | 必须 |
| 3/11 | CAN_High2/Low2 | 第二路CAN(网关架构) | 可选 |
OEM规范对诊断CAN帧的数据链路层有两项硬性约束:
00h。在物联网网关或远程诊断终端的设计中,若将CAN诊断桥接至4G/NB-IoT网络,必须保留这一填充规则,否则原厂的诊断测试仪可能判定帧格式错误。
网络层将诊断消息映射到CAN帧时,每一帧分为地址信息(AI)、协议控制信息(PCI)和数据字段(Data)三部分:
| 字段 | 长度 | 说明 |
|---|---|---|
| 地址信息(AI) | 11位或29位CAN ID | 定义通信模型(物理/功能寻址)与节点地址 |
| 协议控制信息(PCI) | 1~3字节 | 帧类型(SF/FF/CF/FC)、数据长度、流控参数 |
| 数据字段(Data) | 0~7字节(正常寻址) | 实际传输的诊断服务数据 |
OEM为ECU分配诊断CAN ID时,必须区分物理寻址(点对点)与功能寻址(广播)。11位CAN ID的分配范围如下:
| ID类型 | 范围(十六进制) | 用途 |
|---|---|---|
| ECU请求ID(测试仪→ECU) | $620 ~ $6EF | 常规ECU物理寻址请求 |
| ECU响应ID(ECU→测试仪) | $628 ~ $6F7 | 常规ECU物理寻址响应 |
| 排放相关ECU请求ID | $7E0 ~ $7E7 | 法规OBD ECU请求(保留给EMS/TCM) |
| 排放相关ECU响应ID | $7E8 ~ $7EF | 法规OBD ECU响应 |
| 功能请求ID(广播) | $7DF | 全局请求至所有ECU |
对于29位CAN ID,采用ISO 15765-2定义的固定寻址格式:18DB33F1(功能请求)、1BDAXXF1(物理请求)、1BDAF1XX(物理响应)。其中XX为ECU诊断地址,必须在项目启动时由OEM最终确定并确保唯一性。
当诊断消息长度超过单帧承载能力时,ISO 15765-2定义了分段传输机制:
| 帧类型 | PCI首字节 | 说明 | 适用场景 |
|---|---|---|---|
| 单帧(SF) | 0X(X=数据长度) | 数据<=7字节,一次性传输 | 会话控制、简单数据读写 |
| 首帧(FF) | 1X XX(12位数据长度) | 多帧传输的第一帧,携带总数据长度 | 长DTC列表、固件下载 |
| 连续帧(CF) | 2X(X=序列号1~15) | 紧随FF之后的数据帧 | 大数据块分段传输 |
| 流控制帧(FC) | 3X YY ZZ | 接收方控制发送速率(FS/BS/STmin) | 调节CF发送节奏 |
流控制参数的工程意义:OEM强烈建议将块大小(BS)设置为0,表示在完整消息传输过程中不再插入额外的FC帧,从而减少总线交互次数。间隔时间(STmin)在正常诊断模式下应<=5ms,引导加载程序(Bootloader)模式下建议为0ms,以实现最快的刷写速度。
网络层时序是诊断通信稳定性的关键。OEM规范定义的超时参数如下:
| 参数 | 符号 | 超时值 | 说明 |
|---|---|---|---|
| 发送端CAN帧传输时间 | N_As | 1000ms | 发送方完成一帧传输的最大时间 |
| 接收端CAN帧传输时间 | N_Ar | 1000ms | 接收方完成一帧传输的最大时间 |
| 等待下一个FC的时间 | N_Bs | 1000ms | 发送方等待流控制帧的超时 |
| 等待下一个CF的时间 | N_Cr | 1000ms | 接收方等待连续帧的超时 |
| 法规OBD ECU响应时间 | N_Bs/OBD | 75/150ms | 排放相关ECU的流控响应限时 |
| 法规OBD CF接收时间 | N_Cr/OBD | 75/150ms | 排放相关ECU的连续帧接收限时 |
在MCU实现中,建议使用硬件定时器(如STM32的TIM2)单独监控这些时序参数,而非依赖软件延时。当N_Bs或N_Cr超时时,协议栈应自动终止当前多帧传输并上报错误。
通过0x10 DiagnosticSessionControl服务,ECU可在不同会话间切换,每种会话启用不同的诊断服务子集:
当ECU处于非默认会话时,诊断测试仪必须周期性发送0x3E TesterPresent请求以维持会话。OEM规定的时序如下:
| 参数 | 符号 | 建议值 | 超时 |
|---|---|---|---|
| TesterPresent发送周期 | S3Tester | 2000ms | <5000ms |
| 会话保持时间(无交互) | S3ECU | 不适用 | 5000ms |
若ECU在5000ms内未收到任何诊断请求或TesterPresent,应自动回退到默认会话。这一机制在工业RTU远程终端的诊断网关设计中同样适用——网关需代云端维持与设备的诊断会话,避免因无线链路抖动导致会话中断。
并非所有服务在所有会话中都可用。OEM要求ECU供应商明确声明各服务的会话支持情况:
| 服务名称 | SID | 默认会话 | 编程会话 | 扩展会话 | 寻址模式 |
|---|---|---|---|---|---|
| 诊断会话控制 | 0x10 | 支持 | 支持 | 支持 | 物理/功能 |
| ECU复位 | 0x11 | 支持 | 支持 | 支持 | 物理 |
| 安全访问 | 0x27 | — | 支持 | 支持 | 物理 |
| 通信控制 | 0x28 | — | — | 支持 | 功能 |
| 读取数据(DID) | 0x22 | 支持 | 支持 | 支持 | 物理/功能 |
| 写入数据(DID) | 0x2E | — | 支持 | 支持 | 物理 |
| 输入输出控制 | 0x2F | — | — | 支持 | 物理 |
| 清除诊断信息 | 0x14 | — | 支持 | 支持 | 物理/功能 |
| 读取DTC信息 | 0x19 | 支持 | 支持 | 支持 | 物理/功能 |
| 请求下载 | 0x34 | — | 支持 | 支持 | 物理 |
| 传输数据 | 0x36 | — | 支持 | 支持 | 物理 |
| 请求传输退出 | 0x37 | — | 支持 | 支持 | 物理 |
请求:[10] [02](切换至编程会话)
肯定响应:[50] [02] [会话参数记录...]
否定响应:[7F] [10] [NRC](如0x12子功能不支持、0x13消息长度错误)
请求:[22] [F1] [90](读取VIN码,DID=F190)
肯定响应:[62] [F1] [90] [数据...]
否定响应:[7F] [22] [31](请求超出范围)
请求:[34] [数据格式标识] [地址长度格式标识] [内存地址(4B)] [内存大小(4B)]
肯定响应:[74] [长度格式标识] [最大块长度]
否定响应:[7F] [34] [70](上传下载未被接受)
在固件刷写(FOTA)场景中,0x34服务定义的最大块长度直接决定了后续0x36 TransferData每次传输的字节数。典型配置为1024字节/块,配合STmin=0ms可在30秒内完成128KB固件更新。
否定响应是诊断调试与故障定位的关键。当ECU收到无效请求时,回复格式为0x7F + 原请求SID + NRC:
| NRC | 描述 | 典型触发场景 |
|---|---|---|
| 0x10 | 一般拒绝 | 请求无法执行,无更具体的NRC |
| 0x11 | 服务不支持 | ECU未实现该SID |
| 0x12 | 子功能不支持 | 会话类型或子功能无效 |
| 0x13 | 消息长度错误或格式无效 | 请求帧长度不符合服务定义 |
| 0x22 | 条件不正确 | 当前车辆状态不满足服务前提 |
| 0x24 | 请求序列错误 | 未按正确顺序调用服务(如未解锁直接写数据) |
| 0x31 | 请求超出范围 | DID/RID/DTC地址越界 |
| 0x33 | 安全访问被拒绝 | 未通过0x27安全访问验证 |
| 0x35 | 无效密钥 | 安全访问解锁密钥错误 |
| 0x36 | 超出尝试次数 | 连续解锁失败达到上限 |
| 0x78 | 响应挂起 | 请求已正确接收,ECU需要更长时间处理 |
| 0x7E | 当前会话不支持子功能 | 该子功能在当前诊断会话中不可用 |
| 0x7F | 当前会话不支持该服务 | 该服务在当前诊断会话中不可用 |
| 0x92 | 电压过高 | 系统电压超出安全刷写范围 |
| 0x93 | 电压过低 | 电池电压不足,禁止刷写操作 |
特别值得注意的是0x78响应挂起:当ECU需要超过P2CAN_ECU(50ms)才能响应时,应先发送否定响应7F SID 78,随后在P2*CAN_ECU(最大5秒)内给出最终响应。这是Bootloader擦除Flash或大容量DTC上传时的标准做法。
应用层时序直接影响诊断工具的交互体验。OEM规定的默认诊断会话时序参数如下:
| 参数 | 符号 | 最小值 | 最大值 | 工程意义 |
|---|---|---|---|---|
| ECU响应延迟 | P2CAN_ECU | 0ms | 50ms | 单帧请求必须在50ms内得到响应 |
| 扩展响应延迟 | P2*CAN_ECU | 0ms | 5000ms | 发送0x78后的最长等待时间 |
| 测试仪等待时间 | P2CAN_DT | 不适用 | 测试仪等待响应的超时 | |
| 扩展等待时间 | P2*CAN_DT | P2*CAN_ECU + Delta | 收到0x78后的测试仪超时 | |
其中Delta P2CAN应小于P2*CAN_ECUmax的50%。在STM32实现中,建议在CAN接收中断中启动P2定时器,若50ms内未构造好响应帧,则自动触发0x78否定响应流程。
/* UDS应用层主处理循环 */
void UDS_ApplicationLayer_Process(void) {
if (UDS_RxFrameReady) {
UDS_RxFrameReady = 0;
uint8_t sid = rxBuffer[0];
switch (sid) {
case 0x10: UDS_SessionControl(&rxBuffer[1]); break;
case 0x11: UDS_ECUReset(&rxBuffer[1]); break;
case 0x22: UDS_ReadDataByIdentifier(&rxBuffer[1]); break;
case 0x2E: UDS_WriteDataByIdentifier(&rxBuffer[1]); break;
case 0x19: UDS_ReadDTCInformation(&rxBuffer[1]); break;
case 0x34: UDS_RequestDownload(&rxBuffer[1]); break;
case 0x36: UDS_TransferData(&rxBuffer[1]); break;
case 0x37: UDS_RequestTransferExit(&rxBuffer[1]); break;
default: UDS_SendNegativeResponse(sid, 0x11); /* 服务不支持 */
}
}
/* P2超时监控:若响应未在50ms内发出,发送0x78 */
if (P2_TimerElapsed && !ResponseSent) {
UDS_SendNegativeResponse(PendingSID, 0x78);
P2_TimerElapsed = 0;
StartP2StarTimer(5000); /* 启动P2*定时器 */
}
}
除协议实现外,OEM对ECU供应商的交付文档有明确要求。完整的诊断开发文档包应包含以下内容:
在嵌入式开发项目交付中,这些文档不仅是OEM验收的硬性要求,也是后续产线EOL(End of Line)测试、售后诊断工具开发的必要输入。建议开发团队在项目启动阶段即建立诊断数据库(如ODX格式),实现DID/DTC/RID的统一管理与版本控制。
UDS诊断协议在CAN总线上的实现是一项系统工程,必须从物理层的OBD接口、数据链路层的DLC规范、网络层的ISO 15765-2分段传输、会话层的S3保持机制,到应用层的服务消息格式与否定响应代码,逐层精确落实。核心要点可归纳为:DLC固定8字节、网络层N_As/N_Cr不超过1000ms、应用层P2CAN不超过50ms、Bootloader刷写BS=0且STmin<=5ms。对于工业控制领域的开发者而言,将汽车级诊断规范迁移至物联网设备远程运维体系,可显著提升产品的可维护性与客户信任度。
本文技术参数与消息格式引用来源:《OEM诊断工具要求:基于CAN的UDS服务》技术规范译文,涵盖ISO 14229-1应用层、ISO 15765-2网络层、ISO 15765-4数据链路层与物理层、SAE J1962 OBD连接器标准。
沧州艾诺威电子 — 国家高新技术企业,20+项国家专利
嵌入式系统开发 · 物联网方案 · AI智能硬件 · 一站式交付
电话:13930711029 | 邮箱:tech@czinv.com | 24小时内响应