news 2026/8/23 7:25:12

储能 BMS 的绝缘检测,到底是怎么同时测出正、负两路绝缘电阻的

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
储能 BMS 的绝缘检测,到底是怎么同时测出正、负两路绝缘电阻的

在储能系统里,绝缘检测是少数几个「平时没人注意,出事就是大事故」的功能。电池堆的正负极母线动辄几百伏,一旦对机壳的绝缘性能下降,轻则漏电报警,重则电弧、短路、起火。所以几乎每一套正经的储能 BMS 都会把绝缘检测做进安全保护逻辑里,而且它的优先级往往排在所有故障的最前面——绝缘失效意味着系统已经不适合继续上高压了。

这篇文章我想讲清楚一件事:一套储能 BMS 是怎么通过不平衡电桥法,用两次电压测量,同时把「正极对地绝缘电阻」和「负极对地绝缘电阻」两个未知数都解出来的。我会结合一套真实的量产代码来讲一套基于 NXP + LTC2949 的储能 BMU 固件,绝缘检测的完整实现就落在InsuCheck.c里,一共一千五百多行。

一、先搞清楚要测的到底是什么

一个电池堆接到系统里,正极母线和负极母线对机壳(chassis,也就是「地」)之间,天然存在两条漏电路径。我们把它们抽象成两个电阻:

  • Rp:正极对地的绝缘电阻
  • Rn:负极对地的绝缘电阻

理想情况下这两个电阻都无穷大,正负极和机壳之间完全隔离。但现实里因为灰尘、凝露、绝缘材料老化、走线破损,它们会变成有限值,而且往往不是同步下降的——可能正极这边先漏,也可能负极那边先漏。

这就引出了绝缘检测的第一个难点:你得把 Rp 和 Rn 分开测,不能只测「总绝缘」。为什么?因为如果一个故障只发生在正极侧,你测出「总绝缘偏低」,但不知道是正极还是负极漏,保护策略就没法做——正极漏和负极漏对系统安全的影响、对后续排查的方向,是完全不同的两回事。

国标对储能和电动汽车的绝缘电阻都有明确要求,而且这个要求不是固定阻值,而是按电压折算的,通常表述成「每伏特多少欧姆」,比如常见的 100 Ω/V 或者 500 Ω/V。为什么按电压折算?因为绝缘电阻的安全意义本质上是限制漏电流。漏电流等于电压除以绝缘电阻,I = V / R。电压越高,同样的电阻产生的漏电流就越大、越危险。所以「安全」的判据应该是漏电流不超过某个安全值,也就是 R ≥ V / I_safe,等价于 R ≥ V × K,其中 K 是常数(单位 Ω/V)。

这个「按电压折算」的思路,会直接体现在后面要讲的报警阈值判断里。

二、平衡电桥法,以及它的致命盲区

测绝缘电阻最朴素的思路,是电桥法。

在正极和机壳地之间、负极和机壳地之间,各接一个已知阻值的电阻(通常是相同阻值,所以叫「平衡桥」),然后测机壳地对电池的电位。根据分压关系,就能反推出绝缘电阻。

平衡电桥的优点是电路简单、一次测量就能出结果。但它有一个教科书里反复强调的盲区:当正极和负极的绝缘电阻同时、等比例地下降时,平衡桥测不出来

理解这个盲区并不难。平衡电桥的两个桥臂电阻对称,如果 Rp 和 Rn 也对称地下降(比如都从 10MΩ 掉到 1MΩ),那么机壳地的电位根本不会变——因为分压比例没变。测量系统看到的是「一切正常」,实际上两侧绝缘都已经劣化了。对一个以安全为底线的系统来说,这种「故障了但仪表显示正常」的情况,比直接报故障更危险。

所以真正量产的系统,几乎都绕不开不平衡电桥法

三、不平衡电桥法的核心思想:两次测量,两个方程,两个未知数

不平衡电桥的「不平衡」,指的是投切进去的已知电阻不对称。它的核心思路一句话就能概括:

用两个不同的已知电阻,分别做一次测量,得到两个独立的方程,就能解出 Rp 和 Rn 两个未知数。

这是整个方法论的骨架,值得停下来把它想透。一个未知数需要一个方程,两个未知数就需要两个方程。而「两个方程」从哪来?靠的是改变电路条件——投切不同的已知电阻,让电路进入两种不同的状态,各测一次电压。

下面我把这个过程用电路方程走一遍。这部分是理解后面代码的关键。

设电池总电压为 Vbat,正极对地电压为 Up,负极对地电压为 Un(这里 Un 取「地到负极」的电压幅值,是个正数),那么 Up + Un = Vbat。

电路里有三个电阻:正极对地的绝缘电阻 Rp、负极对地的绝缘电阻 Rn,以及一个通过继电器投切的已知电阻 R(一会儿是 20kΩ,一会儿是 2.2MΩ)。这个已知电阻 R 接在正极和地之间。

根据基尔霍夫电流定律,在「地」这个节点上,流入的电流等于流出的电流:正极经 Rp 流入地的电流(Up/Rp),加上正极经已知电阻 R 流入地的电流(Up/R),等于地经 Rn 流入负极的电流(Un/Rn)。写成式子:

Up/Rp + Up/R = Un/Rn

把 Up/Un 这个比值单独拎出来,记作系数 k(它其实就是「正极对地电压」和「负极对地电压」的比值,是可以直接测出来的量):

k = Up/Un

代入上面的方程,整理一下:

k × (1/Rp + 1/R) = 1/Rn

现在关键来了:R 有两个取值。投切 R1 时测一次,得到 k1;投切 R2 时再测一次,得到 k2。两个方程:

k1 × (1/Rp + 1/R1) = 1/Rn k2 × (1/Rp + 1/R2) = 1/Rn

两个方程、两个未知数 Rp 和 Rn,联立求解。用第二个减第一个消掉 Rn,就能先解出 Rp,再代回任意一个方程解出 Rn。

到这里,不平衡电桥法的「道」就讲完了。你会注意到,推导过程里没有任何神奇的东西,就是一个基尔霍夫电流定律加上「改变电路条件做两次测量」这个朴素的思路。真正体现工程功力的,是怎么把这个思路落到具体的芯片和电路上。

四、这套系统是怎么落地的:LTC2949 + 两个电阻 + 一个继电器

回到这套 BMU。它的绝缘检测硬件方案是这样搭的:

  • 采样芯片是 LTC2949。这颗芯片大家更熟悉它的身份是「高压侧电流/能量监控」,但它其实带了不少辅助测量通道,本系统就复用了它来做绝缘检测的电压采样。
  • 两个已知电阻:R1 = 20kΩ,R2 = 2.2MΩ(2200kΩ)。这两个阻值在InsuCheck.h里定义了:
#defineISO_R2(2200.0)/* 绝缘检测电阻值 R2, (KΩ) */#defineISO_R1(20.0)/* 绝缘检测电阻值 R1, (KΩ) */
  • 一个继电器负责在这两个电阻之间切换,也就是前面说的「投切」。代码里它对应 GPIO 端口ePOut_ISO_PGND,检测开始时闭合,通过 LTC2949 内部的 RLY9 通道在 R1 和 R2 之间切换。

这里有一个值得注意的细节:R1 和 R2 差了整整两个数量级(20kΩ 对 2.2MΩ)。这不是随手选的。小电阻 R1 投进去,会把正极「拉低」得比较明显,让分压比变化大、测量更灵敏,适合用来测那一侧的绝缘;大电阻 R2 投进去,对电路几乎没什么扰动,接近开路状态,适合测另一侧。两个数量级的差距,保证了两次测量之间有足够大的「差异」,方程才解得稳。

五、采样流程:一个五步的状态机

绝缘检测不是一个瞬间完成的操作,它在代码里被拆成了一个清晰的状态机,由InsuAdhesMeasurTask()这个 100ms 周期任务驱动。状态定义在InsuCheck.h里:

typedefenum{eIsoVpgnd_Init=0,/* 初始化 */eIsoVpgnd_SeleV1=1,/* 片选 V1 */eIsoVpgnd_SampV1=2,/* 采集 V1 */eIsoVpgnd_SeleV2=3,/* 片选 V2 */eIsoVpgnd_SampV2=4,/* 采集 V2 */eIsoVpgnd_SampOK=5,/* 采集完成 */eIsoVpgnd_DiagOK=6,/* 诊断完成 */eIsoVpgnd_Fin}e_IsoVpgndSampStep;

流程走下来是:先片选 V1(把继电器拨到 R1 一侧),等采样稳定后采集 V1;再片选 V2(拨到 R2 一侧),采集 V2;两次都采完,进入计算。

这里有三个电压量:Vbat(电池总电压)、V1(接 R1 时负极对地的电压)、V2(接 R2 时负极对地的电压)。它们都是通过 LTC2949 采样后,由InputInsuSampDataAPI()喂进绝缘检测模块的。这个函数里同时做了两件事:一是保存采样值,二是当场算出分压比系数。看关键几行:

caseeInsu_V1:IsoCalcMsg.SampV1=...;/* 保存 V1 */IsoCalcMsg.CalcCoeA=(SampVbat-SampV1)/SampV1;/* 系数 A = 正极对地电压 / 负极对地电压 */break;caseeInsu_V2:IsoCalcMsg.SampV2=...;/* 保存 V2 */IsoCalcMsg.CalcCoeB=(SampVbat-SampV2)/SampV2;/* 系数 B */break;

CalcCoeACalcCoeB就是我前面推导里的 k1 和 k2——正极对地电压和负极对地电压的比值。(SampVbat - SampV1)是正极对地电压(总电压减去负极对地电压),SampV1是负极对地电压,二者一除就是分压比。

注意一个工程细节:这些浮点计算里,代码反复在做「乘 10000 再除 10000」的操作,比如:

IsoCalcMsg.CalcCoeA=(u32)(IsoCalcMsg.CalcCoeA*10000);/* 只保留四位小数 */IsoCalcMsg.CalcCoeA=(float)IsoCalcMsg.CalcCoeA/10000;

这是在用整数截断来限制浮点精度,避免系数保留过多小数位导致后续计算不稳定。没有浮点运算单元的嵌入式平台上,这种「先放大、取整、再缩小」的手法很常见,写代码的人显然是吃过精度亏的。

六、从系数到绝缘电阻:两行公式

两次采样完成后,状态机走到计算这一步。核心就是InsuAdhesMeasurTask()里 case 2 的这段:

/* 电池电压大于阈值才进行绝缘判断 */if(IsoCalcMsg.SampVbat>=ISO_MIN_BAT_V){/* 计算正极对地绝缘阻抗 */IsoRp=(IsoCalcMsg.CalcCoeB-IsoCalcMsg.CalcCoeA)*ISO_R2*2/(2+IsoCalcMsg.CalcCoeA);/* 计算负极对地绝缘阻抗(拆成三个中间量,避免中间结果溢出) */IsoAuxValueA=2*(CalcCoeB-CalcCoeA)*(2*ISO_R2+ISO_R1)*ISO_R2;IsoAuxValueB=2*CalcCoeA*(3*ISO_R2+ISO_R1);IsoAuxValueC=2*ISO_R2-2*ISO_R2*CalcCoeA-ISO_R1*CalcCoeA;IsoRn=IsoAuxValueA/(IsoAuxValueB-CalcCoeB*IsoAuxValueC);}

IsoRp就是正极对地绝缘电阻,IsoRn是负极对地绝缘电阻,单位都是 kΩ。这两个公式,就是我前面第三节那组二元方程在这个特定电路拓扑下的解析解。你看IsoRp里出现了(CoeB - CoeA)(2 + CoeA)IsoRn里出现了(2*ISO_R2 + ISO_R1)(3*ISO_R2 + ISO_R1)这样的组合——这些整数系数,全都来自本系统具体电阻网络(20kΩ 和 2.2MΩ 以及它们的并联串联关系)的化简结果。换句话说,公式长得这么「怪」,是因为它已经被针对这个具体电路解好了,代码里直接套用,不重新解方程。

有个细节特别值得提:IsoRn 的计算被拆成了IsoAuxValueAIsoAuxValueBIsoAuxValueC三个中间量,而不是一行写完。原因在注释里——「防止越界」。这三个中间量动辄是2 × 2200 × 2200这种几十万量级的乘积,如果强行在一条表达式里连乘,中间结果可能超出某些数据类型的范围。拆开算,每一步的数值都可控。这是嵌入式浮点/定点计算里一个非常实际、又很容易被忽略的坑。

七、边界条件与异常处理:比公式更见功力

公式只是理想情况。真实系统里,采样值会碰到各种异常,代码花了不少篇幅处理这些边界。我把它们归纳成三类,每一类背后都有一个真实的物理场景。

第一类:电压太低不测。

代码先判断SampVbat >= ISO_MIN_BAT_VISO_MIN_BAT_V定义成 36V。低于这个电压,绝缘检测没有意义(电压太低,漏电流本来就测不准,而且低压下绝缘问题不构成安全威胁),直接把 Rp、Rn 置成无效值3000kΩ(3MΩ),跳过判断。

这里有个值得注意的小细节:头文件里ISO_MIN_BAT_V定义的是 36.0,但代码注释里写的是「电池电压大于 48V 才进行绝缘判断」。注释和实际值对不上——这大概率是历史版本改过阈值、注释没同步更新。这种「注释与代码不一致」的地方,恰恰是阅读存量代码时要留心的点,面试里能主动指出来,是很加分的。

第二类:结果出现负值或无意义值。

理想情况下 Rp、Rn 都该是正数。但采样误差、噪声、以及公式在极端情况下的数值行为,都可能算出负值或者溢出。代码对这些情况做了兜底:

  • 如果IsoRp > 3000(超过量程上限 3MΩ),就把它钳到 3MΩ——超过这个值说明绝缘已经好到超出测量范围,直接按「良好」处理。
  • 如果IsoRp < 0,说明算出了负值。这时再分情况:如果 V1 接近 Vbat(差值小于 5V),说明正极对地几乎短路,Rp 判定为 0;否则判定为量程外的无效值。
  • 类似的逻辑对IsoRn也走一遍:如果 V1 小于 1V,说明负极对地几乎短路,Rn 判定为 0。

你看这段边界处理,本质上是在用「电压的极端取值」来反推「绝缘电阻的物理状态」。V1 接近 Vbat,意味着地电位被抬到了接近正极,正极对地自然就是短路的;V1 接近 0,意味着地电位被拉到了接近负极,负极对地短路。这个对应关系,是理解整套检测物理意义的关键。

第三类:超时保护。

绝缘检测靠 LTC2949 的连续采样,如果芯片通信故障或者采样一直没完成,状态机就会卡住。代码在等待采样完成时设了 25 秒超时:

if(GetSysSecondTimeAPI()>=(sHisInsuTime+25)){SetInsuVpgndSampFlagAPI(eIsoVpgnd_SampOK);/* 超时强制置为采样完成 */}

超时后强制推进状态机,保证不会永远卡死在某个采样步骤上。这种「任何等待都配超时」的做法,是实时系统的基本素养。

八、报警分级:把绝缘电阻翻译成安全等级

算出 Rp、Rn 之后,系统还要把它们翻译成「该不该报警、报什么级别的警」。这一步在InsuErrStateCheck()里完成,输出四级状态:

typedefenum{/* 0:正常 1:一级报警(严重) 2:二级报警(轻微) 3:绝缘检测异常(失效) */}...

判断逻辑是这样的:

/* 绝缘值为失效值 */if((0xffff==isoRp)||(0xffff==isoRn)){sInsuErrStateFlag=3;/* 检测失效 */}/* 绝缘值在一级(严重)范围 */elseif((isoRp*1000)<(Leak1Lim*Vbat)||(isoRn*1000)<(Leak1Lim*Vbat)){sInsuErrStateFlag=1;/* 一级报警 */}/* 绝缘值在二级(轻微)范围 */elseif((isoRp*1000)<(Leak2Lim*Vbat)||(isoRn*1000)<(Leak2Lim*Vbat)){sInsuErrStateFlag=2;/* 二级报警 */}else{sInsuErrStateFlag=0;/* 正常 */}

注意那个判断式:isoRp * 1000 < Leak1Lim * VbatisoRp单位是 kΩ,乘 1000 变成 Ω;Leak1Lim单位是 Ω/V,乘 Vbat 得到「当前电压下允许的最低绝缘电阻」。这正好呼应了第一节讲的「绝缘阈值按电压折算」——电压越高,允许的最低绝缘电阻就越高,因为要保证漏电流不超过安全值。

两级阈值Leak1LimLeak2Lim是参数表里的可配置项(存在gGBmuGenPara_102里),一级对应更低的电阻值(更严重的漏电),二级对应略高的电阻值(轻微劣化)。从严重到轻微逐级判断,符合故障分级的基本逻辑:先看是不是最严重的,不是再看是不是次严重的。

这套分级最终会接到系统的诊断流水线上,转化成具体的保护动作——比如二级报警可能只做提示,一级报警就要限制功率甚至断开高压回路。绝缘检测在整个 BMS 里扮演的就是「第一道安全闸门」的角色。

九、什么时候测:触发条件的设计

绝缘检测不是一直跑,它有明确的触发时机,这部分的逻辑在SysNeedInsuCheckState()里,写得很细致。挑几个关键的讲:

  • 上电早期要测:系统上电后的头几秒会做一次检测,确认初始状态是安全的。
  • 接触器断开时才测:这是很关键的一个约束。接触器闭合时,电池已经和母线、负载连通,此时测到的「绝缘」会受到负载电路的干扰,测不准。所以很多工作模式下,系统要求接触器全部断开后才做绝缘检测。对应代码里的LeakMonitType参数,1/2 表示「只在接触器断开时检测」。
  • 电压变化触发:如果总电压或者负母线电压发生了明显跳变(比如变化超过 10V),说明系统状态变了,需要重新检测。代码里有专门的分支判断ABS(GetGSampSumVoltAPI(), sSumVolt) >= 100
  • 周期性复检:正常运行一段时间后,按参数设定的周期重新检测,防止绝缘性能在运行中慢慢劣化。
  • 外部请求:上位机或调试口可以主动下发检测命令。

这套触发逻辑体现了一个原则:绝缘检测有成本(要断开接触器、要占用采样时间),所以只在「需要」的时候做,而「需要」的定义覆盖了上电、状态跳变、周期性复检、外部请求这几类场景。这个「何时测、测多频」的权衡,是绝缘检测工程化里很容易被忽略、但其实很见功力的一环。

十、写到最后

把整个链路串起来,就是:LTC2949 通过继电器在 20kΩ 和 2.2MΩ 两个已知电阻之间切换,各采一次负极对地电压,算出两个分压比系数,套入预先解好的公式,同时得到正极和负极的绝缘电阻,再按电压折算的阈值分成正常/轻微/严重/失效四级,送入诊断系统驱动保护动作。

拆开看,每一步都不复杂。真正有价值的,是看到一套理论方法(不平衡电桥)是怎么在真实芯片、真实电路、真实代码约束下被一步步落地的——从电阻阻值的选取、采样状态机的设计,到浮点精度控制、超时保护、边界异常兜底、按电压折算的阈值、以及触发时机的权衡。这些细节,才是区分「背过绝缘检测原理」和「真正做过绝缘检测」的分界线。

如果你也在做 BMS 或者准备 BMS 相关的面试,我的建议是别只记那两个公式,去把这段代码从头到尾读一遍。读代码的时候问自己三个问题:为什么两个电阻要差两个数量级?为什么报警阈值要乘电压?为什么很多判断要等接触器断开?这三个「为什么」能答上来,绝缘检测这块你就真正通了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/23 7:24:16

工业边缘AI实战:基于NXP i.MX 8M Plus的嵌入式硬件选型与开发指南

1. 项目概述&#xff1a;当工业边缘遇到AI&#xff0c;我们需要什么样的“硬核”&#xff1f;最近几年&#xff0c;工业圈子里聊得最火的话题&#xff0c;除了数字化转型&#xff0c;就是边缘计算和AI了。大家不再满足于把海量的设备数据一股脑儿往云端传&#xff0c;延迟、带宽…

作者头像 李华
网站建设 2026/8/23 7:23:48

C++函数模板:从类型参数化到泛型编程实战指南

1. 从“重复造轮子”到“一次编写&#xff0c;处处适配”的思维转变如果你写过一段时间的C&#xff0c;尤其是在处理一些需要支持多种数据类型的算法或功能时&#xff0c;大概率会遇到一个让人头疼的问题&#xff1a;代码重复。比如&#xff0c;你想写一个函数来比较两个值的大…

作者头像 李华
网站建设 2026/8/23 7:21:58

OpenAI 开源的 Codex Harness,藏着 Agent 真正的胜负手

OpenAI 开源的 Codex Harness&#xff0c;藏着 Agent 真正的胜负手 2026 年 8 月 19 日&#xff0c;OpenAI 在官方博客发布《Codex as a platform: build on the open agent harness》&#xff0c;宣布将驱动 Codex App、命令行工具与 IDE 扩展运行的底层执行框架——Codex Har…

作者头像 李华
网站建设 2026/8/23 7:20:50

电流调整器MEL71XX 系列

概述 MEL71XX 系列芯片是一个低压差电流调整器&#xff0c;具有260-350mA 的输出恒定电流。 应用场合  给LED驱动提供能源 特点  无外部元器件  输出260-350mA恒定电流  输出短路保护电路  电源电压范围&#xff1a;2.7V~6V 封装形式  3-pin SOT89-3、SO…

作者头像 李华
网站建设 2026/8/23 7:17:25

Python+Django构建智能实习管理系统实践

1. 项目概述这个基于Python的实习实践系统是我在计算机科学教育领域的一次重要尝试。作为一名有多年开发经验的程序员&#xff0c;我深知理论与实践结合的重要性。这个系统旨在解决当前计算机教育中实习环节存在的诸多痛点&#xff1a;实习资源分配不均、过程管理混乱、学习效果…

作者头像 李华