参考文章:
Lin总线通信在STM32作为主机代码以及从机程序
基于STM32的LIN总线的实现
STM32F0-LIN总线通讯程序代码 主从调试OK
LIN协议通信DEMO及源码剖析
前文已讲解关于LIN帧代码如何实现:【LIN】1.LIN通信实战:帧收发全流程代码实现
帧类型
在了解了网上的LIN代码就会发现,所谓的LIN主机程序和从机程序大概是分为四个场景如下:
1. 主机:发送ID -> 从机:响应数据 -> 主机:接收数据
2. 从机:接收ID -> 发送数据
(这描述的是同一个过程,只是从主从两个视角看)
-
LIN帧类型:无条件帧(Unconditional Frame)
-
过程详解:
- 主机(Master):发送帧头(Header)。这个Header里最关键的就是受保护的标识符(PID)。这个PID决定了哪个从机需要响应,以及这个帧的含义是什么(例如,0x30代表请求车速信号)。
- 从机(Slave):总线上所有从机都接收到了这个Header。每个从机都有自己的调度表(Schedule Table) 和信号处理程序,它们会检查这个PID。
- 如果这个PID与自身某个发布(Publish) 任务的PID匹配(例如,车速传感器从机被配置为对PID 0x30进行响应),则该从机负责回复。
- 从机(Slave):在规定的响应时间内,发送响应(Response),即数据场(1-8字节) + 校验和场。
- 主机/其他从机(Master/Other Slaves):接收这个响应。主机或其他需要该数据的从机(配置为订阅(Subscribe) 此PID的节点)会从数据场中解析出具体的信号(如车速值=50km/h)。
-
这是LIN总线最主要的数据广播机制。
3. 主机:发送ID+数据 -> 从机:接收数据并处理
4. 从机:接收ID+数据 -> 处理数据
(这描述的也是同一个过程)
- LIN帧类型:这也是一种无条件帧,但数据流向是主机到从机。
- 过程详解:
- 主机(Master):发送帧头(Header) + 数据场(Data Field) + 校验和场(Checksum)。注意:这里主机发送了完整的帧!
- 从机(Slave):所有从机接收整个帧。它们通过PID来判断这个帧是发给谁的、是干什么的。
- 例如,主机发送一个PID为0x31的帧,数据场包含一个字节0x55,意思是“打开空调”。
- 配置为订阅(Subscribe) PID 0x31的空调控制器从机,会识别这个PID,然后读取数据场,解析出信号,并执行相应的操作(打开空调)。
- 响应问题:从机通常不会在总线上进行响应(ACK)。LIN协议没有规定应用层必须应答。如果主机需要确认命令是否被执行,它必须在后续的调度中,再发起一个查询帧(第一种方式),去读取从机的某个状态信号(例如,读取空调开关状态PID),来间接确认。
由此我们知道了,原来网上所说的主从机代码指的是无条件帧,那么其它帧又是怎么用到的,下面从实际场景出发,了解LIN的5种帧
一、 LIN核心思想:主从结构与单线通信
LIN(Local Interconnect Network)是一种低成本、低速率的车载网络协议,用于实现汽车中的分布式电子系统控制。
- 核心特点:
- 单线通信:仅使用一根信号线,极大降低了线束成本和复杂度。
- 主从结构:通信永远由主节点(Master) 发起,从节点(Slave) 响应。从节点不能主动发送数据。
- 基于调度表:主节点内部有一个像“歌单”一样的调度表,循环决定下一刻要发送哪个帧,保证了通信的有序性。
二、 五种关键“帧”与沟通机制
LIN的“帧”是通信的基本单元。一个完整的帧由帧头(Header) 和响应(Response) 组成。帧头由主节点发送,响应由从节点发送。
我们可以从三个维度来理解LIN的通信方式:帧类型、调度策略和标识符用途。
下面我们通过一个扩展的汽车车窗控制场景来详细讲解这五种方式是如何协同工作的。
场景角色:
- 主机(Master):车身控制模块(BCM)。它是车门LIN总线的主控节点。
- 从机1(Slave 1):主驾驶车门开关模块(内部有LIN芯片)。它负责报告开关状态。
- 从机2(Slave 2):副驾驶车门控制模块(内部有LIN芯片和电机驱动器,带防夹功能)
- 诊断仪:维修设备(通过CAN网关连接)
1. 无条件帧 (Unconditional Frame) - 基石
这是LIN最常用、最基本的通信模式,用于周期性数据交换。
-
理论:主机发送帧头(含PID),指定从机回复数据;或主机发送完整帧(含数据)向从机下达命令。
-
实践(场景:正常控制):
- 步骤a (主机问,从机答):BCM发送帧头
PID=0x21
(查询开关状态)。开关模块(从机1)响应数据Data=0x02
(二进制00000010
,表示“副驾升起”按钮被按下)。 - 步骤b (主机发命令):BCM解析后,发送一个完整帧:
PID=0x32
(控制副驾车窗) +Data=0x02
(命令:上升)。副驾模块(从机2)接收并执行,不产生总线响应。 - 步骤c (主机确认):BCM发送帧头
PID=0x33
(查询车窗状态)。副驾模块响应Data=[50, 0x00]
(位置50%,状态正常)。
- 步骤a (主机问,从机答):BCM发送帧头
-
沟通方式:纯粹的“发布-订阅”模型。BCM“订阅”了开关状态,开关模块“发布”该状态。副驾模块“订阅”了控制命令,BCM“发布”该命令。
2. 事件触发帧 (Event Triggered Frame) - 优化师
用于处理多个从机可能发生、但通常不会同时发生的事件,以节省带宽。
- 理论:主机发送一个公共PID,多个从机被配置可响应它,但只有状态发生变化的从机才会实际回复。若多个从机同时回复导致冲突,主机会退回到轮询模式。
实践(场景:防夹功能激活):
副驾车窗在上升过程中遇到障碍物,电机电流陡增,模块检测到阻力过大,判定为防夹事件。
- 传统方式(低效):BCM需要不断轮询每个车门的状态帧(
PID=0x33
,0x34
,0x35
…)来检查是否有异常,即使大部分时间都没有事件发生,这浪费了总线带宽。 - 高效方式(事件触发帧):BCM发送一个公共的询问帧,谁有事谁回答。
过程如下:
- BCM 发送一个特殊的Header,其
PID=0x40
。这个PID在LDF中被定义为事件触发帧,它对应着一组可能发生事件的从机状态(比如,副驾车窗状态、天窗状态、尾门状态等都属于“事件源”)。 - 多个从机(副驾模块、天窗模块…)都配置为可以响应这个PID。
- 此时:
- 天窗模块状态无变化,它选择保持沉默。
- 副驾模块因为刚刚触发了防夹功能,状态发生了重要变化,它立刻在响应时隙内回复数据。它回复的数据就是它自身的状态数据(例如
Data = [75, 0x01]
,位置75%,防夹触发标志位为1)。
- BCM 接收到响应,解析后知道是副驾车窗发生了防夹,它可能会记录事件、甚至让仪表盘显示一个警告提示。
冲突处理:如果极端情况下,副驾车窗和天窗同时发生事件并都回复,会导致总线冲突和校验和错误。BCM检测到错误后,就会退出事件触发模式,转而逐一发送每个从机专属的PID(0x33
问副驾,0x34
问天窗…)来精确定位所有事件源。
3. 诊断帧 (Diagnostic Frame) - 外科医生
用于执行点对点的深度访问,如读取故障码、写配置参数等。
- 理论:使用保留的专用PID(
0x3C
和0x3D
),遵循UDS等标准诊断服务格式,数据长度固定为8字节。
实践(场景:读取详细故障数据):
车辆维修时,技师需要更详细的信息,而不仅仅是“防夹触发了”这个状态位。他需要知道历史故障码、电机堵转电流值等深层数据。这需要通过诊断帧来实现,这是一种点对点、高可靠性的通信。
过程如下:
- 诊断仪(通过CAN)向BCM发送一个诊断请求:“读取副驾车窗控制模块的故障码(服务ID: 0x22)”。
- BCM 作为LIN总线的主机,充当了网关的角色。它将来自CAN的请求翻译成LIN总线上的诊断帧。
- BCM 在LIN总线上发送一个Header,其
PID=0x3C
。这是一个专用的诊断请求标识符,所有从机都知道这个PID用于诊断。 - BCM 紧接着发送数据场(8字节),这8字节符合UDS(统一诊断服务)标准格式:
Byte 0
: 0x02 — 表示后续有效数据长度。Byte 1
: 0x22 — 服务ID,0x22
代表“按标识符读数据”。Byte 2 & 3
: 0xF1 0x90 — 一个自定义的诊断标识符,代表“读取第一个防夹事件的历史数据”。- 剩余字节填充为0x00。
- 副驾模块 识别到
PID=0x3C
是诊断请求,并且数据场中的标识符0xF190
是给自己的。它准备诊断响应数据。 - BCM 随后再发送一个Header,其
PID=0x3D
。这是一个专用的诊断响应标识符。 - 副驾模块 响应这个
0x3D
帧,回复8字节的诊断数据:Byte 0
: 0x04 — 后续有效数据长度。Byte 1
: 0x62 — 对0x22
请求的响应(0x22 + 0x40)。Byte 2 & 3
: 0xF1 0x90 — 回显请求的标识符。Byte 4
: 0x05 — 故障码,例如0x05
代表“防夹功能激活”。Byte 5
: 75 — 发生时的车窗位置(75%)。
- BCM 接收到响应后,再通过CAN总线转发给诊断仪。技师就在诊断仪屏幕上看到了详细的故障信息。
4. 偶发帧 (Sporadic Frame) - 调度策略
核心思想: 这是一种优化带宽的高级调度策略。主机(Master)不会死板地周期性地发送每一个帧,而是只在确信该帧所携带的数据有可能会更新时,才在调度表中插入这个帧。
为什么需要它?
想象一下,车窗从完全关闭到完全打开需要5秒钟。如果BCM以100ms的周期去查询车窗位置(PID=0x33
),那么在5秒内会发送50次查询,但回复的位置值可能只是从0, 2, 4, 6… 慢慢变到100。很多次查询返回的数据变化极小,这是一种带宽浪费。
“偶发”如何工作?
- 条件触发:主机BCM知道,只有当你按下开关(
PID=0x21
有变化) 或者收到事件触发帧(PID=0x40
报告了事件) 时,车窗位置才会开始快速变化。 - 动态插入:当BCM检测到上述“触发条件”时,它就会在接下来的几个调度周期里,临时、高频地插入查询车窗位置的帧(
PID=0x33
)。 - 停止查询:当BCM发现位置数据在连续几次查询中不再变化(比如车窗已经到达目标位置),它就会停止发送这个查询帧,从而节省出带宽给其他任务。
场景举例(优化后的调度):
- 常态(车窗静止):BCM的调度表主要循环发送:
0x21
(问开关)、0x22
(问门锁)… 它不发送0x33
(问车窗位置),因为位置没变化,问了也是白问。 - 按下开关:BCM通过
0x21
得知用户命令。 - 动态调整:BCM立即修改调度表,在未来5秒内,高频循环:
0x21
->0x32
(发命令)->0x33
(问位置) ->0x21
->0x32
->0x33
… - 恢复常态:BCM通过
0x33
的响应发现位置已达到100%且不再变化,于是从调度表中移除0x33
,恢复到此前的低频查询模式。
所以,“偶发帧”不是一种新帧,它仍然是无条件帧,只是它的发送时机是“偶发的”、“有条件的”,而非周期性的。这是一种主机软件的智能调度算法。
5. 保留帧 (Reserved Frame) - 标识符分类
核心思想: 这是指LIN协议规范中为未来用途预留的标识符(PID)。这些PID有特定的值,不能用于普通的无条件帧。
为什么需要它?
为了保障协议的扩展性和兼容性。LIN联盟预先规定好哪些PID是留给未来新功能或特殊功能的,这样所有厂商的芯片和软件都会遵守这个规则,避免冲突。
常见保留帧:
- 主请求帧 (Master Request Frame):
PID = 0x3C
- 从响应帧 (Slave Response Frame):
PID = 0x3D
- 这两个PID就是我们之前讲的诊断帧的专用通道。它们被“保留”用于诊断目的。
- 其他保留范围:协议还规定了其他一些范围的PID值(例如0x30-0x31之间的某些值)也被保留,用户不能自定义使用。
场景举例:
当BCM需要与副驾模块进行诊断通信时,它必须使用保留的PID:0x3C
和0x3D
。它不能自己定义一个比如PID=0x40
来做诊断,因为:
0x40
可能已经被你用作事件触发帧了。- 副驾模块的厂商是按照标准协议开发的,它的软件只认
0x3C
和0x3D
是诊断帧。如果你用0x40
,它根本不会把它当成诊断请求来处理。
所以,“保留帧”指的是那些使用了保留PID的帧,这些帧用于特定目的(主要是诊断),普通应用层通信不能占用这些PID。
三、 总结与协作图景
在真实的汽车网络中,这五种方式绝非孤立工作,而是紧密协作,形成一个高效的整体。它们的关系如下图所示:
为了更清晰地理解,我们可以用以下表格来总结所有这些概念在车窗控制场景中的具体体现:
概念分类 | 具体类型 | 目的 | 在车窗场景中的具体示例 |
---|---|---|---|
帧类型 | 无条件帧 | 基础数据交换 | PID=0x21 (查询开关状态)PID=0x32 (发送升降命令)PID=0x33 (查询车窗位置) |
事件触发帧 | 高效处理多从机事件 | PID=0x40 (广播查询,谁有异常事件谁响应) | |
诊断帧 | 配置、诊断、读故障码 | 使用PID=0x3C (主请求)和0x3D (从响应)读取详细防夹故障码 | |
调度策略 | 周期调度 | 固定时间间隔查询 | 每100ms查询一次开关状态(PID=0x21 ) |
偶发调度 | 优化带宽,动态查询 | 仅在收到升降命令后,才临时高频查询车窗位置(PID=0x33 ) | |
PID用途 | 自定义PID | 用于普通应用功能 | 0x21 , 0x32 , 0x33 , 0x40 等,由系统设计师定义 |
保留PID | 保证兼容和扩展 | 0x3C , 0x3D 等,协议规定只能用于诊断,不可另作他用 |
调度表(Schedule Table)
如果说LIN总线上的各种帧(无条件帧、事件触发帧等)是乐手们演奏的音符,那么调度表就是主机(Master)手中的指挥棒和乐谱。它规定了在什么时间、由谁来演奏哪个音符,确保了整个LIN网络通信的井然有序,避免冲突。
一、 调度表是什么?
调度表是主机节点(在我们的场景中就是BCM)内部的一个定时任务列表。它定义了:
- 发送顺序:帧与帧之间的先后执行顺序。
- 时间基准:每个帧或每一组帧之间的时间间隔(例如,每个帧槽
Frame Slot
的持续时间)。
它的本质是一个无限循环的“歌单”,主机CPU会严格按照这个歌单,周而复始地依次发送各个帧的Header,从而 orchestrate(协调)整个总线的通信。
二、 调度表里有什么?
一个调度表由多个调度表条目(Schedule Table Entry) 组成。每个条目至少包含两样东西:
- 要发送的帧:例如,发送PID为
0x21
的Header(查询开关状态)。 - 该帧的延迟时间:发送完当前帧后,等待多长时间再发送下一个帧。这个时间称为帧时隙(Frame Slot)。
一个简单的调度表示例(车窗控制基础版):
调度表条目 | 帧的PID | 含义 | 帧时隙(例如:10ms) |
---|---|---|---|
1 | 0x21 | 查询主驾开关状态 | 2个时隙(20ms后发下一个) |
2 | 0x22 | 查询门锁状态 | 3个时隙(30ms后发下一个) |
3 | 0x31 | 控制主驾车窗(命令帧) | 2个时隙(20ms后发下一个) |
4 | 0x32 | 控制副驾车窗(命令帧) | 3个时隙(30ms后发下一个) |
… | … | … | … |
注:帧时隙必须大于该帧完成整个通信(Header + 最大可能Response时间)所需的时间,并为从机的处理留出余量。
三、 调度表如何工作?动态调度与场景结合
调度表并非一成不变。一个优秀的主机程序会管理多个调度表,并根据当前车辆状态在不同调度表之间切换,这就是“动态调度”的概念。结合我们的车窗场景:
1. 基础调度表(正常状态)
当车辆平稳运行,没有紧急事件时,BCM使用一个周期性的基础调度表。这个表就像背景音乐,持续循环,监控着基本状态。
- 内容:主要包含高优先级的、需要持续监控的无条件帧。
PID=0x21
:频繁查询开关状态(用户随时可能操作)。PID=0x22
:查询门锁状态。PID=0x33
:以较低频率查询车窗位置(因为位置不会瞬间变化,无需高频查询,这是偶发帧调度思想的体现)。
- 特点:循环周期短,带宽占用稳定。
2. 事件触发调度(高效响应)
当BCM通过基础调度表收到开关命令(PID=0x21
响应变化)或收到事件触发帧(PID=0x40
)的报告时,它知道有“事情”发生了。
- 动作:BCM可能会临时切换到一个更密集的调度表,或者在基础调度表中动态插入几个帧。
- 场景举例(用户按下开关):
- 基础调度表中,
PID=0x21
的响应数据从0x00
变为0x02
(副驾升起)。 - BCM识别到这个变化,判定为“事件”。
- 在接下来的几个循环中,BCM大幅提高
PID=0x32
(控制副驾车窗)和PID=0x33
(查询副驾车窗位置)的发送频率。 - 这就相当于指挥棒突然指挥某几个乐手(副驾控制模块)快速、密集地演奏一段solo,以实现车窗的平滑移动和实时位置监控。
- 当车窗到达目标位置后,BCM再切回基础调度表。
- 基础调度表中,
3. 诊断调度表(精准干预)
当诊断仪接入(例如,CAN网关转发诊断请求给BCM),需要执行深度诊断时。
- 动作:BCM会暂停当前的调度表,立即切换到一个专为诊断服务的调度表。
- 场景举例(读取故障码):
- BMC收到诊断请求。
- BCM中断当前循环,切换到诊断调度表。这个表里只包含两个条目:
- 发送
PID=0x3C
+ 8字节诊断请求数据。 - 等待一个帧时隙后,发送
PID=0x3D
的Header,准备接收从机的诊断响应。
- 发送
- 完成诊断通信后,BCM再切回之前的调度表,从中断处继续执行。
- 特点:优先级最高,实时响应,执行完即退出。