电源监控与保护电路设计¶
学习目标¶
完成本教程学习后,你将能够:
- 理解电源监控的重要性和基本原理
- 掌握欠压检测电路的设计方法
- 学会设计过流保护电路
- 了解常用电源监控芯片的应用
- 能够设计完整的电源保护系统
- 掌握电源故障诊断和处理方法
前置要求¶
在开始本教程学习之前,你需要:
知识要求: - 了解嵌入式系统电源设计基础 - 熟悉基本的电学概念(电压、电流、功率) - 了解运算放大器和比较器的工作原理 - 掌握基本的电路分析方法
技能要求: - 能够阅读和绘制电路原理图 - 会使用万用表和示波器 - 了解基本的PCB设计知识 - 能够编写简单的嵌入式C代码
推荐但非必需: - 有电源电路设计经验 - 了解模拟电路设计 - 熟悉常见的电源管理芯片
概述¶
电源监控与保护是嵌入式系统可靠性设计的关键环节。一个完善的电源监控系统可以及时发现电源异常,保护系统免受损坏,提高系统的稳定性和安全性。
为什么需要电源监控与保护¶
- 防止硬件损坏:
- 过压可能烧毁芯片
- 欠压导致系统工作异常
- 过流可能损坏电源和负载
-
短路会造成严重损坏
-
提高系统可靠性:
- 及时发现电源异常
- 自动保护和恢复
- 减少系统故障
-
延长设备寿命
-
保障数据安全:
- 掉电前保存数据
- 防止数据损坏
- 保护存储器
-
确保系统状态一致
-
满足安全标准:
- 符合安全认证要求
- 保护用户安全
- 防止火灾等危险
- 满足行业规范
电源监控与保护的主要内容¶
电源监控与保护系统架构:
输入电源
│
├─→ 输入保护
│ ├─ 防反接保护
│ ├─ 过压保护
│ └─ 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:专用电压监控芯片¶
常用芯片:
- TPS3823/TPS3824系列:
- 固定阈值电压监控
- 超低功耗(350nA)
- 高精度(±1.5%)
-
可调延迟时间
-
MAX809/MAX810系列:
- 微处理器监控
- 复位输出
- 看门狗功能
-
手动复位输入
-
ADM706/ADM708系列:
- 多路电压监控
- 看门狗定时器
- 手动复位
- 电池备份切换
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) {
// 检查是否有接收到命令
// 解析命令并执行相应操作
// 例如:查询状态、复位保护、修改配置等
}
总结与最佳实践¶
设计要点¶
- 多层保护:
- 硬件保护(保险丝、TVS管)
- 芯片保护(监控IC)
-
软件保护(监测和控制)
-
快速响应:
- 硬件保护响应最快(μs级)
- 软件监测作为补充(ms级)
-
合理设置保护阈值
-
可靠恢复:
- 自动恢复机制
- 手动复位选项
-
故障记录和分析
-
用户友好:
- 清晰的状态指示
- 详细的故障信息
- 便捷的操作接口
常见问题¶
Q1:如何选择合适的保护阈值? A:根据系统规格和余量设置,通常: - 欠压阈值 = 最低工作电压 + 10% - 过压阈值 = 最高工作电压 - 10% - 过流阈值 = 最大工作电流 + 20%
Q2:保护电路误触发怎么办? A:可能原因和解决方法: - 阈值设置过严:放宽阈值 - 瞬态干扰:增加滤波 - 检测电路问题:检查硬件 - 软件去抖动:增加延时判断
Q3:如何测试保护电路? A:测试方法: - 欠压测试:逐渐降低输入电压 - 过流测试:增加负载或短路测试 - 过温测试:加热或环境测试 - 恢复测试:验证自动恢复功能
扩展阅读¶
- 电源管理芯片数据手册:
- TI电源管理产品选型指南
- Maxim电源监控IC应用笔记
-
Analog Devices电源保护方案
-
设计规范:
- IEC 61000电磁兼容标准
- UL安全认证要求
-
汽车电子AEC-Q标准
-
应用案例:
- 工业控制系统电源设计
- 便携设备电源管理
- 汽车电子电源保护
练习题¶
- 基础练习:
- 设计一个12V系统的欠压检测电路,阈值为10.5V
- 计算0.1Ω检测电阻在2A电流下的功耗
-
为5V/2A系统选择合适的自恢复保险丝
-
进阶练习:
- 实现一个带滞回的电压监测程序
- 设计一个双路电源自动切换电路
-
编写故障诊断和记录系统
-
项目练习:
- 完成本文的实践项目
- 添加OLED显示功能
- 实现远程监控和报警
下一步学习¶
完成本教程后,建议继续学习:
- 功耗测量与分析方法 - 深入了解功耗测试技术
- 电池管理系统设计 - 学习BMS设计
- 动态电源管理技术 - 掌握DVFS等高级技术
- 电源完整性分析 - 学习PI仿真和优化
作者: 嵌入式知识平台内容团队
最后更新: 2026-03-07
版本: 1.0.0