☰
STM32驱动加湿器雾化片:PWM配置、LC谐振与频率跟踪实战
2026/9/25 6:13:34 网站建设 项目流程

1. 加湿器雾化片驱动的整体设计思路

1.1 为什么选STM32来驱动雾化片

雾化片这东西,说白了就是一块压电陶瓷片,给它加上特定频率的交流信号,它就会以同样的频率机械振动,把水打碎成微米级的雾。听起来简单,但实际做起来,频率不对它不雾化、振幅不够它雾化量小、驱动波形不好它发热严重甚至烧片。所以驱动电路的核心就两件事:频率要准,功率要够。

那为什么用STM32而不是用一颗555定时器或者专用雾化芯片?我当初选STM32的考虑是这样的:第一,雾化片的最佳谐振频率会随着水温、水位、老化程度漂移,固定频率的驱动方案在实验室里能雾化,装到加湿器里用两周可能就雾化量明显下降了。STM32有定时器输入捕获功能,可以实时检测雾化片的反馈信号,做频率跟踪。第二,加湿器通常还要做定时、水位检测、缺水保护、档位调节这些功能,用STM32一颗芯片全包了,BOM成本反而比“555+比较器+一堆逻辑”更低。第三,STM32的TIM定时器输出PWM非常灵活,频率和占空比都能精确控制,配合HAL库开发效率也高。

具体到型号,我手上用的是STM32G070CBT6,这款芯片在加湿器这类小家电里很常见,Cortex-M0+内核,64KB Flash,18KB RAM,资源够用,价格便宜。它有一个高级定时器TIM1和多个通用定时器TIM3、TIM4、TIM14等,用来产生雾化片驱动PWM完全够。如果你手上是STM32F103系列,逻辑是一样的,只是时钟树配置和定时器资源略有差异。

1.2 雾化片驱动的核心原理拆解

雾化片本质上是一个容性负载,等效电路大概是一个电容并联一个谐振电阻。它有一个固有的机械谐振频率,常见的有1.7MHz、2.4MHz、3.0MHz几种。注意这个频率是兆赫兹级别的,不是我们平时驱动电机那种几十KHz的PWM。这一点非常关键,很多新手一开始就卡在这里——拿STM32的普通定时器去输出1.7MHz的PWM,发现根本出不来。

为什么出不来?因为STM32G070的主频是64MHz,定时器时钟也是64MHz,要输出1.7MHz的PWM,ARR值只能设到64M/1.7M≈37,也就是计数到37就翻转一次。这个分辨率太低了,占空比只能调出1/37≈2.7%的精度,而且波形抖动会很大。更麻烦的是,1.7MHz的信号用STM32的GPIO直接推,驱动能力完全不够,雾化片根本起不来。

所以实际方案是分两步走:STM32产生一个低频PWM作为“包络”或者“使能信号”,后级用专门的MOS管半桥/全桥驱动电路,配合LC谐振网络,把信号放大到雾化片需要的频率和功率。或者另一种更常见的做法是:STM32输出一个几十KHz到几百KHz的PWM,经过变压器升压和LC谐振,利用谐振电路的选频特性,在雾化片两端产生1.7MHz左右的高频交流信号。

我这次采用的方案是第二种:STM32的TIM4输出一个约85KHz的PWM信号,经过一个半桥驱动芯片(比如IR2104或者EG2133),推动两个MOS管组成半桥,再接到一个升压变压器初级,变压器次级接一个电感L和雾化片串联,构成LC谐振回路。通过调整PWM频率,让LC回路的谐振频率落在雾化片的最佳工作频率附近,这样雾化片两端就能得到足够幅度的高频交流电压。

1.3 方案选型的几个关键取舍

这里有几个选择需要说明一下。第一,为什么用TIM4而不是TIM1?TIM1是高级定时器,有互补输出和死区插入功能,理论上更适合做半桥驱动。但TIM1通常要留着做其他用途,比如互补PWM驱动电机或者做其他关键时序。TIM4是通用定时器,配置简单,输出一路PWM就够了,而且它的时钟来源是APB1,在STM32G070上APB1的时钟是64MHz,和TIM1一样。所以用TIM4完全能满足需求,也方便后续扩展。

第二,为什么用半桥而不是全桥?全桥需要四个MOS管和两路互补PWM,电路复杂、成本高,但输出功率更大。加湿器雾化片一般工作功率在1W到5W之间,半桥方案配合合适的变压器和LC谐振,完全能推到足够的功率。而且半桥只需要一路PWM,控制逻辑简单,故障率低。对于小家电这种对成本敏感、对可靠性要求高的场景,半桥是更务实的选择。

第三,PWM频率到底设多少?这个不能拍脑袋。雾化片标称频率是1.7MHz,但那是它自身的机械谐振频率。我们的驱动电路里,变压器次级电感和雾化片等效电容会形成一个LC串联谐振回路,这个回路的谐振频率才是我们真正要匹配的。实际调试时,我会先用信号发生器扫频,找到雾化片雾化量最大、电流最小的那个频率点,然后反推PWM频率应该设多少。一般来说,PWM频率设在谐振频率的1/20到1/10左右比较合适,这样LC回路能有效滤除高次谐波,在雾化片两端得到接近正弦波的高频驱动信号。

2. STM32端PWM配置的详细实操

2.1 时钟树配置与TIM4时钟源确认

在CubeMX里配置时钟树的时候,STM32G070的最高主频是64MHz。我一般把HSI或者HSE倍频到64MHz作为系统时钟,然后APB1预分频器设为1,这样APB1的时钟就是64MHz。注意STM32G070的TIM4挂在APB1总线上,所以TIM4的时钟源频率就是64MHz。这一点在计算PWM参数时非常重要,如果APB1做了分频,TIM4的时钟频率会跟着变,算出来的ARR和PSC就不对了。

在CubeMX的Clock Configuration界面里,你可以清楚地看到APB1 Timer clocks这一栏显示的是多少。我实测下来,默认配置下APB1 Timer clocks就是64MHz。如果你用的是STM32F103,情况类似,但F103的APB1最高只能到36MHz,TIM4的时钟源是APB1的2倍频,也就是72MHz。所以换芯片的时候一定要重新确认这个时钟频率,不能直接套用参数。

2.2 TIM4 PWM模式参数计算

假设我们要输出一个85KHz、占空比50%的PWM信号,TIM4时钟频率是64MHz。计算过程如下:

首先确定预分频器PSC。PSC的作用是把64MHz的时钟分频到一个合适的计数频率。我一般希望ARR值在100到1000之间,这样占空比调节精度够用,同时计数频率也不会太低导致波形抖动。取PSC=0,也就是不分频,计数频率就是64MHz。那么ARR = 64MHz / 85KHz - 1 ≈ 752 - 1 = 751。实际输出频率 = 64MHz / (751+1) = 85.106KHz,和85KHz非常接近,误差在0.1%以内,完全够用。

占空比50%对应的CCR值 = (ARR+1) * 0.5 = 752 * 0.5 = 376。所以CCR寄存器设为376。

如果你想要更精细的频率调节,可以增大PSC,让ARR更大。比如PSC=7,计数频率变成8MHz,ARR = 8MHz / 85KHz - 1 ≈ 94 - 1 = 93。这样ARR只有93,占空比精度反而下降了。所以PSC和ARR的取舍要看具体需求。对于雾化片驱动,频率精度比占空比精度更重要,所以我倾向于PSC=0,让ARR尽量大。

在CubeMX里配置TIM4的时候,选择PWM Generation CH1,然后设置Prescaler为0,Counter Period为751,Pulse为376。CH Polarity设为High,也就是高电平有效。这样配置下来,TIM4的CH1引脚就会输出85KHz、50%占空比的PWM。

2.3 HAL库初始化代码与启动流程

CubeMX生成代码之后,TIM4的初始化在MX_TIM4_Init函数里。关键代码大概长这样:

static void MX_TIM4_Init(void) { TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; TIM_OC_InitTypeDef sConfigOC = {0}; htim4.Instance = TIM4; htim4.Init.Prescaler = 0; htim4.Init.CounterMode = TIM_COUNTERMODE_UP; htim4.Init.Period = 751; htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; if (HAL_TIM_Base_Init(&htim4) != HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } if (HAL_TIM_PWM_Init(&htim4) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK) { Error_Handler(); } sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 376; sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) { Error_Handler(); } HAL_TIM_MspPostInit(&htim4); }

启动PWM只需要在main函数里调用:

HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1);

这里有个细节要注意:AutoReloadPreload我设成了TIM_AUTORELOAD_PRELOAD_ENABLE。这个设置的作用是,当你动态修改ARR值时,新的值会在下一个更新事件才生效,避免当前周期出现异常波形。对于雾化片驱动来说,如果要做频率跟踪,这个设置很重要,否则调频率的时候可能会输出一个畸变的周期,导致雾化片工作异常。

2.4 动态调频的实现方法

雾化片在工作过程中,最佳谐振频率会漂移,所以我们需要能够动态调整PWM频率。在HAL库下,修改频率有两种方式:一种是直接改ARR和PSC,另一种是用__HAL_TIM_SET_AUTORELOAD宏。我推荐用宏,因为它更直接,也不会触发重新初始化。

// 动态修改PWM频率 void SetMistFrequency(uint32_t freq_hz) { uint32_t timer_clock = 64000000; // TIM4时钟64MHz uint32_t arr = timer_clock / freq_hz - 1; __HAL_TIM_SET_AUTORELOAD(&htim4, arr); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, (arr + 1) / 2); // 保持50%占空比 }

注意,修改ARR之后,CCR也要跟着改,否则占空比会变。比如原来ARR=751,CCR=376,占空比50%。如果ARR改成500,CCR还是376,占空比就变成75%了,雾化片驱动波形会严重不对称,可能导致雾化片发热甚至损坏。所以每次调频都要同步更新CCR。

另外,调频的时候不要一次性跳变太大,比如从85KHz直接跳到80KHz,LC谐振回路可能会失谐,导致电流冲击。我一般以100Hz为步进,慢慢扫频,同时监测雾化片的工作电流,找到电流最小、雾化量最大的那个点。

3. 雾化片驱动电路的硬件配合要点

3.1 半桥驱动与MOS管选型

STM32的GPIO输出电流最大也就20mA左右,驱动能力很弱,直接推MOS管栅极会导致开关速度慢、发热严重。所以中间必须加一级半桥驱动芯片。我常用的是EG2133或者IR2104,这类芯片有自举电路,能驱动高侧N沟道MOS管,输入逻辑电平兼容3.3V,和STM32的GPIO直接对接没问题。

MOS管的选择要看工作电压和电流。加湿器雾化片驱动电压一般在12V到24V之间,电流在0.5A到2A左右。我一般选耐压30V以上、导通电阻小于50mΩ的N沟道MOS管,比如AO3400或者SI2302。这两个管子都是SOT-23封装,体积小,适合小家电的紧凑布局。注意高侧MOS管的源极是浮地的,所以驱动芯片的自举电容一定要选质量好的,容量在100nF到1uF之间,耐压要高于驱动电压。

3.2 LC谐振网络参数计算

LC谐振网络是雾化片驱动的核心。变压器次级电感L和雾化片等效电容C串联,形成串联谐振。谐振频率公式是:

f = 1 / (2 * π * sqrt(L * C))

雾化片的等效电容一般在1nF到3nF之间,具体值可以用LCR表测出来。假设C=2nF,目标谐振频率是1.7MHz,那么:

L = 1 / (4 * π² * f² * C) = 1 / (4 * 3.14159² * (1.7e6)² * 2e-9) ≈ 4.4uH

所以变压器次级电感大概需要4.4uH。实际调试时,我会用一个可调电感或者几个固定电感串联,边调边测雾化效果。注意电感的Q值要尽量高,否则谐振时损耗大,雾化量上不去。我一般选空心电感或者高频磁芯电感,避免用低频铁氧体磁芯,那种磁芯在1.7MHz下损耗极大。

3.3 电流检测与缺水保护

雾化片缺水干烧是加湿器最常见的故障。没有水的时候,雾化片负载变轻,谐振电流会急剧上升,如果不加保护,几分钟就能把雾化片烧裂。所以驱动电路里一定要加电流检测。

我一般用一个0.1Ω的采样电阻串在MOS管源极到地之间,用STM32的ADC采集采样电阻两端的电压。正常雾化时,电流大概在0.5A左右,采样电压50mV。缺水时电流可能冲到1.5A以上,采样电压超过150mV。在软件里设一个阈值,比如100mV,超过就立刻关闭PWM输出,并点亮缺水指示灯。

ADC采集要注意滤波,因为PWM开关噪声会耦合到采样电阻上。我一般在采样电阻两端并一个RC低通滤波,截止频率设在10KHz左右,然后在软件里做多次采样取平均。这样能有效滤掉开关噪声,得到稳定的电流值。

4. 调试过程中踩过的坑与排查技巧

4.1 PWM无输出或频率不对

这是最常见的问题。我遇到过好几次,CubeMX里配置得好好的,代码也编译下载了,但示波器一测,引脚上什么都没有。排查下来通常是这几个原因:

第一,GPIO复用没配置。TIM4的CH1引脚在STM32G070上是PB6,但PB6默认是普通GPIO,需要在CubeMX里把它的Alternate功能设成TIM4_CH1。如果你手动写代码,要确保调用了HAL_TIM_MspPostInit,这个函数里会配置GPIO的复用功能。我见过有人把初始化代码复制过来,但漏掉了MspPostInit,结果PWM死活出不来。

第二,定时器没启动。HAL_TIM_PWM_Start必须在MX_TIM4_Init之后调用,而且要在主循环之前。如果放在while(1)里面,每次循环都调用一次,虽然不会出错,但没必要。

第三,时钟源配置错误。如果APB1预分频器设成了2分频,TIM4的时钟就变成32MHz了,算出来的ARR对应的实际频率会翻倍。所以调频率不对的时候,第一件事就是确认APB1 Timer clocks的实际频率。

4.2 雾化片不雾化或雾化量小

PWM输出正常,但雾化片就是不雾化,或者雾化量很小。这个问题我调试了整整两天才搞定。排查思路是这样的:

先确认驱动电路有没有工作。用示波器测半桥输出端,看有没有高频交流信号。如果没有,检查驱动芯片的输入信号是否正常、自举电容是否焊好、MOS管有没有装反。如果有信号但幅度很小,检查变压器初级和次级的连接是否正确,变压器是不是坏了。

如果驱动电路有信号,但雾化片不雾化,那大概率是频率没匹配上。这时候不要盲目调PWM频率,而是先用信号发生器直接驱动雾化片,手动扫频,找到雾化量最大的频率点。然后测量这个频率下雾化片两端的电压波形,看看是不是接近正弦波。如果波形畸变严重,说明LC谐振网络参数不对,需要调整电感值。

我踩过的一个坑是:变压器次级电感和雾化片电容的谐振频率算出来是1.7MHz,但实际装上去之后,由于PCB走线电感和寄生电容的影响,实际谐振频率偏移到了1.9MHz。所以理论计算只能作为起点,最终一定要以实测为准。

4.3 雾化片发热严重甚至烧裂

雾化片发热通常是因为驱动波形不对称或者频率偏离谐振点太远。PWM占空比如果不是50%,半桥输出的交流信号就会有直流分量,这个直流分量加在雾化片上会导致持续发热。所以每次调频之后,一定要检查CCR值是否同步更新,确保占空比始终是50%。

另一个原因是缺水干烧。前面说了,缺水时电流会急剧上升,如果保护阈值设得太高或者ADC采样太慢,雾化片可能在保护动作之前就已经过热了。我的经验是,保护阈值不要设得太保守,正常电流的1.5倍就可以触发保护。同时ADC采样频率要足够高,至少每10ms采一次,这样缺水后100ms内就能切断PWM。

还有一个容易被忽略的点:雾化片安装方式。雾化片一般是用硅胶圈密封在水箱底部的,如果硅胶圈压得太紧,雾化片的机械振动会受到抑制,导致雾化量下降、发热增加。我一般会在硅胶圈和雾化片之间涂一层薄薄的硅脂,既能密封又能缓冲,效果很好。

4.4 常见问题速查表

现象可能原因排查方法解决方法
PWM无输出GPIO复用未配置示波器测引脚检查MspPostInit
PWM频率偏差大时钟源频率不对查看CubeMX时钟树重新计算ARR/PSC
雾化片不雾化频率未匹配信号发生器扫频调整PWM频率或LC参数
雾化量小谐振回路Q值低测电感Q值更换高频电感
雾化片发热占空比不对称测PWM占空比同步更新CCR
缺水烧片保护阈值过高测采样电阻电压降低阈值,提高采样率
驱动芯片发热自举电容失效测自举电压更换自举电容
电流波动大滤波不足测ADC采样值增加RC滤波和软件平均

5. 频率跟踪与智能化扩展思路

5.1 基于电流反馈的自动扫频

手动扫频虽然能找到一个不错的频率点,但雾化片工作一段时间后,由于温度升高,谐振频率会漂移。这时候如果PWM频率不变,雾化量就会下降。解决方法是做自动频率跟踪。

思路很简单:STM32定期微调PWM频率,同时采集雾化片的工作电流,找到电流最小的那个频率点,因为串联谐振时电流最大、阻抗最小,但雾化片负载最重时电流也会变化。更准确的做法是找雾化量最大的点,但雾化量不好直接测量。实际工程中,我一般用“电流最小”作为跟踪目标,因为谐振时回路阻抗最小,但雾化片负载会吸收功率,导致电流不是最小而是某个中间值。这个需要根据具体雾化片特性做实验确定。

实现上,可以用一个简单的爬山算法:每次调频后,比较当前电流和上一次的电流,如果电流变小了,就继续朝这个方向调;如果变大了,就反向调。步进可以设100Hz,每100ms调一次。这样能实时跟踪谐振点的漂移。

5.2 多档位雾化量控制

加湿器通常需要调节雾化量,比如低档、中档、高档。雾化量的调节可以通过改变PWM占空比来实现,但注意占空比不能偏离50%太多,否则波形不对称会导致发热。更好的方法是调节半桥的供电电压,或者用PWM控制供电的占空比。我一般用后者:用一个单独的PWM通道控制一个MOS管,对半桥供电进行斩波,通过改变斩波占空比来调节雾化量。这样雾化片驱动PWM始终保持50%占空比和最佳频率,只是供电能量变了,雾化量就能平滑调节。

5.3 与整机功能的联动

加湿器不只是一个雾化片驱动,还要和整机功能联动。比如水位检测可以用一个简单的电极式水位开关,接到STM32的GPIO上,低电平表示缺水。定时功能可以用STM32的RTC或者SysTick实现。按键和LED指示可以用GPIO直接驱动。这些功能都可以在同一个STM32工程里实现,通过一个状态机来管理。

我一般把整个加湿器的软件分成几个模块:雾化驱动模块、水位检测模块、按键处理模块、LED指示模块、定时模块。主循环里轮询各个模块的状态,根据状态决定PWM是否输出、输出多大占空比。这样代码结构清晰,后续增加功能也方便。

6. 个人实操心得与几个关键提醒

雾化片驱动这个事,说难不难,说简单也不简单。我做了好几个加湿器项目,总结下来有几个心得值得分享。

第一,示波器是必备工具。没有示波器调雾化片驱动,就像闭着眼睛修车。PWM频率、占空比、驱动波形、谐振波形,这些都要靠示波器看。我建议至少用一个100MHz带宽的示波器,因为1.7MHz的信号用低带宽示波器看会严重失真。

第二,LC谐振参数要留可调余地。PCB上不要直接把电感焊死,留两个焊盘,方便换不同值的电感。我一般会准备几个不同值的电感,从3.3uH到6.8uH,调试的时候逐个试,找到雾化效果最好的那个。

第三,保护逻辑一定要做。缺水保护、过流保护、超时保护,一个都不能少。我见过太多因为省掉保护电路而烧雾化片的案例,一个雾化片虽然不贵,但换起来麻烦,用户投诉更麻烦。

第四,频率不要设得太死。留一个自动扫频的功能,或者至少留一个手动调频的接口,方便售后根据实际使用环境微调。不同地区的水质硬度不同,雾化片的工作特性也会有差异。

第五,代码里加一个软启动。上电的时候不要立刻输出满占空比PWM,而是从0慢慢加到50%,给LC谐振回路一个建立时间。这样能避免上电瞬间的电流冲击,延长雾化片寿命。

最后再分享一个小技巧:如果你发现雾化片用一段时间后雾化量下降,不一定是雾化片坏了,很可能是雾化片表面结了水垢。把雾化片拆下来,用白醋泡半小时,再用软布擦干净,装回去往往就能恢复如初。这个技巧在售后维修里特别实用,能省下不少换片成本。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询