资讯动态

数字电源控制算法逻辑:从PID到STM32 Buck实战解析

发布时间:2026/9/1 3:13:27 来源:尧图企业网站定制
做电源和嵌入式控制的朋友应该对数字电源这个概念不陌生。以前做模拟电源靠的是运放、比较器、RC补偿网络搭出一个闭环参数一旦定死就很难调整。后来切换到数字控制方案用 MCU 或 DSP 内部的控制算法去完成同样的事才发现真正难的往往不是拓扑本身而是“算法怎么写、逻辑怎么排”。环路要稳定动态响应要好保护要可靠启动要平缓这些软的东西比焊板子更考验功底。本文以“电源数字控制算法逻辑”为主线从数字电源的整体架构、核心控制算法、状态机设计到基于 STM32 的 Buck 电源完整实战逐步拆解一套可落地的思路。适合刚接触数字电源的硬件工程师、想转电源方向的嵌入式工程师以及正在做 DC-DC 或反激电源项目的同学参考。1. 数字电源控制系统概览1.1 模拟电源与数字电源的差异传统模拟电源中误差放大器、补偿网络和 PWM 比较器都是由模拟器件实现的。输出电压经过电阻分压后送进误差放大器与参考电压比较放大后的误差信号再与三角波比较产生占空比。整个过程是连续时间的反馈环路带宽可以做得很高但修改补偿参数通常要换元件。数字电源则把这条链路搬到了数字域。MCU 或 DSP 通过 ADC 采集输出电压、输入电压和电流在软件里执行 PID、数字补偿器、限幅和保护逻辑最后通过 PWM 模块输出驱动信号。相比模拟方案数字电源最大的优势是灵活同一块硬件可以通过升级固件改变环路参数可以支持多种输出电压配置还可以记录工作状态、上报故障。当然数字控制也带来了新的成本比如 ADC 采样延迟、PWM 更新延迟和算法执行时间这些都会影响环路相位必须通过合理的控制频率和补偿算法来弥补。1.2 常见拓扑与控制需求数字电源覆盖的拓扑非常多常见的有Buck 降压电路适合低压大电流场景控制简单适合入门。Boost 升压电路适合 PFC、LED 驱动和电池升压需要注意右半平面零点问题。Buck-Boost 升降压电路适合输入电压范围宽的场合。反激电源适合中小功率隔离电源常用于适配器、充电器需要处理变压器漏感尖峰。LLC 谐振变换器适合高效率大功率隔离电源通常用 PFM 调频控制。不同拓扑对控制算法的要求不同但核心思路相通都是“采样状态量、计算误差、调整占空比或频率”。所以本文用 Buck 作为主线案例把数字控制的基础逻辑讲透之后再扩展到反激、Boost 等拓扑也不难。1.3 数字控制器的实现载体数字电源控制器可以从三个方向选型实现方式优势典型场景通用 MCU成本低、外设灵活、开发快中小功率 Buck/Boost、充电器DSP数学运算强、ADC/PWM 性能好中大功率电源、PFC、服务器电源FPGA并行执行、延迟低、控制频率高超高速开关电源、多路交错并联对于学习阶段STM32 这类 MCU 已经足够。STM32 的 ADC 支持外部触发采样高级定时器可以生成互补 PWM 和死区还能使用刹车输入实现硬件级故障保护非常适合搭建数字电源实验平台。2. 数字电源核心算法从 PID 到数字补偿器2.1 离散化思维把连续环路搬进软件模拟控制器的输入是连续变化的电压输出也是连续的占空比信号。数字控制器只能在离散时刻做运算所以必须先理解采样和离散化。假设开关频率是 100kHz那么一个开关周期是 10μs。控制器会按照这个节奏在每个周期内完成一次采样和一次占空比更新这就是“控制频率等于开关频率”的数字控制方式。有的系统会降低控制频率比如每两个开关周期执行一次控制但大多数情况下还是希望控制频率等于开关频率以获得更好的动态响应。离散化带来的直接问题有两个ADC 采样的电压是瞬时值不是连续信号采样点选得不好会采到开关噪声。从采样到 PWM 更新之间存在计算延迟这个延迟会降低相位裕度。所以后面的硬件设计和代码实现都要围绕如何减小采样误差、如何量化延迟来展开。2.2 位置式 PID 算法数字电源中最常用的控制算法是 PID。PID 控制器的输出由三部分组成比例项 Kp * e(k)根据当前误差实时调节占空比是控制的主干。积分项 Ki * sum(e(i))消除稳态误差保证输出电压最终等于目标值。微分项 Kd * (e(k) - e(k-1))抑制误差变化趋势提高动态响应但也容易放大噪声。位置式 PID 的表达式为u(k) Kp * e(k) Ki * sum(e(i)) Kd * (e(k) - e(k-1))写成 C 语言结构体如下// pid.h #ifndef PID_H #define PID_H typedef struct { float Kp; float Ki; float Kd; float integral; float prev_error; float out_max; float out_min; } PID_TypeDef; void PID_Init(PID_TypeDef *pid, float kp, float ki, float kd, float out_max, float out_min); float PID_Update(PID_TypeDef *pid, float ref, float feedback); #endif// pid.c #include pid.h void PID_Init(PID_TypeDef *pid, float kp, float ki, float kd, float out_max, float out_min) { pid-Kp kp; pid-Ki ki; pid-Kd kd; pid-integral 0.0f; pid-prev_error 0.0f; pid-out_max out_max; pid-out_min out_min; } float PID_Update(PID_TypeDef *pid, float ref, float feedback) { float error ref - feedback; // 积分累积并做积分限幅 pid-integral error; if (pid-integral pid-out_max) { pid-integral pid-out_max; } if (pid-integral pid-out_min) { pid-integral pid-out_min; } // 微分采用误差差值计算简单但容易放大高频噪声 float derivative error - pid-prev_error; pid-prev_error error; float output pid-Kp * error pid-Ki * pid-integral pid-Kd * derivative; // 输出限幅 if (output pid-out_max) { output pid-out_max; } if (output pid-out_min) { output pid-out_min; } return output; }这里需要特别注意积分限幅。如果没有积分限幅电源启动时误差持续为正积分项会一直累积到很大的值导致输出电压严重过冲。加了积分限幅后即使启动阶段占空比饱和积分也不会无限增长。2.3 增量式 PID 与改进策略有些场景下我们希望 PID 输出的是占空比的增量而不是绝对值。增量式 PID 的表达式为delta_u(k) Kp * (e(k) - e(k-1)) Ki * e(k) Kd * (e(k) - 2*e(k-1) e(k-2))实际使用时用上一拍的输出叠加增量u(k) u(k-1) delta_u(k)增量式 PID 的好处是即使误差突然变化输出也是连续变化的执行器不容易出现剧烈跳变。在电源控制中占空比突变会引起电感电流震荡所以增量式 PID 在某些场景下更安全。不过增量式 PID 仍然需要对累加后的输出做限幅。而且由于把积分效果转移到了“外部累加器”上代码里必须有一个变量保存当前占空比。2.4 数字补偿器思路PID 只是数字补偿器的一种特殊形式。如果做过模拟电源环路设计会知道 Type II、Type III 补偿网络的概念。数字控制器可以用软件实现等效的零极点补偿常见做法是通过双线性变换将模拟补偿器的传递函数离散化。比如一个模拟 Type II 补偿器传递函数可以写作H(s) G * (1 s/wz) / (s * (1 s/wp))经过双线性变换后可以整理成数字 IIR 滤波器的形式y[n] b0 * x[n] b1 * x[n-1] b2 * x[n-2] - a1 * y[n-1] - a2 * y[n-2]在代码里执行这个差分方程即可。相比普通 PID数字补偿器能更精确地设计零极点同时提供更好的相位裕度。不过实际工程中很多人直接用 PID 加低通滤波也能达到不错的效果重点是理解“增加零极点就是改变环路的幅频和相频特性”这个逻辑。2.5 环路采样与滤波算法数字电源中采样值质量直接影响控制效果。常见的采样滤波算法包括多次平均滤波每个控制周期连续采样多次取平均适合抑制随机噪声。中值滤波对多个采样值排序取中间值适合抑制脉冲干扰。一阶低通滤波对采样序列做平滑适合抑制高频噪声但会引入相位延迟。一阶低通滤波器的实现很简单float LowPass_Filter(float input, float alpha, float *prev) { *prev alpha * input (1.0f - alpha) * (*prev); return *prev; }alpha取 0 到 1 之间alpha越小滤波越平滑但延迟越大。在控制环中滤波延迟会降低相位裕度所以不能为了滤除噪声而无限制加大滤波深度。3. 控制逻辑状态机与保护策略3.1 为什么数字电源需要状态机数字电源不是只跑一个 PID 就结束了。电源在启动、正常运行、过流、过压、短路恢复等阶段控制策略完全不同。比如启动时要软启动过流时要限流或者打嗝过压时要立即关闭 PWM。这些行为如果用 if-else 堆在一起代码会越来越混乱也容易漏掉边界情况。更规范的做法是引入状态机。电源控制可以抽象成几个主要状态IDLE待机状态PWM 不输出。SOFT_START软启动阶段逐步抬高参考电压或限制占空比。RUN正常运行状态PID 闭环控制。FAULT_RETRY故障保护状态等待恢复条件做打嗝重试。FAULT_LATCH故障锁存状态需要重新上电或人工清除。这是一个典型的有限状态机每一步转移都有明确条件。3.2 软启动逻辑数字电源的软启动有两种常见实现方式。方式一是限制占空比爬升。系统上电后PWM 不直接输出目标占空比而是从很小的占空比开始每个控制周期增加一个固定步长。方式二是抬高参考电压。PID 的参考值从一开始的 0V 逐步爬升到目标电压这样输出电压会跟随参考值平滑上升。方式二更接近“让系统自己决定占空比”的思路不会因为限幅导致电流冲击。软启动期间参考电压步长要控制好否则会引起启动过冲。下面是一个参考电压爬升的示例static float g_soft_start_ref 0.0f; void SoftStart_Update(float target_vref) { float step 0.05f; // 每个控制周期参考电压增加 0.05V if (g_soft_start_ref target_vref) { g_soft_start_ref step; if (g_soft_start_ref target_vref) { g_soft_start_ref target_vref; } } }在控制环中PID 的参考值传入g_soft_start_ref而不是直接传入目标电压。当g_soft_start_ref爬升到目标值后软启动自然结束进入运行状态。3.3 过流、过压与温度保护逻辑电源保护是整个系统可靠性的底线。软件层面需要关注以下几类故障故障类型检测方式处理策略过流 OCP采样电感电流或输入电流限流、打嗝、锁存过压 OVP采样输出电压立即关闭 PWM锁存欠压 UVP采样输出电压关闭 PWM等待恢复过温 OTP采样 NTC 温度降功率或关闭输出保护逻辑要注意一点故障不能只靠软件判断。对于过流这类可能损坏功率器件的故障硬件比较器和 PWM 刹车输入优先级更高软件处理速度再快也有延迟。通常的做法是硬件检测到过流后直接拉低 PWM 刹车引脚同时把故障标志位传给软件软件负责故障状态记录和恢复策略。打嗝模式是电源中常用的故障恢复方式检测到故障后关闭 PWM等待一段时间然后重新尝试软启动。如果故障依然存在重试次数达到上限就进入锁存状态需要人工断电或者通过上位机指令清除。3.4 状态机代码示例下面用一个简化的电源状态机说明整体逻辑typedef enum { PWR_STATE_IDLE 0, PWR_STATE_SOFT_START, PWR_STATE_RUN, PWR_STATE_FAULT_RETRY, PWR_STATE_FAULT_LATCH } PwrState_t; typedef struct { PwrState_t state; uint16_t soft_start_step; uint16_t retry_count; uint16_t fault_flags; } PwrFsm_t; void PowerFsm_Update(PwrFsm_t *fsm, uint8_t enable, uint16_t faults) { switch (fsm-state) { case PWR_STATE_IDLE: if (enable) { fsm-state PWR_STATE_SOFT_START; fsm-soft_start_step 0; fsm-retry_count 0; } break; case PWR_STATE_SOFT_START: fsm-soft_start_step; if (faults) { fsm-state PWR_STATE_FAULT_RETRY; fsm-retry_count; } else if (fsm-soft_start_step SOFT_START_MAX) { fsm-state PWR_STATE_RUN; } break; case PWR_STATE_RUN: if (faults) { fsm-state PWR_STATE_FAULT_RETRY; fsm-retry_count; } break; case PWR_STATE_FAULT_RETRY: // 等待故障消失或等待打嗝定时器超时后重新软启动 if (faults 0) { fsm-state PWR_STATE_SOFT_START; fsm-soft_start_step 0; } else if (fsm-retry_count MAX_RETRY) { fsm-state PWR_STATE_FAULT_LATCH; } break; case PWR_STATE_FAULT_LATCH: // 锁存状态只有 enable 拉低或重新上电才能退出 break; } }这段代码的核心思路是让每一种状态都有清晰的进入条件和退出条件避免嵌套 if-else 导致逻辑混乱。实际的电源系统中状态机里还会加入定时器比如打嗝等待时间、软启动超时时间这些逻辑可以在fault_recovery_timer之类的变量中维护。4. 实战基于 STM32 的 Buck 数字电源控制4.1 系统参数与硬件设计这一节我们用 STM32 实现一个同步 Buck 数字电源系统参数如下参数数值说明输入电压24V直流输入输出电压12V目标输出最大输出电流3A设计负载能力开关频率100kHzPWM 与 ADC 同步PWM 分辨率10 位计数器周期 1000电压采样分压比1/2输出电压分压后送 ADC硬件架构分为四部分功率级半桥 MOSFET 驱动器 Buck 电感 输出电容。采样电路输出端电阻分压送入 STM32 ADC 引脚。PWM 输出STM32 高级定时器输出带死区的互补 PWM驱动上下管。保护电路硬件过流比较器接入刹车输入同时通过 GPIO 把故障信号传给软件。需要强调的是ADC 采样点要选在 PWM 载波的中心点。此时开关管已经完成切换电感电流处于平均值附近采样值最能代表输出电压的真实状态。STM32 的定时器可以配置 TRGO 事件触发 ADC 采样这样硬件会自动完成“PWM 周期中点采样”的动作。4.2 ADC 与 PWM 的同步配置使用 STM32CubeMX 可以快速生成初始化代码核心配置思路如下定时器 TIM1配置为 PWM Generation频率 100kHz输出通道 CH1 和 CH1N 带死区。TIM1 的 TRGO 事件选择 Update Event用于触发 ADC。ADC1配置为注入组采样由外部触发启动采样完成后触发中断。DMA将 ADC 结果自动搬运到内存变量减少 CPU 开销。在代码中控制环运行的时刻非常关键。推荐使用“ADC 采样完成中断 定时器更新中断”的配合方式ADC 在 PWM 中点完成采样DMA 搬运结果之后在定时器周期中断中读取采样值、执行 PID、更新占空比。下面是简化后的主控逻辑// 系统参数定义 #define PWM_PERIOD 1000 #define VOUT_TARGET 12.0f #define ADC_VREF 3.3f #define ADC_RES 4095.0f #define VOUT_DIV 0.5f static PID_TypeDef g_pid; static volatile uint16_t g_adc_raw 0; static volatile uint8_t g_adc_ready 0; // ADC 采样完成回调 void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) { if (hadc-Instance ADC1) { g_adc_raw ADC1-DR; g_adc_ready 1; } } // 定时器周期中断中执行控制环 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim-Instance TIM2) { if (!g_adc_ready) { return; } g_adc_ready 0; // 1. 将 ADC 采样值换算为实际输出电压 float vout (float)g_adc_raw / ADC_RES * ADC_VREF / VOUT_DIV; // 2. 执行 PID 运算 float duty PID_Update(g_pid, VOUT_TARGET, vout); // 3. 限制占空比范围 if (duty 0.95f) { duty 0.95f; } if (duty 0.05f) { duty 0.05f; } // 4. 更新 PWM 比较值 __HAL_TIM_SET_COMPARE(htim1, TIM_CHANNEL_1, (uint32_t)(duty * PWM_PERIOD)); } }代码中前两步是核心ADC 原始值先换算成物理电压然后通过 PID 计算目标占空比。__HAL_TIM_SET_COMPARE是 HAL 库中更新 PWM 比较寄存器的宏将浮点占空比转换成计数器的比较值。4.3 主循环与保护状态机控制环放在中断中执行主循环负责状态机管理、故障检测、通信等低频任务。这样可以保证 100kHz 控制频率的确定性同时让低优先级的任务不干扰控制环。主循环流程可以这样组织int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_ADC1_Init(); MX_TIM1_Init(); MX_TIM2_Init(); // 初始化 PID 参数 PID_Init(g_pid, 0.8f, 0.05f, 0.01f, 95.0f, 5.0f); for (;;) { uint16_t faults ReadFaultFlags(); PowerFsm_Update(g_fsm, enable_flag, faults); // 根据状态机决定 PWM 是否输出 if (g_fsm.state PWR_STATE_RUN || g_fsm.state PWR_STATE_SOFT_START) { __HAL_TIM_MOE_ENABLE(htim1); } else { __HAL_TIM_MOE_DISABLE(htim1); } // 等待下一个主循环周期或处理上位机指令 HAL_Delay(1); } }其中__HAL_TIM_MOE_ENABLE和__HAL_TIM_MOE_DISABLE控制 TIM1 的主输出开关。进入故障状态时关闭 PWM 输出可以立即切断功率级的驱动信号。4.4 运行与验证代码下载到板子后建议按以下顺序验证先用小功率电阻作为负载不接输出负载确认输出电压在目标值附近。接上电子负载从空载逐步加载到 3A观察输出电压的跌落和恢复过程。用示波器测量输出电压纹波和开关节点波形确认 PWM 死区正常没有直通短路。给一个阶跃负载比如从 1A 突然跳到 3A观察输出电压的过冲量和恢复时间。如果发现输出电压振荡优先减小 PID 的 Kp 和 Kd或者检查 ADC 采样点是否在 PWM 中心。如果在轻载下出现噪音需要适当增加最小占空比或进入 Burst 模式。5. 常见问题与排查思路5.1 常见问题表格问题现象常见原因解决思路输出电压持续振荡PID 参数不当相位裕度不足降低 Kp增加阻尼检查采样滤波深度满载掉电压或输出啸叫环路带宽过低或占空比触发限幅提高控制频率重新设计补偿器检查电感饱和启动瞬间输出电压过冲软启动时间太短积分累积过大加长软启动爬升时间增加积分限幅开关噪声导致采样值跳变ADC 采样点靠近开关边沿配置 PWM 中点触发 ADC或增加一阶低通滤波轻载时输出电压偏高最小占空比设置过高增加 Burst 模式或降低最小占空比过流保护误触发电流采样包含大量尖峰增加峰值滤波或改用平均值采样5.2 输出电压振荡的深度排查振荡是数字电源调试中最常见的问题。建议按以下顺序排查首先确认振荡频率。如果振荡频率接近控制环带宽说明是环路稳定性问题。此时应该降低 PID 的 Kp 和 Ki或者加入相位补偿把相位裕度拉回 45° 以上。其次确认振荡是否与负载相关。如果重载时才振荡可能是电感饱和导致电流变化率异常也可能与采样点偏移有关。最后检查控制环的执行时间。如果中断中处理的代码太多导致控制周期抖动也会引入额外相位延迟。可以将不紧急的代码移出中断或者用 DMA 搬运 ADC 数据缩短中断处理时间。5.3 启动过冲的细节处理启动过冲的本质是能量过剩。软启动抬升参考电压时PID 的积分项已经在累积如果参考电压爬升速度跟不上 PID 输出输出电压就会过冲。处理方式有两种一是降低参考电压爬升速度让控制环有时间调整占空比。 二是在软启动阶段使用较小的 Ki进入稳态后切换到正常 Ki。第二种方式对动态响应更友好但需要额外维护一组软启动 PID 参数。6. 最佳实践与工程建议6.1 采样与 PWM 严格同步数字电源最容易踩的坑就是“采样点漂移”。如果 ADC 由软件启动而不是由 PWM 定时器硬件触发采样时刻会随着中断优先级的变化而抖动导致采样值不断变化。工程上推荐的做法是用 PWM 定时器的 TRGO 事件触发 ADC 注入组采样。ADC 采样完成后用 DMA 搬运结果。控制环在下一个 PWM 周期开始时读取最新采样值。这样采样点总是固定在 PWM 载波的固定位置环路行为更加确定。6.2 控制参数不要一开始就求完美新手调试 PID 时很容易陷入“调了一个小时电感啸叫一直存在”的困境。更高效的整定顺序是先把 Kp 调到一个让系统稳定的值观察输出电压是否在目标值附近。缓慢增加 Ki消除稳态误差每次改完都加阶跃负载验证。最后加入少量 Kd或者不加 Kd观察动态响应是否满足要求。Kd 对采样噪声非常敏感如果 ADC 没有滤波就开大 Kd输出会明显抖动。所以很多工业数字电源实际使用的是 PI 加低通滤波而不是完整 PID。6.3 保护优先于控制软件环路再快也比不上硬件故障保护。在做系统设计时一定要把优先级理清楚硬件级保护比较器监测过流直接触发 PWM 刹车输入。固件级保护在控制环中断之外用独立任务检查过压、欠压、过温标志。控制环内保护PID 输出限幅、积分抗饱和、软启动参考值限幅。如果出现过流正确的行为是立即关闭 PWM进入打嗝重试而不是继续让 PID 计算。电源可靠性设计的核心是“故障发生时不失控恢复时不留隐患”。6.4 调试记录与可观测性数字电源调试时最高效的工具不是示波器而是“变量的时间曲线”。通过串口或调试器把 ADC 采样值、PID 输出、占空比、状态机状态实时上传到上位机能够快速定位问题。工程上可以在代码中维护一个环形缓冲区记录故障前 100 个控制周期的关键数据。故障发生时把这个数据区冻结后续通过串口读出可以还原故障瞬间的详细过程。7. 总结与学习路线7.1 本文要点回顾围绕“电源数字控制算法逻辑”我们梳理了这样一条主线数字电源用 ADC、PWM 和控制算法替代模拟补偿网络核心优势是灵活和可观测。PID 是基础重点在于积分抗饱和、输出限幅和微分滤波位置式和增量式各有适用场景。状态机把软启动、正常运行、故障恢复串成清晰逻辑避免堆叠 if-else。ADC 采样必须与 PWM 同步采样点选择在 PWM 中心。保护优先级必须高于控制硬件刹车优先软件负责记录和恢复策略。调试时需要把变量曲线可视化不能盲目调参。7.2 下一步学习方向如果你准备继续深入数字电源建议按下面的路线推进在 Buck 基础上加入电流内环实现峰值电流或平均电流模式控制。学习反激电源的数字控制把思路从单环扩展到隔离电源和变压器设计。研究 LLC 和 PFC 的 PFM 控制与相位控制逻辑。学习环路分析仪的使用用幅频和相频曲线指导补偿器设计。尝试用 DSP 或 FPGA 做更高控制频率的电源方案。数字电源是一个“硬件、软件、控制理论”三交叉的领域每一个环节都需要实践验证。建议你直接在现有的 Buck 实验板上跑起来先让电压稳定输出再逐步加入保护、软启动和状态机体会到的问题会比看十篇文章更有价值。如果本文对你有帮助可以收藏备用后续做电源项目时随时翻出来对照排查。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价