4、电源监测与欠压保护:MCU内置POR/PDR/BOR原理,外部电源监测芯片(如TPS3803)应用,欠压时的安全状态机

电源,是嵌入式系统的命脉。这话听起来像废话,但我在项目中见过太多「莫名其妙死机」的案例,最后查出来都是电源问题。你想想看,MCU在电压不稳的时候,行为是完全不可预测的——可能跑飞,可能写坏Flash,甚至可能锁死。

所以这一章,咱们就聊聊怎么让MCU在电源出问题时,能体面地「倒下」,而不是「暴毙」。

4.1 MCU内置的POR/PDR/BOR:芯片自带的「保安」

大部分工业级MCU,内部都集成了电源监测电路。说白了,就是芯片自己给自己配了个保安。这三个缩写你得记住:

  • POR(Power-On Reset):上电复位。芯片刚通电时,电压还没稳定,POR会强制MCU保持在复位状态,直到电压升到安全阈值以上。
  • PDR(Power-Down Reset):掉电复位。电压掉到某个阈值以下,PDR立刻把MCU拉回复位状态。
  • BOR(Brown-Out Reset):欠压复位。这个比PDR更精细,可以设置多个阈值。电压跌到某个设定值,BOR就触发复位。

我个人习惯,在选型时一定会看BOR的阈值档位。比如STM32的BOR,有2.0V、2.2V、2.5V等几个档位。你选哪个?这取决于你的系统工作电压和外部电路。

关键点:BOR不是万能的。它只能保证MCU内核复位,但无法保护外设。比如你正在写EEPROM,电压突然掉到BOR阈值以下,MCU复位了,但EEPROM可能已经写了一半——数据就坏了。

4.2 外部电源监测芯片:为什么需要「外援」?

内置的POR/PDR/BOR够用吗?说实话,在工业现场,我建议你还是加一颗外部电源监测芯片。为什么?

  1. 精度更高:内置电路的阈值精度一般在±5%左右,外部芯片可以做到±1.5%甚至更高。
  2. 响应更快:外部芯片的检测延迟通常在微秒级,内置电路可能到毫秒级。
  3. 可配置性更强:你可以自己设定阈值、复位延迟时间。

我常用的芯片是TPS3803(TI出品)。它体积小、功耗低,非常适合工业场景。来看一个典型电路:

// TPS3803典型应用电路
// VDD ——[R1]——+——[R2]—— GND
//               |
//              SENSE (TPS3803 Pin 3)
// 
// 复位输出:RESET (Pin 2) —— MCU的NRST引脚
// 
// 阈值计算公式:
// Vth = 1.24V * (R1 + R2) / R2
// 
// 例如:R1=100kΩ, R2=47kΩ
// Vth = 1.24 * (100+47)/47 ≈ 3.88V
// 当VDD低于3.88V时,RESET输出低电平

我的经验:R1和R2一定要用1%精度的电阻。我曾经图省事用了5%的,结果阈值偏差了0.3V,差点把一批产品搞废。嗯,从那以后我再也不敢在分压电阻上省钱。

4.3 欠压时的安全状态机:让系统「优雅地倒下」

检测到欠压之后怎么办?直接复位?不一定。有些场景下,你需要先保存关键数据,再复位。这就需要一个安全状态机。

我设计过这样一个状态机,用在工业控制器上:

// 欠压安全状态机(伪代码)
enum PowerState {
    POWER_GOOD,      // 正常
    POWER_WARNING,   // 欠压预警
    POWER_CRITICAL,  // 临界欠压
    POWER_FAIL       // 掉电
};

void PowerMonitor_Task(void) {
    switch(currentState) {
        case POWER_GOOD:
            if (Voltage < V_WARNING_THRESHOLD) {
                // 进入预警状态
                currentState = POWER_WARNING;
                // 启动定时器,开始计时
                StartTimer(T_WARNING_TIMEOUT);
                // 通知应用层:准备保存数据
                NotifyApp("Save your data!");
            }
            break;
            
        case POWER_WARNING:
            if (Voltage < V_CRITICAL_THRESHOLD) {
                // 电压继续下降,进入临界状态
                currentState = POWER_CRITICAL;
                // 强制保存关键参数到EEPROM
                SaveCriticalParams();
                // 关闭非必要外设(如LED、通信模块)
                DisableNonCriticalPeripherals();
            } else if (Voltage > V_WARNING_THRESHOLD + V_HYSTERESIS) {
                // 电压恢复,回到正常状态
                currentState = POWER_GOOD;
                CancelTimer();
            }
            break;
            
        case POWER_CRITICAL:
            if (Voltage < V_FAIL_THRESHOLD) {
                // 电压太低,直接复位
                currentState = POWER_FAIL;
                // 设置复位原因标志
                SetResetCause(RESET_CAUSE_BROWNOUT);
                // 执行系统复位
                NVIC_SystemReset();
            }
            break;
            
        case POWER_FAIL:
            // 等待外部复位或POR
            break;
    }
}

避坑指南:我曾经在预警状态下直接写EEPROM,结果电压掉得太快,写到一半就复位了,EEPROM里的数据全乱套。后来我改成:先判断电压是否稳定,再决定是否写。如果电压已经低于临界值,那就只写最关键的几个字节,其他的放弃。

4.4 实际项目中的几个「坑」

讲几个我踩过的坑,你遇到了可以少走弯路:

  • 迟滞电压:电源监测一定要加迟滞。否则电压在阈值附近抖动时,MCU会反复复位。TPS3803内部有20mV的迟滞,够用。如果自己用比较器搭,记得加正反馈。
  • 复位时间:外部复位芯片的复位脉冲宽度要够长。我见过有人用100μs的,结果MCU还没完全复位,脉冲就结束了。STM32要求至少1.5μs,但保险起见,我一般选100ms以上的。
  • 去耦电容:电源监测芯片的供电引脚,一定要加0.1μF的陶瓷电容。不加的话,高频噪声可能导致误触发。嗯,这个坑我踩过两次才长记性。

4.5 总结一下

电源监测这事儿,说简单也简单,说复杂也复杂。我的建议是:

  1. 优先用MCU内置的BOR,省成本。
  2. 关键系统加外部监测芯片,保可靠性。
  3. 设计好安全状态机,别让数据丢了。
  4. 别忘了迟滞、复位时间、去耦这些小细节。

你想想看,一个电源监测电路,成本可能就几毛钱,但能避免的故障可能是几万块的损失。这笔账,怎么算都划算。