做便携雾化设备的嵌入式开发这行,经常被问到一个问题:电子烟恒功率输出到底是个什么控制逻辑?很多刚入行的朋友一看“恒功率”三个字,觉得不过是把功率算出来然后稳住就行,可真到自己搭电路、写固件、上负载实测的时候,才发现输出功率一路漂,发热丝忽明忽暗,电量一低功率整个就垮掉。这篇就把我实际做“电子烟恒功率输出”这套控制方案的过程完整拆开讲,从为什么不用恒压、闭环怎么搭、关键参数怎么算,到调参踩坑的实操记录,一次说清楚。适合正在做小尺寸加热设备、便携雾化器电源方案的硬件工程师、嵌入式开发者,也适合想搞懂这类控制逻辑的电子爱好者参考。1. 内容整体设计与思路拆解1.1 为什么“恒压”会把体验做成玄学很多初版方案为了省事,直接用一个稳压芯片固定输出电压,然后把发热丝一接就完事。刚上电那几十秒确实还行,可一旦发热丝温度升上来,问题就来了——发热丝用的合金材料有正温度系数,温度上去了电阻值跟着涨,实测下来常见规格的发热丝从常温到工作温度,电阻变化能达到10%~20%甚至更高。电压是稳住了,电流却因为电阻变大而变小,实际功率等于电压平方除以电阻,跟着一路往下掉。表现出来就是:前两口还行,越往后输出越疲,体验完全看发热丝心情。更要命的是电池电压的影响。便携设备用的是单节锂电池,满电4.2V,放到3.4V就基本得保护了,全程电压摆幅将近0.8V。就算后端有个稳压电路,电池放电能力、线路压降也会让实际供给到发热丝的能量飘忽不定。我见过有方案直接用电池电压算功率,结果满电和低电量时同一个输出档位差了将近30%,这种偏差做开发的人自己知道,用户也早晚能感觉出来。1.2 恒功率输出的工程定义与价值恒功率输出,说白了就是让发热丝上消耗的电功率维持在一个设定值附近,不管电池电压怎么掉、发热丝阻值怎么漂,也不管线路接触电阻带来什么扰动,到头来发热丝获得的功率基本不变。工程实现上,它不再把发热丝当成一个固定电阻死算,而是当成一个动态负载去主动控制。核心公式仍然是欧姆定律的功率表达:P = I²R = U²/R,但这里的电压和电流不是拿初始状态定的,而是实时采样、实时调节。这带来的实际价值很直接:同样一颗发热丝,从满电到低压,第一阶段和第十阶段的加热功率都能维持一致;换了不同阻值的雾化芯,用户选定的输出档位对应的实际功率也一致,而不是出现“标称60W,实测45W”这种尴尬。作为控制系统来做,它本质是一个功率闭环,比单纯的恒压、恒流都要更贴近实际负载的需求。1.3 方案选型:几种控制思路的取舍做恒功率输出之前,我先把几种常见技术路线对比了一圈,包括开环查表、恒压加热、恒流加热和自己最终选择的功率闭环。开环查表是最初级的做法,出厂前预设一张电压/功率对应表,根据电池电压查到一个补偿电压输出。好处是省成本、代码量极小,但只补偿了电池电压这一个变量,发热丝阻值漂移和接触电阻变化完全没法处理,精度全靠运气。恒压方案在上一小节已经说过了,只能算半程选手。恒流方案稍好一些,通过采样电阻闭环稳住电流,但功率还受电阻影响,换不同阻值的发热丝仍然会跑偏。功率闭环是目前工程上最合理的方案,原理是采样发热丝两端的实际电压和流过它的实际电流,两者相乘算出真实功率,和设定目标比较,然后通过调整驱动占空比去修正误差。这套思路复杂度不算高,但涉及采样精度、控制频率、PID参数整定这些细节,好在做出来后适应性很强,阻值范围、电压范围都能自动兜住。2. 系统架构与核心参数计算2.1 整体架构拆解先看整体电路架构,我用的方案可以分成几个模块:电池输入、MOS开关驱动、发热丝负载、电压电流采样、MCU控制和保护逻辑。电池进来后先经过一个保险丝和一个低阻抗的电流采样电阻,然后接到MOS管的漏极,MOS管源极直接接地,发热丝一端接电池正极,另一端接MOS管的漏极,也就是发热丝串联在电源正极和开关管之间。这样做的原因是发热丝需要大电流,把它放在高端会让驱动电路复杂化,低端驱动用一颗N沟道MOS就能解决,导通阻抗也低,适合便携设备的空间和成本约束。MCU这一侧负责两件事:输出PWM到MOS的栅极去控制导通比例,同时用ADC去读取电压采样点和电流采样点的模拟量。所有闭环计算都在MCU里完成,外设只需要一个定时器输出PWM和一个ADC连续采样,最基础的8位单片机就能跑起来,这也是这类控制方案能被大量产品采用的原因之一。2.2 采样电路与关键元件的选型计算采样是整个闭环的地基。电压采样相对简单,发热丝工作电压最高也就4.2V左右,直接用电阻分压网络把电压衰减到ADC量程内就行。我这里把分压比例设定为2:1,也就是ADC读到的电压是实际电压的一半,这样4.2V对应2.1V,留足了余量。电流采样要稍微多想一层。方案上用一颗毫欧级采样电阻串联在电路中,通过测它两端的压差来反推电流。采样电阻阻值选大了功耗吃不消,选小了信噪比不够。我选的规格是10毫欧,额定电流设定在15A左右,那它上面的压降最大是0.15V,对应功耗0.225W,用一颗1W的贴片电阻就能稳定扛住。接下来是采样放大。15A的电流在10毫欧电阻上只产生150mV压降,如果直接送ADC,量化精度不够,特别是低功率档位只有几安培电流时,压降几十毫伏,很容易被噪声淹没。所以电流信号要经过一个运放放大。我用的放大倍数是20倍,这样15A对应3V,正好接近ADC量程,同时又保留了一定的线性余量。运放选的是轨到轨单电源型号,3.3V供电下能输出到接近3.2V,保证高电流端不削顶。分压网络和放大电路的时间常数要控制在微妙级别,不能拖慢采样环路。滤波电容取值宁小勿大,我用的是1nF左右的陶瓷电容,配合几十千欧的电阻,截止频率大约在几十千赫兹,既能滤掉一部分高频开关噪声,又不会把功率计算用的瞬时信号抹平。2.3 控制环路:PID与PWM的配合逻辑恒功率控制的核心是把“算功率”和“调占空比”这两件事循环跑起来。每一次控制周期里,MCU先通过ADC读取电压和电流采样值,按比例换算成真实电压和真实电流,功率就是两者相乘的结果。把这个瞬时功率和用户设定的目标功率做差,得到误差值,然后在PID控制器里换算成PWM占空比的修正量。我的控制周期选在20kHz,也就是说每50微秒完成一次采样和计算。这背后有两个理由:第一,发热丝的热惯性非常小,尤其是细丝,温度响应在毫秒量级,控制频率低于1kHz时就会看到明显的功率波动;第二,20kHz刚好高于人耳的听觉上限,避免在电感或者电池线上产生可闻的啸叫噪声。PID参数不需要面面俱到,实际中只用了PI两个环节,微分项基本没用。原因是发热丝的功率响应存在一定的滞后,微分项容易把MOS驱动搞得太激进,反而让PWM占空比剧烈跳变。P项负责快速纠正大偏差,I项负责消除稳态误差。断断续续调了几轮之后,适合这套负载的P值大概在8到12之间,I值在0.05到0.1之间,电机出PID参数会对不同负载差异巨大,每次换发热丝规格都需要重新整定,这是后话。在启动瞬间,发热丝从冷态开始电阻值较低,同样的电压下电流会比稳定工作时大不少。这时候如果直接一上来就满功率追击,瞬时电流会突破电池能力极限,还可能导致MOS过热或电池低压保护。我在软件里加了一个缓启动逻辑:目标功率不是一上来就给满,而是分几个阶段抬高,每个阶段维持几十毫秒,让发热丝逐步进入工作状态,整体体验会更顺。3. 实操过程与核心环节实现3.1 测试环境搭建与负载模拟写固件之前,我先在测试台上把硬件跑通。我用的是一块手焊的测试板,电池用电感模拟,没有直接接真电芯,用的是可编程直流电源,电压设定在3.7V,带载能力能到20A,这样测起来不会受电芯内阻影响,数据也干净。负载端本来可以直接接一颗发热丝测试,但我一开始用的是无感的功率电阻,阻值按目标发热丝规格取,比如我要模拟0.4欧的负载,就用两颗0.8欧的大功率电阻并联。好处是阻值不受温度影响,测试期间功率读数稳定,方便验证控制环路的纯逻辑部分。等控制逻辑确认没问题,再接真发热丝做温度漂移测试。测试过程中我同时接了电流探头和电压探头在发热丝两端,用示波器观察波形。示波器看的是瞬时值,可以直观看到PWM驱动时电压和电流的开关波形,判断有没有振铃、有没有过冲。MCU里的功率计算值是经过数字滤波的,示波器上则能捕捉到每次开关瞬间的真实电流尖峰,两者对照来看才能发现问题。3.2 软件控制环落地细节控制逻辑的代码不复杂,但有几个细节直接关系到最终效果。ADC采样不能直接读一次就用。PWM开关会导致发热丝两端的电压电流在一个周期内经历从零到峰值的跳变,如果采样点刚好落在开关瞬态上,读到的数值就没有代表性。我在一个控制周期内连续采样4次,分别放在PWM周期的不同相位上,再取平均值。这比单次采样稳得多,等效于把开关纹波滤掉了一部分,算出来的功率值更接近真实均值。乘法和除法在单片机上的代价要算清楚。功率是两个16位变量的乘积,结果用32位保存,这个还好。但PID计算里的除法容易拖慢周期,如果每次都调用软除法库,20kHz的周期很难跑满。我在代码里把PID系数都改成整数定标形式,比如把0.08的积分系数乘以256后存在8位整型里,每次计算完右移8位还原,省掉浮点运算,整个控制周期实测不到20微秒就能完成。另一个关键点是占空比的限幅。PWM最大占空比不能给到100%,因为低端MOS的开关需要死区时间回头给栅极充电,如果占空比顶到满会直接失去开关能力。我这套方案把最大占空比限制在92%左右,剩余的时间留给开关切换和采样稳定。最小占空比限制在5%,低于这个值就干脆关断输出,避免极低占空比下电流断续带来的噪声和不受控状态。代码骨架大概长这样:#define ADC_VOLT_SCALE 2.0f // 电压分压比例 #define ADC_CURR_SCALE 20.0f // 电流放大倍数 #define SHUNT_RES 0.01f // 采样电阻10毫欧 float measure_power(void) { uint16_t adc_v = read_adc(ADC_CH_VOLT); uint16_t adc_i = read_adc(ADC_CH_CURR); float volt = adc_v * ADC_REF / ADC_MAX * ADC_VOLT_SCALE; float curr = adc_i * ADC_REF / ADC_MAX / ADC_CURR_SCALE / SHUNT_RES; return volt * curr; } void control_loop(void) { static float integral; float target = get_target_power(); float power = measure_power(); float error = target - power; integral += error * INTEGRAL_SCALE; float output = KP * error + KI * integral; if (output > PWM_MAX) output = PWM_MAX; if (output < PWM_MIN) output = PWM_MIN; set_compare(output); }3.3 实测数据与调参记录硬件和代码都就位之后,我开始记录输出数据。初始状态是目标功率30W,负载用0.4欧的功率电阻模拟,电源电压调成3.7V。第一版控制参数P给得偏大,取到20,结果示波器上能看到功率在目标值附近来回摆动,波形像过阻尼一样有衰减振荡。把P降到10之后,稳定时间从原来的200毫秒左右缩短到80毫秒左右,稳态误差控制在正负1W以内。接下来做阻值漂移测试。我把负载电阻换成0.6欧,发现稳态功率短时间会掉到28W附近,但积分项会在几百毫秒内修正回来,最终回到目标值。这个测试说明闭环对负载变化的敏感性是为了应对发热丝温度变化设计的关键特性,哪怕换成容差不同的雾化芯,最终也能锁住目标功率。电池电压变化的测试也同样验证了环路价值。我把输入电压从4.2V逐步降到3.2V,每0.1V记一次稳态功率。结果全程功率波动在正负1.2W以内,满电和低压的差别基本可以忽略。相比之下,同样条件下开环恒压方案功率从满电时的38W掉到了低压时的25W,差距一目了然。表: 30W目标功率下不同输入电压的实测功率输入电压闭环恒功率开环恒压4.20V30.1W38.2W3.90V29.8W30.5W3.60V30.3W26.7W3.30V29.7W25.1W4. 常见问题与排查技巧实录4.1 功率波动与噪声干扰做闭环控制最常遇到的微信“屏幕闪烁”式问题是功率数值在小数点附近跳来跳去,面板上看着不难受,实际输出其实也在跟着抖。这个情况多半不是控制环没调好,而是采样信号污染严重。开关节点是最大的噪声源,MOS管在导通和关断的瞬间会产生纳秒级的电压尖峰,如果ADC采样线和功率线靠得太近,这个尖峰就会被采样电路捡进去。解决方法是把采样电路的走线远离开关节点,并且在地线上做单点接地。软件层面我也会在ADC读取后做一个中位值滤波,连续读5次取中间3个值的平均,思路上简单,但对抗随机尖峰非常有效。注意滤波不能做得太厚,否则控制环路的带宽被拖慢,功率波动反而变大。4.2 MOS管发烫和低压误保护整机测试时发现一个小批量的现象:同一个设计,有的板子MOS管温度偏高,有的正常。查到最后是栅极驱动电阻的问题。MOS管开关时需要一定的栅极充电电流,驱动电阻太大,开关时间变长,开关损耗上升,管子自然发烫。把栅极电阻从100欧降到12欧之后,结温明显下降。但是电阻也不能太小,太小了开关振铃会变大,需要根据驱动能力和MOS栅极电容选一个平衡点。低压保护的问题更隐蔽。我设了3.2V的低压保护阈值,按道理电池低于这个值才切断输出,但测试的时候发现有些板子3.6V就触发保护了。查了半天,发现是采样电路在PWM关断期间采到了电感反压的毛刺,瞬时电压被ADC误当成电池电压。解决办法是让电池电压采样和驱动PWM错开,在驱动导通稳定之后再采,也就是在控制循环里加一个时间窗,只允许在PWM高电平稳定区间读取电池电压。4.3 发热丝接触电阻的修正策略发热丝和电极之间不是理想接触,夹持稍微松一点,接触电阻可能多出0.05欧以上。这个数值在0.15欧的低阻发热丝面前占到了相当比例,闭环虽然能把总回路功率稳住,但接触电阻会分担一部分功率,发热丝自身获得的功率反而不达标。所以做恒功率输出时不能只盯总功率,还要考虑接触电阻误差带来的发热丝端电压降损失。我的做法是出厂前做一次校准:先用已知阻值的精密电阻替代发热丝,测量整机在不同功率档位下的实际输出电压和电流,建立一条校准曲线,修正分压系数和采样放大的固有偏差。这个步骤在批量生产时尤其重要,因为运放的零漂和电阻分压误差每个板子都略有不同,靠软件校准可以把一致性拉到正负1%以内。需要提一句,如果发热丝是现场更换的,接触状态不稳定的时候校准效果会打折扣,这也是这类设备普遍采用一次性雾化芯结构的原因之一。从我个人的实际体会来说,恒功率输出这套方案最大的价值不是把功率算得有多精准,而是把电池、负载、温度这些变量全都统一到一个闭环里,让使用者感受到的输出尽量一致。做这类系统,不要一开始就追求复杂的算法,先把采样这条链路做干净,把PWM开关频率和控制周期定好,PID用最简单的PI结构就能解决大部分问题。后续如果想继续扩展,可以加入实时功率反馈显示、温升曲线记录甚至通过上位机动态调参,都是在现有这个闭环骨架上加肉的事。希望这篇能帮正在调这套逻辑的同行少走一点弯路。
做便携雾化设备的嵌入式开发这行,经常被问到一个问题:电子烟恒功率输出到底是个什么控制逻辑?很多刚入行的朋友一看“恒功率”三个字,觉得不过是把功率算出来然后稳住就行,可真到自己搭电路、写固件、上负载实测的时候,才发现输出功率一路漂,发热丝忽明忽暗,电量一低功率整个就垮掉。这篇就把我实际做“电子烟恒功率输出”这套控制方案的过程完整拆开讲,从为什么不用恒压、闭环怎么搭、关键参数怎么算,到调参踩坑的实操记录,一次说清楚。适合正在做小尺寸加热设备、便携雾化器电源方案的硬件工程师、嵌入式开发者,也适合想搞懂这类控制逻辑的电子爱好者参考。1. 内容整体设计与思路拆解1.1 为什么“恒压”会把体验做成玄学很多初版方案为了省事,直接用一个稳压芯片固定输出电压,然后把发热丝一接就完事。刚上电那几十秒确实还行,可一旦发热丝温度升上来,问题就来了——发热丝用的合金材料有正温度系数,温度上去了电阻值跟着涨,实测下来常见规格的发热丝从常温到工作温度,电阻变化能达到10%~20%甚至更高。电压是稳住了,电流却因为电阻变大而变小,实际功率等于电压平方除以电阻,跟着一路往下掉。表现出来就是:前两口还行,越往后输出越疲,体验完全看发热丝心情。更要命的是电池电压的影响。便携设备用的是单节锂电池,满电4.2V,放到3.4V就基本得保护了,全程电压摆幅将近0.8V。就算后端有个稳压电路,电池放电能力、线路压降也会让实际供给到发热丝的能量飘忽不定。我见过有方案直接用电池电压算功率,结果满电和低电量时同一个输出档位差了将近30%,这种偏差做开发的人自己知道,用户也早晚能感觉出来。1.2 恒功率输出的工程定义与价值恒功率输出,说白了就是让发热丝上消耗的电功率维持在一个设定值附近,不管电池电压怎么掉、发热丝阻值怎么漂,也不管线路接触电阻带来什么扰动,到头来发热丝获得的功率基本不变。工程实现上,它不再把发热丝当成一个固定电阻死算,而是当成一个动态负载去主动控制。核心公式仍然是欧姆定律的功率表达:P = I²R = U²/R,但这里的电压和电流不是拿初始状态定的,而是实时采样、实时调节。这带来的实际价值很直接:同样一颗发热丝,从满电到低压,第一阶段和第十阶段的加热功率都能维持一致;换了不同阻值的雾化芯,用户选定的输出档位对应的实际功率也一致,而不是出现“标称60W,实测45W”这种尴尬。作为控制系统来做,它本质是一个功率闭环,比单纯的恒压、恒流都要更贴近实际负载的需求。1.3 方案选型:几种控制思路的取舍做恒功率输出之前,我先把几种常见技术路线对比了一圈,包括开环查表、恒压加热、恒流加热和自己最终选择的功率闭环。开环查表是最初级的做法,出厂前预设一张电压/功率对应表,根据电池电压查到一个补偿电压输出。好处是省成本、代码量极小,但只补偿了电池电压这一个变量,发热丝阻值漂移和接触电阻变化完全没法处理,精度全靠运气。恒压方案在上一小节已经说过了,只能算半程选手。恒流方案稍好一些,通过采样电阻闭环稳住电流,但功率还受电阻影响,换不同阻值的发热丝仍然会跑偏。功率闭环是目前工程上最合理的方案,原理是采样发热丝两端的实际电压和流过它的实际电流,两者相乘算出真实功率,和设定目标比较,然后通过调整驱动占空比去修正误差。这套思路复杂度不算高,但涉及采样精度、控制频率、PID参数整定这些细节,好在做出来后适应性很强,阻值范围、电压范围都能自动兜住。2. 系统架构与核心参数计算2.1 整体架构拆解先看整体电路架构,我用的方案可以分成几个模块:电池输入、MOS开关驱动、发热丝负载、电压电流采样、MCU控制和保护逻辑。电池进来后先经过一个保险丝和一个低阻抗的电流采样电阻,然后接到MOS管的漏极,MOS管源极直接接地,发热丝一端接电池正极,另一端接MOS管的漏极,也就是发热丝串联在电源正极和开关管之间。这样做的原因是发热丝需要大电流,把它放在高端会让驱动电路复杂化,低端驱动用一颗N沟道MOS就能解决,导通阻抗也低,适合便携设备的空间和成本约束。MCU这一侧负责两件事:输出PWM到MOS的栅极去控制导通比例,同时用ADC去读取电压采样点和电流采样点的模拟量。所有闭环计算都在MCU里完成,外设只需要一个定时器输出PWM和一个ADC连续采样,最基础的8位单片机就能跑起来,这也是这类控制方案能被大量产品采用的原因之一。2.2 采样电路与关键元件的选型计算采样是整个闭环的地基。电压采样相对简单,发热丝工作电压最高也就4.2V左右,直接用电阻分压网络把电压衰减到ADC量程内就行。我这里把分压比例设定为2:1,也就是ADC读到的电压是实际电压的一半,这样4.2V对应2.1V,留足了余量。电流采样要稍微多想一层。方案上用一颗毫欧级采样电阻串联在电路中,通过测它两端的压差来反推电流。采样电阻阻值选大了功耗吃不消,选小了信噪比不够。我选的规格是10毫欧,额定电流设定在15A左右,那它上面的压降最大是0.15V,对应功耗0.225W,用一颗1W的贴片电阻就能稳定扛住。接下来是采样放大。15A的电流在10毫欧电阻上只产生150mV压降,如果直接送ADC,量化精度不够,特别是低功率档位只有几安培电流时,压降几十毫伏,很容易被噪声淹没。所以电流信号要经过一个运放放大。我用的放大倍数是20倍,这样15A对应3V,正好接近ADC量程,同时又保留了一定的线性余量。运放选的是轨到轨单电源型号,3.3V供电下能输出到接近3.2V,保证高电流端不削顶。分压网络和放大电路的时间常数要控制在微妙级别,不能拖慢采样环路。滤波电容取值宁小勿大,我用的是1nF左右的陶瓷电容,配合几十千欧的电阻,截止频率大约在几十千赫兹,既能滤掉一部分高频开关噪声,又不会把功率计算用的瞬时信号抹平。2.3 控制环路:PID与PWM的配合逻辑恒功率控制的核心是把“算功率”和“调占空比”这两件事循环跑起来。每一次控制周期里,MCU先通过ADC读取电压和电流采样值,按比例换算成真实电压和真实电流,功率就是两者相乘的结果。把这个瞬时功率和用户设定的目标功率做差,得到误差值,然后在PID控制器里换算成PWM占空比的修正量。我的控制周期选在20kHz,也就是说每50微秒完成一次采样和计算。这背后有两个理由:第一,发热丝的热惯性非常小,尤其是细丝,温度响应在毫秒量级,控制频率低于1kHz时就会看到明显的功率波动;第二,20kHz刚好高于人耳的听觉上限,避免在电感或者电池线上产生可闻的啸叫噪声。PID参数不需要面面俱到,实际中只用了PI两个环节,微分项基本没用。原因是发热丝的功率响应存在一定的滞后,微分项容易把MOS驱动搞得太激进,反而让PWM占空比剧烈跳变。P项负责快速纠正大偏差,I项负责消除稳态误差。断断续续调了几轮之后,适合这套负载的P值大概在8到12之间,I值在0.05到0.1之间,电机出PID参数会对不同负载差异巨大,每次换发热丝规格都需要重新整定,这是后话。在启动瞬间,发热丝从冷态开始电阻值较低,同样的电压下电流会比稳定工作时大不少。这时候如果直接一上来就满功率追击,瞬时电流会突破电池能力极限,还可能导致MOS过热或电池低压保护。我在软件里加了一个缓启动逻辑:目标功率不是一上来就给满,而是分几个阶段抬高,每个阶段维持几十毫秒,让发热丝逐步进入工作状态,整体体验会更顺。3. 实操过程与核心环节实现3.1 测试环境搭建与负载模拟写固件之前,我先在测试台上把硬件跑通。我用的是一块手焊的测试板,电池用电感模拟,没有直接接真电芯,用的是可编程直流电源,电压设定在3.7V,带载能力能到20A,这样测起来不会受电芯内阻影响,数据也干净。负载端本来可以直接接一颗发热丝测试,但我一开始用的是无感的功率电阻,阻值按目标发热丝规格取,比如我要模拟0.4欧的负载,就用两颗0.8欧的大功率电阻并联。好处是阻值不受温度影响,测试期间功率读数稳定,方便验证控制环路的纯逻辑部分。等控制逻辑确认没问题,再接真发热丝做温度漂移测试。测试过程中我同时接了电流探头和电压探头在发热丝两端,用示波器观察波形。示波器看的是瞬时值,可以直观看到PWM驱动时电压和电流的开关波形,判断有没有振铃、有没有过冲。MCU里的功率计算值是经过数字滤波的,示波器上则能捕捉到每次开关瞬间的真实电流尖峰,两者对照来看才能发现问题。3.2 软件控制环落地细节控制逻辑的代码不复杂,但有几个细节直接关系到最终效果。ADC采样不能直接读一次就用。PWM开关会导致发热丝两端的电压电流在一个周期内经历从零到峰值的跳变,如果采样点刚好落在开关瞬态上,读到的数值就没有代表性。我在一个控制周期内连续采样4次,分别放在PWM周期的不同相位上,再取平均值。这比单次采样稳得多,等效于把开关纹波滤掉了一部分,算出来的功率值更接近真实均值。乘法和除法在单片机上的代价要算清楚。功率是两个16位变量的乘积,结果用32位保存,这个还好。但PID计算里的除法容易拖慢周期,如果每次都调用软除法库,20kHz的周期很难跑满。我在代码里把PID系数都改成整数定标形式,比如把0.08的积分系数乘以256后存在8位整型里,每次计算完右移8位还原,省掉浮点运算,整个控制周期实测不到20微秒就能完成。另一个关键点是占空比的限幅。PWM最大占空比不能给到100%,因为低端MOS的开关需要死区时间回头给栅极充电,如果占空比顶到满会直接失去开关能力。我这套方案把最大占空比限制在92%左右,剩余的时间留给开关切换和采样稳定。最小占空比限制在5%,低于这个值就干脆关断输出,避免极低占空比下电流断续带来的噪声和不受控状态。代码骨架大概长这样:#define ADC_VOLT_SCALE 2.0f // 电压分压比例 #define ADC_CURR_SCALE 20.0f // 电流放大倍数 #define SHUNT_RES 0.01f // 采样电阻10毫欧 float measure_power(void) { uint16_t adc_v = read_adc(ADC_CH_VOLT); uint16_t adc_i = read_adc(ADC_CH_CURR); float volt = adc_v * ADC_REF / ADC_MAX * ADC_VOLT_SCALE; float curr = adc_i * ADC_REF / ADC_MAX / ADC_CURR_SCALE / SHUNT_RES; return volt * curr; } void control_loop(void) { static float integral; float target = get_target_power(); float power = measure_power(); float error = target - power; integral += error * INTEGRAL_SCALE; float output = KP * error + KI * integral; if (output > PWM_MAX) output = PWM_MAX; if (output < PWM_MIN) output = PWM_MIN; set_compare(output); }3.3 实测数据与调参记录硬件和代码都就位之后,我开始记录输出数据。初始状态是目标功率30W,负载用0.4欧的功率电阻模拟,电源电压调成3.7V。第一版控制参数P给得偏大,取到20,结果示波器上能看到功率在目标值附近来回摆动,波形像过阻尼一样有衰减振荡。把P降到10之后,稳定时间从原来的200毫秒左右缩短到80毫秒左右,稳态误差控制在正负1W以内。接下来做阻值漂移测试。我把负载电阻换成0.6欧,发现稳态功率短时间会掉到28W附近,但积分项会在几百毫秒内修正回来,最终回到目标值。这个测试说明闭环对负载变化的敏感性是为了应对发热丝温度变化设计的关键特性,哪怕换成容差不同的雾化芯,最终也能锁住目标功率。电池电压变化的测试也同样验证了环路价值。我把输入电压从4.2V逐步降到3.2V,每0.1V记一次稳态功率。结果全程功率波动在正负1.2W以内,满电和低压的差别基本可以忽略。相比之下,同样条件下开环恒压方案功率从满电时的38W掉到了低压时的25W,差距一目了然。表: 30W目标功率下不同输入电压的实测功率输入电压闭环恒功率开环恒压4.20V30.1W38.2W3.90V29.8W30.5W3.60V30.3W26.7W3.30V29.7W25.1W4. 常见问题与排查技巧实录4.1 功率波动与噪声干扰做闭环控制最常遇到的微信“屏幕闪烁”式问题是功率数值在小数点附近跳来跳去,面板上看着不难受,实际输出其实也在跟着抖。这个情况多半不是控制环没调好,而是采样信号污染严重。开关节点是最大的噪声源,MOS管在导通和关断的瞬间会产生纳秒级的电压尖峰,如果ADC采样线和功率线靠得太近,这个尖峰就会被采样电路捡进去。解决方法是把采样电路的走线远离开关节点,并且在地线上做单点接地。软件层面我也会在ADC读取后做一个中位值滤波,连续读5次取中间3个值的平均,思路上简单,但对抗随机尖峰非常有效。注意滤波不能做得太厚,否则控制环路的带宽被拖慢,功率波动反而变大。4.2 MOS管发烫和低压误保护整机测试时发现一个小批量的现象:同一个设计,有的板子MOS管温度偏高,有的正常。查到最后是栅极驱动电阻的问题。MOS管开关时需要一定的栅极充电电流,驱动电阻太大,开关时间变长,开关损耗上升,管子自然发烫。把栅极电阻从100欧降到12欧之后,结温明显下降。但是电阻也不能太小,太小了开关振铃会变大,需要根据驱动能力和MOS栅极电容选一个平衡点。低压保护的问题更隐蔽。我设了3.2V的低压保护阈值,按道理电池低于这个值才切断输出,但测试的时候发现有些板子3.6V就触发保护了。查了半天,发现是采样电路在PWM关断期间采到了电感反压的毛刺,瞬时电压被ADC误当成电池电压。解决办法是让电池电压采样和驱动PWM错开,在驱动导通稳定之后再采,也就是在控制循环里加一个时间窗,只允许在PWM高电平稳定区间读取电池电压。4.3 发热丝接触电阻的修正策略发热丝和电极之间不是理想接触,夹持稍微松一点,接触电阻可能多出0.05欧以上。这个数值在0.15欧的低阻发热丝面前占到了相当比例,闭环虽然能把总回路功率稳住,但接触电阻会分担一部分功率,发热丝自身获得的功率反而不达标。所以做恒功率输出时不能只盯总功率,还要考虑接触电阻误差带来的发热丝端电压降损失。我的做法是出厂前做一次校准:先用已知阻值的精密电阻替代发热丝,测量整机在不同功率档位下的实际输出电压和电流,建立一条校准曲线,修正分压系数和采样放大的固有偏差。这个步骤在批量生产时尤其重要,因为运放的零漂和电阻分压误差每个板子都略有不同,靠软件校准可以把一致性拉到正负1%以内。需要提一句,如果发热丝是现场更换的,接触状态不稳定的时候校准效果会打折扣,这也是这类设备普遍采用一次性雾化芯结构的原因之一。从我个人的实际体会来说,恒功率输出这套方案最大的价值不是把功率算得有多精准,而是把电池、负载、温度这些变量全都统一到一个闭环里,让使用者感受到的输出尽量一致。做这类系统,不要一开始就追求复杂的算法,先把采样这条链路做干净,把PWM开关频率和控制周期定好,PID用最简单的PI结构就能解决大部分问题。后续如果想继续扩展,可以加入实时功率反馈显示、温升曲线记录甚至通过上位机动态调参,都是在现有这个闭环骨架上加肉的事。希望这篇能帮正在调这套逻辑的同行少走一点弯路。