1. 总线架构与通信模型
1.1 单主多从架构
- 拓扑为单主多从:1 个主节点 + 最多 15 个从节点。
- 主节点负责总线调度,从节点仅在收到对应帧头后方可发送响应。
- 无主从竞争:不存在总线仲裁机制,通信时序由主节点完全控制。
- 主节点通常同时作为 CAN 网关,负责将 LIN 集群的数据转发到 CAN 骨干网。
1.2 与 CAN 的差异
| 维度 | LIN | CAN |
|---|---|---|
| 主从关系 | 单主多从 | 多主平等 |
| 总线访问 | 主节点调度,无冲突 | CSMA/CA + 非破坏性位仲裁 |
| 物理层线数 | 单线 + 地线 | 双差分线(CAN_H / CAN_L) |
| 典型速率 | 1~20 kbps(常用 9.6 / 10.4 / 19.2 kbps) | 125 kbps ~ 1 Mbps |
| 最大节点数 | 16(1 主 + 15 从) | ≤ 128(理论) |
| 工作电压 | 12V / 24V(汽车电池) | 5V 差分 |
| 同步方式 | 异步,从节点通过 0x55 自同步 | 异步,位填充 + 硬同步/重同步 |
| 错误处理 | 本地检测,无全局错误帧 | 错误帧广播,错误计数器自动退避 |
| 应答机制 | 无显式 ACK | ACK Slot + 应答界定符 |
| 实现成本 | 极低(UART + 简单收发器) | 较高(专用 CAN 控制器 + 收发器) |
1.3 典型应用场景
LIN 作为 CAN 的低成本补充,适用于对实时性要求不高、布线简单的场景:
- 车门模块(车窗升降、门锁、后视镜调节)
- 座椅控制(位置记忆、加热)
- 空调系统(风门执行器、温度传感器)
- 灯光控制(氛围灯、阅读灯)
- 雨刷与洗涤系统
2. 物理层与信号定义
2.1 信号电平
LIN 基于 ISO 9141(K-line)单线架构:
| 状态 | 电平 | 逻辑 |
|---|---|---|
| 显性(Dominant) | 接地(< 0.5 × Vbat) | 0 |
| 隐性(Recessive) | 电池电压(> 0.7 × Vbat) | 1 |
与 CAN 类似,LIN 也采用线与逻辑:任意节点将总线拉低(显性)即可覆盖其他节点的隐性状态。区别仅在于 CAN 用差分对实现,LIN 用单线 + 上拉电阻实现。
2.2 上拉电阻
- 每个节点内部有弱上拉电阻(约 30 kΩ)+ 二极管。
- 主节点外部需接强上拉电阻(典型 1 kΩ),用于维持总线隐性状态。
- 上拉电阻取值影响上升时间、静态功耗与负载能力。典型范围:1 kΩ ~ 2 kΩ。
2.3 位时序与同步
- 采用 UART/SCI 风格的异步串行通信。
- 总线上传输的每一个字节在物理层均封装为:1 个起始位(显性)+ 8 个数据位 + 1 个停止位(隐性),共 10 个位时间。
- 从节点通过 Sync Field(
0x55,即01010101b)测量主节点的位时间,校准自身波特率。
3. 帧格式
LIN 帧由**帧头(Header)和响应(Response)**两部分组成。主节点发送帧头,从节点根据帧头决定是否发送响应。
3.1 帧结构
| 字段 | 长度 | 发送方 | 说明 |
|---|---|---|---|
| 同步间隔场(Sync Break) | ≥ 13 + 1 bit | 主节点 | 至少 13 个连续显性位 + 1 个隐性界定符,用于唤醒从节点并标识帧起始 |
| 同步场(Sync Field) | 8 bit(数据内容) | 主节点 | 固定值 0x55(01010101b),从节点据此测量位时间、校准自身波特率。物理层占用 10 bit |
| 受保护标识符场(PID) | 8 bit(数据内容) | 主节点 | 低 6 位为帧 ID(0~63),高 2 位为奇偶校验位。物理层占用 10 bit |
| 数据场(Data Field) | 1~8 byte | 从节点(或主节点自身) | 实际载荷,Intel 字节序。每个字节物理层占用 10 bit |
| 校验和场(Checksum) | 8 bit(数据内容) | 响应发送方 | Classic:仅校验数据(LIN 1.x);Enhanced:校验数据 + PID(LIN 2.x)。物理层占用 10 bit |
3.2 PID 奇偶校验
PID 中高 2 位 P0、P1 由低 6 位 ID 计算得出:
P0 = ID0 ⊕ ID1 ⊕ ID2 ⊕ ID4P1 = ¬(ID1 ⊕ ID3 ⊕ ID4 ⊕ ID5)
从节点接收后重新计算并比对,若不一致则忽略该帧。
3.3 数据长度与 ID 的关系(典型配置)
| ID 范围 | 数据长度 |
|---|---|
| 0 ~ 31 | 2 byte |
| 32 ~ 47 | 4 byte |
| 48 ~ 63 | 8 byte |
3.4 校验和机制
| 类型 | 校验范围 | 适用版本 |
|---|---|---|
| Classic Checksum | 仅数据场 | LIN 1.x |
| Enhanced Checksum | 数据场 + PID | LIN 2.x |
诊断帧(ID 0x3C / 0x3D)固定使用 Classic Checksum。
4. 帧类型与调度机制
所有帧类型在总线上遵循完全相同的物理帧格式:Sync Break → Sync Field → PID → Data → Checksum。帧类型的差异体现在主节点的调度策略与从节点的响应行为上,而非帧格式本身。
4.1 无条件帧(Unconditional)
- 主节点按调度表周期性发送帧头,指定从节点响应。
- 用于需要持续监控的状态量(如车门状态、座椅位置),即使数据未变化,周期性刷新也可确认节点在线并检测通信故障。
4.2 事件触发帧(Event Triggered)
- 主节点发送帧头,多个关联从节点可能同时响应。
- 用于偶尔变化的状态(如门把手、座椅按键)。若多个从节点同时响应,总线数据冲突,主节点在后续周期改用无条件帧逐一查询关联节点。
- 作用:减少总线负载。避免对低频变化信号进行周期性无条件轮询导致的带宽浪费。
冲突回退机制:主节点在调度表中预先定义该事件触发帧所关联的无条件帧集合。冲突发生后,主节点在接下来的调度周期中,依次发送这些关联无条件帧的帧头,逐一接收响应,间接确定哪些从节点有数据待发送。
4.3 偶发帧(Sporadic)
- 主节点在调度表中预留的时隙内,当关联信号更新时发送。
- 用于主节点需要主动广播的、非周期性数据。
- 动态优先级:多个偶发帧同时待发时,ID 最小者优先发送。
4.4 诊断帧(Diagnostic)
- ID
0x3C(主节点请求),ID0x3D(从节点应答)。 - 固定 8 byte 数据场,基于 UDS/ISO-TP 协议。
- 用途:故障码读取、节点配置(如配置 NAD、PID 映射表)、软件刷写等。
4.5 保留帧(Reserved)
- ID
0x3E:用户自定义帧,厂商可自由定义用途。 - ID
0x3F:LIN 规范保留,不建议使用。
5. 通信调度
5.1 时间触发调度表
LIN 采用时间触发调度表(Schedule Table),由主节点严格按照时隙轮询各从节点。
- 调度表是主节点内部维护的一张时间-动作映射表,规定每个时隙应发送哪个帧头(以 PID 标识)及帧间间隔。
- 无总线竞争:主节点控制所有通信时序,从节点仅在收到对应帧头后才可发送响应。
- 确定性延迟:每个帧的传输时隙预先定义,最坏情况下的响应时间可计算。
- 从节点无主动发信权:不能主动向总线发送数据,必须等待主节点轮询。
5.2 从节点响应机制
- 每个从节点在配置阶段(通过 LDF 文件或诊断配置)建立响应映射表,记录自身需要响应的 PID 列表、对应的数据长度及数据来源。
- 从节点收到帧头后,将 PID 与本地映射表比对;若匹配,则在规定时隙内发送响应(数据场 + 校验和场)。
- 从节点不发送帧头(
Sync Break、Sync Field、PID),仅发送响应部分。 - 若 PID 不匹配,从节点保持静默,不占用总线。
6. 睡眠与唤醒
6.1 睡眠模式
- 进入条件:主节点发送睡眠命令(诊断帧 ID
0x3C,首字节为0x00);或总线空闲 ≥ 4 秒。 - 进入后所有节点停止通信,总线保持隐性状态,降低静态功耗。
6.2 唤醒机制
- 唤醒信号:总线上出现 250~5000 μs 的显性脉冲。
- 主节点或从节点均可发送唤醒信号。
- 若首次唤醒失败,最多重复 3 次,间隔 150~250 ms。
- 唤醒后所有节点重新同步,主节点恢复调度表运行。
7. 版本差异与行业现状
7.1 LIN 1.x 与 LIN 2.x 的差异
| 维度 | LIN 1.x | LIN 2.x |
|---|---|---|
| 校验和 | 仅 Classic Checksum | 支持 Classic 与 Enhanced Checksum |
| 诊断功能 | 诊断传输层不完善 | 增强诊断传输层,规范节点配置流程 |
| 帧类型 | 事件触发帧与偶发帧定义不完整或缺失 | 完整定义事件触发帧、偶发帧及冲突处理机制 |
| 睡眠/唤醒 | 规范较宽松 | 对睡眠命令格式和唤醒脉冲时序更严格 |
| 物理层 | 要求较宽松 | 对收发器参数、上升/下降时间、EMC 要求更严格 |
| API 规范 | 不完善 | 定义更完整的节点配置接口,LDF 文件格式更完善 |
7.2 行业现状
- 当前汽车行业主流使用 LIN 2.x(以 LIN 2.1 和 LIN 2.2A 为主),LIN 1.x 已基本淘汰。
- LIN 2.x 与 AUTOSAR(AUTomotive Open System ARchitecture,汽车领域开放式系统架构标准)兼容,已成为 OEM(Original Equipment Manufacturer,整车厂)的普遍要求。
- 新项目中几乎不会选用 LIN 1.x。
8. 调度表与响应映射表设计
8.1 主节点调度表设计
主节点调度表是一张时间-动作映射表,定义了总线运行期间每个时隙的通信任务。调度表在系统初始化时加载,主节点在运行期间严格按照表中的时隙顺序与间隔时间执行。
调度表条目结构:
| 字段 | 类型 | 说明 |
|---|---|---|
slot_index | uint8 | 时隙编号,从 0 开始递增 |
frame_type | enum | 帧类型:无条件帧 / 事件触发帧 / 偶发帧 / 诊断帧 |
pid | uint8 | 受保护标识符(含奇偶校验的 8 bit PID) |
delay_ms | uint16 | 与下一个时隙的间隔时间(含本帧传输时间) |
assoc_frames | array | 仅事件触发帧有效:关联的无条件帧 PID 列表,用于冲突回退 |
调度表运行逻辑:
- 主节点按
slot_index顺序遍历调度表。 - 在每个时隙开始时,主节点发送对应
pid的帧头(Sync Break+Sync Field+PID)。 - 若为无条件帧 / 诊断帧:主节点发送帧头后等待从节点响应,或主节点自身发送数据(诊断请求)。
- 若为事件触发帧:主节点发送帧头后监听总线,若收到有效响应则记录数据;若检测到冲突(校验和错误),则在后续周期中依次发送
assoc_frames中的无条件帧逐一查询。 - 若为偶发帧:主节点检查关联信号是否更新,若未更新则跳过该时隙(发送帧头但无响应,或完全不发送)。
- 当前时隙结束后,主节点等待
delay_ms再进入下一个时隙。 - 调度表遍历完毕后,主节点可选择循环执行或进入睡眠。
8.2 从节点响应映射表设计
从节点响应映射表是各从节点内部维护的一张PID-响应规则映射表,在配置阶段(通过 LDF 文件或诊断配置)写入。从节点在运行期间仅依赖该表决定是否响应总线上的帧头。
响应映射表条目结构:
| 字段 | 类型 | 说明 |
|---|---|---|
pid | uint8 | 该从节点需要响应的 PID |
data_len | uint8 | 响应数据场的字节长度(1~8) |
data_src | pointer | 数据来源指针,指向本地寄存器或内存中的状态数据 |
checksum_type | enum | 校验和类型:Classic / Enhanced |
enabled | bool | 响应使能标志。若为 false,即使 PID 匹配也不发送响应 |
响应映射表运行逻辑:
- 从节点持续监听总线。
- 检测到
Sync Break后,接收Sync Field并校准波特率。 - 接收
PID,提取低 6 位 ID 并验证奇偶校验位。 - 若奇偶校验失败,忽略该帧,继续监听。
- 若奇偶校验通过,将 ID 与响应映射表中的
pid逐一比对。 - 若匹配且
enabled为 true:从节点在帧头结束后,从data_src读取data_len字节数据,计算checksum_type指定的校验和,依次发送数据场与校验和场。 - 若不匹配或
enabled为 false:从节点保持静默,不占用总线。 - 发送响应期间,从节点持续监听总线;若检测到总线电平与自身发送不一致(事件触发帧冲突场景),立即停止发送并返回监听状态。
8.3 调度表示例
以下为一个典型汽车 LIN 集群的完整调度表:
| 时隙 | 帧类型 | PID | 响应节点 | 数据长度 | 间隔 (ms) | 关联帧(冲突回退) | 说明 |
|---|---|---|---|---|---|---|---|
| 0 | 无条件帧 | 0x10 | Node B | 2 byte | 15 | — | 车门状态(周期性状态量) |
| 1 | 无条件帧 | 0x20 | Node C | 2 byte | 15 | — | 座椅位置(周期性状态量) |
| 2 | 事件触发帧 | 0x30 | Node B / Node C | 2 byte | 20 | 0x10, 0x20 | 按键输入(偶发事件量) |
| 3 | 偶发帧 | 0x40 | Node B | 4 byte | 15 | — | 故障码(主节点广播,有更新时) |
| 4 | 诊断帧 | 0x3C | — | 8 byte | 25 | — | UDS 诊断请求(主节点发数据) |
| 5 | 诊断帧 | 0x3D | Node B / Node C | 8 byte | 25 | — | UDS 诊断应答 |
| 6 | 保留 | 0x3E | 用户定义 | 8 byte | 15 | — | 厂商自定义帧 |
调度表运行流程:
- T=0 ms:时隙 0,Node A 发送 PID
0x10帧头,Node B 响应 2 byte 车门状态,间隔 15 ms。 - T=15 ms:时隙 1,Node A 发送 PID
0x20帧头,Node C 响应 2 byte 座椅位置,间隔 15 ms。 - T=30 ms:时隙 2,Node A 发送 PID
0x30帧头,Node B 与 Node C 可能同时响应。- 若无冲突:正常接收数据,间隔 20 ms。
- 若冲突:Node A 在下一周期中依次发送 PID
0x10(查询 Node B)与 PID0x20(查询 Node C),间隔累加。
- T=50 ms:时隙 3,Node A 检查故障码是否更新,若有则发送 PID
0x40帧头,Node B 响应 4 byte,间隔 15 ms。 - T=65 ms:时隙 4,Node A 发送 PID
0x3C诊断请求帧(主节点自身发送 8 byte 数据),间隔 25 ms。 - T=90 ms:时隙 5,Node A 发送 PID
0x3D帧头,被诊断的从节点响应 8 byte,间隔 25 ms。 - T=115 ms:时隙 6,Node A 发送 PID
0x3E保留帧,间隔 15 ms。 - T=130 ms:调度表遍历完毕,主节点可选择循环执行或进入睡眠。
8.4 响应映射表示例
Node B(车门模块)的响应映射表:
| PID | 数据长度 | 数据来源 | 校验和类型 | 使能 |
|---|---|---|---|---|
0x10 | 2 byte | 车门状态寄存器 | Enhanced | true |
0x30 | 2 byte | 按键状态寄存器 | Enhanced | true |
0x3D | 8 byte | 诊断应答缓冲区 | Classic | true |
0x40 | 4 byte | 故障码寄存器 | Enhanced | true |
Node C(座椅模块)的响应映射表:
| PID | 数据长度 | 数据来源 | 校验和类型 | 使能 |
|---|---|---|---|---|
0x20 | 2 byte | 座椅位置寄存器 | Enhanced | true |
0x30 | 2 byte | 按键状态寄存器 | Enhanced | true |
0x3D | 8 byte | 诊断应答缓冲区 | Classic | true |
映射表运行示例:
- Node B 收到 PID
0x10的帧头 → ID 匹配 → 从车门状态寄存器读取 2 byte → 计算 Enhanced Checksum → 发送数据场 + 校验和场。 - Node B 收到 PID
0x20的帧头 → ID 不匹配 → 保持静默,不发送任何数据。 - Node C 收到 PID
0x30的帧头 → ID 匹配 → 从按键状态寄存器读取 2 byte → 发送响应。若 Node B 同时响应,总线冲突,两者均检测到不一致后停止发送。
9. 三节点网络通信过程模拟
以下以一个典型汽车 LIN 集群为例,模拟三个节点在 LIN 总线上的完整交互过程。
9.1 网络拓扑与节点定义
| 节点 | 角色 | 功能描述 |
|---|---|---|
| Node A | 主节点 / CAN 网关 | 控制总线调度,转发 CAN 骨干网指令 |
| Node B | 从节点 | 车门模块(车窗、门锁、后视镜) |
| Node C | 从节点 | 座椅模块(位置、加热、通风) |
总线波特率:19.2 kbps(位时间约 52 μs)。
9.2 场景一:无条件帧周期性通信
Node A 按调度表发送无条件帧,轮询 Node B 与 Node C。
时隙 1:Node A → Node B
| 阶段 | 总线电平 | 发送方 | 说明 |
|---|---|---|---|
| Sync Break | ≥ 13 个显性位 + 1 个隐性界定符 | Node A | 帧起始,唤醒从节点 |
| Sync Field | 0x55 | Node A | 从节点据此校准波特率 |
| PID | 0x10(假设 ID=0x10,含奇偶校验) | Node A | 指定 Node B 响应 |
| 数据场 | 0x01 0x00 | Node B | 车门状态:锁闭、车窗关闭 |
| 校验和 | 0xXX | Node B | Enhanced Checksum(数据 + PID) |
时隙 2:Node A → Node C
| 阶段 | 总线电平 | 发送方 | 说明 |
|---|---|---|---|
| Sync Break | ≥ 13 个显性位 + 1 个隐性界定符 | Node A | 帧起始 |
| Sync Field | 0x55 | Node A | 波特率同步 |
| PID | 0x20(假设 ID=0x20,含奇偶校验) | Node A | 指定 Node C 响应 |
| 数据场 | 0x05 0x80 | Node C | 座椅位置:前倾 5 格,加热开启 |
| 校验和 | 0xXX | Node C | Enhanced Checksum |
节点过滤行为:
- Node B 在收到 PID 后比对 ID,仅当 ID 匹配自身配置(如
0x10)时才发送响应。 - Node C 收到
0x10的帧头后,忽略该帧,不发送响应。 - Node A 在发送帧头后等待响应超时(约 40 个位时间),若未收到响应则记录通信错误。
9.3 场景二:事件触发帧冲突处理
Node A 在调度表中插入事件触发帧,用于检测门把手或座椅按键的偶发输入。
冲突发生:
| 阶段 | 总线电平 | 发送方 | 说明 |
|---|---|---|---|
| Sync Break | ≥ 13 个显性位 + 1 个隐性界定符 | Node A | 帧起始 |
| Sync Field | 0x55 | Node A | 波特率同步 |
| PID | 0x30(事件触发帧 ID) | Node A | 广播事件查询 |
| 数据场 | 0x01 0x02 | Node B | 车门把手被拉动 |
| 数据场 | 0x02 0x01 | Node C | 座椅加热按键被按下 |
冲突检测:
- Node B 与 Node C 同时在数据场期间发送响应。
- 由于两者发送的数据不同,总线上出现位电平不一致(线与结果与发送方预期不符)。
- Node B 与 Node C 在发送过程中监听总线,检测到不一致后均停止发送。
- Node A 在接收数据时发现校验和不匹配,判定该帧无效。
冲突解决:
- Node A 在下一调度周期中,改用无条件帧分别查询 Node B(ID
0x10)与 Node C(ID0x20)。 - Node B 响应:车门把手状态
0x01。 - Node C 响应:座椅按键状态
0x02。 - 冲突解决后,Node A 恢复事件触发帧的调度。
9.4 场景三:诊断帧通信
Node A 通过 UDS 协议对 Node B 进行诊断。
诊断请求:
| 阶段 | 总线电平 | 发送方 | 说明 |
|---|---|---|---|
| Sync Break | ≥ 13 个显性位 + 1 个隐性界定符 | Node A | 帧起始 |
| Sync Field | 0x55 | Node A | 波特率同步 |
| PID | 0x3C(诊断请求帧 ID) | Node A | 广播诊断请求 |
| 数据场 | 0x02 0x10 0x01 0xFF 0xFF 0xFF 0xFF 0xFF | Node A | UDS 请求:进入默认会话(0x10 0x01),SF 长度为 2 |
| 校验和 | 0xXX | Node A | Classic Checksum(仅校验数据) |
诊断应答:
| 阶段 | 总线电平 | 发送方 | 说明 |
|---|---|---|---|
| Sync Break | ≥ 13 个显性位 + 1 个隐性界定符 | Node A | 帧起始 |
| Sync Field | 0x55 | Node A | 波特率同步 |
| PID | 0x3D(诊断应答帧 ID) | Node A | 指定 Node B 应答 |
| 数据场 | 0x06 0x50 0x01 0x00 0x32 0x01 0xF4 0xFF | Node B | UDS 应答:肯定响应,P2 超时 50 ms,S3 超时 500 ms |
| 校验和 | 0xXX | Node B | Classic Checksum |
诊断帧固定使用 8 byte 数据场,不足部分填充
0xFF。Classic Checksum 仅覆盖数据场,不覆盖 PID。
9.5 场景四:睡眠与唤醒
进入睡眠:
- Node A 发送睡眠命令:诊断帧 ID
0x3C,首字节为0x00,其余字节为0xFF。 - Node B 与 Node C 收到睡眠命令后,在 4 秒内完成本地状态保存,随后进入睡眠模式。
- 若 4 秒内无新帧,总线空闲超时,所有节点自动进入睡眠。
- 睡眠后总线保持隐性,静态功耗降至微安级。
唤醒过程:
| 时刻 | 总线状态 | 触发源 | 说明 |
|---|---|---|---|
| T0 | 隐性 | — | 睡眠状态 |
| T0+0ms | 显性(250 μs) | Node B | 车门把手被拉动,Node B 发送唤醒脉冲 |
| T0+250 μs | 隐性 | — | 唤醒脉冲结束 |
| T0+1ms | 显性(250 μs) | Node B | 首次唤醒未收到主节点响应,重复唤醒脉冲 |
| T0+1.25ms | 隐性 | — | 第二次唤醒脉冲结束 |
| T0+2ms | 显性(250 μs) | Node B | 第三次唤醒脉冲 |
| T0+2.25ms | 隐性 | — | 第三次唤醒脉冲结束 |
| T0+5ms | 帧头 | Node A | 主节点被唤醒,发送 Sync Break 恢复通信 |
| T0+5.7ms | Sync Field | Node A | 0x55,从节点重新校准波特率 |
| T0+6.2ms | PID 0x10 | Node A | 查询 Node B 车门状态 |
| T0+6.7ms | 数据场 | Node B | 响应车门状态 |
若 Node A 在 3 次唤醒脉冲内未响应,Node B 停止唤醒尝试,等待下一次外部事件触发。
9.6 通信时序汇总
以下为一个完整调度周期内三个节点的总线活动概览:
| 时隙 | 总线状态 | 主节点活动 | 从节点活动 | 说明 |
|---|---|---|---|---|
| 1 | 帧头 + 响应 | Node A 发 0x10 帧头 | Node B 响应 2 byte | 车门状态无条件帧 |
| 2 | 帧头 + 响应 | Node A 发 0x20 帧头 | Node C 响应 2 byte | 座椅位置无条件帧 |
| 3 | 帧头 + 冲突 | Node A 发 0x30 帧头 | Node B / Node C 同时响应 | 事件触发帧冲突 |
| 4 | 帧头 + 响应 | Node A 发 0x10 帧头 | Node B 响应 | 冲突后单独查询 Node B |
| 5 | 帧头 + 响应 | Node A 发 0x20 帧头 | Node C 响应 | 冲突后单独查询 Node C |
| 6 | 帧头 + 响应 | Node A 发 0x3C 帧头 | — | 诊断请求(主节点自身发送数据) |
| 7 | 帧头 + 响应 | Node A 发 0x3D 帧头 | Node B 响应 8 byte | 诊断应答 |
| 8 | 空闲 | — | — | 总线空闲,等待下一周期或进入睡眠 |