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