资讯动态

一文掌握CAN总线与UDS诊断开发:从位时序到Bootloader刷写全流程

发布时间:2026/9/9 1:11:30 来源:尧图企业网站定制
1. 项目概述与整体架构设计1.1 从需求到落地的完整链路这套技术方案的起源其实很朴素一个车载ECU要在量产产线上完成软件刷写和功能诊断就必须有一条稳定的CAN链路和一个标准化的诊断服务栈。需求方不会直接告诉你“去实现UDS 19服务”它只会告诉你“产线要在3秒内读完所有DTC”或者“刷写失败时必须准确上报失败原因”。把这些业务需求翻译成CAN报文、服务参数和超时策略就是这份技术文档存在的意义。我当时把整个需求拆成三层来看。最底层是物理信号层负责CAN收发器选型、终端电阻、线束拓扑和位时序参数中间是数据链路层依靠主控里的CAN控制器完成报文的接收、滤波、发送和错误处理最上层才是UDS服务层维护会话状态、安全等级、子功能表、NRC返回规则以及刷写流程的状态机。层与层之间用接口隔离底层的波特率调整不会影响到上层服务逻辑上层新增诊断服务时也不需要把驱动层的报文解析再翻一遍这个结构在后来的实车调试中帮了大忙。整个项目最终跑通的形态是底层用STM32F103的bxCAN外设跑500kbps上层按照ISO 14229实现了一个精简但完整的UDS诊断栈覆盖10/11/19/14/22/2E/27/31/34/36/37这些常用服务同时在Bootloader和APP两层都实现了诊断响应。从发出请求到收到响应P2时间控制在35ms以内满足项目定义的50ms指标。接下来我把每一层的设计思路和具体参数捋一遍你可以直接拿这些配置去对你自己板子上的寄存器。1.2 为什么底层选CAN、上层选UDS选型这件事很多人一上来就纠结“为什么不用以太网”“为什么不上CAN FD”。我的回答是先看手里有什么硬件再看要传多少数据最后看产线和售后工具链愿不愿意跟着换。这个项目的主控是STM32F103内部只集成了bxCAN控制器没有CAN FD外设如果硬要上CAN FD就得换主控、换收发器、换产线工装整套成本的改动量远超功能本身的价值所以经典CAN 2.0B继续用完全没有问题。诊断刷写的数据量其实没有大家想象中那么夸张。一个100KB的应用程序在500kbps的CAN链路上传输就算加上协议开销和块间间隔实际有效吞吐稳定在300-400kbps左右整个刷写流程几十秒能完成这个时间在产线节拍里完全可接受。只要不是动辄几十MB的大数据升级经典CAN就不会成为瓶颈。上层选UDS则几乎没有悬念。ISO 14229把所有诊断服务的报文格式、子功能定义、时序要求、NRC返回规则都规范好了不管是哪家供应商做的ECU只要声明支持UDS测试端就能用同一套脚本去做诊断和刷写。相比OEM私有的诊断协议UDS在工具链支持、人员上手难度和跨平台兼容性上的优势都太明显。对我们这种经常要对接不同主机厂项目的团队来说UDS是唯一一个不用重复解释“你这个0x22的NRC为什么和别家不一样”的协议。2. 底层CAN通信从波形到驱动的硬核细节2.1 位时序、采样点与SJW同步跳跃宽度怎么配CAN通信的底层参数说穿了就是一句话一个位时间怎么切分采样点放在哪个位置万一出现时钟偏差时允许跳多少个时间量子去修正。标题热搜里出现的“sjw同步跳跃宽度”它的全称是Synchronization Jump Width也就是重新同步时允许单个位时间增加或缩短的最大时间量子数。SJW配得太小长总线、多节点场景下跟不上位流边沿的漂移配得太大又可能在位中间误跳到噪声边沿上。常见的稳妥做法是SJW取1到4个TQ一般配置为1只有在总线速率偏高或者节点时钟精度较差时才考虑加大。位时序的具体计算我用实际项目举个例子。目标波特率500kbpsSTM32F103的APB1时钟是36MHz先给CAN外设做4分频得到9MHz的CAN时钟那么一个时间量子TQ就是1/9MHz约等于111ns。500kbps对应每一位2us也就是每个位时间要由18个TQ组成。接着把这18个TQ分配给同步段SYNC_SEG 1个TQ、传播段加相位缓冲段BS1合计13个TQ、相位缓冲段BS2合计4个TQ这样采样点位置就是(113)/18约等于77.8%这个采样点对大多数车身控制器的短距离总线来说都是够用的。配置时最大的坑在于寄存器里的值不是“实际TQ数”而是“实际TQ数减1”。STM32F103的CAN_BTR寄存器里TS1[3:0]和TS2[2:0]这两个字段都是按减一方式编码的。也就是说你算出来BS1需要13个TQ填入寄存器时要写12BS2需要4个TQ填入寄存器时要写3。很多刚上手的人明明算好了分频系数却在寄存器填值上多写或少写一个TQ结果示波器量出来的波特率就是对不上。这类问题用CAN分析仪一抓就能发现所有报文都在报错帧没有任何正常帧能通过总线。2.2 STM32F103 bxCAN的初始化、滤波器与发送接收实现bxCAN的初始化配置代码不长但每个字段都有讲究。实际项目里我用的参数是这样一组预分频器CAN_Prescaler4BS113个TQBS24个TQSJW1个TQ正常模式打开自动离线恢复ABOM和自动唤醒AWUM关闭自动重传NART注意这里是DISABLE关闭NART意味着发送失败不会自动重传方便在上层自己控制重发策略。CAN_InitTypeDef canInit; canInit.CAN_Prescaler 4; canInit.CAN_Mode CAN_Mode_Normal; canInit.CAN_SJW CAN_SJW_1tq; canInit.CAN_BS1 CAN_BS1_13tq; canInit.CAN_BS2 CAN_BS2_4tq; canInit.CAN_ABOM ENABLE; canInit.CAN_AWUM ENABLE; canInit.CAN_NART DISABLE; canInit.CAN_RFLM DISABLE; canInit.CAN_TXFP DISABLE; CAN_Init(CAN1, canInit);初始化里的CAN_RFLM和CAN_TXFP也是两个容易被忽视的选项。CAN_RFLM是FIFO锁定模式如果打开FIFO满了之后新来的报文会被丢弃旧报文保留如果关闭则是先进先出新报文覆盖旧报文。诊断报文的实时性要求高不能容忍旧报文一直占着FIFO所以这里保持DISABLE让最新报文能及时进入。CAN_TXFP是发送优先级由FIFO顺序决定如果关闭则按照报文ID优先级从低到高发送诊断ID通常设得比较低在总线上有优势所以也保持DISABLE。滤波器部分我按诊断报文的实际ID来做掩码匹配。比如APP层用0x7E8作为物理寻址响应ID0x7DF作为功能寻址请求ID那么滤波器就配置成32位掩码模式ID高字节填想要接收的ID掩码高字节填0x7FF表示标准帧ID全匹配这样收到的诊断请求只进FIFO0其他无关报文不会触发中断减少了软件层的无效处理负担。接收中断里只需做一件事从FIFO把报文搬到自己的环形缓冲区然后置一个标志位。不要在中断里直接跑UDS状态机否则一旦来了连续多帧报文中断处理时间会成倍拉长甚至影响S3超时和P2延时的计时精度。我踩过这个坑后来把中断里的逻辑压缩到只做数据搬移解析全部放到主循环或者RTOS任务里问题立刻消失。2.3 CAN总线仲裁与错误处理的工程理解CAN总线的仲裁机制是它区别于其他现场总线的核心。多个节点同时发送时总线通过显性电平覆盖隐性电平的物理特性实现ID仲裁ID值越小优先级越高。举个例子诊断请求的ID 0x7DF和某个动力报文ID 0x0A0同时发送0x0A0的显性位更早出现仲裁获胜诊断报文就需要让出总线等下一轮。这就是为什么在高度拥堵的总线上诊断响应偶尔会晚到你不能把超时参数卡得太死。错误处理方面每个CAN节点内部都有发送错误计数器和接收错误计数器。错误计数值超过127会进入错误主动状态超过255则进入总线关闭状态。STM32的bxCAN可以通过读CAN_ESR寄存器拿到最近一次错误码LEC实现中我把LEC值关联到错误中断里一旦出现位错误、填充错误、CRC错误这些异常就记录下来并恢复。打开ABOM后总线关闭状态会自动恢复但对诊断来说恢复后还要做一次显式的会话重置才可靠因为节点离线期间可能错过了诊断仪的会话激活请求。2.4 CAN与CAN FD的选型对比CAN FD近年在车载新平台用得越来越多但经典CAN并不会立刻被取代。我整理了一张表把两者在这类诊断刷写场景中的关键差异列出来方便你做技术决策时直接对照。对比项经典CAN 2.0BCAN FD最大波特率1Mbps数据段最高到8Mbps以上单帧数据长度8字节最高64字节帧格式标准帧/扩展帧标准帧/扩展帧带FD标志传输效率有效负载率低大数据块刷写效率高控制器成本极低普及度高需支持FD的MCU或外置控制器工具链兼容所有CAN工具都支持需要工具和上位机同步升级适用场景车身控制、诊断、简单标定大数据刷写、自动驾驶高带宽节点如果你是做车身控制器、灯具、门窗这类低速节点的诊断开发经典CAN完全够用如果你做的是域控制器刷写或者OTA大包传输那CAN FD带来的吞吐提升是实打实的。本项目因为主控限制选经典CAN如果后续平台升级到带FD外设的单片机我的建议是直接把500kbps升级为仲裁段500kbps加数据段2Mbps的CAN FD配置UDS服务代码几乎可以不用改因为你本来就是在应用层发数据底层换一套驱动就行。3. UDS诊断协议上层开发的核心要点3.1 诊断会话、寻址与NRC基础机制UDS协议最核心的思想是通过一套统一的诊断服务把ECU内部状态暴露给外部诊断仪。ECU上电后默认处于默认会话如果要做刷写必须先通过10服务切换到编程会话如果要读一些受保护的参数必须先通过27服务做安全访问解锁。会话之间是有时间约束的默认会话的S3超时一般是5000ms扩展会话和编程会话如果超时未收到诊断请求ECU会自动跳回默认会话这个机制是为了防止产线测试时一台设备把ECU锁在某个会话里出不来。寻址模式分物理寻址和功能寻址。物理寻址是一对一诊断仪发到某个特定ECU的地址ECU必须回复功能寻址是一对多比如0x7DF这个功能寻址ID可以同时唤醒总线上所有ECU但ECU收到功能寻址请求时通常不回复避免多个ECU同时应答造成总线冲突。很多开发新手在测试时用功能寻址发了19服务读DTC然后抱怨为什么没有响应其实只是忘了ECU对功能寻址不回复这个约定。NRC是UDS里最能体现实现质量的部分。每个NRC都代表一种明确的拒绝原因我在项目里维护了一张常用NRC速查表开发时每写一个服务都对照这张表检查一遍看有没有漏掉该返回的错误场景。NRC含义典型触发场景0x11服务不支持ECU没有实现该SID0x12子功能不支持SID支持但SF不识别0x13报文长度错误数据长度与SID要求不匹配0x22条件不满足会话不对、前置条件没完成0x24请求序列错误例如没做安全访问就直接请求下载0x31请求超出范围参数值非法、地址不在可访问范围0x33安全访问被拒绝需要先通过27服务解锁0x35密钥错误27服务第二帧的key校验失败0x36尝试次数超限密钥尝试次数超过设定的最大值0x37延时时间未到上一次失败后需要等待一段时间0x78请求已收到但正在处理处理时间超过P2先回一个0x78保活0x7F服务在会话中未激活编程会话中尝试执行默认会话才允许的服务0x22和0x31这两个NRC是最容易用错的。0x22表示条件不满足更多是时序状态不对0x31表示请求参数超出范围更多是值本身非法。比如你在默认会话请求刷写应该回0x22你请求擦除一个超出Flash地址范围的块应该回0x31。这两个如果搞反了测试端的诊断脚本虽然也能识别但诊断工程师查问题时会被误导所以我们内部规定所有服务实现都要写清NRC分支的判定顺序。3.2 DTC状态位一个字节里的八种人生19服务是读DTC14服务是清除DTC29服务是读DTC快照这些服务都围绕一组状态位展开。很多人第一眼看到DTC状态字节会觉得它就是一个十六进制数实际上它每一位都有独立的语义而且不同位之间存在状态转换关系。我在项目文档里专门画了一张位定义表方便对标。位名称含义Bit0testFailed最近一次测试失败Bit1testFailedThisOperationCycle本次上电周期内测试失败过Bit2pendingDTC待确认DTC当前或上次周期测试失败Bit3confirmedDTC已确认DTC连续多个周期失败或经过确认流程Bit4testNotCompletedSinceLastClear上次清除后测试未完成Bit5testFailedSinceLastClear上次清除后测试曾失败Bit6testNotCompletedThisOperationCycle本次上电周期内测试未完成Bit7warningIndicatorRequested请求点亮故障灯或提示诊断仪读DTC时ECU返回的每个DTC后面都带这个状态字节诊断仪可以按状态字判断故障是当前存在还是历史记录。开发时最常见的问题是把DTC状态只更新到Bit0就完事没有按测试周期推进Bit1到Bit5的状态迁移结果实车测试时14服务清除DTC后旧状态还残留着。我建议把DTC状态迁移单独做成一个小模块每次测试结束时统一更新所有状态位而不是在各个功能模块里零散地改否则很容易出现这个模块置了Bit0、那个模块又把它清掉的竞态问题。3.3 安全访问27服务的时序与防破解策略27服务的流程看似简单请求种子算密钥发密钥解锁成功。但实际工程中坑特别多。先看时序诊断仪发27 01请求种子ECU回复67 01加种子数据诊断仪收到种子后计算出密钥发27 02加密钥数据ECU校验通过后回复67 02安全访问才算完成。种子和密钥的算法不能太简单。直接用固定种子、固定密钥的做法在内部开发和测试时效率高但实车落地等于没设防。我在这类项目里的做法是用一个带滚动计数的算法把种子的一部分作为计数器的输入密钥计算时再混入一些厂商自定义的字节这样每请求一次种子结果都不一样能有效防止重放攻击。同时还要在ECU端做尝试次数限制和延时惩罚比如连续三次密钥错误后锁定安全访问30秒这段时间内即使密钥正确也返回NRC 0x37。27服务的NRC返回时机也很有讲究。种子请求阶段如果ECU正处于锁定状态要区分是返回0x36尝试次数超限还是0x37延时时间未到。0x36偏向账户级别的锁定0x37偏向时间层面的惩罚。有些测试脚本会分别验证这两种场景如果你的ECU在这两个NRC的处理上过于笼统测试用例直接挂在安全访问这一项。3.4 常用诊断服务的技术组合UDS服务不是孤立使用的一个完整的诊断流程往往需要多个服务按顺序组合。比如产线刷写后的功能测试通常先用10 02进编程会话再用11 01软复位让ECU带新程序启动复位完成后再通过10 03进扩展会话用22服务读取软件版本号做刷写确认最后用14服务清除历史DTC保证交付给客户的ECU是“干净”的。再比如读取故障码我的建议是先发19 02按状态掩码读DTC再发19 04读快照信息这样诊断仪能拿到完整的故障上下文。0x19服务的亚功能很多19 01按DTC状态掩码读数量19 02按状态掩码读DTC19 04读快照记录19 06读扩展数据。如果你在实现时只做了19 02测试用例里一旦出现19 01或19 04ECU就会返回0x12诊断工程师一看日志马上就明白你的19服务覆盖不全。4. Bootloader刷写流程的完整落地4.1 34/36/37三个服务的协同逻辑刷写是UDS诊断开发的硬骨头它把传输层、会话管理、安全访问、Flash驱动和看门狗全部串在一起。标准刷写流程通常长这样10 02进编程会话、27 01/02安全访问、85 02关闭DTC记录、28 03关闭非诊断报文、31 01 02 02擦除Flash、34请求下载、36传数据、37请求传输退出最后11 01软复位跳APP。每一步都有严格的前置条件比如没做安全访问就发34请求下载ECU至少要回一个0x33不在编程会话里发擦除例程ECU要回0x22。34请求下载的作用是让ECU知道诊断仪准备往哪个地址写多长的数据。请求里包含数据格式标识符、地址和长度信息。ECU收到34后需要检查地址是否在合法Flash范围内、长度是否对齐、安全等级是否足够这些都通过后回复正响应并给出一个blockLength值告诉诊断仪每一块最多可以传多少字节。这个blockLength非常关键它由ECU的接收缓冲区大小决定不要把它设得比实际缓冲区大否则后续36传输过程中ECU会来不及处理连续帧触发流控超时。36传输数据是刷写的主体力每帧都带一个块序列计数器blockSequenceCounter从1开始递增到0xFF后回绕到0。ECU端要严格校验这个计数器的连续性一旦发现跳号说明链路丢帧此时应该返回0x73当前块序列号错误并暂停接收后续块等待诊断仪重新同步。这里有一个经验值块序列计数器在连续传输多帧报警后不要立刻让ECU进入异常状态而是尽量先尝试恢复同步因为EMC干扰引发的瞬间丢帧在实车上并不罕见。37请求传输退出是最后一步它告诉ECU数据传输结束。ECU收到37后要检查已经接收的总长度是否和34请求里的长度一致如果不一致就返回错误并进入恢复流程如果一致则把接收缓冲区里的最后一段数据刷入Flash完成后回复正响应。许多刷写失败案例都卡在最后这一下原因是应用层数据长度是按文件计算的但34请求里的长度忘记把协议开销或者填充字节算进去导致最终累计长度对不上。4.2 一个可复现的刷写时序示例我在实际项目中习惯把刷写时序的控制参数做成一张表方便软件实现和测试评审。这张表里的时间参数不是拍脑袋定的而是根据ECU主频、Flash擦写时间和CAN驱动缓冲区大小测算出来的。参数配置值说明波特率500kbps经典CAN仲裁段和数据段一致P2Server50ms默认服务响应超时P2StarServer5000ms服务处理中0x78保活后的等待上限S3Server5000ms会话保持超时超时回默认会话STmin5ms多帧接收时连续帧的最小间隔BlockSize8字节单帧数据最多8字节blockLength64字节每个传输块最多64字节我实测过在500kbps下的单帧8字节传输一帧报文从发送到收到肯定带的时间大约需要0.3ms如果上位机每发一帧都等肯定带再发下一帧有效吞吐会很低。协议本身支持在连续帧发送时不等肯定带只要控制好块序列计数器和STmin就行。所以在实现刷写时序时我推荐上位机采用流水线模式先连续发一整个block的数据再等待ECU对最后一个36的肯定带或错误帧这样吞吐量能提升接近一倍。刷写过程中每个正响应都要严格匹配请求对应的SID。比如发34之后收到的正响应SID必须是74发36之后必须是76发37之后必须是77。如果出现SID不匹配直接判定流程异常不要再继续下一个服务。我遇到过某个中间版本代码把36的正响应拼成了74数据结果上位机脚本一直以为是34的响应整个状态机卡死在等待传输数据阶段这种bug不看原始响应字节根本发现不了。4.3 校验、擦除与跳转别让最后一步掉链子数据传完不等于刷写结束ECU还需要做完整性校验和跳转。实现上可以在传输完成后由上位机发一个31例程控制调用checkMemory校验例程ECU端把所有接收到的数据做一次CRC或累加和计算返回校验结果。这个校验不能省特别是OTA场景文件在传输过程中哪怕坏一个字节跳转到APP后轻则功能异常重则ECU直接卡死而且这种问题排查起来极其痛苦。校验通过后才是跳转操作。常见的做法是通过11服务ECU复位或者通过31例程跳转到APP。跳转前要先把诊断相关的定时器全部停掉关闭CAN接收中断或者把接收缓冲区清空然后重新初始化APP的向量表再跳转。这里有个必须注意的细节跳转前要复位所有外设状态尤其是看门狗。如果跳转前忘记喂狗APP启动时间稍微长一点看门狗就咬住MCU导致设备反复重启产线测试直接红灯。擦除操作建议放在34请求之前。项目里我用31 01 02 02来触发擦除例程参数02 02表示按指定的地址和长度擦除。擦除时间通常比普通服务响应时间要长得多所以ECU在擦除期间要先返回一个0x78保活让诊断仪知道服务还在处理中。P2Star的时间一定要给足普通服务5秒足够但擦除大块Flash时建议把0x78的保活间隔控制在1秒一条避免上位机在等待期间因为超时放弃整个刷写流程。5. 实车测试与问题排查实录5.1 如何通过CAN波形判断通信质量示波器看CAN波形是排查物理层问题的基本功。正常的CAN差分波形显性电平和隐性电平之间的幅值差在2V左右总线上有两个终端电阻时隐性电平约为2.5V显性电平约为1.5V。如果你看到的差分幅值不到1.5V或者波形边沿明显变圆变缓大概率是终端电阻配置不对、总线分支过长或者节点数过多。除了幅值还要看位时间的一致性。用示波器同时测量两个连续显性位的宽度正常情况下应该等于1/波特率也就是500kbps下为2us。如果每个位的宽度都在抖抖动范围超过位时间的10%那就要怀疑有没有节点的时钟精度不合格或者总线上存在某个节点的采样点配置差异过大。SJW配置偏小时长总线场景下最容易出现这种位宽度抖动排查时可以把SJW临时调整到2或3看看抖动是否缓解。总线波形文件的分析也很重要。抓波形时我一般会把采样率设到50MS/s以上也就是一个位时间至少采样25个点这样能看清楚每个位的边沿细节。导出为CSV或二进制波形文件后再用脚本统计每个显性位的宽度分布如果发现有周期性出现的窄脉冲大概率是某个节点在发送错误帧或过载帧这时候要重点查是哪个节点在拉低总线而不是盲目怀疑线束。5.2 UDS排查三板斧日志、错误帧、时序UDS问题排查和物理层问题完全是一个套路先看有没有错误帧再看有没有响应超时最后看响应内容对不对。错误帧出现时先用总线分析仪定位错误帧的ID如果是某个特定ID反复产生错误帧基本可以断定该节点的驱动配置有问题如果错误帧散布在所有帧之间那就是物理层的共性问题比如终端电阻、线缆长度或者收发器供电。诊断日志的格式在项目启动时就该定好。我习惯在每个UDS服务入口和出口都打印一条日志包含时间戳、请求SID、子功能、数据长度、NRC和耗时。这样问题复现后直接读时间戳就能判断是不是P2超时读SID就知道请求有没有到达ECU读NRC就知道ECU到底拒绝了什么。很多同事喜欢在出问题时才临时加日志结果问题复现不了日志也没抓到白白浪费一个晚上。工具链兼容性问题在实测中也经常遇到。比如某些国产USB-CAN分析仪在Win11系统下驱动不兼容插上就报设备无法启动折腾半天最后只能换一台机器。这个不算项目功能问题但它会影响开发效率我的建议是团队内部统一采购一到两款成熟的CAN分析仪并且把驱动和工具的兼容性验证纳入开发环境搭建清单不要在项目中期才暴露工具链问题。5.3 高频踩坑点速查表最后把我在这个项目里遇到的高频问题整理成一张表。这些问题都很典型很多是UDS和CAN的交叉地带单独看协议文档发现不了只有把代码和测试放在一起跑才会暴露。现象根因解决方案CAN总线上全是错误帧无正常报文波特率配置不一致或终端电阻缺失核对位时序参数测量总线两端电阻约为60欧UDS请求发出后长时间无响应会话超时退出ECU回到默认会话检查S3参数测试前确保进入目标会话服务正响应数据和请求对不上多帧传输的块序列计数器跳号严格校验blockSequenceCounter重传同步27服务密钥正确但仍返回0x37上一次失败后的延时惩罚未到期检查延时锁定逻辑必要时在测试脚本里等待刷写完成跳APP后程序跑飞Flash校验失败或跳转前未停看门狗增加checkMemory校验跳转前关看门狗和中断DTC状态字始终是0x20状态迁移逻辑只更新了Bit0/1未推进历史位按周期更新完整状态字节独立成状态迁移模块功能寻址读DTC无响应忘记ECU对功能寻址不回复的约定区分功能寻址和物理寻址的响应策略NRC返回0x22和实际原因不符条件判断顺序写反固定判定顺序会话-安全-参数-条件排查问题时我还养成了一个习惯不管现象多奇怪第一步永远是把原始报文抓下来用十六进制逐字节去看而不是只看上位机解析后的结果。上位机解析层偶尔会出bug把正常的报文显示成错误也偶尔会漏掉一些字段。只有回到原始报文层面才能确保你看到的是总线上的真相而不是工具想让你看到的东西。这个项目的技术文档沉淀到最后一个阶段我个人的体会是CAN和UDS开发难不在某一个点难在它们之间的缝隙里。位时序配好了不等于UDS状态机就稳定UDS服务写全了不等于刷写流程就顺畅。真正的功力在于把每条报文的时间戳、每个NRC的返回时机、每个超时的边界条件都当成一等公民来对待。你把这些细节掰开揉碎文档化、表格化后面接手的同事才不会在同一个坑里再摔一次。希望这份基于项目实践整理出来的CAN和UDS开发要点能让你在自己的台架上少走几段弯路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价