ARTICLE DETAIL

资讯详情

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

CAN与UDS诊断开发:从底层位定时到刷写流程全解析

CAN与UDS诊断开发:从底层位定时到刷写流程全解析 1. 写在前面为什么 CAN 和 UDS 是车载开发绕不开的两座山车载测试、车载网络、嵌入式诊断这两年几乎是个人都在聊但真正动过手的人都知道车上的东西和普通嵌入式开发完全是两个物种。我最早接触车规项目时最深的感受是你写一版 PC 端串口通信程序可能半天就通了但在车上哪怕只是把 CAN 总线上的一帧报文收发稳定下来都可能磨掉你一整天。原因很简单CAN 和 UDS 底下藏着一整套关于可靠性、实时性、安全性的行业规则这些东西不在芯片手册里也不在协议规范的目录里而是在无数个实测现场里。这篇文章想讲透两件事底层 CAN 通信怎么做到稳定、可控上层 UDS 诊断协议怎么把“读故障码、刷写软件、标定参数”这些动作变成标准化的请求和响应过程。同时把两层之间如何衔接、诊断会话如何切换、安全访问如何绕过、刷写流程如何不掉电跑完全部按实际开发顺序拆开。适合谁来读如果你是车载测试工程师想搞明白问题到底出在物理层还是协议栈如果你是嵌入式软件工程师正准备把诊断功能搬进自己的 MCU 工程或者你只是对 CAN 和 UDS 感兴趣、想从零搭一套可用的开发环境这篇文章都能给你一条相对完整的路径。先声明一下这不是某本协议规范的复述更多是基于项目实践踩出来的经验汇总。2. CAN 底层最容易翻车的三件事位定时、仲裁与容错机制CAN 总线的协议栈本身并不复杂但为什么很多人调不通因为 CAN 能不能跑起来很大程度不取决于你代码写得多漂亮而取决于你对物理层和链路层的理解。这一节把最常翻车的三个点拆开来聊。2.1 位定时不是你想象的那种“波特率”很多人把 CAN 通信配置等同于“把波特率设成 500K”然后调用初始化函数就完事。实际上CAN 波特率的背后是采样点而采样点又由同步段、传播段、相位缓冲段1、相位缓冲段2以及波特率分频系数共同决定。以最常见的 500Kbps、16MHz 晶振、STM32F103 平台为例Fpclk 36MHz 时要得到 500K 的位速率BRP 分频可以取 4那么一个位时间占用的时钟周期数就是 36MHz / 4 / 500K 18 个 TQ。此时如果你把 TSEG1 配成 13、TSEG2 配成 4、同步段固定为 1采样点就在 (1 13) / 18也就是 77.8% 附近。这个值对高速 CAN 来说是合理的但如果你用的是低速容错 CAN比如 125K采样点最好往 80% 以上靠否则长距离传输时信号沿的振铃很容易把你的采样点“拉”到错误电平上去。判断位定时配没配对的土办法有两个一是看 DLC 较大的扩展帧能否稳定收发二是用示波器抓 CAN_H 和 CAN_L 之间的差分波形看位宽度是否整齐、有没有毛刺。实测中位定时导致的故障往往表现为“短报文没问题、长报文随机错误”因为长报文包含更多位边沿任何一个边沿的采样误差都可能引发填充位错误。2.2 仲裁机制低 ID 优先但不是“越小越快”CAN 总线仲裁真的是一个被无数人误解的设计。它并不会让低 ID 的报文“先发出去”而是让多个节点在同一时刻抢总线时ID 数值最小的那一个赢得仲裁。整个过程依赖的是显性电平覆盖隐性电平也就是说在仲裁场中每一位 ID 都要参与电平比较谁先在某个位上写 1 而别人写 0谁就退出竞争转为接收模式。这里有一个常见误区不少人为了让某条报文优先发送直接把 ID 改成 0x000导致所有节点都在跟它抢总线反而把它所在的节点拖进持续发送状态。更合理的做法是结合 DBC 中的报文周期和 ID 分配规则把实时性要求最高的报文放在低 ID 段比如 0x100 到 0x150把周期型但非关键的放在 0x300 以后网络管理报文通常固定在 0x7xx 段。2.3 容错与重同步为什么波形看起来是好的总线上却全是错误帧另一个隐蔽的坑是 CAN 控制器内部的错误计数机制。CAN 的容错能力来自协议层的错误检测和自动重发但自动重发不等于无代价。发送错误计数器和接收错误计数器是根据总线上每一次错误事件动态调整的如果某个节点因为时钟精度差或者位定时配置不合理反复出错它的错误计数器会一路涨到 127 以上进入被动错误状态此时它只能接收不能主动发送这就会造成“节点偶发性失联”的诡异现象。更隐蔽的是重同步机制。CAN 的硬同步只发生在帧起始的下降沿而后续位边沿则通过重同步来修正。如果你的相位缓冲段留得太小频繁的干扰脉冲会让同步跳转宽度不够用错误帧就来了。这类问题只看逻辑分析仪上的报文基本看不出来必须配合 CAN 控制器的错误状态寄存器实测或者直接抓总线波形数错误帧。3. 报文收发链路的代码实现层级从寄存器到驱动再到应用接口CAN 底层的操作在实际工程里一般分三层寄存器操作、驱动封装、应用接口。很多开发者在第一层和第三层之间反复横跳导致代码既不好维护也很难定位问题。3.1 最底层的发送与接收流程以经典 CAN 控制器为例发送流程通常是把报文写入发送邮箱请求发送等待发送完成中断或标志位。这里最容易踩的坑是“发送缓冲区满”。如果网络上有节点迟迟没有 ACK比如终端电阻没接好发送邮箱会一直占住程序如果死等就直接卡死主循环。正确做法是设置超时比如 50ms 内没有发送完成就清掉邮箱并报错而不是无限等待。接收流程同理。验收滤波器是另一个高发问题区——很多芯片默认的滤波器模式会过滤掉所有报文新手往往会在这里抓狂半天。建议初始化时先把滤波器设成接收全部先把通路跑通再逐步按 ID 筛选。3.2 驱动层应该暴露哪些接口实测下来一个真正用得顺手的 CAN 驱动至少应该提供这些接口CAN_Init(BaudRate, SamplePoint)初始化控制器和引脚最好把位定时参数也传进来CAN_Send(MsgId, Data, Len, MsgType)超时可控的发送接口CAN_RegisterRxCallback(callback)注册接收回调中断或轮询里触发CAN_GetErrorStatus()读取错误计数器和总线状态CAN_EnterSleepMode()/CAN_WakeUp()低功耗相关很多工程师只写前两个第三个没有接收靠主循环轮询这在报文量小的时候没问题但一旦诊断刷写或者多帧传输跑起来轮询会带来严重的 jitter直接影响服务质量。下面给一个简化的发送接口伪码注意超时和错误处理部分uint8_t CAN_Send(uint32_t id, uint8_t *data, uint8_t len, uint8_t is_ext) { uint32_t timeout 0; if (CAN_IsTxBufferFull()) { while (CAN_IsTxBufferFull()) { if (timeout 5000) return CAN_ERR_TX_TIMEOUT; // 约50ms } } CAN_WriteTxMailbox(id, data, len, is_ext); CAN_RequestSend(); return CAN_OK; }3.3 中断服务函数里到底该干什么很多人写 CAN 接收中断时喜欢在中断里做协议解析比如直接判断 ID 然后处理 UDS 请求这是个很大的隐患。CAN 中断频率并不低尤其总线负载高时中断里做重逻辑会拉爆 CPU。规范做法是中断里只做数据搬移把报文压入 FIFO 或环形缓冲区然后在主循环或者 RTOS 任务里做解析。实测中FIFO 的深度至少要覆盖总线上最大的突发报文量。以 500K 波特率为例一毫秒内最多可以挤进来接近 50 帧标准帧如果你的接收缓冲区只有 16 深丢帧几乎是必然的。建议至少设 64如果需要做诊断刷写接收缓冲区最好 128。4. UDS 诊断协议栈的骨架诊断寻址、会话切换与服务分发CAN 底层跑通以后UDS 协议栈就是在这条“路”上跑的应用程序。UDS 的全称是 Unified Diagnostic Services标准编号 ISO 14229它定义了一套统一的服务请求和响应格式但具体怎么传输还取决于底层网络比如 CAN 上的传输层是 ISO-TPISO 15765-2。4.1 物理寻址 vs 功能寻址UDS 诊断在 CAN 上分两种寻址模式。物理寻址是点对点的请求方和响应方都有唯一地址比如诊断仪用 0x7E0 向 ECU 的 0x7E8 发请求功能寻址是一对多的比如诊断仪用 0x7DF 发请求总线上所有 ECU 都会接收并各自响应。功能寻址看起来方便但实际开发中坑非常多。比如你发一个功能寻址的 ECU 复位服务结果十几个 ECU 同时回响应总线直接被塞满而且有些 ECU 可能不回响应很难判断谁执行了谁没执行。所以功能寻址一般只用于广播类请求比如进入扩展会话模式、某些特殊的例行测试其他场景尽量用物理寻址。4.2 会话模式三类会话和默认行为UDS 定义了多种诊断会话最常见的三种是默认会话Default Session0x01、编程会话Programming Session0x02、扩展诊断会话Extended Diagnostic Session0x03。默认会话是 ECU 上电后自动进入的会话功能受限通常只能做读取故障码、读取数据标识符这类基础操作。进入扩展会话后才能执行写入、例程控制这类高风险服务。编程会话则专门用于刷写在编程会话下ECU 通常会停掉应用层报文、降低通信负载为固件下载让路。会话切换服务是 0x10请求格式如下请求: 02 10 03 00 00 00 00 00 响应: 06 50 03 00 32 01 F4 00这里的02是 PCI 字节表示后续数据长度为 210是服务 ID03是子功能表示扩展会话响应里的50 03是肯定响应00 32 01 F4是 P2 和 P2* 时间参数含义是服务器能在 50ms 内响应的最快时间以及增强响应时间。会话都有超时机制。如果 ECU 在设定时间内没有收到任何诊断请求会自动跳回默认会话。这个时间在 10 服务响应参数里就有通常 P2 是 50msP2* 是 5000ms。很多测试工程师遇到“明明已经进入扩展会话了过一会儿又不行了”的问题十有八九是上位机没有在超时窗口内持续发送请求。4.3 服务分发一帧请求如何路由到对应处理函数UDS 服务分发是一个典型的表驱动设计。收到一帧诊断请求后先解析第一个字节拿到 SIDService ID然后通过一张函数指针表找到对应的服务处理函数。这是我个人很推荐的一种分发框架typedef struct { uint8_t sid; void (*handler)(uint8_t *data, uint16_t len); } UdsServiceEntry; const UdsServiceEntry serviceTable[] { {0x10, DioCtrl_HandleSessionControl}, {0x11, DioCtrl_HandleEcuReset}, {0x14, DioCtrl_HandleReadDtc}, {0x19, DioCtrl_HandleReadDtcInfo}, {0x22, DioCtrl_HandleReadDataByIdentifier}, {0x27, DioCtrl_HandleSecurityAccess}, {0x2E, DioCtrl_HandleWriteDataByIdentifier}, {0x31, DioCtrl_HandleRoutineControl}, {0x34, DioCtrl_HandleRequestDownload}, {0x36, DioCtrl_HandleTransferData}, {0x37, DioCtrl_HandleRequestTransferExit}, {0x3E, DioCtrl_HandleTesterPresent}, {0x85, DioCtrl_HandleControlDtcSetting}, };每个处理函数接收原始请求数据解析后执行对应逻辑最后把响应数据填入发送缓冲区由传输层发送。服务处理函数内部要层叠做权限检查当前会话模式是否支持这个服务是否需要安全解锁子功能参数是否合法这三大检查缺一不可否则就会出现“用户在默认会话也能执行刷写”这种严重问题。5. 从会话切换到安全访问再到读写服务的报文实战光说不练是假把式这一节从 10 服务开始把几个关键服务逐个做报文级拆解每一帧都给出请求和响应的具体数据这样你可以直接对照抓包验证。5.1 10 服务会话切换的细节请求进入扩展会话发送: 02 10 03 AA AA AA AA AA 2 - PCI表示后面有 2 个数据字节 10 - 服务 SID 03 - 子功能扩展诊断会话正常情况下ECU 回肯定响应接收: 06 50 03 00 32 01 F4 AA 50 03 - 肯定响应 (100x400x5003回显) 00 32 - P250ms 01 F4 - P2*500ms如果收到 0x7F 开头那就是否定响应比如接收: 03 7F 10 22 22 - NRC会话模式不支持这里简单列一下常见的 NRC 含义后面还会系统性总结0x11服务不支持SID 不在服务表里0x12子功能不支持比如 0x10 的 04 子功能0x13报文长度或格式错误0x22条件不满足比如默认会话下执行刷写服务0x31请求超出范围DID 不存在、数据越界0x33安全访问被拒绝未解锁或密钥错误0x35密钥错误0x78请求已收到正在处理多用于耗时服务5.2 27 服务安全访问的完整过程安全访问服务是 UDS 里安全门槛最高的一环它基于挑战-响应机制。诊断仪先发请求种子ECU 返回一串随机数种子诊断仪用约定的算法把种子计算成密钥再通过第二帧请求把密钥发给 ECUECU 校验通过后进入解锁状态。第一帧请求种子发送: 02 27 01 AA AA AA AA AA 27 - 安全访问服务 01 - 子功能请求种子级别1ECU 返回种子接收: 06 67 01 11 22 33 44 AA 67 01 - 肯定响应请求种子成功 11 22 33 44 - 4 字节种子第二帧发送密钥发送: 06 27 02 44 33 22 11 AA 27 - 安全访问服务 02 - 子功能发送密钥级别1 44 33 22 11 - 密钥本地计算得到如果密钥对了ECU 回接收: 02 67 02 AA AA AA AA AA如果错了回接收: 03 7F 27 35 35 - 错误密钥ECU 可能还会启动延时锁定机制实测中要注意几个问题。首先是种子算法的复杂度。很多项目用的是简单异或、位翻转、或查表算法安全性很差能够被轻易逆向。稍微正规点的项目会把种子放进 AES 或者 CRC32 再叠加校准码。第二个是尝试次数限制一般错误密钥 3 次会被锁定一段时间测试时如果连续输错ECU 可能 10 分钟内都不给你出新种子。我遇到过最坑的一次是ECU 和诊断仪都实现了 27 服务但算法里有一个隐含的字节序问题——种子是“小端”存储的算法却按大端计算导致所有解锁都失败。后来抓了两边 log 逐字节比对才发现。这类问题靠代码 review 看不出来必须准备一个能解析 ISO-TP 报文的工具把种子和密钥的每个字节打出来人工核对。5.3 22/2E 服务DID 读写机制22 服务是读数据2E 服务是写数据DIDData Identifier是它们操作的对象。DID 可以是 2 字节的比如 0xF190 表示车辆识别码也可以是厂商自定义的比如 0x1234 表示某个标定参数。读一个 DID发送: 03 22 F1 90 AA AA AA AA 22 - ReadDataByIdentifier F1 90 - DID响应接收: 07 62 F1 90 31 32 33 34 62 - 肯定响应 (0x220x40) F1 90 - 请求的 DID 31 32 33 34 - 数据ASCII 字符串 1234写一个 DID发送: 07 2E F1 90 41 42 43 44 2E - WriteDataByIdentifier F1 90 - DID 41 42 43 44 - 要写入的数据 ABCD响应接收: 04 6E F1 90 AA AA AA AA写 DID 服务在默认会话下通常是被禁止的必须进入扩展会话且安全解锁后才行。很多开发者在这块偷懒只在会话层做了限制没做安全状态检查结果诊断仪在没解锁的情况下也能修改标定值这是很严重的代码缺陷。6. UDS 刷写流程的完整链路从 34 服务到 36 服务再到 37 服务刷写是 UDS 诊断里最复杂、风险最高的一项功能它涉及的是 ECU 的 Flash 存储区域。一旦中途掉电或者传输错误ECU 可能变砖只能靠 bootloader 恢复。所以刷写流程设计得非常保守。6.1 刷写前的会话切换与前置安全条件完整刷写流程一般长这样10 02 进入编程会话27 01/02 安全解锁、通常为 Bootloader 级别的安全等级85 02 关闭 DTC 记录防止刷写过程中产生误报故障28 03 停掉非诊断通信报文34 34 请求下载协商地址和长度36 xx 循环传输数据块37 请求传输退出触发 CRC 校验11 01 复位 ECU启动新程序每一步错一步都可能中断刷写。尤其是第 4 步很多 ECU 如果忽略停通信报文刷写过程中应用报文还在发和诊断流量抢带宽拖慢整个刷写流程不说严重时还会触发看门狗复位。6.2 34 服务请求下载的参数如何计算34 服务RequestDownload请求格式如下发送: 08 34 00 44 00 00 10 00 34 - RequestDownload 00 - 数据格式不压缩不加密 44 - 地址和长度格式地址 4 字节长度 4 字节 00 00 10 00 - 下载起始地址 0x00001000 00 00 00 10 - 数据总长度 16 字节响应返回的是 ECU 愿意接受的传输块大小接收: 07 74 00 44 00 40 00 00 74 - 肯定响应 00 - 数据格式回显 44 - 地址长度格式回显 00 40 - 最大传输块大小为 0x40 64 字节这里要注意最大传输块大小是包括 36 服务头部在内的长度吗其实是数据部分长度。也就是说后面每个 36 服务的块大小不能超过 64 字节数据。实际做上位机时最好把单个块大小设成比 64 小一点留出 PCI 头的余量。6.3 36 服务多帧传输的细节与技术门槛36 服务TransferData是刷写里真正“搬砖”的环节。每个块有一个块序号从 01 开始递增单个块格式如下发送: 44 36 01 11 22 33 44 55 44 - PCI 字节表示后续共 68 字节这里简化了 36 - TransferData 01 - 块序号 11 22 33 44 - 前 4 字节数据响应是接收: 05 76 01 00 00 00 00 00 76 - 肯定响应 01 - 当前块序号回显36 服务的核心难点是稳定性。实测中传输速度、块大小、ISO-TP 的拆分策略、CAN 中断响应时间、ECU 内部 Flash 擦写耗时这些因素叠加在一起会形成非常复杂的时序关系。比如 ECU 在擦除一个扇区时内部 Flash 控制器可能忙上几十毫秒这段窗口内如果诊断请求到了ECU 可能来不及及时回响应上位机如果等待时间不够就直接报超时实际数据已经写进去了重发就会导致数据重复、地址错位。所以标准的实现方式有两种一种是上位机等待 ECU 返回肯定响应再发下一块流控方式另一种是 ECU 在擦写忙时回复 0x78 NRC表示“请求已收到正在处理”上位机收到 0x78 后不重发请求而是继续等待最终响应。实测中0x78 机制是刷写稳定性的关键很多自研刷写工具卡在“发一帧等一帧”的简单逻辑上一遇到擦写慢的 ECU 就失败。6.4 37 服务与刷写后的完整性校验传输完所有数据后发 37 服务请求结束传输发送: 01 37 AA AA AA AA AA AA 接收: 03 77 22 AA AA AA AA AA这个响应里的22是校验和检查的结果。如果 37 服务返回 0x77但后续 ECU 校验固件 CRC 不过ECU 会在复位的自检阶段报错。更严谨的做法是在 34 服务前先发一条诊断指令让 ECU 计算整个镜像的 CRC 或者签名值然后在 37 服务后单独核对。我强烈建议你在刷写协议栈里写一个独立的“完整性自检”逻辑不要写完数据就默认成功。至少要在复位前读一次固件版本号或者执行例程控制里的 CRC 检查确认写入的数据和源文件一致之后再做 11 01 ECU 复位。7. NRC 错误码体系与诊断开发中躲不开的坑NRCNegative Response Code是 UDS 里最容易让人摸不着头脑的地方因为它不是一个单纯错误码而是一个“带上下文的否定响应”。同一帧请求在默认会话和扩展会话下返回的 NRC 可能完全不同。7.1 NRC 到底是哪里来的当一个 ECU 收到诊断请求后会经过一条完整的检查流水线。每层检查失败都会返回对应的 NRC先检查服务 ID 是否支持不支持回0x11再检查子功能是否支持不支持回0x12接着检查是否支持该服务当前会话模式不支持回0x7F再检查安全访问状态未解锁回0x33最后检查请求参数是否超出范围超范围回0x31长度和格式错误会回0x13这个顺序很关键它决定了你排查问题的方式。比如你在扩展会话调用写 DID结果回了0x33那大概率不是参数问题而是安全状态没满足。如果你上来就查 DID 范围纯属白费功夫。7.2 一张表整理高频 NRCNRC名称含义排查建议0x10General Reject服务被普遍拒绝检查是否处于不可诊断状态0x11Service Not SupportedSID 不在服务表查服务表配置0x12Sub-Function Not Supported子功能不受支持查子功能范围0x13Incorrect Message Length报文长度不对核对 PCI 长度0x22Conditions Not Correct条件不满足查会话模式/前置条件0x24Request Sequence Error请求顺序错误比如没做 27 直接做 2E0x31Request Out of Range参数超出范围查 DID/数据范围0x33Security Access Denied安全访问被拒绝先查是否解锁0x34Authentication Failed认证失败查密钥算法0x35Invalid Key密钥无效查密钥计算结果0x72General Programming Failure编程失败查 Flash 写入错误0x78Request Correctly ReceivedResponse Pending已收到待处理等待进一步响应0x7FService Not Supported In Active Session当前会话不支持切换会话模式7.3 排查 NRC 的三个实战套路第一个套路抓时间戳。UDS 响应的时序信息永远比内容更有价值。比如 0x78 出现的频率、每个 0x78 和最终响应之间的间隔、ECU 对连续请求的响应间隔这些数据能直接反映 ECU 在处理什么耗时操作。建议所有诊断日志都带毫秒级时间戳。第二个套路做边界测试。一个服务功能要测稳不能只测正常报文要把长度超限、字节差一、数据越界、子功能非法、会话未切换、安全未解锁这些情况全测一遍确认每种情况下的 NRC 都符合预期。这样才能确保 ECU 在真实环境下收到畸形请求时不会打出错误响应甚至卡死。第三个套路抓 ECU 内部日志。CAN 报文只能告诉你“ECU 回了个 0x31”但说不清是哪个字段越界。这一步要在诊断协议栈里加调试打印把服务分发之前的原始数据、DID 解析结果、加密种子和密钥都打出来。实际项目中这样一个 debug 开关能省掉一整个下午的分析时间。8. 测试工具链与实测过程中的问题定位手段最后聊一聊测试环境。很多人以为 UDS 开发只需要一根 USBCAN 和上位机就够真正上车调的时候才发现手里没有趁手的工具连问题在哪层都说不清楚。8.1 三层工具链是标配我的建议是至少备齐三件套工具类别推荐选择用途总线分析仪CANoe / PCAN / USBCAN抓取 CAN 报文解析 ISO-TP 和 UDS诊断上位机CANdelaStudio 自研脚本按诊断规范构造报文、回放测试序列示波器至少 100MHz 带宽看物理层波形定位位定时和终端电阻问题抓包工具一定要能按 ISO-TP 自动重组多帧报文否则 36 服务刷写时一帧 64 字节的内部数据会被拆成十几帧 CAN 报文手动分析会把人逼疯。8.2 实测中最经典的三个问题第一个终端电阻问题。总线上没有 120 欧终端电阻短距离通信偶尔能通长线或者高负载下错误帧就会急剧增加。判断方法很简单示波器抓 CAN_L 和 CAN_H看差分信号幅值是否在 2V 左右如果不稳定或者反射很重优先查终端电阻。第二个ISO-TP 接收缓冲溢出。这种情况通常表现为短诊断服务一切正常一到 36 服务刷写时ECU 回了一两个 0x78 后直接不回响应。大概率是 ECU 的 ISO-TP 接收缓冲不够刷写的大块数据把它冲垮了。解决方式是增加接收缓冲深度或者把上位机的单块数据长度调小。第三个波特率不一致。CAN 总线上的节点各自配的波特率不同但节点间的报文还能偶尔通过这事儿听起来很不合常理但真的遇到过。原因是一些控制器的同步段容差比较大波特率差个 0.5% 以内可能还能勉强通信但长期运行会有偶发错误帧。排查方式是看错误计数器是否在持续增长或者把所有节点的波特率寄存器配置全部列出来对齐。8.3 用 CAN 总线波形判断通信质量很多人问我怎么从波形上判断 CAN 通信好坏这里给一个简单实用的判断逻辑。先用示波器抓取 CAN_H 和 CAN_L 的电平变化观察单一位的宽度是否稳定。在 500K 波特率下一个显性位的宽度应该是 2 微秒如果位宽度有大范围跳动说明位定时有问题或者总线干扰严重。然后再看波形边沿的单调性。好的差分波形应该有干净的上升沿和下降沿如果边沿有过冲、振铃、台阶说明总线阻抗不匹配或者节点的收发器驱动能力不足。这种问题在实验室短线上往往不明显在你的测试台架上拉一条长线后就会爆发。最后看波形幅值。CAN_H 对地的静态电平约 2.5VCAN_L 对地也约 2.5V显性状态时 CAN_H 升到约 3.5VCAN_L 降到约 1.5V。如果幅值明显偏低比如只有 1V 的差分那很可能是总线负载过重或者收发器已经损伤长期运行出错的概率很高。9. 最后再分享一点个人体会做车载 CAN 和 UDS 开发这几年如果只说一条最值的经验我会选这条不要把 CAN 和 UDS 分开学也不要只看规范不写代码。CAN 的问题是物理世界的问题UDS 的问题是应用逻辑的问题它们之间由 ISO-TP 这座桥连接而这座桥恰恰是诊断开发中最容易被忽略、又最容易出问题的部分。真正动手把 CAN 收发调通、把 10 27 2E 34 36 37 这几个服务跑起来之后你会发现所谓的车载诊断开发核心就是一套标准化的“请求-响应”机制外加一堆对异常流程的防御处理。把这些骨架搭稳了后面无论你要做 Bootloader 刷写、DoIP、LIN 还是车载以太网诊断都只是换一层传输管道而已。
返回列表