3、LIN协议层:帧结构(同步间隔、同步场、标识符场、数据场、校验和场)、报文类型
好,我们直接切入正题。LIN 的帧结构,说白了就是一条消息在总线上的完整样子。你把它想象成一个快递包裹——有包装、有地址、有内容、还有防伪码。搞懂了这些字段,你就掌握了 LIN 通信的底层逻辑。
3.1 帧的总体结构
一个完整的 LIN 帧,由主机任务发送的报文头,和从机任务发送的报文响应组成。我习惯把帧拆成两部分看:
- 报文头:同步间隔段、同步段、标识符段
- 报文响应:数据段(1~8 字节)、校验和段
注意,报文头永远是主机节点发的。从机只能乖乖等着,收到跟自己 ID 匹配的帧头,才出来发响应。嗯,这里要注意——如果从机没在规定时间内发响应,总线就进入“无响应”状态,主机会报超时。
3.2 同步间隔段(Break Field)
同步间隔段,是帧开始的标志。它由主机拉低总线至少 13 个位时间(显性),然后拉高至少 1 个位时间(隐性)。
为什么要这么长?因为 LIN 总线没有单独的时钟线,所有节点靠这个“长低电平”来识别一帧的开始。我在项目中遇到过一个问题:某个从机偶尔丢帧,查了半天发现是同步间隔长度不够,只有 11 个位时间。有些从机芯片对时序要求严,少于 13 位就不认。所以,我建议你写代码时把同步间隔长度设成 14~15 位,留点余量。
关键参数:
- 同步间隔段:至少 13 位显性电平
- 间隔分隔符:至少 1 位隐性电平
- 总长度:14~16 位时间
3.3 同步场(Sync Field)
同步场就是一个固定的字节:0x55(二进制 01010101)。
为什么是 0x55?因为它有规律的跳变沿,从机用它来校准自己的波特率。说白了,就是主机告诉从机:“你看,我的 1 位时间就是这么长,你跟着我调。”
我曾经调试过一个项目,从机老是收到乱码。用示波器一看,同步场的边沿抖动很大。后来发现是主机的晶振精度不够,导致波特率偏差超过 2%。LIN 规范要求节点间波特率误差在 ±2% 以内,超过这个范围,从机就锁不住同步了。所以,选主机的晶振时,我建议用 ±1% 精度的,别省那几毛钱。
3.4 标识符场(Protected Identifier Field)
标识符场由两部分组成:6 位 ID 和 2 位奇偶校验位。
6 位 ID 的范围是 0~63,但实际能用的只有 0~59(60~63 是诊断帧等特殊用途)。你想想看,一条 LIN 总线最多挂 16 个节点,60 个 ID 完全够用。
奇偶校验位是自动计算的,公式如下:
P0 = ID0 ⊕ ID1 ⊕ ID2 ⊕ ID4
P1 = !(ID1 ⊕ ID3 ⊕ ID4 ⊕ ID5)
嗯,这里要注意——标识符场发送时,是先发 ID0~ID5,再发 P0、P1。从机收到后,会重新计算校验位,跟收到的比对。如果不一致,说明 ID 被干扰了,这帧直接丢弃。
个人经验:我在设计节点地址时,习惯把 ID 分配表做成 Excel 文档,每个 ID 对应一个信号类型(比如车门、车窗、灯光)。这样后期排查问题,一眼就能看出哪个 ID 在报错。
3.5 数据场(Data Field)
数据场是帧的核心,长度 1~8 字节。具体传几个字节,由 LDF 文件(LIN Description File)定义。
举个例子,一个车门模块的 LIN 帧可能这样定义:
// 车门状态帧 (ID = 0x01)
// Byte 0: 门锁状态 (0x00=解锁, 0x01=上锁)
// Byte 1: 车窗位置 (0~100%)
// Byte 2: 后视镜折叠状态 (0x00=展开, 0x01=折叠)
// Byte 3~7: 保留
数据场是低位先发(LSB first)。比如你要发 0x53,二进制是 01010011,先发最低位 1,再发 1,再发 0... 这个顺序别搞反了,否则数据全乱套。
避坑指南:我曾经在项目中遇到一个 bug——从机收到的数据总是反的。查了半天,发现是主机的 MCU 库函数默认是 MSB first,而 LIN 要求 LSB first。所以,写代码时一定要确认字节序的设置。
3.6 校验和场(Checksum Field)
校验和场用来检测数据传输是否出错。LIN 协议有两种校验和:
- 经典校验和:只对数据场做校验(LIN 1.x 版本)
- 增强校验和:对数据场 + 标识符场做校验(LIN 2.x 版本)
计算方法是:把所有字节加起来,取反,再取低 8 位。嗯,说白了就是“和的反码”。
举个例子,假设数据场是 [0x01, 0x02, 0x03]:
和 = 0x01 + 0x02 + 0x03 = 0x06
反码 = ~0x06 = 0xF9
校验和 = 0xF9 & 0xFF = 0xF9
从机收到数据后,用同样的方法计算校验和,跟收到的比对。不一致就说明数据被篡改了,这帧丢弃。
注意:LIN 2.x 的从机必须支持增强校验和,但为了兼容老设备,有些节点会配置成“自动识别”——先按增强校验和算,不对再按经典校验和算。不过我不建议这么干,容易出歧义。
3.7 报文类型
LIN 的报文类型,按功能分主要有三种:
| 报文类型 | 描述 | 典型用途 |
|---|---|---|
| 无条件帧 | 主机按调度表定时发送,从机响应 | 周期性状态上报(如车门状态) |
| 事件触发帧 | 多个从机共享一个 ID,谁有变化谁响应 | 减少总线负载,用于变化不频繁的信号 |
| 诊断帧 | ID 为 60~63,用于配置和诊断 | 刷写固件、读取故障码 |
无条件帧是最常用的。主机每隔 10ms 或 20ms 发一次,从机收到就回。我做过一个项目,车身控制器每 10ms 发一次车门状态帧,从机(门模块)收到后返回当前的门锁、车窗状态。这种模式简单可靠,适合周期性数据。
事件触发帧就灵活多了。比如车窗防夹功能——平时车窗不动,总线很安静。一旦检测到防夹事件,从机立刻发数据。这样能省带宽。但要注意,如果两个从机同时响应,会发生冲突。所以事件触发帧后面通常会跟一个无条件帧来确认。
诊断帧嘛,说白了就是给售后用的。修车师傅拿诊断仪一插,就能读到各个模块的故障码。我建议你在设计阶段就把诊断帧的 ID 和格式定好,别等到量产了再改,那可就麻烦了。
3.8 小结
帧结构是 LIN 协议的基石。同步间隔段负责帧同步,同步场负责时钟校准,标识符场负责寻址,数据场负责传内容,校验和场负责防错。报文类型则决定了通信的调度方式。
我个人觉得,搞懂帧结构最好的方法就是拿示波器抓波形。你亲眼看到 13 位的低电平、0x55 的方波、ID 的校验位,比看一百遍文档都管用。嗯,下次调试时,不妨试试。