汽车LIN总线通信 LIN协议车载总线 - 第3节

3、LIN总线协议层:LIN帧结构

好,咱们今天聊聊LIN帧结构。说白了,LIN总线上跑的数据,就是按照这个帧格式来组织的。我刚开始接触LIN的时候,觉得它比CAN简单多了,但后来发现,简单归简单,坑也不少。

一个完整的LIN帧,由这么几部分组成:同步间隔场、同步场、标识符场、数据场,最后是校验和场。咱们一个一个来看。

3.1 同步间隔场(Break Field)

这是帧的起始信号。主节点会拉低总线至少13个位时间,告诉所有从节点:“注意,我要发新消息了!”

关键参数:

  • 同步间隔:至少13个显性位(低电平)
  • 间隔分隔符:至少1个隐性位(高电平)

我记得有一次调试,从节点老是收不到数据。查了半天,发现是主节点的同步间隔只拉了12个位时间。你想想看,就差这么1个位,从节点就不认。从那以后,我习惯把间隔时间留足余量,比如拉到14~15个位时间。

3.2 同步场(Sync Field)

同步场就是一个固定的字节:0x55(二进制 01010101)。从节点用它来校准自己的位时钟。

为什么会用 0x55?因为它有最多的电平跳变,从节点可以精确测量每一位的长度。说白了,就是给从节点一个“对表”的机会。

小技巧: 如果你发现某个从节点偶尔丢帧,先检查同步场的波形。我曾经遇到过因为总线电容太大,导致同步场边沿变缓,从节点采样出错的案例。

3.3 标识符场(Protected Identifier, PID)

标识符场占1个字节,高6位是帧ID,低2位是奇偶校验位。

位 7 6 5 4 3 2 1 0
含义 P1 P0 ID5 ~ ID0(帧ID)

帧ID的范围是0x00~0x3F,一共64个。其中:

  • 0x00~0x3B(60个): 用于信号传输
  • 0x3C~0x3D(2个): 用于诊断
  • 0x3E~0x3F(2个): 保留

奇偶校验的计算方式如下:

P0 = ID0 ⊕ ID1 ⊕ ID2 ⊕ ID4
P1 = ¬(ID1 ⊕ ID3 ⊕ ID4 ⊕ ID5)

嗯,这里要注意,从节点收到PID后,会先校验奇偶位。如果校验失败,整帧数据直接丢弃。我见过有人把ID配错了,结果奇偶位算出来不对,从节点死活不响应。

3.4 数据场(Data Field)

数据场包含1~8个字节。具体传几个字节,由LDF(LIN描述文件)决定,不是由帧里某个字段指定的。

这一点和CAN不一样。CAN帧里有DLC字段告诉你有几个数据字节,但LIN没有。所以主节点和从节点必须提前约定好:这个ID的帧,到底传几个字节。

避坑指南: 我曾经遇到过主节点发了5个字节,但从节点按3个字节来解析,结果后面的数据全对不上。所以LDF文件一定要和所有节点对齐,这是LIN通信的铁律。

3.5 校验和场(Checksum Field)

校验和分两种:

  • 经典校验和(Classic Checksum): 只对数据字节做校验
  • 增强校验和(Enhanced Checksum): 对数据字节 + PID一起做校验

计算方法是:把所有字节加起来,取低8位,然后取反。

// 经典校验和示例
uint8_t classic_checksum(uint8_t *data, uint8_t len) {
    uint16_t sum = 0;
    for (uint8_t i = 0; i < len; i++) {
        sum += data[i];
    }
    while (sum > 0xFF) {
        sum = (sum & 0xFF) + (sum >> 8);
    }
    return (uint8_t)(~sum);
}

我个人习惯用增强校验和,因为能顺便检查PID有没有被干扰。不过要注意,LIN 1.x只能用经典校验和,LIN 2.x才支持增强校验和。

帧类型

LIN定义了四种帧类型。咱们一个个说。

3.6 无条件帧(Unconditional Frame)

这是最常用的帧类型。主节点发一个帧头,指定某个从节点必须响应。从节点收到后,无条件地把数据发出来。

说白了,就是“点名回答”。主节点问谁,谁就得答。

应用场景: 车窗位置、车门状态、灯光开关等周期性信号,都用无条件帧。

3.7 事件触发帧(Event Triggered Frame)

这个有点意思。多个从节点共享同一个帧ID,但平时不占用总线。只有当某个从节点有事件发生时,它才响应。

你想想看,如果每个从节点都定期发数据,总线负载会很高。事件触发帧就是为了解决这个问题——没事别说话,有事再说。

但这里有个问题:如果两个从节点同时响应,就会冲突。所以事件触发帧后面通常会跟一个无条件帧,用来确认到底是谁发了数据。

我的经验: 事件触发帧适合那些不常发生的事件,比如门把手触摸传感器。如果事件太频繁,反而会降低效率。

3.8 偶发帧(Sporadic Frame)

偶发帧是主节点主动发的,但只在需要的时候发。比如某个信号值变化了,主节点才发一帧。

和无条件帧的区别在于:无条件帧是定时发的,偶发帧是“看心情”发的。

帧类型 谁发起 触发条件 典型用途
无条件帧 主节点 定时触发 周期性信号
事件触发帧 从节点 事件发生 非周期性事件
偶发帧 主节点 信号变化 状态变化通知
诊断帧 主/从节点 诊断请求 故障诊断

3.9 诊断帧(Diagnostic Frame)

诊断帧使用固定的帧ID:

  • 主节点请求: ID = 0x3C
  • 从节点响应: ID = 0x3D

诊断帧的数据场固定为8个字节,遵循ISO 14229(UDS)协议。说白了,就是用来读故障码、写参数、做例程控制的。

注意: 诊断帧的优先级最高。如果总线上同时有无条件帧和诊断帧,诊断帧会先被处理。这是为了确保故障诊断的实时性。

LIN帧结构总览

下面这张图,把整个帧结构串起来了。

LIN帧结构总览 同步间隔场 同步场 标识符场 数据场 校验和场 帧头由主节点发送,数据场和校验和由从节点发送 数据场长度:1~8字节,由LDF文件定义 帧类型 无条件帧 事件触发帧 偶发帧 诊断帧

好了,LIN帧结构就这些。说白了,就是主节点发帧头,从节点响应数据。帧类型的选择,取决于你的应用场景。我个人建议:能用无条件帧解决的,就别用事件触发帧,简单可靠才是王道。