24V 系统与 SAE J2602 实战:12V 上跑得好好的 LIN 子网,接到 24V 母线就”整条失联”——门限比率、偏差预算、J2602 那四条裁剪,我从头对了一遍
去年做一台 24V 平台的工程机械,座舱面板、风机、后视镜、雨刮、座椅这几路附件走的是 LIN 子网,一条总线、一个主机、八个从节点。这套东西在 12V 平台上跑了三年,通讯故障一次没出过。整机电气平台换成 24V 之后,问题一次来了三条:
- 上电后主机能正常发帧,从节点偶发不响应,发生率大概 1%;
- 充电机一启动、母线冲到 28.8 V,整条子网集体掉线几秒;
- 客户要求电气与网络口径按 SAE J2602 走(北美供应体系),我们发现原来那套「事件触发帧 + 从节点互读对方应答」的设计,直接不合法。
三条现象看着是三个问题,最后拆出来是同一件事的三个面:我把 12V 平台的 LIN 设计当成了”电气无关”的东西。实际上 LIN 的电平从来不是”12V 逻辑”,而是”本节点 VSUP 的一个比例”;速率和位速率偏差预算是跟着电压等级换口径的;而 J2602 不是”更高级的 LIN”,它是把 LIN 里所有厂商各自解释的地方钉死之后的一个裁剪子集。
这一篇就把 24V 与 J2602 这两件事从头对一遍。数字全部来自公开规范与数据手册(ISO 17987-4、SAE J2602、TI 收发器数据手册),文末给了配套的现场估算器。
LIN 的基础部分(帧结构、PID、校验和、调度表、休眠唤醒、物理层)在《LIN 总线主从调度与报文超时实战》里已经铺过了,这篇只讲 24V 和 J2602 多出来的那一层——上下两层,不重复。顺带说一句 24V 母线的来源:24V 平台的”母线冲到 28.8 V”其实就是两串 12V 铅酸/锂电在充电态,这一点在《电池管理与 SOC 估算实战》里算过。
先把三件事分清:LIN 2.x / ISO 17987 / SAE J2602
这是第一个容易混的地方,混了之后查资料永远查不到点上。
| 名称 | 是什么 | 管什么 | 关键点 |
|---|---|---|---|
| LIN 2.x | LIN 联盟的规范(1.0/1.1/1.2/1.3/2.0/2.1/2.2A) | 协议 + 物理层 + 节点配置 + 诊断 | 速率 1~20 kbps 任选,12V 口径;24V 参数在这套规范里没定义 |
| ISO 17987 系列 | 2016 年把 LIN 收成国际标准(-1/-2/-3/-4 等部分),2025 出第 2 版 | 同 LIN 2.2A,但补齐了 24V 的电气物理层 | 24V 的电气参数就写在 17987-4 里;第 2 版还把 master/slave 改称 commander/responder |
| SAE J2602 | 北美车厂基于 LIN 2.0 派生的裁剪子集(-1 网络、-2 一致性测试) | 只规定”怎么用”,不加新功能 | 固定 10.417 kbps、禁从-从通信、禁事件触发帧、EMI/ESD 更严 |
一句话:你要查 24V 的电气参数,去 ISO 17987-4;你要查”哪些用法在北美的供应体系里不许用”,去 SAE J2602。 两者不冲突,是正交的两件事——J2602 的节点通常也符合 ISO 17987-4 的 24V 电气要求。
口径澄清:网上有些厂商支持页面把 J2602 的速率写成 19.2 kbps。NXP 官方技术支持的答复与 SAE J2602-1 的口径都是固定 10.417 kbps,ISO 17987-4 里 24V 的档位命名也是 BR_Range_10K。以 10.417 kbps 为准。
第一条红线:LIN 的电平不是”12V 逻辑”,是”VSUP 的比率”
这是整篇文章最值钱的一条,也是”12V 抄 24V”翻车的头号原因。
LIN 是单线总线,节点靠一只上拉电阻(主机 900~1100 Ω,从机 20~60 kΩ)把总线拉高,任何一个节点把总线拉到地就是显性位(逻辑 0),没人拉的时候就是隐性位(逻辑 1)。电平是按本节点 VSUP 的百分比定义的,不是固定电压:发送端要求显性 ≤0.2×VSUP、隐性 ≥0.8×VSUP;接收端要求显性 ≤0.4×VSUP、隐性 ≥0.6×VSUP;接收门限中心 VBUS_CNT 是 0.475~0.525×VSUP。
把这组比率换算成绝对值,差别就出来了:
| 门限 | 比率 | 12V 平台(VBAT 13.5 V) | 24V 平台(VBAT 27.6 V) |
|---|---|---|---|
| 发送 显性 ≤ | 0.200×VSUP | 2.70 V | 5.52 V |
| 发送 隐性 ≥ | 0.800×VSUP | 10.80 V | 22.08 V |
| 接收 显性 ≤ | 0.400×VSUP | 5.40 V | 11.04 V |
| 接收 隐性 ≥ | 0.600×VSUP | 8.10 V | 16.56 V |
| 门限中心 | 0.475~0.525×VSUP | 6.41~7.09 V | 13.11~14.49 V |
看最后两行:在 24V 母线上,”隐性”要求总线电压高于 16.56 V(接收侧)/ 22.08 V(发送侧)。如果是 12V 平台抄过来的设计——比如主机那只 1 kΩ 上拉接在了稳压后的 12V 轨上(很多人下意识觉得”LIN 不就是 12V 逻辑嘛”)——那 24V 母线上的隐性平台只有 11.3 V 左右:
- 接收侧 11.3 V < 16.56 V → 判不出隐性;
- 发送侧 11.3 V < 22.08 V → 从节点发出的隐性位不合法。
现象就是”整条子网失联”或者”总线一直贴着低电平”,而示波器上看波形还挺干净,特别容易误判成收发器坏了。
一个反直觉的推论:24V 的接收窗口其实更宽
按比率算,24V 的接收窗口宽度是 27.6×(0.6−0.4) = 5.52 V,比 12V 的 13.5×0.2 = 2.70 V 宽了一倍多。也就是说,从抗绝对干扰的角度看,24V 反而更宽松——同样 1 V 的共模干扰,在 24V 系统里占窗口的比例只有 12V 的一半。
所以”24V 更容易受干扰”这个说法是错的。24V 真正的问题是另外三条:器件耐压、门限口径、速率与偏差预算。这也是为什么排查 24V LIN 问题的第一步不是查 EMC,是量隐性平台的绝对电压。
/* 门限判定的定点实现:把比率乘进去,别在代码里写死 5.4V/8.1V 这种 12V 时代的常数 */
#define LIN_RX_DOM_NUM 4u /* 接收显性 <= 0.4 x VSUP */
#define LIN_RX_DOM_DEN 10u
#define LIN_RX_REC_NUM 6u /* 接收隐性 >= 0.6 x VSUP */
#define LIN_RX_REC_DEN 10u
/* vsup_mv: 本节点实测 VSUP(mV);bus_mv: ADC 采到的总线电压(mV)
返回 0=显性 1=隐性 2=落在门限中间的不确定带(要计数上报,别硬判) */
uint8_t lin_level(int32_t vsup_mv, int32_t bus_mv)
{
int32_t th_dom = (int32_t)(((int64_t)vsup_mv * LIN_RX_DOM_NUM) / LIN_RX_DOM_DEN);
int32_t th_rec = (int32_t)(((int64_t)vsup_mv * LIN_RX_REC_NUM) / LIN_RX_REC_DEN);
if (bus_mv <= th_dom) return 0;
if (bus_mv >= th_rec) return 1;
return 2; /* 不确定带:24V 下这个带宽 5.52V,落进来通常意味着上拉轨或器件不对 */
}
ISO 17987-4:24V 到底改了哪些参数
LIN 1.3~2.x 里”供电 7~18 V、耐压 −0.3~40 V”是 12V 系统的口径,24V 系统在这套规范里根本没有定义。24V 的电气参数是 ISO 17987-4 才补齐的(2016 版 5.3.5 章节,2025 第 2 版继续沿用并调整了若干取值)。
| 参数 | 12V 系统 | 24V 系统 |
|---|---|---|
| 工作电压 VBAT(正常) | 8 ~ 18 V | 16 ~ 36 V(20k 档)/ 8 ~ 36 V(10k 档) |
| 低压工作区间 | 6.5 ~ 8 V | 同 10k 档下限 8 V |
| 非破坏电压 VSUP_NON_OP | −0.3 ~ 40 V | −0.3 ~ 58 V |
| 总线限流 IBUS_LIM | 40 ~ 200 mA | 75 ~ 300 mA |
| 主机上拉 R_commander | 900 ~ 1100 Ω | 900 ~ 1100 Ω(没变) |
| 从机上拉 R_responder | 20 ~ 60 kΩ | 20 ~ 60 kΩ(没变) |
| 接收门限中心 VBUS_CNT | 0.475 ~ 0.525×VSUP | 0.475 ~ 0.525×VSUP(没变) |
| 通信不保证 | VBAT > 18 V 或 < 16 V(20k) | VBAT > 36 V 或 < 16 V(20k) |
| 主节点偏差 | < ±0.5% | 20k: < ±0.3% / 10k: < ±0.5% |
| 从节点同步后偏差 | < ±2% | 20k: < ±0.6% / 10k: < ±2% |
| 从-从节点偏差 | < ±2% | 20k: < ±0.6% / 10k: < ±2% |
这张表里能直接读出四条设计约束:
- 上拉/下拉电阻、门限中心的比例口径,两套系统完全一样。 变的只有 VSUP 本身。所以”把电阻改一下就能上 24V”是错的方向——要改的是器件耐压、门限换算和速率。
- 非破坏耐压从 40 V 提到 58 V。 24V 母线充电可到 28.8 V,再留 load dump 余量,40 V 不够。(TVS、放电管、接地路径那一层的账在《ESD/浪涌防护实战》里算过,这里只管”正常工作时能不能活”这一层。)
- 总线限流上限从 200 mA 放宽到 300 mA(下面第三节讲为什么)。
- 24V 的偏差预算分 20k / 10k 两档,20k 档比 12V 严一倍以上。 这是选速率的硬约束,也是 24V 系统几乎只跑 10.4 k 的真正原因(第四节展开)。
24V 的 duty-cycle 测试门限是三组,不是一组
再往下一层:LIN 收发器的一致性测试里有 duty cycle 参数(D1~D4),它靠”在规定门限上量总线边沿时间”来判定波形质量。24V 系统的这套测试门限,跟 12V 的 0.4/0.6 不是一组数,而是按速率和 VSUP 区间分三组给(ISO/DIS 17987-4 Param 73/74/75,TI 收发器数据手册会照抄这张表):
| 测试项 | VSUP 区间 | 位时间 | TH_DOM | TH_REC | 限值 |
|---|---|---|---|---|---|
| D2_24V(20 kbps) | 15.6 ~ 36 V | 50 µs | 0.302×VSUP | 0.446×VSUP | ≥ 0.642 |
| D3_24V(10.4 kbps) | 7 ~ 36 V | 96 µs | 0.581×VSUP | 0.744×VSUP | ≥ 0.386 |
| D4_24V(10.4 kbps) | 4.6 ~ 36 V | 96 µs | 0.284×VSUP | 0.422×VSUP | ≥ 0.591 |
换算到 VSUP = 27.6 V:
- D2_24V:TH_DOM = 8.34 V,TH_REC = 12.31 V
- D3_24V:TH_DOM = 16.04 V,TH_REC = 20.53 V
- D4_24V:TH_DOM = 7.84 V,TH_REC = 11.65 V
注意这三组比值:0.284/0.422 和 0.302/0.446 在 0.4/0.6 下面,0.581/0.744 在 0.4/0.6 上面——12V 那组 0.4/0.6 正好被夹在中间。 也就是说,在 24V 上单拿 0.4/0.6 去套”既不充分也不必要”,必须按目标工况(哪一档速率、VSUP 落在哪个区间)查表。
这一条对现场的意义很直白:你拿 12V 的模板去测 24V 收发器,测出来的”合格”没有意义;反过来,24V 上的波形看着”有点怪”,也未必超标。判定必须回到当档的门限上。
第二条红线:显性电流与总线限流
上拉电阻没变(主机 1 kΩ ±,串一只防反灌二极管),但 VSUP 翻倍了。显性位时,电流从 VBAT 经二极管、经主机上拉电阻、经某个节点的输出管灌到地:
I_dom = (VSUP − V_diode − V_DS) / R_master
取 V_diode = 0.7 V、V_DS = 1.0 V(工程典型值)、R_master = 1000 Ω:
| 工况 | VSUP | 显性位电流 | 隐性平台 | 适用限流区间 |
|---|---|---|---|---|
| 12V 静态 | 12.6 V | 10.90 mA | 11.90 V | 40 ~ 200 mA |
| 12V 充电 | 13.5 V | 11.80 mA | 12.80 V | 40 ~ 200 mA |
| 24V 静态 | 25.2 V | 23.50 mA | 24.50 V | 75 ~ 300 mA |
| 24V 充电 | 27.6 V | 25.90 mA | 26.90 V | 75 ~ 300 mA |
| 24V 上限 | 28.8 V | 27.10 mA | 28.10 V | 75 ~ 300 mA |
同一颗 1 kΩ 上拉,什么都没改,24V 下的显性电流是 12V 的 2.195 倍。 这就直接解释了 ISO 17987-4 为什么把总线限流上限从 200 mA 放宽到 300 mA:这个参数管的是”多节点并联显性或总线对电源/对地短路时,节点能不能活着、主机还能不能区分故障”。24V 下单节点的显性电流已经是 26 mA 量级,多个节点并联很容易顶到 12V 时代的 200 mA 上限。
两条推论:
- 总线短路保护的门限要按 24V 复核。 12V 时代”总线拉到 3 V 就是短路”的判据,在 24V 上不一定成立。
- 发热预算翻倍。 上拉本身在隐性时不耗电,但显性期间是实打实的 I²R,而且显性占空比越高越热。24V 下若显性占空比 30%,平均上拉电流 = 25.90×0.30 = 7.77 mA(12V 是 11.80×0.30 = 3.54 mA)。调度表里连着发长诊断帧(一条 8 字节诊断帧在 10.4 k 下最长 16.7 ms)时,主机上拉电阻、防反二极管、从节点输出管的温升要单独核一遍——这是 12V 平台上从来不用管的事。
物理层这笔账我们在《RS485/Modbus 抗干扰实战》里算过一遍(偏置电阻、门限、接地),思路完全互通;差别只是 LIN 是单端对地、门限按 VSUP 比率,而 RS485 是差分对、门限是固定的 ±200 mV。
第三条红线:速率、偏差预算和时隙
10.417 kbps 这个数不是拍出来的
10.417 kbps 就是”位时间 96 µs”的另一种写法(1/96 µs = 10416.67 bps)。LIN 的标称速率都这么派生:20 kbps = 50 µs、19.2 kbps = 52.083 µs。所以位时间是本体,bps 是派生物——改速率时要改的是时间轴,不是”波特率寄存器里的那个数”。
顺便一个好消息:96 µs 位时间在常见主频下能整除。
/* STM32 类 USART,16 倍过采样:USARTDIV = f_CK / (16 x baud) */
/* 10.417 kbps: f_CK = 48 MHz -> USARTDIV = 287.99 -> 取 288
f_CK = 24 MHz -> USARTDIV = 143.99 -> 取 144
两种主频下实际速率都是 10416.667 bps,偏差 -0.003%,可以忽略 */
/* 对照 19.2 kbps @48 MHz: USARTDIV = 156.25 -> 尾数 156、小数 4/16,也是整除的 */
所以速率切换本身不难。难的是所有”以时间为单位”的东西都要跟着重算。
位时间从 52.083 µs 变到 96 µs,全表都要动
LIN 的帧时间是按位算的:帧头固定 34 位(13 位 break + 1 位分隔 + 10 位 sync 场 + 10 位 PID),应答部分 10×(N+1) 位(起始位 + 8 数据位 + 校验 + 停止位,N 是数据字节数)。帧最大时间 = 1.4 × 标称帧时间(40% 余量分给应答空间和字节间间隔)。
| 位速率 | 位时间 | 同步场(8 位) | 帧头 标称/最大 | 4 字节整帧 标称/最大 | 8 字节整帧 标称/最大 | 8 字节帧率上限 |
|---|---|---|---|---|---|---|
| 19200 bps | 52.083 µs | 416.7 µs | 1.771 / 2.479 ms | 4.375 / 6.125 ms | 6.458 / 9.042 ms | 154.8 帧/s |
| 10417 bps | 96.000 µs | 768.0 µs | 3.264 / 4.570 ms | 8.064 / 11.290 ms | 11.904 / 16.666 ms | 84.0 帧/s |
| 20000 bps | 50.000 µs | 400.0 µs | 1.700 / 2.380 ms | 4.200 / 5.880 ms | 6.200 / 8.680 ms | 161.3 帧/s |
位时间比 = 19200/10417 = 1.8432。 8 字节帧最大时间从 9.042 ms 涨到 16.666 ms,帧率上限掉了一半(154.8 → 84.0 帧/s)。
于是最典型的翻车现场就是:位速率改了、时基和时隙没改。
时隙规则是 T_Frame_Slot > jitter + T_Frame_Maximum,而且时隙必须是时间基的整数倍、从 tick 起点开始。以 5 ms 时间基、1 ms jitter 为例:
| 字节数 | 帧最大(10.4k) | 需占用 = 最大 + jitter | 最少 mini-slot | 19.2k 时代需要几格 |
|---|---|---|---|---|
| 1 字节 | 7.257 ms | 8.257 ms | 2 格 | 1 格 |
| 2 字节 | 8.601 ms | 9.601 ms | 2 格 | 2 格 |
| 4 字节 | 11.289 ms | 12.289 ms | 3 格 | 2 格 |
| 8 字节 | 16.665 ms | 17.665 ms | 4 格 | 3 格 |
19.2k 时代配 5 ms 时间基,1 字节帧最大 3.937 ms + 1 ms jitter 刚好占 1 格;换到 10.4k,同样一个 1 字节帧要 7.257 ms,直接吃掉 2 格。 调度表里每一个时隙都得跟着重算。
不改会怎样?一格的时隙塞不下这一帧,主机的下一个 break 就把应答尾巴顶掉了。从节点不知道自己被截断(它只管收到帧头就应答),只有主机看得到 no_response 在涨。 这正是我们上电后那 1% 偶发不响应的来源——它不是”偶尔干扰”,是”每一格都在悬崖边,偶尔被顶掉”。
一个字节能容多少位时间漂移
偏差预算这条第一次看容易忽略,但它正是”为什么 24V 只跑 10.4 k”的答案。
从节点在同步场(0x55,量”第一个下降沿到最后一个下降沿”= 8 个位时间)上量出主机的位时间,然后按这个位时间采样。偏差预算约束的是”从节点自己时钟相对主节点的偏差”,它最坏情况下的影响可以这样估:一个字节 = 10 个位时间,中位采样的裕量是 0.5 位。
| 档位 | 从节点同步后偏差预算 | 每字节(10 位)累积 | 占 0.5 位裕量 |
|---|---|---|---|
| 12V 系统 | < ±2.0% | 0.200 位 | 40.0% |
| 24V / BR_Range_20K | < ±0.6% | 0.060 位 | 12.0% |
| 24V / BR_Range_10K | < ±2.0% | 0.200 位 | 40.0% |
看第二行:24V 跑 20 k 时,从节点时钟要比 12V 平台严 3.3 倍(±0.6% vs ±2.0%)。LIN 从节点的卖点本来就是”用廉价 RC 振荡器就能跑,靠同步场对齐”,±0.6% 这个口径下,大量用 RC 时钟的低成本从节点会被挤出预算,尤其是温度扫到 −40 ℃ / +105 ℃ 两端的时候。这就是我们第三条现象里”高温/低温才开始丢帧”的那一类。
而 10k 档把口径放回了 12V 的水平(±0.5% / ±2% / ±2%)。所以:
24V 系统选 10.4 kbps,不是”为了省成本”或”为了降 EMI”这么简单,而是为了让现成的 RC 时钟从节点拿过来就能用,不用换晶振。
再叠加一条:10.4 k 的位时间是 19.2 k 的 1.84 倍,压摆率要求相对位时间放宽了——24V 下幅值更大、边沿更陡,同样的位宽里更容易满足 EMI 要求。速率、预算、EMC 三件事在 10.4 k 这个点上刚好凑齐。
SAE J2602:LIN 的”裁剪版”
J2602 是 SAE 在 2010 年前后把 LIN 2.0 收编成北美车厂口径的产物(-1 管网络定义、-2 管一致性测试)。它不加功能,只做裁剪,目标是”跨供应商、跨车型的可互换性”——一个供应商的 ECU 和另一个供应商的从节点,装上去就该能用,不能靠”我们是这么解释规范的”糊过去。
四条硬裁剪,条条都会打到现场设计:
| 项目 | LIN 2.x | SAE J2602 | 对设计的影响 |
|---|---|---|---|
| 速率 | 1 ~ 20 kbps 任选 | 固定 10.417 kbps | 时基/时隙/超时窗口全部按 96 µs 位时间重算 |
| 从-从通信 | 允许(从节点可以读总线上别的应答) | 禁止 | 任何”从从节点直接取信号”的设计直接非法,信号必须走主机转发 |
| 事件触发帧 | 允许(碰撞时自动转无条件帧) | 禁止 | 只剩无条件帧 + 零星帧;碰撞回退那套状态机白写 |
| 节点配置 | 动态配置(NAD 可变) | 预定义静态配置 | NAD/PID 必须在产线写入并落 NVM,不能靠上电再协商 |
| 错误处理 | 常规诊断服务 | 更严(J2602-1 下 0xB5 变 Targeted Reset) | 从节点必须实现”被点名复位”并回滚到安全状态 |
| EMI / ESD | 常规 | 更严 | 压摆率、滤波、ESD 等级按汽车级核;工业现场同样受益 |
从-从通信被禁这条最容易被低估。我们原来有个用法:座椅从节点直接读面板广播的”用户模式”应答,省一次主机转发。在 LIN 2.x 下这是允许的(虽然不推荐),在 J2602 下直接不合法——因为”哪个节点在什么时候应答”必须完全由主机的调度表决定,从节点擅自读别人的应答会破坏这个确定性。
事件触发帧被禁则是砍掉了一整套机制。事件触发帧的本意是”多个从节点共享一个 ID,谁有事件谁应答;碰撞了就退化成无条件帧逐个问”。J2602 干脆不允许——代价是轮询变多、带宽变紧,收益是调度表完全可预测。这在带宽本来就只有 10.4 k 的 24V 系统上是要认真算账的:帧率上限 84 帧/s,扣掉诊断帧和零星帧,剩下的信号帧预算并不宽裕。
这种”为了确定性牺牲带宽/兼容性”的取舍在 CAN 那边也见过——《CAN FD 与经典 CAN 混合组网实战》里那个”一开 BRS 老节点就广播错误帧”的坑,本质也是两套口径混跑把确定性打坏了。错误计数与分桶的排查套路,可以照《CAN 总线错误帧排查实战》那篇来做。
静态节点配置与 Targeted Reset
J2602 要求节点是预定义静态配置:NAD(节点地址)和 PID(帧标识)在产线写入、存 NVM,上电直接可用,不依赖主机来”动态分配”。这带来的直接要求是:
- 产线必须有写入工位,把 NAD/PID 按工单写进每个从节点,并且能读回来核对。
- 擦写必须原子。 NAD 落在 NVM 里,上电自检若发现 NAD 非法(比如落在保留值、或与工单不符),节点必须能进入一个可被重新配置的安全状态,而不是”带着错 NAD 硬跑”。
- 0xB5 这个服务在 J2602-1 下语义变了:LIN 2.x 里 0xB5 是 “Assign NAD via SNPD”(靠节点位置检测自动寻址),J2602 下它变成 Targeted Reset(被点名复位)——主机的”最后手段”,用来把某个行为异常的节点强制拉回初始状态。从节点收到后要复位,并让应用层知道”这次复位是主机要求的”。
第 3 条是 J2602 里少有的”加了行为”的地方,也是现场排障最好用的一招:怀疑某个从节点状态跑飞了,发 0xB5 看它是不是能干净地复位并从安全态重启。如果复位后行为依旧,那就不是软件状态问题,回到电气层查。
节点配置服务 0xB0~0xB7:这张表要背下来
不管是 LIN 2.x 还是 J2602,节点配置与识别都走同一套服务号(0xB0~0xB7),单帧承载、逐节点配置。通配 NAD 是 0x7F,功能寻址 NAD 是 0x7E,响应 RSID = SID + 0x40,未用字节填 0xFF。
| SID | 服务 | LIN 2.x 里 | 说明 |
|---|---|---|---|
| 0xB0 | Assign NAD | 可选 | 重新分配 NAD;用初始 NAD 或通配 0x7F 发起 |
| 0xB1 | Assign frame identifier | LIN 2.0 已废弃 | 仅 LIN 2.0 兼容模式保留 |
| 0xB2 | Read by Identifier | 强制 | 读产品 ID(Id=0) / 序列号(Id=1) / 用户自定义(Id=32~63) |
| 0xB3 | Conditional Change NAD | 可选 | 按条件改 NAD,用来分离冲突节点 |
| 0xB4 | Data Dump | 可选 | 开发用,多数协议栈不实现 |
| 0xB5 | Assign NAD via SNPD | J2602-1 下改为 Targeted Reset | J2602 下这条是硬需求 |
| 0xB6 | Save Configuration | 可选 | NAD/PID 落 NVM,擦写动作由应用层做 |
| 0xB7 | Assign frame identifier range | 强制 | 一帧最多改 4 个 PID,比 0xB1 省时间 |
只有两条是强制的:0xB2(读标识)和 0xB7(改 PID 范围)。0xB2 之所以强制,是因为”能读出自己是谁”是跨供应商互换的前提;0xB7 强制,是因为 PID 必须能被主机统一重排。
一个正响应的完整样子(Assign NAD,0xB0):
请求(MRF,8 字节): NAD_initial | 0x06 | 0xB0 | SupID_LSB | FunID_LSB | FunID_MSB | FunID_MSB | NewNAD
响应(SRF,8 字节): NAD_initial | 0x01 | 0xF0 | 0xFF | 0xFF | 0xFF | 0xFF | 0xFF
^ 初始 NAD,不是新 NAD
^ RSID = 0xB0 + 0x40 = 0xF0,PCI=0x01 表示单帧 1 字节
两个现场特别容易踩的点:
- 响应里回的是初始 NAD,不是新 NAD。 很多人以为”改了地址当然回新地址”,结果上位机校验对不上,误判成节点没响应。
- 通配符 0x7F 按功能寻址处理时,数据场必须全 0xFF。 不然合规的从节点会直接不应答,你会以为是节点坏了。
固件侧:从 19.2 k 迁到 10.4 k 要动哪些地方
把上面几条落到代码上,改动的清单其实不长,但漏一条就是一整类现场故障。
一、时轴全部改成”以位时间为单位”。 不要在代码里散落”2.5 ms””5 ms”这种绝对数,统一用位时间派生:
/* 全部用 ns 表示,改速率只改 LIN_TBIT_NS 一处 */
#define LIN_TBIT_NS 96000u /* 96.000 us */
#define LIN_HEADER_NS (34u * LIN_TBIT_NS) /* 3264000 ns */
#define LIN_RESP_NS(n) (10u * ((n) + 1u) * LIN_TBIT_NS)
#define LIN_FRAME_NOM_NS(n) (LIN_HEADER_NS + LIN_RESP_NS(n))
#define LIN_FRAME_MAX_NS(n) ((LIN_FRAME_NOM_NS(n) * 14u) / 10u) /* x1.4 */
/* 时隙:向上取到时间基整数倍,且 > 帧最大 + jitter */
static uint32_t lin_slot_ms(uint8_t nbytes, uint32_t base_ms, uint32_t jitter_ms)
{
uint32_t need_ms = (LIN_FRAME_MAX_NS(nbytes) + 999999u) / 1000000u;
need_ms += jitter_ms;
return ((need_ms + base_ms - 1u) / base_ms) * base_ms;
}
二、错误分桶要重排,超时窗口要乘 1.84。 沿用 LIN 那份三层超时模型(位/字节级、帧级应答窗口、会话级),但帧级应答窗口的基准值全部要按新位时间重算——应答窗口定时器不能跟时隙计时器共用(时隙是 10~20 ms 级的周期性计时,应答窗口是 16.7 ms 级的一次性计时,10.4 k 下两者数值已经很接近,共用必然出错)。
三、J2602 下删掉两套状态机。 事件触发帧的碰撞回退、从-从通信的”偷听”逻辑,全部删掉,别留着当”兼容模式”——留着就会有人在某个分支里把它打开。
四、NAD/PID 的 NVM 落盘要原子。 双区 + 校验的自然做法:
typedef struct {
uint16_t magic;
uint8_t nad;
uint8_t pid_map[8];
uint16_t crc16;
} lin_cfg_t;
/* 0xB0 / 0xB7 改的是 RAM 副本;只有 0xB6 (Save Configuration) 才落 NVM。
写新槽 -> 校验 -> 置 magic -> 才让新槽生效;掉电时旧槽仍然完整 */
五、加一路 VSUP 采样。 门限判定要用实测 VSUP 按比率算(第 1 节的 lin_level())。这是 24V 平台必须有的——12V 时代很多实现直接用固定门限蒙过去,24V 上蒙不了。
现场五招
这五招都是低成本、当天就能做的,按顺序做,能把上面三条红线逐条排除掉。
- 示波器上量三个数:隐性平台电压(应 ≥0.8×VSUP,24V 下约 22 V)、显性谷值(应 ≤0.2×VSUP)、位时间(用同步场 8 位量,10.4 k 下应为 768 µs)。三个数一出来,器件选型和上拉轨的问题基本就定位了。
- 母线拉到两个边界各测一轮:28.8 V(充电上限)和 16 V(20k 档工作下限)。充电机一启动就掉线这类现象,就在这一步现形。
- 确认主机上拉接的是真实 VBAT,不是稳压后的 12V/5V 轨。这一条看着像废话,但它是”整条子网失联”的头号原因。顺手量一下防反二极管的正向压降,别用错成 1 V 以上的管子。
- 逐个从节点记录同步场量到的位时间,做一张漂移分布表。找出时钟最差的那颗——24V 20k 档只有 ±0.6% 预算,差的那颗一定是最先在温度边界上丢帧的。
- 配置通道自检三步:先发 0xB2 读产品 ID(能读出来说明配置通道活着),再 0xB7 改 PID + 0xB6 保存、断电重启重读(验证真落进 NVM),最后发 0xB5 验 Targeted Reset(J2602 节点)。
自查清单(13 项)
- ☐ 收发器是否明确标注支持 12V/24V(核对 VSUP_NON_OP 到 58 V,不是 40 V)
- ☐ 主机上拉接真实 VBAT,1 kΩ(900~1100 Ω),串防反二极管
- ☐ 从机上拉 20~60 kΩ(典型 30 kΩ)
- ☐ 隐性平台实测 ≥ 0.8×VSUP(在最低工作电压下量)
- ☐ 显性谷值实测 ≤ 0.2×VSUP(在最高工作电压 28.8 V 下量)
- ☐ 总线限流/短路保护在 75~300 mA 区间内复核过
- ☐ 位速率 10.417 kbps、位时间实测 96 µs;MCU 分频余量核对(48 MHz→288、24 MHz→144)
- ☐ 所有时隙按 16.666 ms 级帧最大时间重算,且是时间基整数倍
- ☐ 帧级应答窗口定时器与时隙计时器分开,窗口基准值乘过 1.84
- ☐ 诊断帧 0x3C / 0x3D 走经典校验和
- ☐ J2602:无事件触发帧、无从-从通信(代码里也没留”兼容分支”)
- ☐ NAD/PID 静态写入并落 NVM(0xB0/0xB7 + 0xB6),上电自校验
- ☐ 0xB5 Targeted Reset 已实现,且复位后回到安全态;唤醒脉冲 250 µs~5 ms、从节点 100 ms 内就绪
配套工具
文里所有数字都可以用 lin24_j2602_calc.py 自己复算(纯标准库、全离线、16 项自检)。几个常用调用:
python lin24_j2602_calc.py iso # 12V/24V 参数对照表
python lin24_j2602_calc.py thresh 27.6 # 给定 VSUP 的门限绝对值与判定裕量
python lin24_j2602_calc.py duty 27.6 # 24V duty-cycle 三组测试门限
python lin24_j2602_calc.py rate # 19.2k/10.4k/20k 的帧时间与帧率对照
python lin24_j2602_calc.py slot 10417 5 # 时隙体检 + 速率迁移重算
python lin24_j2602_calc.py curr 27.6 # 显性电流与限流余量
python lin24_j2602_calc.py tol # 偏差预算与位漂移累积
python lin24_j2602_calc.py j2602 # J2602 裁剪清单
python lin24_j2602_calc.py svc # 0xB0~0xB7 服务表
python lin24_j2602_calc.py triage # 症状分诊表
结语
回到开头那三条现象,最后是这样收口的:
| 现象 | 根因 | 处理 |
|---|---|---|
| 上电后 1% 偶发不响应 | 时基没跟着从 19.2k 重算,1 字节帧在 10.4k 下要占 2 格却只给了 1 格 | 全部时隙按 96 µs 位时间重排 |
| 充电机一启动集体掉线 | 工作电压窗口 + 24V 门限比率没按实测 VSUP 算 | 门限改按 VSUP 比率换算,28.8 V/16 V 两边界各测一轮 |
| J2602 下原设计不合法 | 用了事件触发帧和从-从通信 | 改主机轮询 + 无条件帧,信号走主机转发;NAD/PID 产线静态写入 |
一句话总结:24V 不是”电压高一点的 12V”,它是另一套口径。门限按比率、速率按 96 µs、预算按 20k/10k 分档、用法按 J2602 裁剪——四条都对齐了,24V 上的 LIN 子网跟 12V 一样稳。
下一篇打算写逆变器侧的母线电压采样链路(高压分压电阻串 + 隔离放大器):它是上一篇《电流采样链路设计实战:同一台逆变器早上显示 5.00A、中午 5.42A》的姊妹篇,也是”电压/电流双采样”这条线上的另一半——高压侧多电阻串联分压、比值匹配、电阻的电压系数与自热、隔离放大器输入阻抗与偏置电流、以及母线电压采样必须与开关同步的那几条。对我们做离网/储能逆变器的,这条链路的坑不比电流采样少。