第2章:车载网络协议基础:CAN总线协议详解、CAN诊断协议(UDS on CAN)、DoIP协议入门

各位同学,咱们今天聊聊车载网络协议。说实话,搞TBOX远程诊断,网络协议就是你的“普通话”。车上的ECU(电子控制单元)们怎么交流?诊断仪怎么跟ECU对话?这些都得靠协议来约定。

我个人习惯把车载网络协议分成三层来看:底层通信(CAN总线)、诊断应用(UDS on CAN)、高速远程(DoIP)。咱们一层层剥开。

2.1 CAN总线协议详解

CAN总线,全称Controller Area Network。1980年代由Bosch发明,初衷是为了减少汽车线束。你想想看,一辆车几十个ECU,如果每个都单独拉线,那线束比发动机还重。CAN总线用两根线(CAN_H和CAN_L)就把所有节点串起来了。

2.1.1 物理层:差分信号

CAN总线用差分信号传输。说白了,就是两根线上的电压差来表示0和1。

  • 显性电平(Dominant):CAN_H比CAN_L高2V左右,代表逻辑0。总线空闲时是隐性电平。
  • 隐性电平(Recessive):CAN_H和CAN_L电压差接近0,代表逻辑1。

我在项目中遇到过一个问题:某次台架测试,CAN通信时不时丢帧。查了半天,发现是CAN_H和CAN_L线接反了。嗯,这种低级错误,新手最容易犯。记住:CAN_H接CAN_H,CAN_L接CAN_L,别搞混

2.1.2 数据链路层:报文结构

CAN报文分两种格式:标准帧(11位ID)和扩展帧(29位ID)。咱们做TBOX诊断,大部分用标准帧就够了。

一个标准CAN数据帧长这样:

| SOF | 仲裁场(11位ID + RTR) | 控制场(IDE + r0 + DLC) | 数据场(0-8字节) | CRC场 | ACK场 | EOF |
|  1  |         12           |           6            |      0-64       |  16   |   2   |  7  |

这里我重点说两个东西:

  • 仲裁场:ID越小,优先级越高。0x000优先级最高,0x7FF最低。所以诊断请求报文ID通常设得很小,保证优先传输。
  • 数据场:最多8字节。这是CAN总线的硬伤——一次只能传8个字节。做诊断时,如果数据量大,就得分包发送。

重要提示:CAN总线的波特率常见的有125kbps、250kbps、500kbps。诊断通信一般用500kbps。波特率不匹配,ECU根本不理你。

2.1.3 总线仲裁:谁先说话?

CAN总线是“多主”架构。任何节点都可以随时发消息。那冲突了怎么办?靠仲裁。

仲裁机制很简单:谁ID小,谁先发。发送过程中,每个节点都在监听总线。如果自己发的位和总线上的位不一致(自己发隐性,但总线上是显性),说明有更高优先级的节点在发,自己就乖乖退出发送。

我曾经调试过一个现象:诊断仪发请求,ECU偶尔不响应。后来发现是总线上有个报文ID=0x000的周期性消息,优先级太高,把诊断报文挤掉了。解决办法是调整诊断请求的ID,或者等总线空闲再发。

2.2 CAN诊断协议(UDS on CAN)

UDS(Unified Diagnostic Services)是ISO 14229定义的一套诊断服务。它不依赖底层通信介质,可以跑在CAN上,也可以跑在以太网上。咱们这里重点讲UDS on CAN。

2.2.1 诊断寻址:物理请求 vs 功能请求

UDS on CAN用CAN ID来区分不同的诊断会话。标准做法是:

角色 CAN ID(标准帧) 说明
诊断仪→ECU(物理请求) 0x7E0 发给特定ECU
ECU→诊断仪(物理响应) 0x7E8 对应ECU回复
诊断仪→ECU(功能请求) 0x7DF 广播给所有ECU

物理请求是一对一的。功能请求是一对多的。比如你想让所有ECU都进入扩展诊断模式,就发功能请求。

我的经验:功能请求虽然方便,但响应处理很麻烦。所有ECU同时回复,总线会瞬间爆满。我建议非必要不用功能请求,尤其是读取数据时。

2.2.2 诊断服务:常用的几个

UDS定义了26种服务(SID从0x10到0x3E)。咱们做TBOX远程诊断,最常用的是这几个:

  • 0x10 诊断会话控制:切换诊断模式(默认、扩展、编程)。
  • 0x22 读取数据标识符:读ECU内部数据,比如车速、水温。
  • 0x2E 写入数据标识符:写数据到ECU,比如配置参数。
  • 0x31 例程控制:执行特定功能,比如自检、复位。
  • 0x19 读取故障码:读DTC(诊断故障码)。
  • 0x14 清除故障码:清DTC。

举个例子,读取ECU的VIN码(车辆识别号):

// 诊断请求:0x22 + DID(数据标识符)
// DID = 0xF190 表示VIN码
// 发送:02 22 F1 90
// 解释:02(数据长度) 22(服务ID) F1 90(DID)

// 正常响应:0x62 + DID + 数据
// 接收:10 14 62 F1 90 4C 56 47 00 00 00 00 00 00 00 00 00 00
// 解释:10(首帧,表示后续还有数据) 14(剩余20字节) 62(响应SID) F1 90(DID) 后面是VIN数据

注意看,VIN码17个字节,CAN一次只能传8字节。所以这里用了多帧传输。首帧(0x10)告诉接收方:我还有20字节要发。后续用连续帧(0x20、0x21...)把数据发完。

避坑指南:我曾经在项目里遇到一个bug——ECU发送多帧时,连续帧的序列号从0开始还是从1开始?标准规定从1开始。但有个供应商的ECU从0开始,导致TBOX一直收不全数据。后来加了兼容逻辑才解决。

2.2.3 网络层协议:ISO 15765-2

UDS on CAN的网络层由ISO 15765-2定义。它解决了CAN单帧8字节的限制。核心概念是:

  • 单帧(SF):数据≤7字节,直接发。
  • 首帧(FF):数据>7字节,第一帧告诉对方总长度。
  • 连续帧(CF):后续数据,每帧7字节。
  • 流控帧(FC):接收方告诉发送方“慢点发”或“继续发”。

流控帧很重要。如果ECU处理不过来,它会发FC帧要求发送方暂停。我见过一个案例:TBOX连续发诊断请求,ECU来不及处理,直接丢帧。后来加了流控机制,问题解决。

2.3 DoIP协议入门

DoIP(Diagnostic over Internet Protocol),说白了就是把UDS诊断跑在以太网上。为什么需要DoIP?因为CAN太慢了。500kbps的CAN,传一个512字节的数据块,要拆成70多帧,耗时几十毫秒。而以太网一帧就能搞定。

2.3.1 DoIP的物理层

DoIP通常用100BASE-TX(百兆以太网)或1000BASE-T(千兆以太网)。车上用双绞线,和家用网线一样。但注意:车载以太网用的是单对双绞线(100BASE-T1),不是标准的四对线。别买错线缆。

2.3.2 DoIP协议栈

DoIP的协议栈长这样:

| 应用层 | UDS (ISO 14229) |
| 传输层 | TCP/UDP (DoIP封装) |
| 网络层 | IPv4/IPv6 |
| 数据链路层 | Ethernet MAC |
| 物理层 | 100BASE-T1 / 100BASE-TX |

DoIP用TCP端口13400进行诊断通信。UDP端口13400用于发现车辆(车辆发现功能)。

2.3.3 车辆发现:怎么找到ECU?

DoIP有个很酷的功能——车辆发现。诊断仪发一个UDP广播消息,车上所有支持DoIP的ECU都会回复。回复内容包括:

  • VIN码
  • ECU的逻辑地址
  • 支持的诊断服务列表

这样诊断仪就能自动发现车上有哪些ECU,不用手动配置。我在做远程诊断时,特别喜欢这个功能。TBOX启动后,先发一个车辆发现请求,就知道车上挂了多少个ECU,省去了配置文件的麻烦。

2.3.4 DoIP vs CAN诊断:怎么选?

对比项 CAN诊断 DoIP诊断
传输速率 最高1Mbps 100Mbps~1Gbps
单帧数据量 8字节 1500字节(以太网MTU)
传输距离 几十米 100米以上
实时性 高(微秒级) 中(毫秒级)
应用场景 车内ECU诊断 远程诊断、刷写

我的建议是:车内诊断用CAN,远程诊断用DoIP。TBOX作为网关,一边接CAN总线,一边接以太网(4G/5G)。远程诊断时,TBOX把DoIP请求转成CAN诊断请求,再把CAN响应转成DoIP响应。

核心要点:搞懂CAN和DoIP,你就掌握了TBOX远程诊断的“任督二脉”。CAN是车内通信的基石,DoIP是远程通信的桥梁。两者结合,才能实现真正的远程诊断。

好了,这一章的内容就这些。下一章咱们聊聊TBOX的硬件架构设计,包括MCU选型、通信模块、电源管理等。到时候见。