ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

CAN到UDS诊断链路全解析:从物理层到应用层实战指南

CAN到UDS诊断链路全解析:从物理层到应用层实战指南 搞车载嵌入式这几年我接过最多的需求就是两类一类是“CAN报文就是调不通偶尔还掉线”另一类是“诊断仪连不上ECU刷写老失败”。这两类问题背后说白了就是底层CAN通信和上层UDS诊断协议没有形成一条完整的认知链路。这篇文档不聊虚的从CAN总线的物理层、数据链路层到ISO-TP传输层再到UDS应用层把整条诊断链路完整拆一遍。你会看到一条诊断报文从诊断仪发出去之后底层是怎么变成CAN电平、怎么经过仲裁和时钟同步、怎么被ECU拆包重组、最终如何返回响应码。适合刚入行的车载软件工程师、测试工程师也适合准备车载测试面试的兄弟照着这篇文章可以把项目经历里的“CAN/UDS”讲得更扎实。1. 先从CAN开始底层报文这事儿没那么玄1.1 为什么整车底层选了CAN而不是其他总线现在去翻任何一辆量产车的网络架构图底盘、动力、车身这些域里面CAN总线仍然是绝对的主力。很多人会问整车为什么不用更高速的以太网或者更简单的UART和LIN答案是成本和容错性。以太网带宽高但接口电路、线束、交换机成本摆在那里而且电磁兼容要求极高LIN便宜但速率只有20kbps适合车窗、座椅这种低速场景UART虽然简单但点对点通信根本没法在一个网络里挂几十个节点。CAN总线采用差分信号传输CAN_H和CAN_L两条线互为参考抗共模干扰能力很强这对发动机舱这种电磁环境恶劣的场景太重要了。同时CAN是多主网络任何节点都能主动发报文靠报文ID仲裁决定优先级不需要中心节点某一节点挂了不会把整个网络带崩。500kbps的经典CAN虽然速率不算高但足够覆盖整车控制器之间的实时控制数据。很多工程师对CAN的第一印象是“老”但“老”不代表“落后”它是整个车载诊断体系的地基UDS、OBD、刷写这些功能全得站在CAN肩膀上。1.2 一条CAN报文到底怎么构成的刚入行的时候我也是盯着CANoe里的报文列表发懵满屏的十六进制数据不知道谁是谁。后来把CAN帧结构吃透之后再看报文就清晰多了。经典CAN报文分标准帧和扩展帧标准帧11位ID扩展帧29位ID。帧结构从SOF起始帧开始接着是仲裁场、控制场、数据场、CRC场、ACK场和EOF。真正在应用层关心的主要是三块ID、DLC和数据场。ID决定了这条报文的身份和优先级仲裁的时候ID越小优先级越高这是CAN协议最核心的设计DLC表示数据场长度经典CAN最多8字节CAN FD最多能到64字节数据场里面放的就是具体信号比如车速、转速、开关状态。车里常见的做法是定义一套DBC文件把每个字节哪位是车速、哪位是档位、精度偏移量是多少全都描述出来。报文到了CAN控制器之后硬件会自动处理CRC校验、位填充、错误帧这些杂事应用层只需要读ID和数据场。但如果你想排查总线上的偶发错误那就得往物理层看了。1.3 仲裁和时钟误差CAN通信最容易忽略的两个坑仲裁机制是CAN最巧妙的点也是最容易被忽视的。多个节点同时发报文时总线上的显性电平逻辑0会覆盖隐性电平逻辑1发送节点一边发一边监听总线如果发现自己发的是隐性位但总线上是显性位就立刻退出等下一个总线空闲再发。所以ID小的报文先走紧急的控制报文必须分配小ID。实际排查问题的时候如果发现某条低优先级报文经常延迟不要去怀疑控制器死机先看一下总线负载率和ID分配是否合理。另一个更隐蔽的坑是时钟误差与重同步。CAN用的NRZ编码没有独立时钟线接收节点靠总线上的电平跳变来同步自己的位时间。每个CAN控制器的晶振精度不可能完全一致时间长了就会累积相位偏差。CAN协议因此把每一位时间分成同步段、传播段、相位缓冲段1、相位缓冲段2通过重同步机制在检测到边沿跳变时调整采样点位置。采样点一般来说建议设置在75%~85%左右很多控制器默认配置在80%附近。经典CAN的位时间误差容忍度通常在1.5%以内但如果晶振偏差大、采样点配置不合理就会出现偶发错误帧甚至Bus Off。这个问题在常温台架上很难复现上了整车高低温环境就冒出来排查起来相当费头发。1.4 CAN FD带来的变化现在的车越来越多开始用CAN FD它和经典CAN的帧结构、仲裁机制基本兼容但有两个关键变化一是可变速率仲裁阶段和ACK阶段仍然用低速比如500kbps数据阶段可以切到2Mbps甚至5Mbps、8Mbps二是数据场从8字节扩展到最多64字节。这对诊断刷写意义重大比如UDS的34/36/37服务经典CAN一次最多传7字节有效数据还有1字节留给协议头而CAN FD一次可以传更多刷写时间能大幅缩短。但CAN FD也带来了新的坑波特率切换点必须双方协商一致如果发送端已经切到高速接收端还没准备好就会报格式错误。另外数据阶段速率提高之后对线束质量和终端电阻匹配更敏感反射和振铃更容易导致位错误。所以做CAN FD项目的时候除了看协议栈配置还要关注物理层的信号质量后面我会专门说波形怎么看。2. 从CAN到UDS诊断协议解决的是“人机对话”问题2.1 没有诊断协议时你面对的是什么CAN报文本身只是一堆ID加数据场它只解决“节点之间能通信”的问题不解决“诊断仪该问ECU什么问题”的问题。想象一个场景产线上要对一个新下线的ECU做功能测试测试台需要知道“这个控制器里有没有存故障码”“软件版本是多少”“能不能执行一次自检”。如果没有统一协议每个ECU厂家都得自己定义一套报文格式那产线、售后、OBD检测全得跟着乱套。UDSUnified Diagnostic Services就是ISO 14229定义的一套应用层诊断协议。它规定了诊断仪和ECU之间“怎么问”“怎么答”“答不了怎么报错”。在物理层和数据链路层UDS跑在CAN或者CAN FD上中间还需要ISO-TPISO 15765-2这个传输层来负责分包和重组因为CAN一帧最多放8字节经典CAN而一条UDS消息可能几十上百字节。2.2 UDS的寻址、会话和安全访问UDS的第一个基本概念是寻址。诊断仪发的请求有两种物理寻址和功能寻址。物理寻址是发给指定的某一个ECU比如0x7E0通常对应发动机ECU就只发给它功能寻址一般用0x7DF网络上所有支持诊断的ECU都会响应适合广播式的请求比如读取所有ECU的DTC。响应报文通常用物理寻址回地址是请求地址加8例如请求0x7E0响应就是0x7E8。这个“请求8”的规则在做抓包分析时非常实用一眼就能看出来哪条请求对应哪条响应。第二个概念是会话。ECU默认上电处于默认会话10 01很多诊断服务在默认会话下是不允许执行的需要先切到扩展会话10 03或编程会话10 02。为什么这么设计为了安全。ECU在正常运行过程中不希望被诊断仪乱改数据只有进入特定会话并且通过安全访问才能执行写数据、例程控制这些敏感操作。会话还有个超时机制比如扩展会话如果一段时间没有诊断请求ECU会回到默认会话这个时间由S3Server定时参数控制。第三个概念是安全访问对应UDS的27服务。27服务是一种挑战-应答机制诊断仪先发27 01请求种子SeedECU返回一串随机种子诊断仪根据种子和约定的算法算出一个密钥Key再发27 02给ECUECU校验通过后解锁。之后才能执行写数据、刷写这类高风险操作。很多初学者会把种子和密钥搞混记不住“先要种子再发密钥”。这个流程的价值在于防止非授权设备乱写ECU数据密钥算法和种子长度每个厂家都不一样通常还会加延迟计数器和尝试次数限制防止暴力破解。3. 核心服务逐个拆常用UDS服务与NRC3.1 必须吃透的几个UDS服务UDS服务号很多但实际项目里翻来覆去用的就那几个。10服务是会话控制切默认、扩展、编程会话都靠它是诊断的第一步。22服务是按ID读数据比如读软件版本号、读VIN每个数据都有对应的DID数据标识符。2E服务是按ID写数据往ECU里写配置信息。19服务是读DTC信息DTC就是故障码报文中包含DTC状态字节这个状态字节每一位都有含义bit0表示测试失败bit3表示已确认故障bit6表示自上次清除后未完成测试面试时经常会被问到。14服务是清除DTC执行完维修后一般要清码验证。再往上是和刷写强相关的三个服务34请求下载、36传输数据、37请求传输退出。34服务是告诉ECU“我要开始下载了数据的格式是什么、地址从哪开始、总长度是多少”ECU返回一个允许的最大数据块长度之后36服务就是一块一块地把数据传进去每块大小不能超过ECU允许的长度。数据传完之后用37服务结束整个传输过程。31服务是例程控制最典型的应用是擦除Flash或者执行自检、复位。11服务是ECU复位刷写完成后通常要发一个11 01来重启ECU。3.2 NRC到底在说什么ECU收到一条请求之后不可能每次都回 positive response。如果请求不满足ECU就回一条7F开头的负响应格式是7F 请求的服务ID NRC。NRCNegative Response Code就是负响应码相当于ECU在说“你让我干的事我没法干原因是这个”。最常见的NRC包括0x11表示服务不支持往往是请求的服务ID超出ECU支持范围0x12表示子功能不支持服务号对但子功能号不对0x22表示条件不满足就是说你现在这个状态不能执行这个操作比如没有进入相应的会话就尝试写数据0x31表示请求超出范围这个最容易让人迷惑它可能表示参数值不对也可能表示当前会话不支持这个例程还可能是安全等级不够0x33表示安全访问被拒绝说明你还没解锁就干了需要解锁才能干的事0x7F表示服务处理过程中发生了内部错误一般还要继续细分。很多测试同学一看到0x31就慌了以为是内存地址写错了。实际上要结合当前会话状态和上一个服务一起看。我踩过最典型的一个坑刷写流程里34服务之前必须先完成擦除例程但擦除例程又要求在编程会话下执行。如果我在扩展会话里直接发31 01 02 01请求擦除ECU回了0x31。这个并不是地址错了而是我根本不在编程会话里。后来养成了习惯任何NRC问题先查会话状态再查安全访问状态最后查参数。4. 底层CAN和上层UDS怎么配合从请求到响应走一遍4.1 ISO-TP传输层一条长诊断消息怎么塞进CAN帧UDS一条消息动不动几十个字节但经典CAN单帧数据场只有8个字节根本塞不下。ISO-TP就是干这个的。ISO-TP把上层消息分成四种帧单帧SF、首帧FF、连续帧CF、流控帧FC。如果消息不超过7个字节CAN FD场景下更多直接一个单帧就发出去超过7个字节就发首帧告诉接收方“总共要传多少字节”然后接收方回一个流控帧告诉发送方“我准备好了你可以发连续帧了每帧最多发多少、间隔多久”之后发送方用连续帧把剩下的数据发完。这里有一个很实用的分析技巧在CANoe或者周立功的报文软件里看到以“10”开头的数据说明这是一个首帧后面跟着的是总长度信息看到以“01”“02”这类开头的数据且前面已经出现过首帧那就是连续帧。诊断请求和响应在同一个CAN ID通道里走ISO-TP所以抓包的时候要等所有分帧收齐才能看到完整的UDS消息。底层和上层配合不好的问题也常常出在这里。比如曾经遇到过UDS响应一直超时怎么查都查不到。后来用CANoe的协议统计一看ECU返回的是多帧响应但ECU在发完首帧之后流控帧的发送条件没满足导致诊断仪一直不发连续帧。其实是诊断仪侧的ISO-TP实现里接收缓冲配置得太小导致流控帧延迟。这种问题不是UDS逻辑错了而是传输层参数不匹配。4.2 一次完整诊断请求响应的报文级流程把前面这些知识串起来我们看一条实际诊断请求的完整流程。第一步诊断仪发功能寻址或物理寻址的CAN帧。比如要读发动机ECU的DTC诊断仪先发10 03进扩展会话这条消息很短ISO-TP直接打包成单帧CAN ID是0x7E0数据是02 10 03 00 00 00 00 00。开头的02表示PCI类型是单帧且带两个有效字节10是服务ID03是子功能。第二步ECU收到后回50 03表示进入扩展会话成功。此时如果直接发19 02来读DTC是不需要安全访问的但如果要执行擦除Flash就得走27服务做安全访问。第三步安全访问通过后发31 01 02 01执行擦除例程。这个请求如果报文较长会变成FFCF多帧交互。ECU在执行擦除操作期间可能不会很快响应诊断仪必须等待这个等待时间由P2*定时器控制。第四步擦除完成之后发34 00 44请求下载告知地址和长度ECU回34 00 44 块长度。然后循环发36服务传数据每一帧数据块都要带块序列号ECU每回一个36的肯定响应再发下一块。如果块序号没对上ECU会回NRC 0x13报文长度错误或格式错误。传完之后发37退出然后11 01复位ECU。我把这段流程做成了一张表方便对照抓包软件逐条看步骤方向CAN ID数据内容含义1诊断仪→ECU0x7E002 10 03请求进入扩展会话2ECU→诊断仪0x7E802 50 03扩展会话确认3诊断仪→ECU0x7E002 27 01请求种子4ECU→诊断仪0x7E804 67 01 AA BB返回种子AA BB5诊断仪→ECU0x7E004 27 02 11 22发送密钥11 226ECU→诊断仪0x7E802 67 02安全访问通过7诊断仪→ECU0x7E004 31 01 02 01请求执行擦除例程8ECU→诊断仪0x7E802 71 01例程执行成功9诊断仪→ECU0x7E006 34 00 44 00 00 10 00请求下载地址0x00100010ECU→诊断仪0x7E805 74 00 44 00 20允许每块传输0x20字节11诊断仪→ECU0x7E022 36 01 01 02 03 ...传输第1块数据12ECU→诊断仪0x7E802 76 01第1块确认...............13诊断仪→ECU0x7E002 37 01请求传输退出14ECU→诊断仪0x7E802 77 01传输退出确认15诊断仪→ECU0x7E002 11 01请求ECU复位16ECU→诊断仪0x7E802 51 01复位确认4.3 刷写流程里的检查点设计热词里反复出现“检查点流程”这在刷写开发里确实是个高频考点。刷写不是把数据一股脑发过去就完事每一大步都要有确认机制。检查点可以理解为刷写流程中的里程碑确认进入编程会话算一个检查点安全访问通过算一个检查点擦除完成算一个检查点整个下载结束再校验一次。如果某个检查点没通过流程就立刻终止避免刷写一半导致ECU变成砖。实际工程里还会在刷写前做完整性检查比如先通过22服务读取ECU当前软件版本、VIN、硬件版本把信息回传到上位机确认刷写包和ECU匹配才开始操作。刷写中间如果发生总线掉线或者电压不稳ECU要靠内部看门狗和升级标志恢复这也是为什么很多刷写流程要求先擦除后下载、先检查后复位。做刷写测试的时候建议把检查点做成自动化脚本每一步都留日志出问题的时候回溯到具体步骤比对着抓包数据猜快得多。5. 实车与台架上的问题排查实录5.1 CAN波形怎么看判断通信质量的基本功排查CAN通信问题示波器是绕不开的工具。很多人看CAN波形只会看“有没有波形”但真正要判断通信质量得看细节。CAN总线空闲时CAN_H和CAN_L都处于2.5V左右显性位时CAN_H拉到3.5V左右、CAN_L降到1.5V左右差分电压约2V隐性位时两条线回到2.5V附近。正常波形应该是边沿陡峭、幅值稳定、无畸变。如果波形上升沿变缓、过冲明显、振铃大多半是终端电阻匹配问题或者线束过长。CAN总线的标准做法是在网络两端各接一个120欧终端电阻中间节点不接。我遇到过整车下线后某段CAN通信偶发错误量波形发现某节点分支线太长反射叠加导致采样点附近电平不确定后来把分支线缩短问题就消失了。还有一次是CAN_H和CAN_L接反了波形完全是反的用示波器一眼就能看出来。采样点和时钟误差的排查往往要看长时间波形。比如某节点晶振偏差偏大实时性要求高的报文会周期性出现位错误。这种问题常规排查手段是降低波特率或者调整采样点位置。例如把采样点从70%调到80%可能就把本来在采样点附近翻转的电平错开误码率显著下降。注意采样点不是越高越好太高了留给传播延迟的余量就小要结合线束长度和波特率综合设置。5.2 总线负载率、仲裁丢帧和重同步的排查思路总线负载率是另一个容易踩坑的地方。经典CAN 500kbps下理论最大利用率也就是每秒能传约6500帧标准帧但实际设计中一般建议把负载率控制在60%以下超过70%就会有明显的排队延迟。如果某条低优先级报文周期性超时先算一下负载率再查它的ID是不是太小。我之前遇到过一个项目把一条周期10ms的安全气囊状态报文设成了大ID结果网络上报文一多它经常被高优先级报文挤到后面最后其实是把ID调小解决的。所谓重同步调试其实更多是看错误帧和Bus Off统计。CAN控制器的错误计数器会在错误帧时增加连续错误超过255就会进入Bus Off状态节点主动与总线隔离。很多偶发性问题都是“过一段时间才出现复现困难”这时候可以把CAN控制器的错误计数器读出来做成标定变量出了故障记录错误类型比如位错误、格式错误、CRC错误。这些错误类型对应的物理原因各不相同位错误多半是波特率不匹配或时钟偏差格式错误多半是CAN FD切换逻辑有问题CRC错误多半是干扰导致数据被破坏。按照错误帧类型去反推原因比盲目换线束或换控制器有效得多。5.3 UDS交互问题的经典排查清单UDS开发中我遇到的绝大多数问题最后都能归类到几个固定原因。第一是会话问题请求返回0x7F 0x22先查当前是不是正确的会话。第二是安全访问问题返回0x33说明还没做27服务或者种子密钥算法不对。第三是请求数据格式不对返回0x13说明PCI长度或子功能长度有问题。第四是NRC 0x31这个万能响应它含义最广必须结合文档确认是“地址超出范围”还是“例程不被支持”。这里给一个我日常排查NRC的个人习惯每收到一个负响应先不要急着查数据先看返回NRC的服务ID是什么然后对照当前会话、当前安全等级、请求参数列表画一个三步判断。如果服务ID本身就不支持基本不用查参数直接查ECU的配置清单如果服务ID支持但子功能不对查ISO 14229规范里该服务的子功能定义如果都支持再查参数范围和前提条件。这套流程看起来简单但能让我快速把问题从“不知道从哪查”收敛到具体方向。排查表格整理如下现象常见NRC优先排查常见原因请求服务不被接受0x11ECU诊断配置服务未实现或未使能子功能不支持0x12子功能号用了保留值或当前会话不支持条件不满足0x22当前会话/状态未进入正确会话或前置条件缺失请求超出范围0x31参数列表/例程内存地址、参数值或例程ID非法安全拒绝0x3327服务流程未解锁或密钥错误长度/格式错误0x13ISO-TP分包/PCI长度字段与数据不符5.4 车载测试工具链的选择与避坑工具选型也是车载网络测试的日常。CANoe功能强大是行业标准级工具但License贵适合在公司统一用个人学习或者验证小项目周立功CANTest、PCAN-View都是便宜好用的选择。这里说一个常见的坑周立功的驱动在WiFi热点共享、网络切换频繁的环境下偶尔会被系统防火墙干扰导致设备无法识别Windows 11下特别容易遇到设备枚举失败建议先重装驱动再换USB口别一上来就以为硬件坏了。抓包软件我一般会配合CANoe的离线回放功能把问题复现时候的报文全部录下来回到电脑上反复看。排查UDS多帧交互问题时用CANoe的Diagnostics窗口可以直接解析ISO-TP和UDS层比手动数十六进制高效得多。如果是CAN FD项目还要确认工具链支持CAN FD的数据段波特率和自动采样点配置否则抓到的高速数据阶段报文可能会显示成错误帧。6. 最后分享几个实操经验在真正做车载CAN和UDS开发之前我也觉得这就是一份配置文档的事。但项目做得越多越明白底层和上层必须放在一起理解。底层的时钟误差、采样点、仲裁优先级随时可能把你上层的UDS流程搅成一锅粥而上层的会话、安全访问、NRC又反过来决定了底层需要支持多大的PDU、多快的传输速率。做车载测试和开发遇到问题记得先分层定位物理层看波形、数据链路层看错误帧计数、传输层看ISO-TP帧交互、应用层看NRC。每一层都有自己的特征锁定层次之后问题基本就解决了一半。我个人还有个习惯所有诊断报文都先记录下来整理成一套自己的速查表包含服务ID、子功能、常见NRC、请求响应示例。这套速查表陪了我好几个项目面试的时候拿出来讲也特别有说服力。后面如果你做的项目升级到车载以太网DOIP、SOME/IP这些新协议本质上也是先解决“怎么传数据”再解决“传什么数据”底层CAN和UDS这套认知框架依然成立。先把CAN和UDS吃透车载通信这棵树的根就扎稳了。
返回列表