3、LIN总线协议基础:LIN帧结构、帧头与帧响应、同步间隔场与同步场

好,咱们今天聊聊LIN总线最核心的东西——帧结构。说白了,LIN总线上跑的就是一帧一帧的数据。你搞懂了帧长什么样,后面那些调度啊、诊断啊,就都顺了。

我个人习惯把LIN帧拆成两大部分来看:帧头帧响应。帧头由主机任务发出,帧响应由从机任务发出。这个主从关系,是LIN总线的根本。

3.1 帧头(Header)里有什么?

帧头一共四个部分:同步间隔场、同步场、标识符场,以及一个间隔分隔符。嗯,这里要注意,间隔分隔符在标准里是有的,但很多实际实现里并不严格检查它。

咱们一个一个说。

3.1.1 同步间隔场(Synch Break)

这是帧头的第一个信号。它的作用很简单——告诉总线上所有节点:“注意了,新的一帧要开始了!”

同步间隔场的特征是:总线被拉低至少13个位时间。为什么是13?因为正常的字节传输中,起始位加8个数据位加停止位,最多也就10个位时间。13个位时间,足够让所有节点识别出这不是正常数据,而是一个“帧开始”信号。

关键参数:

  • 同步间隔场长度:13~26个位时间(标准要求至少13)
  • 间隔分隔符:至少1个位时间(总线恢复为隐性)

我在项目中遇到过一个问题:某个从节点老是丢帧。查了半天,发现是主机发送的同步间隔场只有12个位时间。那个从节点的晶振有点偏,12个位时间它没认出来。后来我把间隔场设成了15个位时间,问题就解决了。所以我的建议是:别卡着13的下限,留点余量

3.1.2 同步场(Synch Field)

同步场就是一个字节:0x55。二进制是 01010101。你想想看,这个字节在总线上会产生什么波形?对,一个方波,高低电平交替出现。

所有从节点就靠这个方波来校准自己的时钟。因为LIN总线没有单独的时钟线,节点只能靠同步场来“对表”。

我曾经见过一个案例:某个从节点用的内部RC振荡器,精度只有±10%。结果同步场之后,它算出来的位时间偏差太大,后面的数据全读错了。后来我强制要求所有从节点必须用±2%以内的时钟源,或者做硬件自动同步。嗯,这个坑踩过之后,我再也不敢在LIN节点上用便宜的RC振荡器了。

3.1.3 标识符场(Protected Identifier, PID)

标识符场占一个字节,但真正有用的只有6位——也就是0~63共64个ID。剩下的2位是奇偶校验位。

为什么要有奇偶校验?因为ID一旦传错,从节点可能响应了错误的帧,或者多个节点同时响应,总线就乱套了。

PID的计算方式是这样的:

ID[0..5] = 用户定义的标识符
P0 = ID0 ⊕ ID1 ⊕ ID2 ⊕ ID3 ⊕ ID4
P1 = !(ID1 ⊕ ID2 ⊕ ID3 ⊕ ID4 ⊕ ID5)
PID[0..7] = {P1, P0, ID5, ID4, ID3, ID2, ID1, ID0}

说白了,P0是ID的低5位异或,P1是ID的1~5位异或再取反。你写代码的时候,可以直接查表,省得每次算。

我的小技巧:调试阶段,我经常用逻辑分析仪抓PID,然后手动算一下奇偶校验对不对。如果不对,八成是主机任务发错了,或者从机任务解析错了。这个排查思路,能帮你快速定位问题。

3.2 帧响应(Response)里有什么?

帧响应由从机任务发出,包含1~8个字节的数据场,以及一个校验和场。

3.2.1 数据场(Data Field)

数据场就是你要传的实际数据。LIN 2.x标准支持1~8个字节。注意,是1到8,不是固定8个。你传1个字节也可以,传8个也可以,取决于你的信号打包方式。

我个人习惯:能用1个字节传的信号,绝不用2个。LIN总线速度本来就慢(最高20kbps),能省则省。

3.2.2 校验和场(Checksum)

校验和分两种:经典校验和(LIN 1.x)和增强校验和(LIN 2.x)。

经典校验和:只对数据场做校验。
增强校验和:对数据场加上PID一起做校验。

为什么LIN 2.x要改成增强校验和?因为PID在帧头里传,如果帧头被干扰了,从节点可能响应错了ID。加上PID一起校验,能发现这种错误。

注意:如果你的网络里混用了LIN 1.x和LIN 2.x的节点,校验和方式必须统一。我曾经在一个项目里,主机是2.x,从机是1.x,结果校验和总是不对。后来我把主机配置成经典校验和模式才解决。所以,兼容性测试一定要做

3.3 完整的帧结构长什么样?

把帧头和帧响应拼起来,一个完整的LIN帧就是这样的:

| 同步间隔场 | 间隔分隔符 | 同步场 | 标识符场 | 数据场(1~8字节) | 校验和场 |

从时间上看,帧头由主机任务发出,帧响应由从机任务发出。中间有一个帧内响应空间(Inter-byte Space),但标准里没强制要求,很多实现里直接忽略。

我画个表格,帮你理清每个场的长度:

场名称 长度(位时间) 说明
同步间隔场 13~26 显性电平,标志帧开始
间隔分隔符 ≥1 隐性电平,分隔间隔场和同步场
同步场 10(1起始+8数据+1停止) 固定为0x55,用于时钟同步
标识符场 10 6位ID + 2位奇偶校验
数据场 10 × N(N=1~8) 实际传输的数据
校验和场 10 经典或增强校验和

3.4 避坑指南:我踩过的几个坑

做LIN总线这么多年,有些坑我印象特别深,分享给你:

  • 同步间隔场长度不够:前面说了,至少13个位时间。但有些便宜的晶振或者RC振荡器,12个位时间就认不出来了。我建议设成15~18个位时间,兼容性最好。
  • PID奇偶校验算错:这个错误很隐蔽。你写代码的时候,如果手动算PID,一定要对照标准再算一遍。我建议直接用查表法,或者用现成的库函数。
  • 校验和方式不统一:LIN 1.x和LIN 2.x混用时,校验和方式必须一致。否则从节点会报错,主机也收不到正确数据。
  • 帧内响应空间被忽略:虽然标准里没强制,但有些从节点对时序要求很严。如果主机连续发帧头,中间没有间隔,从节点可能来不及处理。我习惯在帧头和帧响应之间留至少2个位时间的空闲。

总结一下:LIN帧结构其实不复杂,但细节决定成败。同步间隔场、同步场、PID、校验和,这四个地方最容易出问题。你只要把这四个点盯住了,LIN总线的基本通信就不会有大问题。

下一章,咱们聊聊LIN的调度表。说白了,就是怎么安排这些帧在总线上跑。嗯,那个更有意思。