ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于STM32的半导体制冷片温度控制与PID调参实战

基于STM32的半导体制冷片温度控制与PID调参实战 做温控类的项目很多人的第一反应就是“PID三个字母背下来”可真到自己上手调的时候温度要么冲过头要么半天拉不回来最后只能拍脑袋瞎试。这篇东西不打算把STM32和半导体制冷片的基础知识从头念一遍而是按我自己实际做这套“基于STM32的半导体制冷片温度控制”系统的过程来讲重点放在硬件链路怎么搭、软件逻辑怎么写、PID参数怎么一点点整出来以及那些文档上查不到的实际坑点。无论你是准备拿它当毕设题目还是想给实验室做个小恒温槽这套思路和代码框架都可以直接拿过去改。1. 项目全景这套恒温系统到底解决什么问题1.1 你真正要控制的对象是谁先说清楚这套系统控制的对象不是半导体制冷片本身而是被制冷片影响的那个“负载温度”。半导体制冷片TEC只是一个执行器它靠帕尔贴效应把热量从一端搬到另一端通正向电流制冷反向电流加热本质上就是个“热泵”。真正需要稳定的是传感器探头放到的那块目标区域比如光学室内的样品池、恒温培养皿、激光器的底座或者一个金属块。控制目标就是让这个区域的温度始终贴着设定值走不能因为环境温度变化、负载发热或者制冷片两端温差变化而跑偏。所以整个系统的核心链路是温度传感器采集目标区温度 → STM32读取AD值并换算成实际温度 → 与设定值做差得到误差 → PID控制器算出一个输出量 → 转换成PWM占空比和制冷/加热方向 → 通过驱动电路控制TEC的工作状态 → TEC改变目标区温度 → 传感器再测到新的温度。看起来简单可要在这个闭环里把温度控制到±0.1度级别硬件和软件的细节一个都不能含糊。1.2 系统划分与选型思路这套系统从功能上可以分成四个模块传感模块、调理模块、主控模块、驱动模块。传感模块我选了NTC热敏电阻10K 3950的规格便宜、精度够用、响应速度在SMD封装下也还行调理模块用一个仪表放大器和单片机自带的ADC配合把电阻变化转换成清晰的电压信号主控用STM32F103C8T6蓝色Pill那种小板子就行没必要上F4系列性能完全溢出驱动模块用的是集成H桥芯片DRV8870用来给TEC提供双向可控电流。选STM32而不是51或者Arduino主要图三样一是片上ADC分辨率够12位对0.1度级别的分辨率来说富裕二是定时器输出PWM的精度和灵活性强频率、死区都能调三是生态成熟CubeMX生成工程HAL库写起来速度快后面想加个显示屏、加个串口通信、加个上位机曲线曲线功能都是现成的。对比51做闭环温度控制实验那种教学型项目STM32在这里更像一个正经的控制平台。1.3 系统框图与信号流向我不画流程图了直接用文字把信号走得走一遍NTC和精密电阻串联构成分压器分压点电压送入运算放大器做缓冲和放大运放输出接STM32的ADC引脚STM32内部DMA循环采样在代码里用查表加插值把ADC值算成温度温度值经过一阶低通滤波后送给PID模块PID输出先经过符号判断确定TEC的制冷/加热方向通过GPIO控制H桥的方向脚用输出的绝对值作为PWM占空比指标STM32定时器产生的PWM接到H桥的输入脚最终驱动TEC。明白信号流向后面写代码和排查问题就有章法了。比如温度读数跳就顺着从NTC分压到ADC配置去排查TEC不动作就从GPIO方向和PWM占空比去查。模块化思路越清晰调试的时候越省心。2. 硬件链路拆解从TEC到温度读数的每个环节2.1 半导体制冷片的选型与工作特性半导体制冷片的选型最常听到的型号是TEC1-12706意思是127对PN结额定12V、6A最大制冷功率约60W。选哪一片不是看功率越大越好要看你的负载有多大的热负载。比如给一个边长10厘米的铝块恒温环境温度和设定温度相差20度热负载可能就十瓦出头12706已经绰绰有余。如果只是给一个小光学腔体恒温可能TEC1-12703就够了电流小一点电源和散热压力都小。实际选型时还要看清楚一件事TEC的制冷效率不是恒定的它取决于热端温度和冷端温度的温差。温差越小效率越高能搬运的热量越大温差超过60度左右基本不搬热了电流全变成热量。这个特性决定了热端散热系统有多重要后面2.4节再说。还有一点是TEC是电流型器件不是说接上12V它就自动吃6A电流由输入输出特性决定。所以在驱动上我们最好做恒流或至少是电流受限的控制而不是简单的PWM电压开关。用PWM调平均电压实际上是在调平均电流也要特别注意启动瞬间的浪涌电流一不小心就容易把电源和驱动芯片拉崩。2.2 H桥驱动正逆都通温度才能稳TEC最大的特点是可以反向工作。正向通电制冷反向通电制热。如果你只打算做单向制冷、靠风扇和自然对流降温那确实一个MOSFET就够了。但做真正的“双方向温度控制”让系统既能降温又能升温就必须用H桥电路。H桥的方案有三个层次完全用分立MOSFET搭、用集成电机驱动芯片、用专门的TEC驱动器芯片。分立方案电压和电流的适配性最强但需要自己设计栅极驱动电路还要处理上下管直通的保护调试成本高专门的TEC驱动IC比如MAX1968或者ADN8834控制精度和纹波表现天下无敌但价格也感人一颗可能顶一片开发板。权衡下来集成电机驱动芯片DRV8870是最平衡的选择。DRV8870内部就是一颗单H桥工作电压6.5V到45V连续电流3.6A峰值3.6A以上也扛得住内置续流和限流保护。控制也很简单IN1和IN2给PWM和方向逻辑或者IN1给PWM、IN2给方向。我采用的方式是IN2接STM32的一个普通GPIO作为方向控制IN1接定时器的PWM输出作为功率控制。方向脚为高时制冷为低时制热占空比决定功率大小。这种接法代码逻辑最直观。要注意的是H桥带动TEC这种纯阻性负载续流电流问题比电机小但切换方向的瞬间仍然存在电流突变。所以我强烈建议在驱动板的电源输入端加大容量电容至少470uF电解电容加上0.1uF的陶瓷电容做去耦。实测下来没有这个电容PWM启动瞬间电源轨会被拉下去几百毫伏ADC读数直接就跳了。2.3 温度采集NTC不是简单分压就行NTC热敏电阻是最常见的温度传感器之一利用阻值随温度变化而变化的特性工作。市面上常见的规格是10K 3950意味着25度时阻值10KB常数为3950。它的阻值随温度变化关系满足指数规律温度越低阻值越大温度越高阻值越小。最简单粗暴的接法是NTC和固定电阻串联分压ADC读分压电压然后算电阻值。这种方法当然也能用但在测量范围比较大的时候容易踩坑因为分压电路在量程两端的分辨率严重不均匀。对做半导体温控来说工作范围可能就在0度到80度之间我推荐用电桥结构配合差分放大器把微小的电阻变化放大这样可以整体迁就ADC的输入范围让整个范围内的分辨率都更高。我实际用的方法更简单在目标区贴一片10K NTC和10K精密电阻串联分压电压经过一个轨到轨运放做电压跟随器缓冲再进STM32的ADC。跟随器是为了降低NTC的等效源阻抗对ADC采样电容的影响保证采样结果的稳定。实际测试下来加入跟随器前后的ADC跳动可以从正负十几个LSB降到两三个LSB。还有一点NTC自热效应不可忽略。流过NTC的电流不能太大我控制在0.5mA以内这样自热温升大约是0.05度左右。虽然在控制精度要求特别高的场合还要校掉这一部分但一般项目做到这个程度已经可以接受了。2.4 热端散热与系统布局TEC的制冷效率直接跟热端散热能力挂钩。所谓热端就是TEC通电时往外排热的那一面它的温度越低冷端才能越低系统才能把更多热量搬走。如果热端散热跟不上热量堆积在热端整个TEC就会变成一块大发热片不但制冷效果差还可能烧坏TEC本身。我的方案是用CPU风冷散热器压在TEC热端不要省这个散热器越厚越好。用导热硅脂把TEC热端和散热器底座紧密贴合固定方式用手机螺丝加弹簧垫片保证压力均匀否则接触热阻大温度差全浪费在缝隙里。冷端则直接接触目标金属块同样要涂导热硅脂并尽量减小两端的接触热阻。布局方面要注意TEC和温度传感器必须保持合理的相对位置。传感器不能直接贴在TEC冷端陶瓷片上因为那里温度波动非常剧烈测到的不是目标区的实际温度。正确做法是把传感器放在目标负载的侧面或内部让传感器测的是“整个负载的平均温度”这样PID控制的效果才稳定。3. 软件实现PWM、ADC和PID三座大山3.1 工程搭建与引脚规划我用CubeMX生成STM32F103C8T6的工程HAL库开发软件环境是Keil5。如果虚拟机里还没装STM32芯片包记得先用STM32CubeMX或者打开Keil5的Pack Installer把F1系列的芯片支持包装好这一步卡住的人不少。引脚规划比较灵活但有一个原则PWM输出引脚和ADC采样引脚要避开同一组定时器的冲突方向和风扇控制可以用任意的普通GPIO。我自己在CubeMX里的规划是这样的功能引脚定时器/外设备注PWM输出PA6TIM3_CH1输出到DRV8870的IN1方向控制PA7GPIO输出输出到DRV8870的IN2高电平制冷ADC采样PA4ADC1_IN4采集NTC分压电压风扇控制PB0GPIO输出高电平开通热端风扇串口调试PA9/PA10USART1打印温度和PID输出PWM频率我选的是20kHz。这个选择是综合了TEC特性和驱动芯片能力之后的结果TEC本身是一个阻性加容性负载频率太低了电流纹波大不利于温度平滑频率太高呢驱动芯片的开关损耗会变大而且STM32的定时器在高速PWM下分辨率会下降。20kHz也是可听范围以外避免电感啸叫。3.2 温度换算查表加插值才可靠NTC阻值和温度的关系可以用B值公式表达Rt R25 × exp(B × (1/T - 1/T25))其中T单位是开尔文R25是25度时的阻值10KB是3950。直接用这个公式在单片机上算log和exp函数性能开销比较大。更常用的做法是预先把ADC值和温度对应关系做成一张表格运行时用二分查表再用线性插值把中间的数值补出来。建表的方法不复杂在电脑上用脚本把温度从 -10 到 90 度、每 0.5 度一档的ADC值算出来存成const数组。ADC值本身是12位算的时候用上分压电压和参考电压。STM32的参考电压一般用内部3.3V如果想更准可以用ADC内部参考电压校准功能或者直接用外部基准。查表插值不算复杂核心代码也就几十行uint16_t adc_table[] { /* 用脚本生成的查表数据共200个点 */ }; float Temp_Calc(float adc_value) { if (adc_value adc_table[0]) return -10.0f; if (adc_value adc_table[199]) return 90.0f; uint16_t idx 0; for (uint16_t i 0; i 199; i) { if (adc_value adc_table[i] adc_value adc_table[i 1]) { idx i; break; } } float ratio (adc_value - adc_table[idx]) / (adc_table[idx 1] - adc_table[idx]); float temp (-10.0f idx * 0.5f) ratio * 0.5f; return temp; }代码里我故意没写二分实际工程建议用二分数据量大时能节省很多时间。线性插值这个操作本质上就是拿两个端点之间近似一条直线温度间隔0.5度时NTC的非线性已经足够低插值误差远小于0.05度可以放心用。3.3 软件PID的完整代码与计算过程温度控制领域最常用的是位置式PID。它的离散公式长这样u[k] Kp × e[k] Ki × sum(e[1..k]) Kd × (e[k] - e[k - 1])这里的e是误差sum是对误差的积分累积温度系统里为了避免积分饱和要给积分项加限幅。思路就是输出u最后是要转换成PWM占空比的占空比极限是0到100%所以输出先限幅到 [-100, 100]同时积分项还单独限幅到积分上限避免误差持续积累导致回程超调。另一个温控系统特别容易忽略的点是“制冷和加热的不对称性”。制冷时热端散热风扇对系统有额外扰动加热时只是纯阻性加热两个方向的系统响应速度不一样。直接用同一个PID参数往往加热方向还好制冷方向就振荡或响应慢。一个合适的做法是制冷和加热方向分别用两组PID参数。Kp_cool、Ki_cool、Kd_cool和Kp_heat、Ki_heat、Kd_heat代码里面加一个方向判断误差正还是负决定用哪一组参数。代码框架如下typedef struct { float Kp_cool, Ki_cool, Kd_cool; float Kp_heat, Ki_heat, Kd_heat; float integral; float prev_error; float integral_max; float out_max; } PID_TypeDef; float PID_Calc(PID_TypeDef *pid, float target, float current) { float error target - current; float kp, ki, kd; if (error 0) // 需要加热 { kp pid-Kp_heat; ki pid-Ki_heat; kd pid-Kd_heat; } else // 需要制冷 { kp pid-Kp_cool; ki pid-Ki_cool; kd pid-Kd_cool; } pid-integral error; if (pid-integral pid-integral_max) pid-integral pid-integral_max; if (pid-integral -pid-integral_max) pid-integral -pid-integral_max; float output kp * error ki * pid-integral kd * (error - pid-prev_error); pid-prev_error error; if (output pid-out_max) output pid-out_max; if (output -pid-out_max) output -pid-out_max; return output; }这个PID计算在STM32F103上跑一次只要几微秒完全无压力。真正吃性能的是ADC滤波和TI的插值所以说STM32做这种项目是绰绰有余。3.4 双向功率输出与切换保护PID算出来的输出是带符号的浮点数比如45.0表示需要45%功率加热-30.5表示需要30%功率制冷。把这个输出转换成物理动作就要做下面几步第一步判断符号。正数走加热方向把DRV8870的IN2拉低负数走制冷方向把IN2拉高。第二步取绝对值和100做比较后直接赋给定时器的比较寄存器。假如定时器ARR设为999那么abs(output)按百分比映射成比较值小于1的当作0处理避免极小的占空比导致功率管一直微导通发热。还有一个非常关键的切换保护逻辑当PID输出符号翻转的时候比如从加热切到制冷必须先让PWM输出降到0等待几毫秒再切换方向然后再恢复PWM输出。这个“先关断、再换向、再导通”的动作就是所谓的“死区时间”。不这么做的话H桥可能在瞬间直通驱动芯片直接烧掉而且TEC两端会有一个很大的电压尖峰。void TEC_SetOutput(float output) { if (output 0) { // 需要加热 if (tec_direction COOLING) { __HAL_TIM_SET_COMPARE(htim3, TIM_CHANNEL_1, 0); HAL_Delay(5); TEC_DIR_GPIO_Port-BRR TEC_DIR_Pin; // 切成加热方向 tec_direction HEATING; } uint32_t compare_value (uint32_t)(output / 100.0f * 999.0f); __HAL_TIM_SET_COMPARE(htim3, TIM_CHANNEL_1, compare_value); } else if (output 0) { // 需要制冷 float abs_output -output; if (tec_direction HEATING) { __HAL_TIM_SET_COMPARE(htim3, TIM_CHANNEL_1, 0); HAL_Delay(5); TEC_DIR_GPIO_Port-BSRR TEC_DIR_Pin; // 切成制冷方向 tec_direction COOLING; } uint32_t compare_value (uint32_t)(abs_output / 100.0f * 999.0f); __HAL_TIM_SET_COMPARE(htim3, TIM_CHANNEL_1, compare_value); } else { __HAL_TIM_SET_COMPARE(htim3, TIM_CHANNEL_1, 0); } }这段代码虽然看起来简单但“开关方向保护”那两行是整套驱动最值钱的部分。调试过程中我至少因为这个换向问题烧了两片TEC原因就是方向切换太快H桥的关断还没完成就反向导通了。4. 实操过程PID参数整定到底怎么整4.1 整定前的开环测试PID调参前一定先把系统摸清楚。开环测试意思是只给定一个固定的PWM占空比记录温度随时间变化曲线搞清楚系统的响应时间、滞后时间、时间常数、还有最大升温/降温速率。这些数据是后面确定采样周期和PID参数范围的基础。我的测试方法是ADC采样的温度通过串口打印出来在电脑上用串口助手收数据记录下来之后放到Excel里画曲线。这个过程可能很笨但信息量极大。我测试时用的是TEC1-12706 铝块负载 热端CPU散热器满功率制热时温度从25度升到60度大约用了40秒升温速率接近1度每秒满功率制冷时从60度降到25度大约是30秒说明制冷方向比加热方向快。系统的“纯滞后时间”也在这个测试里清楚了。从发出PWM到温度探针读数开始变化大概滞后了2秒左右。为什么滞后热量从TEC表面穿过导热硅脂、穿过铝块传到NTC所在位置需要时间这是不可避免的热特性和安装位置决定的。滞后越大PID的Kp和Kd能调的范围就越小否则很容易振荡。4.2 先用保守参数跑起来我调PID不喜欢直接上什么临界比例度法先算个理论值因为很多新手在这个数学环节就被劝退了。我的做法是先给一组非常保守的参数让系统先跑起来、先看曲线走向然后逐步逼近。首次试验我用的参数是Kp 5.0Ki 0.02Kd 0.5两个方向共用一组。这个参数组合在大部分温控系统上不会振荡只会响应偏慢正好用来观察系统的“正常表现”和基线噪声。设定目标温度为40度从室温开始观察温度是逼近、是振荡、还是爬不上去。首次跑完的曲线很有价值温度在初段快速上升接近设定值时有一个明显超调大概超了2度左右然后回落再轻微超调一次在40度附近做衰减振荡稳定下来大约花了四分钟。稳定之后的波动范围大约是正负0.3度不算好但也不离谱说明PID逻辑和硬件整条链路是通的问题只是参数没到位。4.3 逐步收紧的调参操作下一步的操作方向有两个减小超调和提高稳定精度。增大Kd可以抑制超调同时适当提高Kp可以加快响应。我调整的节奏是每次只改一个参数改完至少观察三分钟记录曲线再决定下一步。第二次我改成Kp 8.0Ki 0.02Kd 1.2。结果超调明显减小了从2度降到了约0.8度但稳定时间还是有点长大概三分钟。此时我意识到Ki太小消除稳态误差主要就靠积分项0.02这个数值在误差为0.5度时积分项每秒只增加0.01%升温到40度到顶后残留的稳态误差需要累加很久。于是第三次把Ki提到0.08Kp保持8.0Kd保持1.2。实测下来稳定时间缩到了约80秒稳态波动降到正负0.1度以内效果很理想。此时制冷和加热方向的响应差异开始显露从35度降温到30度的小阶跃测试制冷方向的超调和振荡明显比加热方向大。于是我把制冷方向的Kp降到6.0Kd修到1.5Ki不变再测阶跃响应两个方向的行为就基本一致了。调参过程中我一直在用串口打印实时的PID数据目标温度、当前温度、误差、PID输出、方向状态。串口调试PID这个过程比看数码管高效太多了数据串出来就是实时曲线不然靠眼睛看数字根本看不出来超调趋势。正好热词里也提到“stm32串口调试pid”这确实是常干的事没有上位机的话就用串口把数据打出来然后用Excel画曲线效率也还可以。4.4 实验数据记录最终调试完成后的实测数据大概是这样负载为100g铝块环境温度约26度目标温度40度项目测试结果从25度升温到40度的稳定时间约65秒最大超调0.6度40度恒温时的稳态波动±0.08度从40度降温到30度的稳定时间约50秒制冷方向超调0.4度这个数据对大多数温控需求完全够用了。如果项目要求正负0.01度那种精度那要换更高分辨率的ADC、用PID参数自适应甚至上LQR或者模型预测控制但大部分场景真的用不到。5. 常见问题与排查技巧实录5.1 温度读数跳变不稳定的原因温度显示跳先别怀疑PID大概率是硬件链路上的问题。我用排除法来排查顺序是先用万用表直接测NTC两端的电阻看数值是不是稳定再测ADC输入引脚上的电压如果把电源的纹波一起量进去很大就是电源问题如果电压稳定但ADC读数跳那就是STM32的ADC配置或者参考电压问题。实际排查中最常见的原因有两个一个是直接用了开发板上的3.3V给NTC分压供电而这个3.3V来自一颗低压差稳压器的输出在PWM驱动TEC大电流的瞬间电源轨会有比较大的纹波直接污染了ADC参考。解决方法就是给NTC的供电做独立滤波或者干脆用一个独立的精密参考电压芯片比如REF3033。另一个是ADC采样时间太短STM32F103的ADC在12位分辨率下建议采样时间至少1.5us以上我用的是55.5周期的采样时间稳定很多。代码里我还加了一级一阶低通滤波对ADC原始值做平滑时间常数取100ms左右。不要用太长的滤波时间常数否则会把温度信号本身的有效变化也滤掉导致PID反应迟钝。5.2 TEC不动作或功率不足的排查如果PID输出有值但TEC不工作那问题基本出在驱动链路。先查GPIO方向脚的电平对不对再看PWM引脚的输出波形有没有用逻辑分析仪或者示波器看IN1和IN2。用万用表看PWM平均电压是不靠谱的因为占空比不同平均电压本来就不一样。还有一个特别容易踩的坑是STM32的JTAG引脚冲突。F103的PA13、PA14、PA15、PB3、PB4默认是JTAG功能如果你把这些引脚用作普通GPIO会发现电平怎么都拉不起来或者一拉就复位。我在早期规划引脚时差点就把方向脚放在PB4上后来才想起这个坑。解决方法是先调用__HAL_AFIO_REMAP_SWJ_NOJTAG()语句让PA15、PB3、PB4恢复普通GPIO功能或者干脆避开这五个引脚。另外一个实际遇到的是风扇不转导致TEC热端过热PWM大功率连续工作几分钟后TEC的效率急剧下降温度控制不住。后来程序中加了保护逻辑如果检测到当前输出接近100%且温度偏差长时间不收敛就关断TEC并报警。这个保护逻辑在长时间运行中真的救过系统一次。5.3 问题排查速查表故障现象可能原因排查与解决温度读数跳变剧烈NTC供电纹波大/ADC配置不对独立供电、增大采样时间、加滤波温度一直冲不停方向接反或PID参数过冲交换H桥方向脚测试、减小Kp增大Kd温度像正弦波一样振荡滞后太大或Kp/Ki过大增大Kd、减小Ki、检查传感器位置TEC完全不动作GPIO方向异常/PWM未输出/驱动烧毁测IN1/IN2波形确认电源和驱动芯片温度上位机显示的温度始终为负值NTC接线接反或分压电阻计算错误检查分压电路和查表数据控制一段时间后突然失控热端过热导致TEC反向检查散热风扇转速和风道加温度保护5.4 避坑技巧和长期运行心得这套系统如果要长期运行有几个细节值得花时间处理。第一是NTC传感器的固定方式和导热介质用导热硅胶把NTC粘在目标区表面比用双面胶更稳定老化慢导热系数更高。第二是TEC两端的导热硅脂会随着冷热循环逐渐干涸建议每半年重新涂一次否则热阻上升会引起控制性能的缓慢恶化。第三是不要反复让TEC在满功率和零功率之间快速切换对TEC的冷热冲击大会明显缩短寿命。可以在程序里加一个输出变化率限制让PID输出不能瞬间从0跳到100而是每100ms最多变化5%相当于给系统的执行器加了一个软化环节。这个技巧对温度超调也有抑制作用非常实用。另外控制程序里的采样周期也要固定好。我用的定时器中断频率是10Hz每100ms采一次温、算一次PID、刷新一次PWM。这个频率跟系统的滞后时间匹配得很好太高了容易造成积分的过度积累太低了控制不及时。具体到不同项目采样周期大约设定成纯滞后时间的十分之一到五分之一之间是比较合理的区间。从30度阶跃到50度再回到30度的整个过程从串口看数据、看曲线这套系统已经从“能转”进化到“好看”了。硬件上就是常见的TEC加散热器软件上就是STM32加一个PID控制器整个项目跑通之后回头看真正有价值的不是某个元器件选得多高级而是每一个环节都有据可依。把H桥换向逻辑、NTC查表插值、PID参数整定这些细节做扎实这套温度控制方案可以说就很成熟了。
返回列表