2. LIN协议规范:版本、帧结构与报文类型

好,咱们进入正题。

LIN协议,说白了就是汽车里那些“不太重要”的节点之间的通信方式。比如车窗、座椅、后视镜这些。它们不需要CAN那么高的速率,成本也敏感。我最早接触LIN是在做车门控制器的时候,那时候还踩过不少坑。

2.1 LIN协议版本

LIN协议从1.0开始,到现在主流是2.1和2.2。2.0之后基本稳定了。

我个人习惯,新项目直接上2.1或2.2。为什么?因为2.0之前的版本,诊断功能太弱。你想想看,车厂现在都要求支持诊断,你总不能为了省那点资源,把自己逼到墙角。

几个版本的关键区别,我列个表:

版本 主要变化 我的建议
LIN 1.0 / 1.1 最早版本,基本功能 别用了,兼容性差
LIN 1.2 引入配置命令 老项目可能见到
LIN 2.0 帧结构大改,增加诊断 勉强能用
LIN 2.1 完善诊断,增加偶发帧 推荐
LIN 2.2 小修小补,兼容2.1 当前主流

嗯,这里要注意:版本向下兼容,但主节点和从节点的版本最好一致。我曾经遇到过主节点用2.1,从节点用1.3,结果配置命令死活不认。折腾了两天才发现是版本不匹配。

2.2 LIN帧结构

LIN的帧结构,其实不复杂。它不像CAN那样有那么多仲裁场、控制场。LIN帧就两部分:报头响应

报头由主节点发出,响应可以由主节点或从节点发出。这个设计很有意思——主节点掌握着总线的“话语权”。

具体来看:

  • 同步间隔场:至少13个显性位。这是用来让从节点“醒过来”的。我调试时经常用示波器看这个间隔,如果小于13位,从节点根本不理你。
  • 同步场:0x55。说白了就是让从节点校准自己的时钟。LIN是低成本方案,从节点常用内部RC振荡器,精度差。靠这个同步场,大家才能对上节奏。
  • 标识符场:6位ID + 2位奇偶校验。这里有个坑——ID范围是0x00到0x3F,但0x3C和0x3D被保留给诊断帧。你设计节点时,别把这两个ID分配给普通报文。
  • 数据场:1到8字节。注意,LIN的数据场长度是可变的,不像CAN固定8字节。这个灵活性很好,但也会带来问题。我后面会讲。
  • 校验和场:经典校验和或增强型校验和。2.0以后推荐用增强型,把标识符也参与校验。安全一些。

来个代码示例,看看从节点怎么解析标识符:

// 解析LIN标识符
uint8_t lin_parse_id(uint8_t id_byte) {
    uint8_t id = id_byte & 0x3F;  // 取低6位
    // 校验奇偶位(简化版)
    uint8_t p0 = ((id & 0x01) ^ ((id & 0x02) >> 1) ^ ((id & 0x04) >> 2) ^ ((id & 0x10) >> 4)) & 0x01;
    uint8_t p1 = ~(((id & 0x02) >> 1) ^ ((id & 0x08) >> 3) ^ ((id & 0x10) >> 4) ^ ((id & 0x20) >> 5)) & 0x01;
    // 如果校验失败,返回0xFF
    if (p0 != ((id_byte >> 6) & 0x01) || p1 != ((id_byte >> 7) & 0x01)) {
        return 0xFF;
    }
    return id;
}
小技巧:实际项目中,我建议把ID解析和校验做成一个独立函数。因为主节点发过来的ID可能受干扰,校验失败时直接丢弃,别处理。

2.3 报文类型

LIN的报文类型,一共四种。我一个个说。

2.3.1 无条件帧

这是最常用的。主节点发出报头,指定ID,然后对应的从节点必须响应。说白了就是“点对点”的强制通信。

比如,主节点发ID=0x01的报头,从节点A收到后,必须把自己的数据发出来。没有商量的余地。

我在做车窗控制器时,大部分控制信号都用无条件帧。简单、可靠、实时性好。

2.3.2 事件触发帧

这个就有意思了。它用来处理“偶尔发生”的事件。比如,某个开关被按下。

主节点发一个事件触发帧的报头,多个从节点都可以响应。但为了避免冲突,每个从节点在响应前会先判断自己的数据有没有变化。如果没变化,就不响应。

你可能会问:如果两个从节点同时响应怎么办?

嗯,这就是设计上的妥协。LIN协议允许冲突,冲突后主节点会改用无条件帧轮询。说白了,事件触发帧是“优化手段”,不是“可靠手段”。

避坑指南:我曾经在一个项目中,把三个门把手的状态都放在同一个事件触发帧里。结果用户同时拉两个门把手时,总线冲突,主节点收不到数据。后来改成每个门把手一个无条件帧,问题解决。事件触发帧适合“很少同时触发”的场景。

2.3.3 偶发帧

偶发帧,名字听着玄乎,其实很简单。它是主节点发出的,但数据内容可以来自多个从节点。主节点在发送前,会检查哪个从节点有数据更新,然后只发送那个节点的数据。

说白了,偶发帧是“主节点主动问,但只问有变化的”。

这个在2.1版本才引入。我一般用它来传输一些状态信息,比如温度、电压等。这些数据变化慢,没必要每个周期都发。

2.3.4 诊断帧

诊断帧,ID固定为0x3C和0x3D。0x3C是主节点发请求,0x3D是从节点发响应。

诊断帧的格式遵循ISO 15765-2(也就是UDS over LIN)。数据场第一个字节是诊断服务ID,后面跟着参数。

比如,读取从节点的软件版本:

// 主节点发送诊断请求:读取数据标识符 0xF1(软件版本)
// 数据场: 0x22 0xF1 0x00 0x00 0x00 0x00 0x00 0x00
// 0x22 = 读取数据标识符服务
// 0xF1 0x00 = 数据标识符

// 从节点响应:
// 数据场: 0x62 0xF1 0x00 0x01 0x02 0x03 0x00 0x00
// 0x62 = 读取数据标识符响应
// 0xF1 0x00 = 数据标识符
// 0x01 0x02 0x03 = 版本号 V1.2.3

诊断帧是强制实现的。车厂验收时,一定会用诊断工具读你的节点信息。所以,哪怕你的节点功能再简单,诊断部分也得做全。

核心要点:四种报文类型,各有各的用途。无条件帧是主力,事件触发帧是优化,偶发帧是补充,诊断帧是必须。设计时,先想清楚你的数据流,再选合适的类型。

好了,这一章就到这里。LIN协议规范,说白了就是这些内容。版本选2.1以上,帧结构记清楚,报文类型用对地方。下一章,我会讲从节点的硬件设计,包括收发器选型和电源管理。到时候见。