跳转至

电源监控与保护电路设计

学习目标

完成本教程学习后,你将能够:

  • 理解电源监控的重要性和基本原理
  • 掌握欠压检测电路的设计方法
  • 学会设计过流保护电路
  • 了解常用电源监控芯片的应用
  • 能够设计完整的电源保护系统
  • 掌握电源故障诊断和处理方法

前置要求

在开始本教程学习之前,你需要:

知识要求: - 了解嵌入式系统电源设计基础 - 熟悉基本的电学概念(电压、电流、功率) - 了解运算放大器和比较器的工作原理 - 掌握基本的电路分析方法

技能要求: - 能够阅读和绘制电路原理图 - 会使用万用表和示波器 - 了解基本的PCB设计知识 - 能够编写简单的嵌入式C代码

推荐但非必需: - 有电源电路设计经验 - 了解模拟电路设计 - 熟悉常见的电源管理芯片

概述

电源监控与保护是嵌入式系统可靠性设计的关键环节。一个完善的电源监控系统可以及时发现电源异常,保护系统免受损坏,提高系统的稳定性和安全性。

为什么需要电源监控与保护

  1. 防止硬件损坏
  2. 过压可能烧毁芯片
  3. 欠压导致系统工作异常
  4. 过流可能损坏电源和负载
  5. 短路会造成严重损坏

  6. 提高系统可靠性

  7. 及时发现电源异常
  8. 自动保护和恢复
  9. 减少系统故障
  10. 延长设备寿命

  11. 保障数据安全

  12. 掉电前保存数据
  13. 防止数据损坏
  14. 保护存储器
  15. 确保系统状态一致

  16. 满足安全标准

  17. 符合安全认证要求
  18. 保护用户安全
  19. 防止火灾等危险
  20. 满足行业规范

电源监控与保护的主要内容

电源监控与保护系统架构:

输入电源
   ├─→ 输入保护
   │    ├─ 防反接保护
   │    ├─ 过压保护
   │    └─ EMI滤波
   ├─→ 电源转换
   │    ├─ DC-DC转换
   │    ├─ LDO稳压
   │    └─ 电源开关
   ├─→ 电源监控
   │    ├─ 电压监测
   │    ├─ 电流监测
   │    ├─ 温度监测
   │    └─ 功率监测
   ├─→ 保护功能
   │    ├─ 欠压保护
   │    ├─ 过压保护
   │    ├─ 过流保护
   │    ├─ 短路保护
   │    └─ 过温保护
   └─→ 输出负载
        └─ 系统电路

第一部分:欠压检测

欠压检测原理

什么是欠压: - 电源电压低于系统正常工作所需的最低电压 - 可能导致系统工作不稳定、数据错误、芯片损坏 - 需要及时检测并采取保护措施

欠压检测的重要性

欠压对系统的影响:

1. 逻辑错误
   - 时序混乱
   - 数据错误
   - 程序跑飞

2. 存储器问题
   - Flash写入失败
   - EEPROM数据损坏
   - RAM数据丢失

3. 外设异常
   - 通信错误
   - 传感器读数异常
   - 执行器动作失效

4. 系统损坏
   - 芯片闩锁效应
   - 电路损坏
   - 无法恢复

方法1:电压比较器检测

基本原理: 使用比较器将电源电压与参考电压比较,当电源电压低于阈值时输出报警信号。

电路设计

VCC ──┬── R1 ──┬── 比较器+ ──┬── 输出 → MCU
      │        │             │
      │        R2            │
      │        │             │
     GND      GND           GND

参考电压 ────→ 比较器-

工作原理:
1. R1、R2分压得到采样电压
2. 采样电压与参考电压比较
3. 当VCC下降,采样电压 < 参考电压时输出低电平
4. MCU检测到低电平,触发欠压保护

参数计算:
采样电压 = VCC × R2 / (R1 + R2)
欠压阈值 = Vref × (R1 + R2) / R2

示例:
- VCC = 5V,欠压阈值 = 4.5V
- Vref = 2.5V
- R2 / (R1 + R2) = 2.5 / 4.5 = 0.556
- 选择 R1 = 10kΩ,R2 = 12.5kΩ

代码实现

/**
 * @file    power_monitor.c
 * @brief   电源监控实现
 */

#include "stm32f1xx_hal.h"
#include <stdio.h>

/**
 * @brief  欠压检测GPIO配置
 */
#define UVLO_PIN        GPIO_PIN_0
#define UVLO_PORT       GPIOA

/**
 * @brief  欠压检测初始化
 */
void undervoltage_detect_init(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    // 使能GPIO时钟
    __HAL_RCC_GPIOA_CLK_ENABLE();

    // 配置为输入模式,上拉
    GPIO_InitStruct.Pin = UVLO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(UVLO_PORT, &GPIO_InitStruct);

    printf("欠压检测初始化完成\n");
}

/**
 * @brief  读取欠压状态
 * @retval 0: 电压正常, 1: 欠压
 */
uint8_t is_undervoltage(void) {
    // 读取比较器输出(低电平表示欠压)
    return (HAL_GPIO_ReadPin(UVLO_PORT, UVLO_PIN) == GPIO_PIN_RESET) ? 1 : 0;
}

/**
 * @brief  欠压处理函数
 */
void handle_undervoltage(void) {
    printf("警告:检测到欠压!\n");

    // 1. 保存关键数据
    save_critical_data();

    // 2. 关闭非必要外设
    disable_non_essential_peripherals();

    // 3. 降低系统频率
    reduce_system_clock();

    // 4. 发送报警信号
    send_alarm_signal();

    // 5. 等待电压恢复或进入安全关机
    while(is_undervoltage()) {
        HAL_Delay(100);
    }

    printf("电压已恢复正常\n");
}

/**
 * @brief  保存关键数据
 */
void save_critical_data(void) {
    printf("正在保存关键数据...\n");
    // 保存配置参数到Flash
    // 保存运行状态到EEPROM
    // 标记数据有效性
}

/**
 * @brief  关闭非必要外设
 */
void disable_non_essential_peripherals(void) {
    printf("关闭非必要外设...\n");
    // 关闭LED
    // 关闭LCD
    // 关闭音频
    // 保留通信接口
}

/**
 * @brief  降低系统频率
 */
void reduce_system_clock(void) {
    printf("降低系统频率以节省功耗...\n");
    // 切换到低速时钟
    // 降低CPU频率
}

/**
 * @brief  发送报警信号
 */
void send_alarm_signal(void) {
    printf("发送欠压报警信号...\n");
    // 通过串口发送报警
    // 点亮报警LED
    // 发送网络通知
}

方法2:ADC采样检测

优势: - 可以精确测量电压值 - 可以设置多级阈值 - 可以记录电压变化趋势 - 灵活性高

电路设计

VCC ──┬── R1 ──┬── ADC输入
      │        │
      │        R2
      │        │
     GND      GND

注意事项:
1. ADC输入电压不能超过参考电压(通常3.3V)
2. 需要合理选择分压比
3. 考虑ADC输入阻抗
4. 添加滤波电容

参数计算:
ADC输入电压 = VCC × R2 / (R1 + R2)
要求:ADC输入电压 ≤ VREF

示例(VCC = 12V,VREF = 3.3V):
- R2 / (R1 + R2) ≤ 3.3 / 12 = 0.275
- 选择 R1 = 27kΩ,R2 = 10kΩ
- 分压比 = 10 / 37 = 0.27
- ADC输入 = 12V × 0.27 = 3.24V

代码实现

/**
 * @brief  ADC电压监测配置
 */
#define ADC_CHANNEL_VCC     ADC_CHANNEL_0
#define VOLTAGE_DIVIDER     3.7f    // 分压比 (R1+R2)/R2
#define ADC_RESOLUTION      4096    // 12位ADC
#define ADC_VREF            3.3f    // ADC参考电压

/**
 * @brief  电压阈值定义
 */
#define VOLTAGE_NORMAL      11.0f   // 正常电压
#define VOLTAGE_WARNING     10.5f   // 警告阈值
#define VOLTAGE_CRITICAL    10.0f   // 严重阈值
#define VOLTAGE_SHUTDOWN    9.5f    // 关机阈值

/**
 * @brief  电压状态枚举
 */
typedef enum {
    VOLTAGE_STATUS_NORMAL = 0,
    VOLTAGE_STATUS_WARNING = 1,
    VOLTAGE_STATUS_CRITICAL = 2,
    VOLTAGE_STATUS_SHUTDOWN = 3
} VoltageStatus;

/**
 * @brief  读取电源电压
 * @retval 电压值(V)
 */
float read_supply_voltage(void) {
    // 启动ADC转换
    HAL_ADC_Start(&hadc1);
    HAL_ADC_PollForConversion(&hadc1, 100);

    // 读取ADC值
    uint16_t adc_value = HAL_ADC_GetValue(&hadc1);

    // 计算电压
    float adc_voltage = (float)adc_value * ADC_VREF / ADC_RESOLUTION;
    float supply_voltage = adc_voltage * VOLTAGE_DIVIDER;

    return supply_voltage;
}

/**
 * @brief  获取电压状态
 * @param  voltage: 电压值(V)
 * @retval 电压状态
 */
VoltageStatus get_voltage_status(float voltage) {
    if (voltage >= VOLTAGE_NORMAL) {
        return VOLTAGE_STATUS_NORMAL;
    } else if (voltage >= VOLTAGE_WARNING) {
        return VOLTAGE_STATUS_WARNING;
    } else if (voltage >= VOLTAGE_CRITICAL) {
        return VOLTAGE_STATUS_CRITICAL;
    } else {
        return VOLTAGE_STATUS_SHUTDOWN;
    }
}

/**
 * @brief  电压监测任务
 */
void voltage_monitor_task(void) {
    static VoltageStatus last_status = VOLTAGE_STATUS_NORMAL;

    // 读取电压
    float voltage = read_supply_voltage();
    VoltageStatus status = get_voltage_status(voltage);

    // 状态变化时打印
    if (status != last_status) {
        printf("\n电压状态变化\n");
        printf("当前电压: %.2f V\n", voltage);

        switch(status) {
            case VOLTAGE_STATUS_NORMAL:
                printf("状态: 正常\n");
                break;

            case VOLTAGE_STATUS_WARNING:
                printf("状态: 警告 - 电压偏低\n");
                // 发送警告通知
                send_voltage_warning();
                break;

            case VOLTAGE_STATUS_CRITICAL:
                printf("状态: 严重 - 电压过低\n");
                // 进入省电模式
                enter_power_saving_mode();
                // 保存数据
                save_critical_data();
                break;

            case VOLTAGE_STATUS_SHUTDOWN:
                printf("状态: 关机 - 电压极低\n");
                // 立即保存数据并关机
                emergency_shutdown();
                break;
        }

        last_status = status;
    }
}

/**
 * @brief  电压监测统计
 */
typedef struct {
    float min_voltage;
    float max_voltage;
    float avg_voltage;
    uint32_t sample_count;
    uint32_t warning_count;
    uint32_t critical_count;
} VoltageStatistics;

VoltageStatistics voltage_stats = {
    .min_voltage = 999.0f,
    .max_voltage = 0.0f,
    .avg_voltage = 0.0f,
    .sample_count = 0,
    .warning_count = 0,
    .critical_count = 0
};

/**
 * @brief  更新电压统计
 * @param  voltage: 当前电压
 */
void update_voltage_statistics(float voltage) {
    // 更新最小值
    if (voltage < voltage_stats.min_voltage) {
        voltage_stats.min_voltage = voltage;
    }

    // 更新最大值
    if (voltage > voltage_stats.max_voltage) {
        voltage_stats.max_voltage = voltage;
    }

    // 更新平均值
    voltage_stats.avg_voltage = 
        (voltage_stats.avg_voltage * voltage_stats.sample_count + voltage) /
        (voltage_stats.sample_count + 1);

    voltage_stats.sample_count++;

    // 统计异常次数
    if (voltage < VOLTAGE_WARNING) {
        voltage_stats.warning_count++;
    }
    if (voltage < VOLTAGE_CRITICAL) {
        voltage_stats.critical_count++;
    }
}

/**
 * @brief  打印电压统计信息
 */
void print_voltage_statistics(void) {
    printf("\n电压统计信息\n");
    printf("─────────────────────────\n");
    printf("采样次数: %lu\n", voltage_stats.sample_count);
    printf("最小电压: %.2f V\n", voltage_stats.min_voltage);
    printf("最大电压: %.2f V\n", voltage_stats.max_voltage);
    printf("平均电压: %.2f V\n", voltage_stats.avg_voltage);
    printf("警告次数: %lu\n", voltage_stats.warning_count);
    printf("严重次数: %lu\n", voltage_stats.critical_count);
    printf("─────────────────────────\n");
}

方法3:专用电压监控芯片

常用芯片

  1. TPS3823/TPS3824系列
  2. 固定阈值电压监控
  3. 超低功耗(350nA)
  4. 高精度(±1.5%)
  5. 可调延迟时间

  6. MAX809/MAX810系列

  7. 微处理器监控
  8. 复位输出
  9. 看门狗功能
  10. 手动复位输入

  11. ADM706/ADM708系列

  12. 多路电压监控
  13. 看门狗定时器
  14. 手动复位
  15. 电池备份切换

TPS3823应用示例

VCC ──┬── TPS3823 ──┬── RESET输出 → MCU
      │   (监控IC)  │
      │             │
     GND           GND

特性:
- 监控电压:2.93V(TPS3823-30)
- 复位延迟:200ms(典型值)
- 功耗:350nA
- 精度:±1.5%

工作原理:
1. 持续监控VCC电压
2. VCC < 阈值时,RESET输出低电平
3. VCC恢复后,延迟200ms再释放RESET
4. 确保电源稳定后系统才启动

第二部分:过流保护

过流保护原理

什么是过流: - 电路中的电流超过设计的最大安全电流 - 可能由短路、负载过重、器件故障等引起 - 需要快速切断电流以保护电路

过流的危害

过流对系统的影响:

1. 发热问题
   - 导线过热
   - 元件温升
   - PCB板烧毁
   - 引发火灾

2. 器件损坏
   - 电源芯片烧毁
   - MOSFET击穿
   - 保险丝熔断
   - 连接器损坏

3. 系统故障
   - 电压跌落
   - 系统复位
   - 数据丢失
   - 功能失效

4. 安全隐患
   - 电气火灾
   - 人身伤害
   - 设备报废
   - 财产损失

方法1:保险丝保护

保险丝类型

1. 快断保险丝(Fast-Acting Fuse)
   - 响应速度快(ms级)
   - 适合保护半导体器件
   - 用于短路保护

2. 慢断保险丝(Slow-Blow Fuse)
   - 允许短时过载
   - 适合电机等感性负载
   - 用于过载保护

3. 自恢复保险丝(PPTC)
   - 过流后自动断开
   - 故障消除后自动恢复
   - 可重复使用
   - 响应时间较慢

选型参数:
- 额定电流:正常工作电流的1.5-2倍
- 额定电压:大于电路工作电压
- 分断能力:能够安全切断故障电流
- 响应时间:根据保护对象选择

自恢复保险丝应用

VIN ──┬── PPTC ──┬── 负载
      │          │
     GND        GND

工作原理:
1. 正常状态:低阻态,电流正常通过
2. 过流时:温度升高,阻值急剧增大
3. 限流状态:阻值很大,限制电流
4. 故障消除:温度下降,阻值恢复

选型示例:
- 正常电流:500mA
- 选择:0.75A/6V PPTC
- 保持电流:0.75A
- 动作电流:1.5A
- 最大电压:6V

方法2:电流检测电阻

原理: 在电流路径中串联一个小阻值电阻,通过测量电阻两端的压降来检测电流。

电路设计

VIN ──┬── R_sense ──┬── 负载
      │             │
      │             ├── 运放+ ──┬── 输出 → ADC
      │             │           │
      └─────────────┴── 运放-  GND

参数计算:
I = V_sense / R_sense
P_sense = I² × R_sense

选型考虑:
1. 阻值选择
   - 足够小以减少功耗
   - 足够大以获得可测量的压降
   - 典型值:0.01Ω - 0.1Ω

2. 功率选择
   - P_sense = I_max² × R_sense
   - 留有余量(2-3倍)

3. 精度选择
   - 1%或更高精度
   - 低温度系数

示例(I_max = 2A):
- 选择 R_sense = 0.1Ω
- V_sense = 2A × 0.1Ω = 0.2V
- P_sense = 2² × 0.1 = 0.4W
- 选择 0.1Ω/1W/1% 电阻

代码实现

/**
 * @brief  电流监测配置
 */
#define CURRENT_SENSE_RESISTOR  0.1f    // 检测电阻(Ω)
#define CURRENT_AMPLIFIER_GAIN  10.0f   // 放大倍数
#define CURRENT_MAX_NORMAL      1.5f    // 正常最大电流(A)
#define CURRENT_MAX_WARNING     2.0f    // 警告阈值(A)
#define CURRENT_MAX_CRITICAL    2.5f    // 严重阈值(A)

/**
 * @brief  读取负载电流
 * @retval 电流值(A)
 */
float read_load_current(void) {
    // 启动ADC转换
    HAL_ADC_Start(&hadc1);
    HAL_ADC_PollForConversion(&hadc1, 100);

    // 读取ADC值
    uint16_t adc_value = HAL_ADC_GetValue(&hadc1);

    // 计算电压
    float adc_voltage = (float)adc_value * ADC_VREF / ADC_RESOLUTION;

    // 计算原始检测电压(考虑放大倍数)
    float sense_voltage = adc_voltage / CURRENT_AMPLIFIER_GAIN;

    // 计算电流
    float current = sense_voltage / CURRENT_SENSE_RESISTOR;

    return current;
}

/**
 * @brief  电流状态枚举
 */
typedef enum {
    CURRENT_STATUS_NORMAL = 0,
    CURRENT_STATUS_WARNING = 1,
    CURRENT_STATUS_CRITICAL = 2,
    CURRENT_STATUS_OVERLOAD = 3
} CurrentStatus;

/**
 * @brief  获取电流状态
 * @param  current: 电流值(A)
 * @retval 电流状态
 */
CurrentStatus get_current_status(float current) {
    if (current <= CURRENT_MAX_NORMAL) {
        return CURRENT_STATUS_NORMAL;
    } else if (current <= CURRENT_MAX_WARNING) {
        return CURRENT_STATUS_WARNING;
    } else if (current <= CURRENT_MAX_CRITICAL) {
        return CURRENT_STATUS_CRITICAL;
    } else {
        return CURRENT_STATUS_OVERLOAD;
    }
}

/**
 * @brief  电流监测任务
 */
void current_monitor_task(void) {
    static CurrentStatus last_status = CURRENT_STATUS_NORMAL;
    static uint32_t overload_count = 0;

    // 读取电流
    float current = read_load_current();
    CurrentStatus status = get_current_status(current);

    // 状态处理
    switch(status) {
        case CURRENT_STATUS_NORMAL:
            overload_count = 0;
            if (last_status != CURRENT_STATUS_NORMAL) {
                printf("电流恢复正常: %.2f A\n", current);
            }
            break;

        case CURRENT_STATUS_WARNING:
            printf("警告:电流偏高 %.2f A\n", current);
            send_current_warning();
            break;

        case CURRENT_STATUS_CRITICAL:
            printf("严重:电流过高 %.2f A\n", current);
            overload_count++;
            if (overload_count > 10) {  // 连续10次过流
                printf("持续过流,触发保护\n");
                trigger_overcurrent_protection();
            }
            break;

        case CURRENT_STATUS_OVERLOAD:
            printf("过载:电流严重超标 %.2f A\n", current);
            // 立即切断电源
            emergency_power_off();
            break;
    }

    last_status = status;
}

/**
 * @brief  触发过流保护
 */
void trigger_overcurrent_protection(void) {
    printf("触发过流保护\n");

    // 1. 切断负载电源
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);

    // 2. 记录故障信息
    log_fault_event("过流保护触发");

    // 3. 发送报警
    send_alarm_signal();

    // 4. 等待一段时间后尝试恢复
    HAL_Delay(5000);

    // 5. 检查是否可以恢复
    float current = read_load_current();
    if (current < CURRENT_MAX_NORMAL) {
        printf("故障已清除,恢复供电\n");
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
    } else {
        printf("故障未清除,保持断电状态\n");
    }
}

/**
 * @brief  紧急断电
 */
void emergency_power_off(void) {
    printf("紧急断电!\n");

    // 立即切断所有负载
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);

    // 点亮故障LED
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);

    // 记录严重故障
    log_fault_event("紧急断电 - 严重过流");

    // 进入安全模式,等待人工干预
    while(1) {
        HAL_Delay(1000);
    }
}

方法3:专用电流监控芯片

INA219 - 高精度电流/电压/功率监控芯片

特性: - 高侧或低侧电流检测 - 0-26V电压范围 - ±3.2A电流范围(可配置) - I2C接口 - 12位ADC - 可编程增益

应用电路

VIN ──┬── R_sense ──┬── 负载
      │             │
      ├── INA219 ───┤
      │   VIN+      │
      │   VIN-      │
      │   SDA ──────┼── MCU SDA
      │   SCL ──────┼── MCU SCL
      │             │
     GND           GND

配置:
- R_sense = 0.1Ω
- 最大电流 = 3.2A
- 分辨率 = 0.8mA

代码实现

/**
 * @brief  INA219寄存器地址
 */
#define INA219_I2C_ADDR         0x40
#define INA219_REG_CONFIG       0x00
#define INA219_REG_SHUNT_V      0x01
#define INA219_REG_BUS_V        0x02
#define INA219_REG_POWER        0x03
#define INA219_REG_CURRENT      0x04
#define INA219_REG_CALIBRATION  0x05

/**
 * @brief  INA219配置
 */
#define INA219_CONFIG_RESET             0x8000
#define INA219_CONFIG_BVOLTAGERANGE_32V 0x2000
#define INA219_CONFIG_GAIN_8_320MV      0x1800
#define INA219_CONFIG_BADCRES_12BIT     0x0400
#define INA219_CONFIG_SADCRES_12BIT     0x0018
#define INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS 0x0007

/**
 * @brief  INA219初始化
 */
void ina219_init(void) {
    uint16_t config = INA219_CONFIG_BVOLTAGERANGE_32V |
                     INA219_CONFIG_GAIN_8_320MV |
                     INA219_CONFIG_BADCRES_12BIT |
                     INA219_CONFIG_SADCRES_12BIT |
                     INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS;

    // 写入配置寄存器
    ina219_write_register(INA219_REG_CONFIG, config);

    // 设置校准值(根据检测电阻计算)
    // Calibration = 0.04096 / (Current_LSB × R_shunt)
    // Current_LSB = Max_Current / 32768
    uint16_t calibration = 4096;  // 示例值
    ina219_write_register(INA219_REG_CALIBRATION, calibration);

    printf("INA219初始化完成\n");
}

/**
 * @brief  写INA219寄存器
 * @param  reg: 寄存器地址
 * @param  value: 写入值
 */
void ina219_write_register(uint8_t reg, uint16_t value) {
    uint8_t data[2];
    data[0] = (value >> 8) & 0xFF;
    data[1] = value & 0xFF;
    HAL_I2C_Mem_Write(&hi2c1, INA219_I2C_ADDR << 1, 
                      reg, 1, data, 2, 100);
}

/**
 * @brief  读INA219寄存器
 * @param  reg: 寄存器地址
 * @retval 寄存器值
 */
uint16_t ina219_read_register(uint8_t reg) {
    uint8_t data[2];
    HAL_I2C_Mem_Read(&hi2c1, INA219_I2C_ADDR << 1, 
                     reg, 1, data, 2, 100);
    return (data[0] << 8) | data[1];
}

/**
 * @brief  读取总线电压
 * @retval 电压值(V)
 */
float ina219_read_bus_voltage(void) {
    uint16_t value = ina219_read_register(INA219_REG_BUS_V);
    // 右移3位,LSB = 4mV
    return ((value >> 3) * 4) / 1000.0f;
}

/**
 * @brief  读取分流电压
 * @retval 电压值(mV)
 */
float ina219_read_shunt_voltage(void) {
    int16_t value = (int16_t)ina219_read_register(INA219_REG_SHUNT_V);
    // LSB = 10μV
    return value * 0.01f;
}

/**
 * @brief  读取电流
 * @retval 电流值(A)
 */
float ina219_read_current(void) {
    int16_t value = (int16_t)ina219_read_register(INA219_REG_CURRENT);
    // LSB根据校准值确定,这里假设1mA
    return value / 1000.0f;
}

/**
 * @brief  读取功率
 * @retval 功率值(W)
 */
float ina219_read_power(void) {
    uint16_t value = ina219_read_register(INA219_REG_POWER);
    // LSB = 20 × Current_LSB
    return value * 0.02f;
}

/**
 * @brief  INA219监测任务
 */
void ina219_monitor_task(void) {
    float voltage = ina219_read_bus_voltage();
    float current = ina219_read_current();
    float power = ina219_read_power();

    printf("\n电源监测数据\n");
    printf("─────────────────────────\n");
    printf("电压: %.2f V\n", voltage);
    printf("电流: %.3f A\n", current);
    printf("功率: %.2f W\n", power);
    printf("─────────────────────────\n");

    // 检查是否超限
    if (current > CURRENT_MAX_CRITICAL) {
        printf("警告:电流过大!\n");
        trigger_overcurrent_protection();
    }

    if (voltage < VOLTAGE_CRITICAL) {
        printf("警告:电压过低!\n");
        handle_undervoltage();
    }
}

第三部分:电源监控芯片应用

集成电源监控方案

TPS2116 - 电源多路复用器

特性: - 双路输入自动切换 - 过流保护 - 反向电流阻断 - 可调电流限制 - 优先级控制

应用场景: - USB供电 + 电池供电自动切换 - 主电源 + 备用电源切换 - 多路电源冗余设计

电路设计

VIN1 (USB 5V) ──┬── TPS2116 ──┬── VOUT
                │   PR1=High  │
VIN2 (电池)  ────┤   (优先级1) │
                │             │
               GND           GND

工作原理:
1. VIN1和VIN2都存在时,选择VIN1(优先级高)
2. VIN1断开时,自动切换到VIN2
3. VIN1恢复时,自动切回VIN1
4. 切换过程无缝,输出不中断
5. 内置过流保护,限制输出电流

代码示例

/**
 * @brief  电源切换监测
 */
#define POWER_SOURCE_PIN    GPIO_PIN_0
#define POWER_SOURCE_PORT   GPIOA

/**
 * @brief  电源源枚举
 */
typedef enum {
    POWER_SOURCE_USB = 0,
    POWER_SOURCE_BATTERY = 1
} PowerSource;

/**
 * @brief  读取当前电源源
 * @retval 电源源
 */
PowerSource get_current_power_source(void) {
    // 读取TPS2116的状态引脚
    GPIO_PinState state = HAL_GPIO_ReadPin(POWER_SOURCE_PORT, 
                                           POWER_SOURCE_PIN);
    return (state == GPIO_PIN_SET) ? POWER_SOURCE_USB : POWER_SOURCE_BATTERY;
}

/**
 * @brief  电源切换监测任务
 */
void power_source_monitor_task(void) {
    static PowerSource last_source = POWER_SOURCE_USB;
    PowerSource current_source = get_current_power_source();

    if (current_source != last_source) {
        printf("\n电源切换\n");

        if (current_source == POWER_SOURCE_USB) {
            printf("切换到USB供电\n");
            // USB供电时可以充电
            enable_battery_charging();
        } else {
            printf("切换到电池供电\n");
            // 电池供电时进入省电模式
            enter_power_saving_mode();
        }

        last_source = current_source;
    }
}

第四部分:保护电路设计实战

完整的电源保护系统

系统架构

输入电源 (12V)
   ├─→ 防反接保护 (P-MOSFET)
   ├─→ 过压保护 (TVS管)
   ├─→ EMI滤波 (LC滤波器)
   ├─→ 自恢复保险丝 (PPTC)
   ├─→ 电流检测 (INA219)
   ├─→ DC-DC转换 (Buck)
   ├─→ 电压监控 (TPS3823)
   └─→ 输出 (5V/3.3V)

防反接保护电路

VIN ──┬── P-MOSFET ──┬── VOUT
      │   (IRF9540)  │
      │   S    D     │
      │   │    │     │
      │   G────┘     │
      │   │          │
      └───┴──────────┴── GND

工作原理:
1. 正接时:VGS为负,MOSFET导通
2. 反接时:VGS为正,MOSFET截止
3. 保护后级电路不受反接损坏

优点:
- 压降小(< 0.1V)
- 功耗低
- 可靠性高

注意:
- 选择合适的MOSFET(VDS、ID、RDS(on))
- 添加栅极保护电阻

过压保护电路

VIN ──┬── TVS管 ──┬── 后级电路
      │  (P6KE18A) │
     GND          GND

工作原理:
1. 正常时:TVS管高阻态
2. 过压时:TVS管击穿,钳位电压
3. 保护后级电路

选型:
- 击穿电压:略高于最高工作电压
- 钳位电压:低于后级耐压
- 功率:根据能量计算

示例(12V系统):
- 工作电压:12V
- 最高电压:15V
- 选择:P6KE18A(18V/600W)

综合保护电路实例

完整代码实现

/**
 * @file    power_protection_system.c
 * @brief   完整的电源保护系统实现
 */

#include "stm32f1xx_hal.h"
#include <stdio.h>
#include <stdbool.h>

/**
 * @brief  电源保护系统配置
 */
typedef struct {
    // 电压阈值
    float voltage_min;
    float voltage_max;
    float voltage_warning;

    // 电流阈值
    float current_max;
    float current_warning;

    // 温度阈值
    float temp_max;
    float temp_warning;

    // 保护使能
    bool enable_uvlo;           // 欠压保护
    bool enable_ovp;            // 过压保护
    bool enable_ocp;            // 过流保护
    bool enable_otp;            // 过温保护

    // 保护动作
    bool auto_recovery;         // 自动恢复
    uint32_t recovery_delay_ms; // 恢复延迟
} PowerProtectionConfig;

/**
 * @brief  电源保护状态
 */
typedef struct {
    bool is_protected;
    uint32_t fault_code;
    uint32_t fault_count;
    uint32_t last_fault_time;
} PowerProtectionStatus;

/**
 * @brief  故障代码定义
 */
#define FAULT_NONE          0x00
#define FAULT_UNDERVOLTAGE  0x01
#define FAULT_OVERVOLTAGE   0x02
#define FAULT_OVERCURRENT   0x04
#define FAULT_OVERTEMP      0x08
#define FAULT_SHORT_CIRCUIT 0x10

/**
 * @brief  全局变量
 */
PowerProtectionConfig protection_config = {
    .voltage_min = 10.0f,
    .voltage_max = 14.0f,
    .voltage_warning = 10.5f,
    .current_max = 3.0f,
    .current_warning = 2.5f,
    .temp_max = 85.0f,
    .temp_warning = 75.0f,
    .enable_uvlo = true,
    .enable_ovp = true,
    .enable_ocp = true,
    .enable_otp = true,
    .auto_recovery = true,
    .recovery_delay_ms = 5000
};

PowerProtectionStatus protection_status = {
    .is_protected = false,
    .fault_code = FAULT_NONE,
    .fault_count = 0,
    .last_fault_time = 0
};

/**
 * @brief  电源保护系统初始化
 */
void power_protection_init(void) {
    printf("\n电源保护系统初始化\n");
    printf("─────────────────────────\n");

    // 初始化电压监测
    undervoltage_detect_init();
    printf("✓ 欠压检测初始化完成\n");

    // 初始化电流监测
    ina219_init();
    printf("✓ 电流监测初始化完成\n");

    // 初始化温度监测
    temperature_sensor_init();
    printf("✓ 温度监测初始化完成\n");

    // 初始化保护输出
    protection_output_init();
    printf("✓ 保护输出初始化完成\n");

    // 打印配置
    printf("\n保护配置:\n");
    printf("电压范围: %.1f - %.1f V\n", 
           protection_config.voltage_min, 
           protection_config.voltage_max);
    printf("最大电流: %.1f A\n", protection_config.current_max);
    printf("最高温度: %.0f °C\n", protection_config.temp_max);
    printf("自动恢复: %s\n", 
           protection_config.auto_recovery ? "使能" : "禁止");
    printf("─────────────────────────\n");
}

/**
 * @brief  保护输出初始化
 */
void protection_output_init(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    // 使能GPIO时钟
    __HAL_RCC_GPIOB_CLK_ENABLE();

    // 配置电源使能引脚
    GPIO_InitStruct.Pin = GPIO_PIN_0;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    // 默认使能电源输出
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
}

/**
 * @brief  电源保护主任务
 */
void power_protection_task(void) {
    static uint32_t last_check_time = 0;
    uint32_t current_time = HAL_GetTick();

    // 每100ms检查一次
    if (current_time - last_check_time < 100) {
        return;
    }
    last_check_time = current_time;

    // 读取监测数据
    float voltage = read_supply_voltage();
    float current = ina219_read_current();
    float temperature = read_temperature();

    // 检查各项保护
    uint32_t fault = FAULT_NONE;

    // 欠压检测
    if (protection_config.enable_uvlo && voltage < protection_config.voltage_min) {
        fault |= FAULT_UNDERVOLTAGE;
        printf("故障:欠压 %.2f V\n", voltage);
    }

    // 过压检测
    if (protection_config.enable_ovp && voltage > protection_config.voltage_max) {
        fault |= FAULT_OVERVOLTAGE;
        printf("故障:过压 %.2f V\n", voltage);
    }

    // 过流检测
    if (protection_config.enable_ocp && current > protection_config.current_max) {
        fault |= FAULT_OVERCURRENT;
        printf("故障:过流 %.2f A\n", current);
    }

    // 过温检测
    if (protection_config.enable_otp && temperature > protection_config.temp_max) {
        fault |= FAULT_OVERTEMP;
        printf("故障:过温 %.1f °C\n", temperature);
    }

    // 处理故障
    if (fault != FAULT_NONE) {
        handle_protection_fault(fault);
    } else if (protection_status.is_protected) {
        // 尝试恢复
        try_protection_recovery();
    }
}

/**
 * @brief  处理保护故障
 * @param  fault: 故障代码
 */
void handle_protection_fault(uint32_t fault) {
    // 记录故障
    protection_status.fault_code = fault;
    protection_status.fault_count++;
    protection_status.last_fault_time = HAL_GetTick();

    // 如果未处于保护状态,触发保护
    if (!protection_status.is_protected) {
        printf("\n触发电源保护\n");
        printf("故障代码: 0x%02lX\n", fault);
        printf("故障次数: %lu\n", protection_status.fault_count);

        // 切断电源输出
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
        protection_status.is_protected = true;

        // 点亮故障LED
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);

        // 记录故障日志
        log_protection_fault(fault);

        // 发送报警
        send_protection_alarm(fault);
    }
}

/**
 * @brief  尝试保护恢复
 */
void try_protection_recovery(void) {
    // 检查是否允许自动恢复
    if (!protection_config.auto_recovery) {
        return;
    }

    // 检查恢复延迟
    uint32_t elapsed = HAL_GetTick() - protection_status.last_fault_time;
    if (elapsed < protection_config.recovery_delay_ms) {
        return;
    }

    printf("\n尝试恢复电源\n");

    // 重新检查所有参数
    float voltage = read_supply_voltage();
    float current = ina219_read_current();
    float temperature = read_temperature();

    bool can_recovery = true;

    // 检查电压
    if (voltage < protection_config.voltage_min || 
        voltage > protection_config.voltage_max) {
        printf("电压异常,无法恢复: %.2f V\n", voltage);
        can_recovery = false;
    }

    // 检查温度
    if (temperature > protection_config.temp_max) {
        printf("温度过高,无法恢复: %.1f °C\n", temperature);
        can_recovery = false;
    }

    if (can_recovery) {
        printf("条件满足,恢复电源输出\n");

        // 恢复电源输出
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
        protection_status.is_protected = false;
        protection_status.fault_code = FAULT_NONE;

        // 熄灭故障LED
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);

        // 记录恢复日志
        log_protection_recovery();
    } else {
        printf("条件不满足,延迟恢复\n");
        protection_status.last_fault_time = HAL_GetTick();
    }
}

/**
 * @brief  记录保护故障
 * @param  fault: 故障代码
 */
void log_protection_fault(uint32_t fault) {
    printf("\n记录故障日志\n");
    printf("时间: %lu ms\n", HAL_GetTick());
    printf("故障: ");

    if (fault & FAULT_UNDERVOLTAGE) printf("欠压 ");
    if (fault & FAULT_OVERVOLTAGE) printf("过压 ");
    if (fault & FAULT_OVERCURRENT) printf("过流 ");
    if (fault & FAULT_OVERTEMP) printf("过温 ");
    if (fault & FAULT_SHORT_CIRCUIT) printf("短路 ");

    printf("\n");

    // 保存到Flash或EEPROM
    // save_fault_log_to_flash(fault);
}

/**
 * @brief  发送保护报警
 * @param  fault: 故障代码
 */
void send_protection_alarm(uint32_t fault) {
    printf("发送保护报警\n");

    // 通过串口发送
    // uart_send_alarm(fault);

    // 通过网络发送
    // network_send_alarm(fault);

    // 触发蜂鸣器
    // buzzer_alarm();
}

/**
 * @brief  获取保护状态
 * @retval 保护状态字符串
 */
const char* get_protection_status_string(void) {
    if (!protection_status.is_protected) {
        return "正常";
    }

    static char status_str[64];
    sprintf(status_str, "保护中 (故障: 0x%02lX)", 
            protection_status.fault_code);
    return status_str;
}

/**
 * @brief  打印保护统计信息
 */
void print_protection_statistics(void) {
    printf("\n电源保护统计\n");
    printf("─────────────────────────\n");
    printf("当前状态: %s\n", get_protection_status_string());
    printf("故障次数: %lu\n", protection_status.fault_count);

    if (protection_status.is_protected) {
        uint32_t protected_time = HAL_GetTick() - 
                                 protection_status.last_fault_time;
        printf("保护时长: %lu ms\n", protected_time);
    }

    printf("─────────────────────────\n");
}

/**
 * @brief  手动复位保护
 */
void manual_reset_protection(void) {
    printf("\n手动复位保护\n");

    // 清除保护状态
    protection_status.is_protected = false;
    protection_status.fault_code = FAULT_NONE;

    // 恢复电源输出
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);

    // 熄灭故障LED
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);

    printf("保护已复位\n");
}

第五部分:故障诊断与处理

常见故障诊断

故障诊断流程

故障诊断步骤:

1. 识别故障现象
   - 系统无法启动
   - 频繁复位
   - 工作异常
   - 保护触发

2. 测量关键参数
   - 输入电压
   - 输出电压
   - 负载电流
   - 温度

3. 分析故障原因
   - 电源问题
   - 负载问题
   - 保护电路问题
   - 环境问题

4. 采取纠正措施
   - 更换故障元件
   - 调整参数
   - 改进设计
   - 优化布局

故障诊断代码

/**
 * @brief  故障诊断结构
 */
typedef struct {
    char description[64];
    float voltage;
    float current;
    float temperature;
    uint32_t fault_code;
    uint32_t timestamp;
} FaultDiagnostic;

/**
 * @brief  执行故障诊断
 * @retval 诊断结果
 */
FaultDiagnostic perform_fault_diagnostic(void) {
    FaultDiagnostic diag;

    // 读取当前参数
    diag.voltage = read_supply_voltage();
    diag.current = ina219_read_current();
    diag.temperature = read_temperature();
    diag.fault_code = protection_status.fault_code;
    diag.timestamp = HAL_GetTick();

    // 分析故障
    if (diag.fault_code & FAULT_UNDERVOLTAGE) {
        sprintf(diag.description, "欠压故障 - 检查输入电源");
    } else if (diag.fault_code & FAULT_OVERVOLTAGE) {
        sprintf(diag.description, "过压故障 - 检查稳压电路");
    } else if (diag.fault_code & FAULT_OVERCURRENT) {
        sprintf(diag.description, "过流故障 - 检查负载或短路");
    } else if (diag.fault_code & FAULT_OVERTEMP) {
        sprintf(diag.description, "过温故障 - 检查散热");
    } else {
        sprintf(diag.description, "正常");
    }

    return diag;
}

/**
 * @brief  打印诊断报告
 * @param  diag: 诊断结果
 */
void print_diagnostic_report(FaultDiagnostic *diag) {
    printf("\n故障诊断报告\n");
    printf("═════════════════════════\n");
    printf("时间: %lu ms\n", diag->timestamp);
    printf("描述: %s\n", diag->description);
    printf("─────────────────────────\n");
    printf("电压: %.2f V\n", diag->voltage);
    printf("电流: %.2f A\n", diag->current);
    printf("温度: %.1f °C\n", diag->temperature);
    printf("故障码: 0x%02lX\n", diag->fault_code);
    printf("═════════════════════════\n");

    // 提供建议
    printf("\n处理建议:\n");

    if (diag->fault_code & FAULT_UNDERVOLTAGE) {
        printf("1. 检查输入电源是否正常\n");
        printf("2. 检查电源线是否接触良好\n");
        printf("3. 测量输入电压是否在范围内\n");
    }

    if (diag->fault_code & FAULT_OVERCURRENT) {
        printf("1. 断开负载,检查是否短路\n");
        printf("2. 逐个连接负载,找出故障点\n");
        printf("3. 检查电流检测电路是否正常\n");
    }

    if (diag->fault_code & FAULT_OVERTEMP) {
        printf("1. 检查散热器是否安装正确\n");
        printf("2. 检查环境温度是否过高\n");
        printf("3. 检查风扇是否正常工作\n");
    }
}

实践项目:完整的电源监控系统

项目目标

设计并实现一个完整的电源监控与保护系统,具备以下功能: - 实时监测电压、电流、功率 - 多级保护(欠压、过压、过流、过温) - 自动保护和恢复 - 故障记录和诊断 - 串口通信和显示

硬件清单

必需元件:
1. STM32F103C8T6开发板 × 1
2. INA219电流传感器模块 × 1
3. 电压比较器(LM393) × 1
4. 自恢复保险丝(1.5A) × 1
5. P-MOSFET(IRF9540) × 1
6. TVS管(P6KE18A) × 1
7. 温度传感器(DS18B20) × 1
8. OLED显示屏(0.96寸) × 1
9. 电阻、电容若干

可选元件:
1. 蜂鸣器 × 1
2. LED指示灯 × 3
3. 按键 × 2

完整示例代码

主程序

/**
 * @file    main.c
 * @brief   电源监控系统主程序
 */

#include "stm32f1xx_hal.h"
#include "power_protection_system.h"
#include <stdio.h>

// 外设句柄
ADC_HandleTypeDef hadc1;
I2C_HandleTypeDef hi2c1;
UART_HandleTypeDef huart1;

/**
 * @brief  系统初始化
 */
void system_init(void) {
    // HAL库初始化
    HAL_Init();

    // 配置系统时钟
    SystemClock_Config();

    // 初始化外设
    MX_GPIO_Init();
    MX_ADC1_Init();
    MX_I2C1_Init();
    MX_USART1_UART_Init();

    // 初始化电源保护系统
    power_protection_init();

    printf("\n系统初始化完成\n");
}

/**
 * @brief  主函数
 */
int main(void) {
    // 系统初始化
    system_init();

    uint32_t last_monitor_time = 0;
    uint32_t last_display_time = 0;

    while (1) {
        uint32_t current_time = HAL_GetTick();

        // 电源保护任务(100ms)
        if (current_time - last_monitor_time >= 100) {
            power_protection_task();
            last_monitor_time = current_time;
        }

        // 显示更新任务(1000ms)
        if (current_time - last_display_time >= 1000) {
            display_power_status();
            last_display_time = current_time;
        }

        // 处理串口命令
        process_uart_commands();

        HAL_Delay(10);
    }
}

/**
 * @brief  显示电源状态
 */
void display_power_status(void) {
    float voltage = read_supply_voltage();
    float current = ina219_read_current();
    float power = voltage * current;
    float temperature = read_temperature();

    printf("\n电源状态\n");
    printf("─────────────────────────\n");
    printf("电压: %.2f V\n", voltage);
    printf("电流: %.3f A\n", current);
    printf("功率: %.2f W\n", power);
    printf("温度: %.1f °C\n", temperature);
    printf("状态: %s\n", get_protection_status_string());
    printf("─────────────────────────\n");
}

/**
 * @brief  处理串口命令
 */
void process_uart_commands(void) {
    // 检查是否有接收到命令
    // 解析命令并执行相应操作
    // 例如:查询状态、复位保护、修改配置等
}

总结与最佳实践

设计要点

  1. 多层保护
  2. 硬件保护(保险丝、TVS管)
  3. 芯片保护(监控IC)
  4. 软件保护(监测和控制)

  5. 快速响应

  6. 硬件保护响应最快(μs级)
  7. 软件监测作为补充(ms级)
  8. 合理设置保护阈值

  9. 可靠恢复

  10. 自动恢复机制
  11. 手动复位选项
  12. 故障记录和分析

  13. 用户友好

  14. 清晰的状态指示
  15. 详细的故障信息
  16. 便捷的操作接口

常见问题

Q1:如何选择合适的保护阈值? A:根据系统规格和余量设置,通常: - 欠压阈值 = 最低工作电压 + 10% - 过压阈值 = 最高工作电压 - 10% - 过流阈值 = 最大工作电流 + 20%

Q2:保护电路误触发怎么办? A:可能原因和解决方法: - 阈值设置过严:放宽阈值 - 瞬态干扰:增加滤波 - 检测电路问题:检查硬件 - 软件去抖动:增加延时判断

Q3:如何测试保护电路? A:测试方法: - 欠压测试:逐渐降低输入电压 - 过流测试:增加负载或短路测试 - 过温测试:加热或环境测试 - 恢复测试:验证自动恢复功能

扩展阅读

  1. 电源管理芯片数据手册
  2. TI电源管理产品选型指南
  3. Maxim电源监控IC应用笔记
  4. Analog Devices电源保护方案

  5. 设计规范

  6. IEC 61000电磁兼容标准
  7. UL安全认证要求
  8. 汽车电子AEC-Q标准

  9. 应用案例

  10. 工业控制系统电源设计
  11. 便携设备电源管理
  12. 汽车电子电源保护

练习题

  1. 基础练习
  2. 设计一个12V系统的欠压检测电路,阈值为10.5V
  3. 计算0.1Ω检测电阻在2A电流下的功耗
  4. 为5V/2A系统选择合适的自恢复保险丝

  5. 进阶练习

  6. 实现一个带滞回的电压监测程序
  7. 设计一个双路电源自动切换电路
  8. 编写故障诊断和记录系统

  9. 项目练习

  10. 完成本文的实践项目
  11. 添加OLED显示功能
  12. 实现远程监控和报警

下一步学习

完成本教程后,建议继续学习:

  1. 功耗测量与分析方法 - 深入了解功耗测试技术
  2. 电池管理系统设计 - 学习BMS设计
  3. 动态电源管理技术 - 掌握DVFS等高级技术
  4. 电源完整性分析 - 学习PI仿真和优化

作者: 嵌入式知识平台内容团队
最后更新: 2026-03-07
版本: 1.0.0