BLOG8
跳转至

电源监控与保护电路设计

学习目标

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

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

前置要求

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

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

技能要求: - 能够阅读和绘制电路原理图 - 会使用万用表和示波器 - 了解基本的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