低功耗电压检测电路:MOS管门控消除分压电阻漏电 干过几年带电池的硬件项目之后你会发现一个特别反直觉的现象系统主控在低功耗模式上已经抠到了几百纳安传感器全部断电无线模块也睡了结果整机待机电流还是比理论值高出几十微安。最后逐项扒开问题往往出在一个最不起眼的地方——电池电压检测的分压电阻。电压检测电路在原理上简单得不能再简单两只电阻分压、一颗ADC引脚采样十分钟就能画出原理图。但麻烦就麻烦在分压网络一旦接到电池上就是一条永远在线的漏电路径。对于用纽扣电池、锂电池或者两节干电池供电的产品来说这种“不见血”的电流偷吃比短路更难查。本文就把这套基于电阻分压和MOS管控制的低功耗电压检测方案掰开揉碎讲一遍从功耗模型、器件选型、参数计算到实板踩坑适合正在做物联网传感器、便携仪表、低功耗蓝牙设备或者任何电池供电产品的硬件/嵌入式工程师参考。1. 分压电阻常年挂电一年能偷走一整块纽扣电池1.1 一个“正常设计”为什么成了功耗黑洞先看最基础的分压拓扑电池正极接R1R1和R2的中间抽头接ADC引脚R2下端接地。电池一接上R1和R2组成的通路就开始持续从电池抽电电流大小是I VBAT / (R1 R2)很多人觉得“我选了100kΩ电阻电流肯定小得可以忽略”。但我们把账算到底一颗CR2032纽扣电池标称容量约210mAh实际到终止电压能放出来的电量大约在170~180mAh。如果用两个100kΩ电阻分压3.7V电池下持续漏电流是18.5μA一年8760小时就是162mAh。也就是说这一颗不起眼的电压检测电路一年时间几乎把整块纽扣电池吃干抹净。故障表现也非常迷惑——产品不是立刻坏而是用着用着突然在某天没电换块电池又能撑一阵。如果把电阻换成1MΩ1MΩ持续漏电降到1.85μA一年约16.2mAh占可用容量9%左右很多项目可能会觉得“能接受”。但问题是低功耗系统里的漏电路径往往不止一条——温湿度传感器待机漏电、LDO静态电流、DC-DC反馈电阻、蓝牙模块休眠电流七七八八加起来最后分压电阻就成了压垮电池寿命的最后一根稻草。1.2 低功耗目标不是“尽量小”而是“算得清楚”低功耗设计的第一原则不是追求绝对零电流而是建立预算。拿CR2032举例如果一个产品目标寿命是2年可用容量按170mAh算平均电流预算只有170mAh / (2 × 8760h) ≈ 9.7μA这9.7μA是整机包含所有工作模式的均值预算。假设主控睡眠占99.9%时间睡眠电流3μA传感器偶尔工作平均摊下来2μA留给检测电路的预算就只有不到5μA。如果检测网络常年挂着1MΩ1MΩ那1.85μA虽然没超预算但也已经占了三分之一。假如系统目标是待机1~2μA的超低功耗场景常开分压电阻就完全不能接受了。所以问题的本质不是选多大的电阻而是能不能让检测支路在非采样期间完全不耗电。这里思路要转一下既然电压检测在时间维度上是稀疏事件——一分钟甚至十分钟才需要读一次——为什么电路要7×24小时通电用MOS管把分压网络的地端切开就是最省事的办法。1.3 用时间换电流把“持续导通”变成“按需通电”按这个思路重新设计平时MOS管关断分压电阻回路断地电路里没有任何电流通路需要检测电压时MCU拉高GPIO让MOS管导通分压网络只供电几十毫秒ADC完成采样后立刻关断。假设每60秒采样一次每次导通20ms占空比为0.02/60 ≈ 0.033%。如果导通时分压电流是2.45μA平均下来只有0.0008μA也就是0.8nA完全可以当作零处理。这就是“用时间换电流”的设计哲学——不跟泄漏电流死磕而是从时间维度上把功耗切掉。提示这种事件驱动采样思路不仅仅适用于电压检测。任何“低占空比”功能的电路比如温湿度采样、按键扫描、传感器供电切换都可以用同样的门控思想把常开电路变成按需电路。2. NMOS低边开关与分压网络的原理拆解2.1 为什么首选低边NMOS而不是PMOS高端开关MOS管控制分压网络有两种常见接法一种是把PMOS放在电源正端做高端开关另一种是把NMOS放在分压网络地端做低边开关。很多工程师第一反应是“高端开关才能彻底断开电源”但在3.7V锂电池配3.3V MCU的典型场景下低边NMOS才是更简单的方案。核心原因在于栅极电压的确定性。NMOS低边开关的栅极直接接MCU的GPIO高电平时VGS3.3V低电平时VGS0V逻辑清清楚楚。而PMOS高端开关的源极接电池正极3.7~4.2V漏极接负载栅极由MCU输出3.3V控制时VGS 3.3 - 4.2 -0.9V这个压差介于阈值边缘管子开通不完全想要可靠关断/开通还得额外加一级电平转换电路或者三极管反相器。为了一个采样功能引入那么多外围器件成本和不稳定性都上去了。NMOS低边开关的导通条件也很直观栅源电压VGS大于阈值电压VGS(th)时D-S之间等效为低阻通道。分压网络的地端通过NMOS接到系统地GPIO拉高地回路建立分压网络正常工作GPIO拉低地回路断开R1和R2两端虽然没有压差但整个链路对电池而言是开路任何电流都不会产生。可以把它类比成装在水管末端的阀门——阀门关了前面管路再长再粗也没有水流。2.2 MOS管选型VGS(th)和漏电流是关键RDS(on)反而无关紧要在这个应用里MOS管流过的是微安级电流RDS(on)几百毫欧和几欧差别几乎没有影响。选型时真正要盯住的是两个参数栅极阈值电压VGS(th)和关断漏电流。先看阈值。3.3V MCU的GPIO高电平输出电压一般在3.0V以上所以要选阈值电压明显低于3.0V的型号留出至少1V以上余量。下表是几种常见NMOS在3.3V驱动场景下的表现型号VGS(th)典型/最大值VDS最大额定ID最大额定3.3V GPIO驱动评估2N7002约1V~2.1V / 最大3V60V0.3A边缘低温或工艺偏差下可能不饱和BSS138约0.8V~1.5V / 最大1.5V50V0.2A合适低压驱动余量充足AO3400约0.4V~1.0V / 最大1.4V30V5A很合适低压驱动更稳2N7002是很多工程师手里常备的管子但在这类低压门控场景里我吃过亏。它的VGS(th)最大能做到3V碰上偏上限的批次3.3V驱动时管子只能勉强半开压降增大采样节点建立时间变长表现就是电压读数隐隐偏低。相比之下BSS138的VGS(th)最大只有1.5V驱动余量充足AO3400更极端低压导通特性很好但耐压只有30V只能用在24V以下场景。再看不该漏掉的关断漏电流。NMOS关断时D-S之间并非绝对绝缘数据手册上的I_DSS一般在几百nA到几μA量级。在3.7V电池电压下实际漏电流通常落在几十nA到几百nA这个区间虽然比常开分压电阻的1.85μA好一个数量级以上但在设计预算时还是要记上这笔账。要选择I_DSS数据手册值较小的型号BSS138和AO3400在这个电压下实测都能做到比较低的漏电流。2.3 栅极下拉电阻防止复位瞬间的“幽灵导通”这个细节是最容易被遗漏的。MCU在上电复位、烧录、掉电的瞬间GPIO还没有被初始化成推挽输出处于高阻态。此时MOS管栅极悬空只要周围PCB漏电流或者电场耦合把栅极电位拉到阈值以上分压网络就会在你不希望的阶段悄悄导通白白耗电。解决办法是在栅源之间并联一颗下拉电阻R3阻值取100kΩ~1MΩ常态下把栅极电位钉在0V。采样时GPIO高电平通过这个电阻会额外流掉几微安电流但因为只有采样期间才存在平均下来完全可以忽略。选1MΩ比较合适既能有效下拉又不至于在采样时增加太多电流。注意这里不推荐再加一个MOS管做栅极驱动隔离纯属多余。一颗NMOS加一颗下拉电阻已经是最简可靠的结构。另外这个电路的MOS管工作在极低频率开关状态跟PWM高频驱动完全是两码事米勒效应和开关损耗在这里都不构成问题不必担心。3. 采样时序与参数计算从电池电压到稳定ADC读数3.1 分压比设计留出裕量再选取标准电阻现在开始算具体参数。以3.7V锂电池、两节AA干电池串联电压2.4~3.2V这类低压场景为例目标检测范围设为3.0~4.2V。MCU采用STM32L151系列ADC参考电压VDDA3.3V12位分辨率。设计分压比时要留出上限裕量。电池最高电压4.2V但我们把设计上限压到4.5V同时ADC输入电压在4.5V时控制在3.0V不顶到3.3V参考电压给实际量产中的电池电压波动和参考电压偏差留出缓冲。于是分压比ratio VADC_max / VBAT_max 3.0 / 4.5 ≈ 0.667标准电阻组合取R1510kΩ、R21MΩratio 1MΩ / (510kΩ 1MΩ) ≈ 0.662实际对应关系如下表电池电压ADC引脚电压ADC原始码VDDA3.3V4.20V2.781V34533.70V2.450V30423.20V2.119V26303.00V1.987V2467ADC最小分辨率折算成电池电压约为3.3V / 4096 / 0.662 ≈ 1.22mV/LSB这个分辨率对电池电压监测来说绰绰有余。反推代码里的换算公式VBAT raw × VDDA / (4096 × ratio) raw × 3.3 / (4096 × 0.662)为什么不选更大的阻值比如10MΩ主要卡在ADC输入阻抗和PCB阻抗污染上。MΩ级电阻的等效输出阻抗太高PCB上的导电残留物、潮湿环境下的表面漏电流都会直接影响分压精度而且RC建立时间会显著变长。510kΩ和1MΩ这个量级已经能把常开漏电控制到纳安级别没有必要再赌更高的阻抗。3.2 RC建立时间GPIO拉高后先别急着转换很多人踩过这个坑GPIO刚拉高让MOS管导通立即启动ADC采样结果读到的电压偏低。原因是分压节点电容上的电荷需要时间建立。分压网络从抽头看进去的等效输出电阻是Rth R1 ∥ R2 (510k × 1M) / (510k 1M) ≈ 337kΩ如果ADC引脚放置了一颗1nF的滤波电容我强烈建议放那么节点建立时间常数τ Rth × C 337kΩ × 1nF 337μs电阻分压网络的电压建立是RC指数充电过程需要等5τ才能认为误差降到1%以下这里大约1.7ms。实际固件建议留双倍余量延时5ms再启动转换。如果省掉外部电容只靠ADC内部十几pF的采样电容τ只有约4μs这时把ADC采样周期配置到最长的239.5周期ADC_CLK4MHz时约60μs也能在单次采样窗口内建立完毕。计算公式可以记下备用。ADC采样保持阶段内部开关导通采样电容充电的建立误差为ε Vfull × exp(-t_sample / τ_sample)其中τ_sample由等效输出电阻和采样电容决定。把Rth压到337kΩ级别配合最长采样周期误差能被压制到远低于1个LSB量产后不会出现批次漂移。3.3 ADC参考电压与通道配置别让VDDA的漂移毁了精度采样精度的问题有一半藏在参考电压里。如果VDDA直接来自LDO稳压输出电池电压在一定范围内变化时VDDA能稳在3.3V那么直接用VDDA做参考没问题。但为了量产一致性我推荐使用MCU内部基准电压VREFINT做实时校准——每次采样后同时读VREFINT通道用校准系数修正ADC读数消除温度变化和VDDA微漂的影响。通道配置上ADC设为单次转换模式、软件触发、采样时间拉到最长。触发方式用软件触发足够不需要定时器硬件触发——毕竟采样频率极低软件开销可以忽略。void ADC_Init_SingleChannel(void) { ADC_InitTypeDef adc_init; GPIO_InitTypeDef gpio_init; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); GPIO_StructInit(gpio_init); gpio_init.GPIO_Pin GPIO_Pin_4; gpio_init.GPIO_Mode GPIO_Mode_AN; GPIO_Init(GPIOA, gpio_init); ADC_StructInit(adc_init); adc_init.ADC_Resolution ADC_Resolution_12b; adc_init.ADC_ContinuousConvMode DISABLE; adc_init.ADC_ExternalTrigConvEdge ADC_ExternalTrigConvEdge_None; adc_init.ADC_SamplingTime ADC_SamplingTime_239Cycles5; // 最长采样时间 adc_init.ADC_NbrOfConversion 1; ADC_Init(ADC1, adc_init); ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SamplingTime_239Cycles5); ADC_Cmd(ADC1, ENABLE); }3.4 完整采样时序与低功耗主循环代码全套采样流程在固件层面分四步唤醒MCU、打开MOS管使能分压网络、等待稳定并完成ADC转换、关断MOS管回到低功耗模式。uint16_t SampleBatteryVoltage(void) { GPIO_SetBits(GPIOB, GPIO_Pin_0); // 拉高GPIONMOS导通分压网络供电 DelayMs(5); // 等待节点电压稳定见RC计算 ADC_SoftwareStartConv(ADC1); while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) RESET); uint16_t raw ADC_GetConversionValue(ADC1); GPIO_ResetBits(GPIOB, GPIO_Pin_0); // 拉低GPIONMOS关断分压网络彻底断电 return raw; }主循环采用“采样完成立即睡”的结构用RTC周期性唤醒。进入STOP模式前必须先确认MOS管栅极已经被拉低否则分压网络会在睡眠期间保持导通等于变回常开电路。void EnterStopModeAndWait(void) { GPIO_ResetBits(GPIOB, GPIO_Pin_0); // 强制关断MOS管 RTC_WakeUpCmd(DISABLE); RTC_SetWakeUpCounter(60 - 1); // 60秒后唤醒 RTC_WakeUpCmd(ENABLE); PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI); SystemClock_Config(); // 唤醒后恢复系统时钟 } int main(void) { // 系统和外设初始化... while (1) { uint16_t raw SampleBatteryVoltage(); float vbatt (float)raw * 3.3f / 4096.0f / 0.662f; if (vbatt 3.2f) { // 低电量处理比如点亮指示灯或发送报警报文 } EnterStopModeAndWait(); } }低电量判断建议加一个滞回窗口。比如3.20V触发报警后要等电压恢复到3.35V以上才清除报警标志避免电池在临界电压附近波动时反复切换状态反而造成额外功耗和用户困扰。4. 实板验证与踩坑记录仿真软件不会告诉你的差异4.1 万用表实测三种方案的待机电流对比把电路打样回来后用六位半万用表串在电池正极测整机待机电流数据最能说明问题。主控用STM32L151STOP模式RTC开启状态下睡眠电流约3μA场景设为每分钟采样一次方案分压网络电流形态整机待机电流实测100k100k常开18.5μA持续21.5μA1M1M常开1.85μA持续4.85μA510k1MNMOS门控采样时2.45μA平时0约3.05μA第三种方案中采样期间平均电流2.45μA × 0.02/60 ≈ 0.0008μA加上MOS管关断漏电流和GPIO翻转的瞬间电流实测附加电流在几十nA量级对总待机时间几乎没有影响。用CR2032跑测试方案三的理论待机时间比方案一翻了好几倍以上。提示测这种微安级电流时不要用普通万用表的μA档直接测万用表的采样电阻本身会引入压降影响MCU供电。最好用高精度台式万用表或者串一个1kΩ采样电阻用示波器测压降换算成电流。4.2 三个我亲自踩过、别人也可能踩的坑坑一第一次采样结果总是偏低差几十毫伏。这是RC建立时间不够导致的不是分压电阻精度问题。解决方法是打开MOS管后延时5ms或者连续采两次丢弃第一次结果只用第二次。我偏向两者都做延时保证建立完成第二次采样值用于消除极端情况下的残余扰动。坑二MCU进入STOP前没有复位GPIO导致MOS管在整个睡眠期间保持导通。排查过程很费劲因为示波器挂在GPIO上看波形是正常的但漏看了进入STOP的入口路径上有多个return分支其中一个分支绕过了GPIO拉低操作。后来把GPIO复位操作收敛到EnterStopModeAndWait函数入口保证所有休眠路径都会执行。硬件的坑不可怕软件的隐藏路径才是真杀手。坑三低压报警阈值在温度变化后漂移。原因是依赖VDDA做参考而VDDA在低温时有小幅下降。后来增加VREFINT校准每次换算电压前先读内部基准通道修正系数报警阈值的温度稳定性明显改善。温度范围宽的产品建议直接内置校准不要偷懒。4.3 PCB布局采样节点要“短、净、稳”这块PCB很小但布局规则不能省。分压电阻要尽量靠近MCU的ADC引脚R1和R2的中间抽头走线越短越好避免长走线变成天线耦合噪声。1nF滤波电容必须放在ADC引脚旁边也就是R1-R2分压节点和地之间而不是放在MOS管附近。分压电阻下方的PCB表面要保持干净不要走数字信号线。MΩ级电阻对表面污染非常敏感潮湿环境下PCB残留助焊剂或水汽形成的漏电通路会直接在分压节点引入误差。量产品可以加三防漆至少保证助焊剂清洗到位。采样节点周围不要铺大块浮空铜皮浮空铜皮在开关瞬间会通过寄生电容耦合到节点上影响稳定时间。如果空间允许在采样节点周围打一圈地过孔形成局部屏蔽效果更好。5. 方案扩展24V工业母线、交流市电与纯硬件监控5.1 24V工业母线的改动要点如果检测对象换成24V工业开关电源或者24V电池组分压比需要重新计算。设计上限取30VADC上限3.3Vratio≈0.11。取R13.3MΩ、R2470kΩratio0.12530V时VADC3.75V略超3.3V需要在ADC引脚加一颗3.3V齐纳二极管或钳位二极管保护。如果不想加保护可以把ratio再压低比如R14.7MΩ、R2510kΩratio≈0.09830V时VADC≈2.94V安全余量充足。24V场景下电阻功率需要验算。R14.7MΩ在30V下的功耗是30²/4.7M≈0.19mW远低于0805封装0.125W额定值没问题。但要注意电阻的额定工作电压0805封装厚膜电阻额定电压一般在150V级别24V使用完全安全。MOS管选型要跟着改耐压至少留2倍裕量BSS138的50V够用AO3400的30V就偏紧了建议换耐压更高的型号。5.2 交流市电电压检测的延伸如果要做交流220V电压检测不能把市电直接接进MOS管和ADC。常见做法是先用变压器隔离降压或者用阻容降压后再经光耦隔离得到和市电成比例的低压直流信号再进入本文这套分压加门控电路。MOS管门控放在整流滤波后的直流侧开关时机选在信号稳定后原理和电池检测完全一致。交流检测涉及高压布局安全间距和安规要求是另一套体系这里不展开但务必记住低压电路不能直接碰高压。5.3 纯硬件监控方案比较器/复位监控IC做补充如果MCU死机或者程序跑飞上述方案就失效了需要真正的“看门狗”来兜底。硬件复位监控IC比如MAX809、TPS3839系列或者STM32专用的复位监控芯片可以做到几百纳安的静态电流在电压跌到阈值以下时强制拉低复位引脚。这类芯片只能给数字阈值不能读出精确电压值。实际产品里我更倾向于组合使用主控正常工作时用本文这套MOS管分压方案采集精确电压并做软件阈值判断同时留一颗硬件复位监控IC做第二道防线防止MCU异常时锂电池被过放到损坏。其实两者并不冲突硬件监控IC的电流预算几百纳安在低功耗系统里完全付得起。最后分享一点个人习惯。我在设计这类电池供电产品时会先画一张功耗预算表把每个功能模块的睡眠电流、工作电流、占空比、平均电流全部列出来再做方案选型。这套电阻分压加上MOS管门控的电路材料成本不到两毛钱固件逻辑也就十来行却能把纽扣电池的待机时间从几个月拉回两三年。低功耗设计的价值从来不在某个神奇的芯片或复杂的算法而在于把每一个细节支路的电流都算得明明白白——这也是我最想传达的一句话电池供电系统里没有“理所当然能跑”的设计只有算不到位的账。