ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

UDS诊断0x10会话控制详解:从CAN报文到超时机制

UDS诊断0x10会话控制详解:从CAN报文到超时机制 第一次在CANoe里手动发了一条02 10 03我盯着Trace窗口看了快一分钟总线上一片安静心里想的是地址错了波特率不对还是ECU直接死机了。后来才反应过来0x10会话控制服务不是“问一句答一句”的读数据服务它是在给ECU换一套运行模式——换模式这件事本身就藏着不少规矩理解不到位后面刷写、标定、售后诊断全都会卡壳。这篇文章就把UDS诊断里最基础也最重要的0x10服务彻底讲透它为什么存在、报文怎么拆、三种子功能怎么选、S3和P2超时怎么算以及我踩过的那些NRC的坑。内容基于ISO 14229-1协议并结合实际CAN工具操作适合刚接触车载诊断、想搞懂UDS协议栈、或者正准备做刷写和诊断工具的朋友看完可以直接上手发第一条0x10请求。1. 为什么ECU需要“会话”这个概念1.1 会话是权限和运行模式的总开关很多人刚学UDS诊断时第一个疑惑就是既然服务有了为什么还要专门做一个“会话控制”服务直接让诊断仪想干嘛就干嘛不就行了这个问题用一句话回答ECU不是为某一个诊断仪服务的它要考虑安全、生命周期和资源开销。假如任何诊断仪都能在车辆行驶中直接写Flash或者随便执行一次ECU复位后果不堪设想。所以ISO 14229定义了不同的诊断会话每个会话对应不同的服务权限和ECU内部行为模式。你可以把会话理解成ECU的一扇门。默认会话0x01是门锁最严的状态只允许基础服务比如读故障码、读VIN、ECU复位这种低风险操作。扩展会话0x03门开得更大允许读写数据、执行例程、调整参数适合产线和售后维修。编程会话0x02则进入“刷写模式”ECU会停止正常应用逻辑等待Bootloader接收新固件。也就是说0x10服务的作用不是“做某件事”而是“让ECU变成可以干某件事的状态”。这也是为什么它被放在UDS所有服务的最前面——你几乎所有的诊断流程都要从一次0x10请求开始。1.2 不同场景对会话的不同需求从ECU的整个生命周期看会话控制几乎是贯穿始终的产线下线需要刷写标定参数、写VIN、校准传感器这时候要进入扩展会话或编程会话权限不够很多服务会直接返回负响应。售后维修读取故障码、做执行器测试、学习匹配通常进扩展会话就够用了。远程升级或OTA核心链路是默认会话→编程会话→安全访问→擦除写入→复位0x10会话切换是第一脚油门。研发标定工程师要大量读数据、写参数、抓内部状态扩展会话是主战场。不同会话下ECU支持的诊断服务集合不一样甚至同样一个服务在不同会话下的行为也不一样。比如擦除Flash的例程控制服务你在默认会话下发ECU大概率回你一个7F 31 7F或者7F 31 22意思就是当前状态不让你干这事。一上来就排查半天结果发现只是会话没切对这种事我在新手期干过不少次。1.3 一个类比你肯定秒懂会话的概念可以和手机系统类比默认会话 手机正常模式用户能装App、打电话但碰不到系统底层。扩展会话 开发者模式能看到更多选项能抓日志、做调试但还没到刷机那一步。编程会话 恢复模式平时系统应用都不跑了专门用来刷固件、做底层恢复。手机切到恢复模式需要手动操作ECU切换到编程会话也需要诊断仪主动发一条0x10请求而且ECU不是无脑切换它会检查当前条件是否满足——比如车速为零、电源电压稳定、没有关键故障。而这些“检查逻辑”正是后面NRC 0x22条件不满足的常见来源。2. 从CAN报文角度拆解0x10请求与响应2.1 UDS在CAN总线上的“快递包装”ISO-TP协议UDS是应用层协议它本身不关心数据怎么在CAN总线上传输。在传统的CAN总线场景下UDS数据包要经过ISO 15765-2通常叫ISO-TP来分包和重组。这里只需要记住一个核心规则标准CAN帧的数据场最多塞8个字节而ISO-TP的第一个字节用来放PCIProtocol Control Information用来标识这是单帧、首帧还是连续帧。所以一个CAN帧里真正能放UDS payload的最多只有7个字节如果UDS消息超过7个字节就要拆成多帧来发。很多新手第一次抓包看到一串10 08、21 ...、22 ...开头的帧会蒙其实10 08是ISO-TP首帧标志注意这个0x10是PCI不是UDS的服务ID 0x10后面的21、22是连续帧索引。0x10服务正好和ISO-TP的首帧标志撞车我第一次看到的时候也绕了很久。2.2 请求帧解读02 10 03到底是什么意思以最常见的“进入扩展会话”为例诊断仪通过物理寻址发往ECUCAN ID是0x7E0数据场是CAN ID: 0x7E0 Data: 02 10 03 00 00 00 00 00逐字节拆解02ISO-TP单帧标志低7位表示payload长度这里长度是2也就是后面的10 03。10UDS服务ID诊断会话控制即SID 0x10。03子功能表示扩展诊断会话。后面的00 00 00 00 00CAN帧DLC不足8字节时的填充位ECU会忽略。同一帧如果是请求进入编程会话就把第三个字节改成0202 10 02。想回到默认会话则发02 10 01。就这么简单。这里还有个细节值得一提UDS的子功能字节最高位可以置1表示“抑制正响应”。比如发02 10 83意思是“我要求进入扩展会话但你别回正响应了”。这个机制在功能寻址广播场景下很有用能避免总线上一堆ECU同时响应造成拥堵。但平时单点调试不建议用因为看不到反馈出了问题不好定位。2.3 正响应解读50 03里的P2/P2*/S3参数ECU如果接受会话切换会通过物理响应CAN ID0x7E8返回正响应。常见的单帧响应如下CAN ID: 0x7E8 Data: 06 50 03 00 32 00 C8 00逐字节拆解06单帧标志payload长度6。50正响应SID等于请求SID加0x40也就是0x10 0x40。03子功能回显告诉你ECU确认自己已经进入扩展会话。00 32P2_server_max十六进制0x0032换算成十进制是50单位ms也就是ECU承诺在50ms内给出当前会话下的首个响应。00 C8P2*_server_max0x00C8 200单位ms。这是ECU在扩展会话下允许的延长响应时间。最后一个00CAN帧填充位。有些ECU还会在正响应里带上S3_server_max也就是会话保持超时时间。比如13 88换算成十进制是5000代表5000ms。如果ECU把P2、P2*、S3全部返回总payload会达到8字节超过单帧7字节上限此时ISO-TP就会把响应切成首帧和连续帧发送。你在抓包工具里看到的可能是ID 0x7E8 Data: 10 08 50 03 00 32 00 C8 ID 0x7E8 Data: 21 13 88 00 00 00 00 00第一帧10 08是首帧标志表示后续总长度8字节第二帧21是连续帧序号1带出剩下的13 88。2.4 负响应解读03 7F 10 12如果ECU拒绝请求会返回负响应格式是固定的三字节payloadCAN ID: 0x7E8 Data: 03 7F 10 12 00 00 00 00逐字节拆解03单帧payload长度3。7F负响应SID标志。10出错的服务ID表示“这条负响应是针对0x10服务的”。12NRCNegative Response Code表示子功能不支持。新手最容易犯的错就是把7F和10的顺序搞反或者看到12不知道去哪查。实际上NRC就是判定整个诊断流程能不能走通的关键每一个NRC都有明确含义后面我会专门开一节来讲0x10常见的NRC。3. 三种标准会话子功能怎么选3.1 默认会话0x01上电后的“待机模式”ECU上电后默认进入的就是默认会话不需要任何请求触发。在这个会话下ECU支持的服务最有限一般只保留安全风险低的基础服务比如0x10本身切换会话0x11 ECU复位0x14 清除故障码0x19 读取故障码信息部分功能0x22 按ID读数据通常只开放公共DID0x3E 保持在线默认会话的特点是被动、安静。ECU不会主动执行复杂的内部操作应用层功能正常运行诊断相关的高级能力全部锁着。你在默认会话下尝试读一个需要扩展会话才能访问的DID大概率会收到7F 22 7F或7F 22 7E意思是当前会话不支持该服务。理解默认会话的“贴地感”很重要。你发02 10 01回到默认会话不等于重启ECU它只是把诊断状态机切回了初始模式。很多诊断仪在流程结束时会主动发0x10 01就是为了让ECU退出非默认会话避免长时间占据高级权限。3.2 编程会话0x02刷写专用的“飞线模式”编程会话是刷写固件的专属通道。进入编程会话后ECU会做一系列准备工作停止应用层报文输出、关闭故障码检测、必要时切到Bootloader模式。这也是为什么刷写过程中你会看到ECU“突然不说话”了——别慌那是它正在进入编程状态。编程会话下通常开放的服务包括0x27 安全访问先解锁再操作0x31 例程控制比如擦除Flash0x34 请求下载0x36 传输数据0x37 请求退出传输0x11 ECU复位刷写完复位让新固件跑起来注意进入编程会话通常有前置条件。比如车速必须为0、发动机不能运行、电源电压要稳定。不满足条件时ECU会返回NRC 0x22conditionsNotCorrect。这时候别去查报文先看车辆状态是不是满足要求。另外编程会话是一种“高功耗”会话很多ECU在编程会话中会关闭网络管理报文诊断仪如果没有提前设计好超时策略容易误判为ECU掉线。实际的刷写流程里刷写工具通常在收到7F 10 78后持续发0x3E保活而不是傻等一个响应。3.3 扩展会话0x03绝大多数故障排查的主战场扩展会话是日常开发、产线检测、售后维修里用得最多的会话。它的权限介于默认和编程之间支持读写大量数据、执行例程控制、调整标定参数等。相比默认会话扩展会话往往还会放宽响应超时预算P2*从默认值变长因为有些请求确实需要ECU花更多时间才能完成。扩展会话里常见的操作用0x22读自定义DID用0x2E写参数比如配置车辆配置字用0x31执行例程比如部件测试、传感器校准用0x19读更详细的故障码快照用0x27做安全解锁后再进行敏感写入区别在于扩展会话不会像编程会话那样打断ECU的正常工作ECU的应用层功能通常还在跑。这也是为什么很多诊断仪在普通售后诊断时默认切到扩展会话而不是更激进的编程会话。3.4 三种会话对比总结项目默认会话 0x01扩展会话 0x03编程会话 0x02进入方式上电自动进入发送02 10 03发送02 10 02权限等级最低中等最高应用层功能正常运行正常运行通常停止典型服务0x10/0x11/0x19/0x22/0x3E增加0x2E/0x31/0x27增加0x34/0x36/0x37主要场景基础诊断、复位产线/售后/开发OTA、固件刷写P2*超时预算短默认约50ms中长可能200ms以上长可能达到5000ms三种会话并不是互斥的“阶梯”而是各有分工。你要写配置参数进扩展会话你要刷写固件进编程会话你只想读个VIN默认会话就够了。选错会话不会造成物理损坏但会浪费大量排查时间。4. S3定时器和P2/P2*超时机制才是0x10的隐藏难点4.1 S3超时后到底会发生什么S3_server_max是0x10正响应当中最容易被忽略的参数但它几乎决定了所有诊断工具的状态机设计。当ECU从默认会话切换到扩展会话或编程会话后ECU内部会启动一个S3定时器。标准默认值是5秒但具体值以ECU返回的正响应为准。如果在S3时间内ECU没有收到来自诊断仪的任何请求S3超时ECU自动退回默认会话。这个机制不复杂但它带来的实际影响很大。比如你手动用CAN工具发了02 10 03看到正响应后开始慢慢悠悠翻文档找下一个要发什么找了半分钟才发出下一条请求这时候ECU可能已经悄无声息地退回默认会话了你下一条请求自然被拒绝。怎么判断是否真的超时掉回了默认会话最直接的办法就是重新读一次ECU返回的会话参数或者用专门的状态DID去查当前激活会话。部分ECU支持用0x22读0xF186这个DID来确认当前处于哪个会话如果你的ECU支持这就是最直观的验证手段。4.2 0x3E保活为什么它叫“保持在线”S3超时机制的存在催生了0x3E TesterPresent服务。0x3E的请求格式很简单02 3E 00正响应是02 7E 00。它的唯一作用就是告诉ECU“诊断仪还活着”从而重置S3定时器。这里要厘清一个细节并不是只有0x3E才能重置S3。主流协议栈的实现里几乎任何有效的UDS请求都会重置S3定时器因为ECU收到请求本身就说明诊断仪在线。0x3E的特殊之处在于它是个“无事发生”的请求专门用来在客户端没有实际诊断任务可发的时候保活。我见过不少新手在刷写流程中收到ECU返回的7F 10 78后就干等着结果S3超时ECU掉回默认会话刷写失败。正确做法是在等待期间周期性地发0x3E比如每隔1到2秒发一次确保ECU一直留在编程会话里。4.3 P2和P2*ECU给你的两段式响应时间预算P2_server_max和P2*_server_max这两个参数很多人看到但不太理解它们的应用场景。P2是ECU在正常情况下处理一个请求并给出响应的最大时间默认是50ms。诊断仪发出请求后如果在P2时间内没收到响应就会启动P2计时。P2是ECU在某些需要长时间处理的请求下允许的延长响应时间默认值是5000ms但实际值通常由0x10正响应返回。举一个实际例子。你发了一个擦除Flash的例程控制请求ECU在50ms内肯定擦不完它也不会让你干等而是先回一个7F 31 78response pending然后继续干活。诊断仪收到0x78后知道ECU还在处理就进入P2超时等待。如果在P2时间内还是没有最终响应客户端才判定超时。所以客户端诊断栈的实现要会“读”0x10响应里的P2和P2*值动态调整自己的超时预算。如果写死一个固定的500ms超时遇到扩展会话里一个需要刷Flash的操作就很容易误报失败。4.4 客户端状态机该怎么管会话基于上面的机制诊断工具的会话管理其实可以收敛成一个简单的状态机初始状态默认会话P2 50ms。发送0x10请求后进入等待正响应状态。收到正响应后更新本地的P2、P2*、S3参数进入“非默认会话”状态。在非默认会话状态下维护一个S3倒计时每次收到任何正响应或负响应都重置倒计时。如果没有活跃任务周期性发送0x3E保活。S3超时回到默认会话更新超时参数为默认值。这个状态机是所有诊断仪工具链的地基。理解了它你后面写UDS刷写工具、诊断仪固件甚至只是用现成工具排查问题都会清晰很多。5. 实战用CAN工具把ECU切到扩展会话并验证5.1 硬件和软件准备动手实验前先准备好工具。硬件方面最常用的是PCAN-USB、周立功USBCAN-II或者Kvaser这类CAN分析仪接OBD-II接口的6号引脚CAN High和14号引脚CAN Low。如果没有整车用ECU台架或者带CAN接口的开发板也一样。软件方面可以直接用厂商自带的CAN调试工具比如PCAN-View、CANTest、CANoe。也可以用开源的python-can库通过几行Python就能发送和接收UDS报文。我个人建议入门阶段先用PCAN-View这类图形工具因为能直观看到总线上每一帧报文。5.2 连接前的三个确认我踩过几个坑先帮你避开第一确认CAN_H和CAN_L没有接反。接反后总线会出现大量错误帧抓包窗口全是Error Frame基本没法用。第二确认波特率和ECU匹配。绝大多数OBD诊断走的是500kbps但有些ECU或台架可能是250kbps。波特率不对现象同样是错误帧或完全收不到响应。第三确认收发地址。常规物理寻址是诊断仪发0x7E0、ECU响应0x7E8但不同OEM可能自定义地址务必以车型的诊断规范为准。5.3 第一步发送02 10 03请求在PCAN-View里新建一个发送帧CAN ID填7E0标准帧数据场填02 10 03 00 00 00 00 00然后发送。正常情况下Trace窗口中会出现一条ID为7E8的响应帧。如果ECU返回的是单帧响应你会看到类似06 50 03 00 32 00 C8 00的数据。如果什么响应都没有先检查是不是用了功能寻址ID7DF。功能寻址会把请求广播给总线上所有ECU如果多个ECU同时响应总线可能发生仲裁碰撞抓包界面看起来会非常乱。建议单ECU调试时只走物理寻址。5.4 第二步解读响应中的会话参数正响应里的关键不是那个50 03而是后面的P2和P2参数。假设你收到的是06 50 03 00 32 00 C8 00说明ECU告诉你我已经切到扩展会话接下来我处理请求的时限是P250ms延长响应时限P2200ms。如果你后续要发一个耗时可能超过50ms的服务客户端超时就不能只等50ms。有的ECU会返回06 50 03 00 32 01 F4 00这种01 F4也就是500ms代表P2*更高。各家实现不一样不要用一套固定参数应对所有车型要以实际响应为准。5.5 第三步验证ECU确实在扩展会话收到正响应后如何确认ECU不是“嘴上说切换、实际没切换”最稳的方法是用一个需要扩展会话权限才能执行的服务来验证。比如你的OEM规范里有某个DID只能在扩展会话下读取那就在默认会话下先读一次记下返回的NRC再切到扩展会话后重新读一次如果这次正常返回数据说明会话切换生效了。如果没有合适的DID也可以反向验证进入扩展会话后发一条0x3E保活观察ECU是否会持续在扩展会话里。然后停止发送任何请求等超过S3时间比如6秒后再发一条0x3E或0x22如果ECU回到默认会话此时你需要重新发02 10 03才能继续高级操作这就间接说明S3机制在工作。5.6 第四步观察S3超时自动回默认在完成上面的扩展会话操作后停下手不要发任何帧然后盯着CANoe或PCAN-View的Trace窗口。等5秒之后再试着发送一个只在扩展会话下支持的服务请求。如果ECU已经自动回到默认会话这个请求大概率返回负响应NRC是7F SID 7F或7F SID 7E。这时候你再发一次02 10 03又能正常切回扩展会话。整个过程能帮你直观建立“会话不是一劳永逸”的认知。6. 0x10容易踩的NRC坑和排查思路6.1 NRC 0x12子功能不支持03 7F 10 12是最容易遇到的负响应之一。它的含义是ECU根本不认识你发的这个子功能。常见原因子功能值写错。比如把0x02写成了0x04而ECU没有实现0x04。ECU是阉割版只实现了部分会话。低配ECU可能只有默认会话和扩展会话不支持编程会话。OEM自定义了会话集合和你参考的标准文档不一致。排查思路打开OEM的诊断规范确认该ECU支持的会话列表和子功能编号。不要想当然认为所有ECU都支持三种标准会话。6.2 NRC 0x13报文长度或格式错误03 7F 10 13说明请求的长度不对。0x10请求的标准格式是SID 子功能两个字节也就是ISO-TP单帧payload长度必须等于2。如果诊断仪发送了03 10 03 00多了一个字节ECU通常会回0x13。这个错误看起来低级但我在给客户做工具联调时真遇到过上位机在组包时多塞了一个保留字节的情况。排查时先检查发送缓冲区的长度字节是不是2。6.3 NRC 0x22条件不满足03 7F 10 22表示ECU认为当前外部条件不允许切换会话。最典型的场景是尝试在车速不为零、发动机运行中、或电压不足时进入编程会话。ECU为了安全会拒绝请求。这种NRC不是协议栈的Bug而是整车状态约束。排查思路查看车辆状态确保满足刷写或扩展诊断的前置条件。如果是台架测试检查电源电压是否稳定、是否有模拟车速信号在影响ECU判断。6.4 NRC 0x78请求已收到但需要时间03 7F 10 78不是错误它表示ECU已经接收到请求但需要更长时间准备暂时给不出最终正响应或负响应。这个NRC在进入编程会话时特别常见。ECU需要停应用、切Bootloader、初始化Flash驱动一套动作下来可能几百毫秒超出P2预算所以先回一个0x78稳住你。收到0x78后客户端要做两件事第一重置S3定时器发0x3E或保持请求通道活跃第二进入P2*超时等待继续监听后续响应。最终ECU会再返回一条最终的正响应或负响应。很多人在这一步直接判超时失败其实是对0x78的语义没理解透。它不是让你重新发请求而是让你“再等等”。6.5 NRC 0x7E / 0x7F当前会话不支持7F 10 7E表示当前会话下不支持该子功能7F 10 7F表示当前会话下不支持0x10这个服务。后者在实际中很少见因为0x10是基础服务默认会话里基本都支持。但如果出现0x7F先确认ECU是不是处于某个特殊模式比如Bootloader已经进入、编程会话未正常建立等这个时候ECU的完整协议栈可能还没有跑起来服务集和正常情况不一样。排查方向是ECU当前状态而不是0x10报文本身。7. 从0x10往后的路编程会话、安全访问和刷写链路7.1 一次完整刷写流程里的0x10角色理解了0x10之后你就能看懂UDS刷写流程的开头了。标准刷写链路大致是这样默认会话下诊断仪发02 10 02请求进入编程会话。ECU返回7F 10 78准备中或直接正响应50 02。如果收到0x78诊断仪持续发0x3E保活等待ECU完成切换。ECU进入编程会话后诊断仪发0x27服务做安全解锁。解锁成功后发0x31例程控制擦除Flash。然后通过0x34请求下载、0x36传输数据、0x37结束传输把固件写进去。最后发0x11复位让ECU带着新固件重新启动。在这一整条链路中0x10是第一道门。门没有打开后面的0x27、0x34、0x36全都会被负响应弹回来。7.2 编程会话中要注意的“掉线”假象进入编程会话后很多ECU会停止发送应用层CAN报文包括网络管理报文和周期数据帧。如果你用的是诊断工具的“在线列表”或者在看ECU心跳信号会以为ECU挂了。这不是故障而是ECU进入编程会话后的正常表现。判断ECU是否还在要看它是否响应你发的UDS请求而不是看它有没有周期性发应用报文。另外编程会话下有些ECU只允许物理寻址禁止功能寻址请求。如果你在切换会话后继续往0x7DF发请求可能得不到任何响应。这也是刷写工具要格外注意的兼容性问题。7.3 保活频率和时间参数怎么配置根据我的经验0x3E保活频率取1s到2s是比较稳妥的区间。太频繁会占用总线带宽太慢可能在0x78处理的长任务期间造成S3超时。超时参数不要硬编码。建议用0x10正响应返回的P2、P2*、S3来动态配置所有相关计时器。如果ECU没返回S3字段就用协议默认值5000ms。但不同OEM可能配置不同的S3值有些ECU的S3只有3000ms甚至更短这时候客户端如果不适配大概率会在实际项目中翻车。写在最后做诊断工具这些年我最大的体会是0x10看似只有两三个字节但它背后牵扯的是ECU状态管理、安全权限、超时机制、OEM自定义策略这一整套东西。把0x10吃透了后面学0x27安全访问、0x31例程控制、0x34/36/37刷写链路都会顺很多。我自己的习惯是每拿到一个新项目先抓一次真实的0x10请求响应把P2、P2*、S3记录到测试文档里再开始写代码。这个习惯帮我在无数个联调现场提前躲过了“会话超时”“权限不足”这类坑。下一课准备详细写0x27安全访问的种子与密钥流程那又是另一个让人头皮发麻的话题。
返回列表