STM32这个系列做数字电源,说实话在行业里已经不算新鲜事了,但每次看到有人用片内ADC直接采输出电压、再用定时器输出PWM驱动Buck电路,我还是会觉得这套组合非常经典。它把模拟电源里最麻烦的环路补偿、保护逻辑、参数整定,全部搬到了固件里,改一个系数就是一次方案迭代,这在传统模拟方案里想都不敢想。
这篇笔记我不打算讲大而全的理论,而是聚焦STM32数字电源设计中最关键的几个外设:ADC采样链路、高级定时器PWM、以及过流保护相关的刹车机制,然后用手把手的方式带你把一个最简单的Buck降压电源跑起来。适合刚接触数字电源、或者已经会点STM32但不知道怎么把外设组合成电源系统的朋友,当然,如果你在调环路时被噪声和振荡折磨过,这篇也能帮你少踩几个坑。
1. 数字电源设计的外设选型与架构思路
1.1 为什么STM32适合做数字电源
很多人问,电源控制为什么不用专门的数字电源控制器,比如TI的UCD系列或者一些DSP,非要拿STM32这种通用MCU来做?我个人的看法是:STM32的优势不在极致性能,而在外设的完整度和生态成熟度。
一个典型的数字电源闭环需要什么?高精度ADC采样输出电压和电流,PWM模块输出驱动信号,比较器或模拟看门狗做快速故障检测,然后是足够快的控制中断响应。这些需求STM32基本都能满足,F1系列虽然老,但12位ADC加高级定时器已经能跑10kHz到几十kHz的开关频率和控制环路;G4系列更是带了内置运放和比较器,几乎是为数字电源量身定做的;H7系列则适合更高速、更复杂的拓扑。选择什么型号,取决于你的开关频率和控制精度需求,而不是越贵越好。
数字电源相对模拟电源的核心优势,就是灵活性和可观测性。环路参数不用换电阻电容,直接在代码里改PID系数;调试时可以把ADC采样值、占空比、误差信号这些中间量全部通过串口或DAC输出出来,用上位机看波形分析环路稳定性,模拟电路根本做不到这一点。
1.2 关键外设清单与分工
在做数字电源之前,先把外设的分工理清楚,后面写代码才不会乱。我通常把一套数字电源系统里的外设划分为三类:感知、执行、保护。
感知类外设主要是ADC,负责采集输出电压、输入电压、电感电流或负载电流。执行类就是定时器PWM,产生固定频率、可调占空比的开关驱动信号。保护类则包括比较器、ADC模拟看门狗、定时器的刹车输入端,这些外设的目的是在固件还没来得及反应时,用硬件把PWM输出封锁掉。这三类外设必须协同工作,任何一环掉链子,电源都可能出问题。
一个容易忽略的外设是DMA。ADC多通道采样如果靠CPU逐次读取,中断开销会非常大,而且采样时序不稳定。正确的做法是ADC配DMA循环传输,让采样数据自动搬运到内存缓冲区,CPU只在需要时去读取数组里的最新值。
下面这张表是我做数字电源时常用的外设资源分配参考:
| 外设 | 功能定位 | 典型配置要点 |
|---|---|---|
| ADC1 | 输出电压/电流采样 | 多通道扫描,DMA循环模式 |
| ADC2 | 输入电压/温度采样 | 可与ADC1同步采集 |
| TIM1/TIM8 | 高频PWM输出 | 互补输出,带死区和刹车 |
| TIM6/TIM7 | 控制环定时触发 | 固定频率触发ADC或中断 |
| COMP(部分型号) | 硬件过流保护 | 直接输出到刹车引脚 |
| DMA | ADC数据搬运 | 环形缓冲,半满/全满中断 |
| 串口 | 调试监控 | 打印采样值和占空比 |
1.3 我为什么推荐电压模式控制起步
数字电源的控制方式有电压模式、峰值电流模式、平均电流模式等,复杂度差别很大。新手做第一个数字电源,我强烈建议从电压模式控制开始。
电压模式控制就是只采样输出电压,和参考电压做差,经过PID调节后直接决定PWM占空比。它只有一根控制环,不需要电感电流采样,硬件简单,控制逻辑也容易调试。缺点是动态响应相对慢,环路带宽做不高,但对于学习和验证外设功能来说完全够了。
等你把电压模式跑通了,再往电流模式迁移,就会发现只是多了一个电流采样通道和一个内环PI,控制结构并没有本质变化。基础打牢固了,后面的路自然就顺畅。
2. 关键外设详解:ADC采样链路与精确测量
2.1 ADC多通道扫描和DMA配置的细节
数字电源里ADC采样有个特点:不是采一次就完了,而是需要连续、周期性地采。比如你开关频率20kHz,控制环也是20kHz,意味着每50微秒就要完成一次全部通道的采样和转换,这个频率下用单次查询模式的ADC,CPU基本被拖死。
所以第一件事就是配置ADC为扫描模式加连续转换(或定时器触发),配合DMA循环传输。我的习惯是开DMA的循环模式,配置一个数组缓冲区,DMA每次转换完成自动把结果存进数组。这样CPU根本不用管采样过程,只需要在控制中断里直接从数组取最新值。
配置时要特别注意两个地方。第一,ADC采样时间不要太短,STM32的ADC是逐次逼近型,采样时间短了,输入电容充不满,采样结果会偏小。数字电源采样电压一般用电阻分压,输出阻抗较高,我会把采样时间拉到最大,或者加一级运放做跟随器降低输出阻抗。第二,多通道扫描时,通道顺序要和DMA缓冲区一一对应,不然采回来的数据错位,排查起来非常痛苦。
2.2 采样数据的软件滤波和校准
ADC原始数据直接用于PID计算通常会出问题,因为电源的开关纹波会耦合到采样值里,控制环会把这部分高频噪声当成真实误差去响应,轻则输出抖动,重则整个环路振荡。
我在项目里常用两种滤波手段。第一种简单粗暴,直接做滑动平均,取最新8次或16次采样值求平均,代价是会增加延迟;第二种是IIR低通滤波,用一个一阶滤波公式就够了。一阶IIR的代码如下,系数alpha越小滤波越重,但延迟也越大,需要根据环路带宽权衡,我通常在0.1到0.3之间调。
float filtered_value = 0.0f; float alpha = 0.2f; // 滤波系数 void adc_filter(uint16_t raw_value) { filtered_value = alpha * (float)raw_value + (1.0f - alpha) * filtered_value; }除了滤波,校准也很关键。STM32的ADC有偏移误差和增益误差,直接测出来的值可能偏差一两个LSB,对电压精度要求高的场合不能让这个误差直接进入控制环。最简单的做法是采集两个已知电压点,比如0V和一个精密基准,然后算出增益和偏移量做线性修正。正规一点的做法是使用ADC内部校准功能,很多STM32型号内置了自校准,初始化时记得调用一次。
我曾经在一版板子上发现输出电压总是比设定值低0.15V左右,排查了很久,最后定位到是电阻分压的精度问题加上ADC偏移误差叠加导致。后来换用1%精度的分压电阻,并在固件里做了两点校准,输出精度立刻好了一个数量级。
2.3 模拟看门狗:不依赖中断的异常检测
ADC采样通常交给控制环处理,但控制环是有周期的,万一控制环卡死或者PID计算异常,输出电压可能会飞起来。这时候单靠软件检测是不够的,需要模拟看门狗(Analog Watchdog)这种硬件机制兜底。
STM32的ADC模拟看门狗可以设定上限和下限阈值,一旦采样值超出这个范围,会立刻置位标志并产生中断,甚至可以直接触发一些硬件动作。我在数字电源里就把输出电压的上限保护配置为模拟看门狗,正常工作时它几乎不占用资源,一旦电压越限,中断立刻执行保护措施,比单纯依赖主循环的轮询快得多。
配置模拟看门狗要注意它作用的是哪几个通道。有些型号的ADC支持对扫描序列中的所有通道进行监控,有些只支持单个通道,需要查参考手册确认。在电源应用里,最需要监控的是输出电压和电感电流这两个通道,如果你用的型号只支持一个通道监控,优先监控电感电流,因为电流过冲比电压过冲更危险。
3. 关键外设详解:高级定时器PWM与硬件保护
3.1 高级定时器为什么适合驱动电源开关管
STM32系列里有普通定时器和高级定时器,做数字电源一定要用高级定时器,也就是TIM1和TIM8,部分型号还有TIM20等。高级定时器的核心优势在于三点:互补PWM输出、死区插入、刹车功能。
互补输出是驱动半桥或全桥拓扑的刚需。一个PWM通道输出高边驱动信号,互补通道输出低边驱动信号,两者中间必须插入死区时间,否则上下管会同时导通造成直通短路。STM32高级定时器的死区发生器是硬件实现的,精度可以达到几十纳秒级别,这对电源安全至关重要。
刹车功能更是一个保命的外设。你可以把比较器输出或者外部故障信号直接连接到定时器的刹车输入引脚,一旦触发,PWM输出立即被硬件拉低,不需要软件介入。这个响应时间在纳秒级,比固件中断快几个数量级。我设计的每块电源板,都会把过流保护信号引到刹车脚上。
3.2 死区时间怎么算
死区时间设置的依据是开关管的关断延迟和开通延迟。以常见的MOSFET为例,关断延迟通常比开通延迟长一些,死区时间至少要大于关断延迟减去开通延迟的差值,同时还要留出一定裕量。
具体计算方式是通过高级定时器的死区寄存器DTG配置。STM32的文档里有一套死区时间的计算公式,根据DTG[7:5]的不同范围,时基分为三档。举例来说,如果你需要200ns的死区,使用72MHz的定时器时钟,那么每格约13.9ns,配置值大约是14到15。手算容易出错,我一般直接参考ST官方的参考例程,里面有现成的计算宏。
提示:死区时间设置过大,输出波形会出现平顶,有效占空比被吃掉,输出电压带载能力下降;死区时间设置过小,则可能出现上下管直通,管子瞬间发热烧毁。调试时先用示波器观察栅极驱动波形,确认死区合适再上主电。
3.3 刹车机制和过流保护的实际接线
数字电源的过流保护,理想状态下是分级处理的。第一级是硬件比较器直接触发刹车,瞬间封锁输出;第二级是ADC采样电流后在固件里做慢速过流判断,如果电流持续超过阈值但还没到硬件保护的触发点,就执行降额或者软关机。
硬件比较器可以用STM32G4系列内置的COMP外设,也可以用外部比较器芯片。不管是哪种,输出端要连接到定时器的刹车输入。STM32高级定时器的刹车输入有多路,可以分别配置为高电平有效或低电平有效,还能配置自动重装载刹车和可控刹车。
我踩过的一个坑是刹车信号的电气连接。早期设计时,比较器输出直接接MCU的刹车引脚,但电源板功率部分的大电流切换会产生很强的地弹噪声,比较器输出被干扰,导致PWM偶尔误关断。后来把比较器输出做了RC滤波,并用施密特触发器整形,才彻底解决。
4. 动手实验:基于STM32的Buck降压电源
4.1 硬件电路搭建和主要参数计算
实验目标我设定为:输入12V,输出5V,最大输出电流2A,开关频率50kHz。选择Buck拓扑是因为它结构最简单,又能完整展现数字电源的各个环节。
Buck电路的核心元件是电感、续流二极管(或同步整流MOSFET)、输出电容。电感值的选择公式是:L = (Vin - Vout) × D / (ΔI × f)。其中D = Vout/Vin = 5/12 ≈ 0.417,ΔI取输出电流的20%到40%,按0.6A纹波计算,L = (12-5) × 0.417 / (0.6 × 50000) ≈ 97μH,取标称100μH。
输出电容的选取主要看输出电压纹波要求以及环路稳定性,容值大一些对纹波有好处,但太大会让环路响应变慢,需要配合PID参数调整。这里可以选一个470μF的电解电容并联几个10μF的MLCC,兼顾低频储能和高频滤波。
采样电路上,输出电压用两个电阻分压后进ADC。分压电阻选值时要考虑ADC输入阻抗和功耗的平衡,我通常用10kΩ和3.3kΩ的1%精度电阻,分压比约3.03。ADC参考电压如果用的是内部VREF,精度有限,最好外接一个精密基准源,比如REF3030,这样输出电压精度才有保证。
4.2 工程初始化:ADC+DMA+PWM的代码骨架
初始化代码我基于STM32CubeMX生成,然后手动调整,这里把核心配置说清楚。
首先配置ADC1为多通道扫描模式,通道0接输出电压分压采样,通道1接输入电压采样。DMA配置为循环模式,数据宽度半字,缓冲区两个uint16_t的数组。ADC触发源选择TIM1的更新事件,这样PWM每个周期自动触发一次采样,保证采样点和开关周期严格同步,这是降低采样噪声的重要技巧。
接着配置TIM1为PWM模式1,输出通道1和通道1N作为互补输出,插入500ns死区。PWM频率设置为50kHz,对应ARR值为72MHz / 50000 - 1 = 1439,初始占空比设为30%左右,等电压环跑起来后由固件自动调节。刹车功能配置为输入有效时输出强制低电平,这样硬件保护就能立即断开开关管。
最后配置TIM6为500μs周期中断,作为控制环的节拍。在主中断里做PID计算,更新TIM1的CCR值。这样整个系统的工作流程是:PWM周期触发ADC采样,DMA搬运数据,TIM6定时控制环读取最新采样值并调节占空比。
初始化流程中最容易出错的是外设时钟和引脚复用,漏配一个GPIO的AF模式,整个外设就等于没配置。所以先从CubeMX生成基础工程,避免手写寄存器时漏掉某个RCC使能位。
4.3 核心控制环:PID实现与调试
电压模式控制的核心是PID控制器。数字PID的离散公式是:输出 = Kp × 误差 + Ki × 误差积分 + Kd × 误差微分。在嵌入式里实现时,要注意抗积分饱和、微分滤波、输出限幅这几个工程细节,否则理论上再完美的PID到了实际硬件上都可能失控。
我常用的PID结构是增量式PID,输出的是占空比增量而不是绝对值,这样天然带限幅保护,也方便做软启动。一个简单的实现如下:
float pid_update(float target, float current) { float error = target - current; float p_out = Kp * error; integral += error; // 积分限幅,防止饱和 if (integral > INTEGRAL_LIMIT) integral = INTEGRAL_LIMIT; if (integral < -INTEGRAL_LIMIT) integral = -INTEGRAL_LIMIT; float i_out = Ki * integral; float derivative = error - last_error; // 微分低通,滤掉高频噪声 derivative_filtered = alpha * derivative + (1 - alpha) * derivative_filtered; float d_out = Kd * derivative_filtered; last_error = error; float output = p_out + i_out + d_out; // 输出限幅,防止占空比突变 if (output > PWM_MAX) output = PWM_MAX; if (output < PWM_MIN) output = PWM_MIN; return output; }调参的时候,我习惯先让积分和微分归零,只调比例项,找到临界稳定点。临界比例增益记作Kcr,临界振荡周期记作Tcr,然后按齐格勒-尼科尔斯经验公式算出Kp、Ki、Kd。这个经验公式给的是一个起点,实际调试时还是得靠示波器观察负载阶跃响应来修正。
在数字电源里,PID参数还会受到采样延迟和控制频率的影响。控制频率越高,可以获得的环路带宽越高,但延迟也会影响相位裕度。我实测下来,50kHz开关频率下,控制环跑10kHz是个比较稳妥的起点,太高的控制频率反而会因为延迟导致环路不稳定。
4.4 软启动和负载阶跃测试
直接上电是数字电源调试的大忌。刚上电时,输出电容相当于短路,如果PID一开始就全力输出,瞬间电流可能会烧掉MOSFET。所以软启动是必须的。
实现软启动最简单的方式是让参考电压从0缓慢爬升到目标值。比如设定目标5V,以每10ms增加0.1V的速度逐步提高参考电压,这样输出会平滑地达到目标,不会产生过冲。这个功能在代码里只需要用一个软启动计数器,在控制环里对目标值做斜率限制即可。
负载阶跃测试是用来验证环路动态响应的重要方法。我在输出端接一个电子负载,从0.5A突跳到1.5A,用示波器观察输出电压的变化。理想的响应是电压有一小幅度跌落(几十毫伏),然后迅速恢复,没有明显振荡。如果看到电压反复震荡,说明相位裕度不足,需要降低Kp或者增加阻尼;如果恢复太慢,则说明带宽不够,可以尝试提高Kp和Ki。
我遇到过最头疼的问题是输出电压在阶跃后出现等幅振荡,频率大概是几kHz。排查了很久,最后发现是采样滤波太深,引入了过大的控制延迟,导致环路相位裕度被吃掉。把滤波系数从0.1改到0.3后,振荡立即消失。这个案例也说明,数字电源的环路调试是一个整体的平衡过程,采样延迟、滤波、PID参数必须一起考虑。
5. 常见问题与排查技巧实录
5.1 快速排查参照表
做数字电源调试踩过的坑,我整理了一份速查表,方便大家上手时对照排查:
| 现象 | 可能原因 | 解决思路 |
|---|---|---|
| 输出电压偏低 | 分压电阻误差、ADC校准偏差 | 用万用表测量分压点电压,做两点校准 |
| 输出电压纹波大 | LC滤波器参数不合适、采样噪声耦合 | 加大输出电容,优化采样时序和滤波 |
| 带载后电压跌落严重 | 占空比受限、环路带宽不足 | 检查PWM最大占空比设置,提高控制环增益 |
| 输出振荡 | 相位裕度不足、采样延迟过大 | 降低KP、调整滤波系数,用示波器观察环路响应 |
| PWM输出突然消失 | 刹车被触发、过流保护误动作 | 检查刹车输入信号,排查比较器阈值和噪声干扰 |
| 开关管异常发热 | 死区时间不足、驱动波形异常 | 用示波器查看栅极波形,确认死区设置 |
| ADC数据跳动大 | 采样时间不足、参考电压不稳 | 增加采样时间,检查VREF引脚滤波电容 |
5.2 深入分析:采样噪声导致环路不稳定的实际案例
这里展开讲一个我调试中花了两天才解决的问题。现象是输出电压在轻载时正常,一加负载就有明显的抖动声,示波器看输出波形有大约1kHz的低频振荡,叠加在正常的PWM纹波上。
一开始我怀疑是PID参数问题,把Kp调低,积分系数减小,振荡幅度有所下降但依然存在。后来用ADC的原始数据去分析,发现采样值在加负载后噪声明显增大,峰峰值从原来的3个LSB变成了30个LSB。这些噪声进入控制环后,被放大器放大,最终调制到占空比上形成振荡。
问题的根源是PCB布局,电流采样回路和功率开关回路没有做单点接地,噪声通过地平面耦合进了ADC采样通道。后来重新改板,把采样回路的地单独走线,距离功率地拉开,噪声水平大幅下降,环路也稳定了。这个案例让我明白一个道理:数字电源的很多疑难杂症,根源往往不在固件,而在硬件布局。
5.3 关于调试工具的几点建议
调试数字电源,示波器是刚需,至少要能同时观察PWM驱动波形和输出电压波形。如果预算有限,一个便宜的入门级示波器也够用,关键是触发功能要好,方便捕捉瞬态过程。
逻辑分析仪对于查看PWM和刹车信号的时序关系很有帮助,比如确认刹车信号比PWM更新快了多少。如果调试PID参数,可以在固件里把PID中间变量通过DAC输出,用示波器观察,相当于一个简易的数字信号分析仪。
最后是串口监控。我会在固件里定期打印ADC采样值、当前占空比、PID输出这些数据,配合一个简单的上位机工具画成曲线,能直观看到环路的状态。这个做法虽然简陋,但很多时候比高级调试器更高效。我用的STM32型号都自带USART,接线也简单,一根USB转串口线就能搞定。
6. 从实验到产品的几个进阶方向
如果顺利跑通了上面这套Buck电源,说明STM32数字电源的基础链路已经掌握。但在实际产品里,还需要处理更多工程化的问题。比如多路输出间的交叉调整率、不同负载状态下的频率切换、以及更复杂的拓扑如LLC、全桥移相等,这些都是数字电源工程师日常要面对的内容。
我自己在实验板上验证完电压模式控制后,紧接着把电路改成了峰值电流模式,增加了一路电感电流采样和一个内部比较器。改动最大的不是硬件,而是对电流环路的理解——电流内环一旦跑起来,输出电压的动态响应会有质的提升。这个进阶过程强烈建议有条件的朋友试一试,数字电源的核心竞争力就在多环控制上。
另外,G4系列的内置运放和比较器,真正用起来之后会发现省掉了很多外围器件,整个板的面积可以做得很小。我后面做便携式设备的电源方案时,已经开始全面转向G4了,片内集成度带来的可靠性提升,是分立方案比不了的。