
做这个小制冷器项目最初是被学校里没法放冰箱的小需求逼出来的。到了夏天一杯冰咖啡想要留住低温实验器材需要短时间降温用小半导体制冷片搭配STM32做温控就成了一个既实用又能当毕设的选题。整块系统的核心思路并不复杂STM32负责采集温度、跑PID控制算法、驱动制冷片再加一块ESP8266或者用有线接口把数据传到物联网平台实现远程查看温度曲线和修改设定值。对正在做毕业设计或者想上手单片机物联网项目的同学来说这个项目的覆盖面非常合适既有传感器采集、PWM功率控制又有PID闭环算法和联网通信几乎是把单片机开发里最常用的模块都过了一遍。我用的主控是STM32F103C8T6成本不到十块钱资料多到数不清遇到问题基本都能搜到答案。温度传感器选了DS18B20一个引脚就能完成测温省GPIO。执行端是TEC1-12706半导体制冷片配上12V驱动电路和散热风扇。从实际跑下来的效果看一个10升以内的密闭小箱体大约25分钟能把温度从室温降到15℃左右如果设定值再低一些配合更好的热端散热还能往下走。这套方案最大的优点在于没有压缩机那种震动和制冷剂管路体积小、噪音低、控制响应快很适合桌面级的应用场景。1. 项目整体设计与方案选型1.1 制冷方案对比半导体制冷片为什么比压缩机更合适小型制冷器的核心矛盾在于“小型”两个字。传统压缩机制冷效率确实高但压缩机本身体积就占了大半空间还附带冷凝器、蒸发器、毛细管和制冷剂充注工艺做毕设的加工难度和成本都会成倍往上翻。半导体TEC制冷片的原理是帕尔贴效应两种不同的半导体材料串联成电偶对通直流电后一端吸热、另一端放热。只要把热端的热量及时带走冷端就能持续从目标物体身上吸走热量达到降温效果。对比维度半导体制冷片 TEC压缩机制冷体积重量小一体扁平结构大含多部件噪音振动几乎没有明显控制响应毫秒级调PWM即可慢启停频敏制冷温差视热端散热条件一般可达20-40℃大可低于环境温度40℃以上能效比较低1左右高2.5以上毕设成本单个TEC约20-30元部件多成本高对于毕设场景来说TEC最吸引人的地方是控制方式极其友好。想多冷给 PWM 占空比大一点想恒温PID算出的占空比直接输出。压缩机制冷在这个量级下很难做连续调节只能开开停停温度波动大也体现不出“设计”的深度。所以选TEC作为制冷执行器完全是冲着“可编程控制”这个核心来的。1.2 整个系统由哪几个模块组成把需求拆开来看小型制冷器要解决的不只是“通电制冷”这么简单它还需要有传感器、有控制器、有显示、有交互、有联网。我的系统框图在最终版本里分成了五层主控层STM32F103C8T6负责逻辑控制、PID运算、状态管理感知层DS18B20数字温度传感器放在箱体内采集实时温度执行层MOS管驱动电路 TEC1-12706制冷片 12V散热风扇交互层OLED显示屏 三个按键本地查看和设定通信层ESP8266模块通过串口发数据到物联网平台这个架构也是大多数物联网单片机项目的通用模板。毕设答辩时老师通常第一句就问“你系统由哪些部分组成各部分之间怎么通信”这个分层回答最能体现工程思维——先把系统从功能边界上切开再逐个击破。我当时画原型图时还特意把电源部分单独列出来12V输入给TEC和风扇5V给ESP82663.3V给STM32和OLED防止大电流负载工作时拉低逻辑电压。1.3 为什么选STM32而不是51或Arduino做毕设选型时51单片机可能也能完成基本制冷控制但物联网上报和PID算法会让它捉襟见肘。51内核不带硬件乘法器做定点PID乘除运算还能凑合一旦涉及浮点运算和JSON格式化字符串CPU占用率会非常难看。Arduino虽然开发快但毕设答辩时“工程设计含量”容易被老师挑刺。STM32F103C8T6属于Cortex-M3内核主频72MHz20KB RAM、64KB Flash。在这个项目里DS18B20单总线驱动时钟要求很严格PWM输出要能精准调频率和占空比串口要同时处理按键显示和ESP8266通信。STM32的定时器、USART、I2C、SPI外设配置非常灵活而且支持HAL库和标准外设库两套写法。我用的是标准外设库加一点HAL混合调试起来效率很高。实际运行PID算法和驱动OLED时CPU占用率不到20%留出了大量余量给后续扩展。2. 硬件电路设计与关键参数2.1 核心器件清单和引脚分配整个项目用到的物料不算多下面是核心器件的清单和我实际的引脚分配。引脚分配看似小事实际上很影响布线一开始没规划好后面飞线会乱成一团。功能模块器件型号接STM32引脚备注温度采集DS18B20PA1需接4.7k上拉电阻到3.3VOLED显示SSD1306模块PB6(SCL)、PB7(SDA)I2C模式地址0x3C按键设定轻触按键 x3PA4、PA5、PA6配置为上拉输入内部上拉即可制冷驱动IRLZ44N MOS管PA0(TIM2_CH1)PWM输出控制栅极联网模块ESP8266PA2(USART2_TX)、PA3(USART2_RX)串口通信115200需共地调试串口USB转TTLPA9、PA10打印日志方便调现场问题GPIO的分配有几个讲究。首先是DS18B20用的PA1单总线协议要求引脚能灵活切换输入输出且延时控制要精准所以选在APB2总线上、直接挂到GPIOA的引脚访问速度快、翻转时延小。其次是PWM输出PA0对应TIM2_CH1定时器2是APB1外设最大时钟72MHz分频之后能输出很宽的PWM频率范围。ESP8266的串口尽量避开调试串口这样在线调试时不会互相干扰。2.2 冷端温度采集DS18B20接线和信号处理DS18B20是Dallas半导体出的数字温度传感器量程-55℃到125℃12位分辨率模式下精度是0.0625℃在小型制冷器这个场景完全够用。它用的是一线总线1-Wire协议只靠一根数据线就能双向传输时钟和数据。这个设计省GPIO但代价是对时序要求极其严格。STM32主频72MHz每条指令的周期都是纳秒级直接用延时函数模拟时序必须把初始化、读位、写位几个关键延时调准确。实际使用时4.7kΩ上拉电阻是必须的。这颗电阻的作用是让总线在空闲时保持高电平因为DS18B20是漏极开路输出。很多第一次做单总线项目的同学漏掉这颗电阻结果读上来的温度一直是85℃或0℃排查半天找不到原因。DS18B20的数据引脚上还建议并联一个100nF电容滤掉单片机工作时产生的电源高频噪声。读取温度时并不需要每次都发Skip ROM指令。如果总线上只挂了一个DS18B20可以跳过ROM匹配直接发0xCC跳过后再发0x44启动温度转换。转换时间在12位分辨率下需要750ms。如果把它放在主循环里每秒钟读一次那就要注意不能让这750ms阻塞整个系统。我采用的方案是发完启动转换指令后不立刻等待而是去刷新OLED或者处理按键等下一次循环再读温度寄存器。这样系统看起来永远是“响应很快”的。2.3 驱动电路MOS管PWM调速的核心细节TEC1-12706的额定电压12V额定电流6A峰值电流甚至能到8A以上。直接用STM32的GPIO不可能驱动这么大电流中间必须加功率开关器件。我用的IRLZ44N是逻辑电平MOS管栅极阈值电压低3.3V的GPIO可以直接驱动不需要额外的电平转换电路。IRLZ44N最大连续漏极电流47A导通电阻0.022Ω余量很足即使长时间工作也不至于烫到离谱。驱动电路的接法非常简单MOS管漏极接TEC的负极TEC正极接12V电源正极MOS管源极接地。STM32的PA0输出PWM波经过一个100Ω电阻接到MOS管栅极电阻的作用是限制栅极充放电电流减少开关振铃。栅源之间再并一个10kΩ电阻确保单片机上电瞬间、GPIO尚未配置为PWM输出时MOS管栅极处于低电平不会出现TEC误启动导致上电就猛制冷的情况。这个下拉电阻经验不足的人特别容易漏掉。还有一点容易被忽略TEC是阻性负载但实际连接导线上也有寄生电感。MOS管关断瞬间会产生一个反向感应电动势如果不在TEC两端并联续流二极管尖峰电压很可能击穿MOS管。我用了一个1N5822肖特基二极管反并联在TEC两端实测关断时MOS管的漏源电压始终被钳位在安全范围内。3. 软件核心PID控温与显示逻辑3.1 主循环状态机设计一套清晰的控制流单片机程序最忌讳把所有逻辑都堆在main函数里一个while循环几百行改一处就要动全身。我使用的是状态机结构把系统分为开机初始化、运行制冷、温度恒定、待机几个状态状态之间通过事件切换。主循环做的事可以概括成先读取按键事件更新设定值再读温度传感器跑PID运算把PID输出映射成PWM占空比刷新OLED最后每5秒通过串口发一帧数据给ESP8266。这样每一步都短平快一旦某一步卡住串口日志能立刻定位到位置。尤其是在调试PID参数的时候这个结构让我能快速修改Kp、Ki、Kd参数值编译下载后直接观察曲线不用反复修改业务逻辑代码。主循环的伪代码如下while (1) { key_scan(); // 非阻塞扫描按键 if (key_pressed) update_setpoint(); temp_value read_temp(); // 如果转换未完成返回上一次值 pid_output pid_calc(setpoint, temp_value); pwm_set_duty(TIM2, pid_output); oled_refresh(); if (report_tick 5000) { mqtt_report(temp_value, setpoint, pwm_output); report_tick 0; } delay_ms(10); }这个10ms的主循环节拍是精心选的。PID运算周期10ms也就是控制频率100Hz对于热惯性很大的制冷系统来说完全足够。如果循环太快传感器噪声反而会让PID输出抖动太慢则温度波动大。传感器本身有750ms的转换时间所以read_temp函数返回的是最近一次有效转换值并不会因为读取频率高于传感器刷新率而出错。3.2 PID控温从公式到可运行的代码PID控制是整个系统设计的灵魂。假设目标温度是15℃当前温度是25℃控制目标就是让制冷片输出适当的功率使温度以合适的速率降到15℃并维持稳定。单纯的开环模式没法做到这一点固定100%功率制冷温度会一路往下冲固定50%功率又会由于环境温度变化导致稳态误差。PID算法的输出公式是u(k) Kp * e(k) Ki * Σe(k) * Δt Kd * [e(k) - e(k-1)] / Δt其中e(k)是当前误差Δt是采样周期。一上来直接实现位置式PID会遇到一个问题输出是绝对值一旦误差历史累计值很大上电瞬间就可能输出100%占空比导致系统过调。所以我改用了增量式PID输出的是“PWM占空比的增量”每次在上一次的基础上微调。这样上电时从零开始系统永远是在平缓过渡。增量式PID在实际代码里长这样float pid_update(float setpoint, float temp) { float error setpoint - temp; float output; pwm_out Kp * (error - last_error) Ki * error Kd * (error - 2 * last_error last_last_error); if (pwm_out 100.0f) pwm_out 100.0f; if (pwm_out 0.0f) pwm_out 0.0f; last_last_error last_error; last_error error; return pwm_out; }这段代码里最关键的调参过程我用的是工程上常用的“先P后I再D”法。先把Ki和Kd置零只调Kp从很小的值开始逐步增大直到温度出现轻微振荡然后取振荡临界值的一半作为Kp。再加入KiKi取Kp的十分之一到五分之一用来消除稳态误差。最后加少量Kd抑制超调。实际调下来Kp8Ki1.5Kd0.2效果就比较理想了。调参时建议把整定过程记录下来打印到串口观察曲线。我后来发现只看OLED上的瞬时温度根本看不出趋势必须用OLED画简易曲线或者直接把数据打到串口上位机里看。这一点对后面物联网上报的数据可视化反而是一种正向铺垫。3.3 显示与交互一分钟看懂本地界面OLED采用SSD1306控制器128x64分辨率用I2C接口只需要两根线。显示内容我分成了三行第一行显示实时温度第二行显示设定温度和当前PWM输出百分比第三行显示TEC的工作状态。按键方面三个按键分别承担“模式切换”“设定值加”“设定值减”的功能。按住加减键时设定值连续变化变化步长0.5℃。OLED刷新有个讲究不要在每次循环都重复绘全屏。SSD1306的I2C速率最多400kHz全屏刷新一次要传1024字节大约需要20ms以上这个时间在主循环里占比太大了。我改成只在温度值或者状态变化时更新对应的局部区域这样肉眼看着流畅也不会拖慢PID运算的节奏。另外OLED模块上拉电阻很多山寨板已经内置时钟线数据线直接接单片机即可不用额外接上拉。4. 物联网远程监控从串口到云端4.1 通信架构STM32怎么和ESP8266配合物联网部分按真实“联网”流程走我用的是最稳的方案STM32通过串口2发送AT指令控制ESP8266模块ESP8266以TCP客户端方式连到MQTT服务器。选择MQTT协议而不是HTTP是因为MQTT是长连接每次温度上报只需几字节开销且服务器端能缓存离线设备的数据适合传感器这种低功耗高频次上报场景。通信链路是这样STM32将温度、设定值、PWM输出百分比打包成JSON字符串通过串口发给ESP8266。ESP8266里已经烧写好了带MQTT透传功能的AT固件只需要发送ATMQTTCONN连接服务器然后ATMQTTPUB发布主题。这种方案的好处是把WiFi协议栈和TCP/IP协议栈全部丢给ESP8266处理STM32只负责业务逻辑开发量小很多。JSON数据格式设计如下{ temp: 15.6, setpoint: 15.0, power: 62 }这个包大约50字节串口115200的波特率下发送消耗不到5ms几乎不影响控制实时性。在上位机端可以用Python脚本接收、解析数据入库也可以用现成的物联网平台直接看曲线。4.2 通信协议设计怎么保证数据不出错串口通信最怕的就是数据错位。如果STM32发送数据的节奏和ESP8266接收的节奏不一致或者中间有某个字节丢失ESP8266收到的JSON就是断的MQTT发布出去也是乱码。我从一开始就定了基本规则每条上报数据以‘{’开头、‘}’结尾采用固定字段顺序STM32每5秒只发一帧ESP8266侧不回应答。因为MQTT本身有TCP的确认机制ESP8266收到完整JSON后再发布出去的可靠性由MQTT协议保证。ESP8266的初始化配置在首次使用时需要用串口助手手动设一次工作模式选STA连上路由器WiFiMQTT服务器地址填你的云服务器IP或域名端口1883设备接入的clientID和主题名提前规划好设置完用ATSAVE命令保存配置。之后STM32复位只要串口发送ATMQTTCONN指令ESP8266就能自动恢复连接。我在代码里加了断线重连逻辑ESP8266返回ERROR后STM32等待5秒重新发送连接指令。实测家庭WiFi环境下模块连上路由器后几乎不掉线稳定性够用。4.3 远程控制云端修改设定值只上报数据在毕设里的“物联网”属性还差一点。有联网能力最好还能双向控制。MQTT天然支持订阅主题我在服务器端配置了一个下行主题STM32周期性订阅当云端下发新的设定温度时解析指令并更新本地设定值。下行消息也走JSON格式例如{cmd: set, value: 12}STM32收到后通过strstr函数从字符串里提取数字然后转成浮点数更新到全局变量setpoint。远程控制空调、远程设置鱼缸温度的经典动作在这个项目里就落地了。这一部分给答辩加分很多因为演示现场用手机改一个温度然后看着屏幕上的实际温度缓缓降下去效果非常直观。5. 联调实测与问题排查5.1 实测数据从27℃降到10℃用了多久整机组装完成后我在室温约27℃的环境里做了静置降温测试。测试对象是一个10升的保温箱体TEC冷端贴在箱体内壁热端外挂铝挤散热片加12V风扇。设定温度10℃初始温度27℃记录每隔2分钟的温度值。时间(分钟)箱内温度(℃)当前PWM输出(%)备注027.0100启动热端风扇全速222.5100降温速度最快419.1100仍在全力制冷616.4100接近目标814.782PID开始收功率1013.265接近稳态1211.852温度缓慢下降1411.045接近设定值1610.438稳定1810.135基本恒定这个结果说明半导体制冷片在给10升箱体降温时的能力大概就是这样前6分钟最快的降温速率约1.8℃/分钟之后由于热端散热压力增大制冷效率逐渐下降。实际运行2小时后温度稳定在10℃附近波动范围不超过0.5℃。如果想降温更快备选方案是换更大电流的TEC或者给热端加水冷排但这会提高成本和结构复杂度毕设范畴内目前的性能已经够展示。5.2 踩坑记录五个最容易翻车的地方硬件问题里最离谱的一次是TEC刚接上电STM32就不断复位。查了半天发现是12V 6A电源在TEC启动瞬间电流过大导致电源输出电压跌落3.3V也跟着掉单片机就复位了。解决办法是在12V输入端并联了一个470μF电解电容和几个100nF陶瓷电容提供瞬态电流支撑。如果驱动负载再大就得上软启动PWM从0开始慢慢升到目标值。还有一次温度显示卡在85℃不动排查后确定是新买的散装DS18B20没有初始化好读到的默认值是85℃。重新上电、把初始化延时调长到480μs之后恢复正常。DS18B20的上拉电阻也很重要我最初图省事用了一根杜邦线飞线测试没有上拉电阻读回来的数据全是乱码。焊接的时候才发现其实面包板跳线虽然看着方便但接触不良和寄生电容问题会让单总线时序变得极不稳定后来改成直接焊在洞洞板上问题彻底消失。PID参数不当还导致过一次温度大幅振荡。最开始Kp30温度到设定值附近时PWM输出剧烈抖动箱内温度上下波动接近3℃。后来按“先P后I再D”的顺序把Kp降到8Ki设1.5Kd设0.2曲线立刻平滑下来。调参这件事没有任何捷径就是一轮一轮看曲线。我曾把PID的输出打点到串口里配合Python拿matplotlib画出来比自己盯着OLED硬猜高效太多。5.3 常见问题与排查技巧速查表现象可能原因排查重点温度一直显示85℃DS18B20初始化失败检查上拉电阻检查初始化时序延时温度波动超过2℃PID参数不合适先降Kp再检查传感器是否固定牢靠一上电单片机就复位电源被TEC拉垮加电容缓冲软启动或分时供电MOS管烫手开关频率太高或驱动电阻不当降低PWM频率检查栅极串联电阻ESP8266无法连接MQTT路由器限制或配置错误检查SSID密码确认端口1883开放OLED显示花屏I2C速率过高或接线过长降低I2C时钟到100kHz检查线长排查这些问题的通用方法论我总结出来就一句话先硬件后软件先模拟后数字。所有现象列出来先确认电源电压、检查MOS管温度、听风扇有没有转、摸散热片是不是烫的这套“看听摸”大法能排除80%的硬件故障。软件层面的问题用串口打印是最直接的手段。从一开始就把UART日志打好比如温度读取值、PID输出值、ESP8266返回的AT响应出问题后几分钟就能定位到具体模块。6. 扩展思路与个人经验做完这个基础版之后我紧接着做了几个小升级都基于现有硬件改软件就能实现把DS18B20换成NTC热敏电阻加ADC采样响应速度会明显更快。DS18B20的750ms转换时间对普通恒温箱够用但如果想看到更精细的升温降温过程NTC配合ADC的采样率能做到毫秒级。代价是NTC阻值-温度关系是非线性的需要查表或者用Steinhart-Hart公式计算。再把单路TEC控制扩展成双路就能实现半导体制冷制热双向温控。TEC本身就是可逆器件换向电流就能从制冷变制热。通过H桥电路改变电流方向再配合PID和死区控制一个小盒子就能实现全年恒温。我自己试过用两片TEC做“冷热两用杯垫”冬天加热夏天制冷效果还挺好。在物联网上报方面如果不想依赖HTTP轮询可以用ESP32代替“STM32ESP8266”的双芯片方案。ESP32自带WiFi和蓝牙以及双核处理器单芯片就能跑FreeRTOS、WiFi协议栈和MQTT客户端。前期用STM32学会了底层逻辑切到ESP32几乎是无缝的只是把UART发AT指令换成直接调用WiFi库就能实现。对于做毕设的同学们我最后再唠叨一句永远不要把所有时间放在“能不能跑通”上多花点精力想清楚“为什么这么设计”。答辩时老师关心的不是你的程序能跑而是你对系统设计的理解深度。比如为什么选增量式PID而不是位置式PID、为什么PWM频率选1kHz而不是10kHz、为什么TEC热端要用风扇强冷——这些问题真被问到时能解释清楚项目分数就不会低。我在实际设计中的体会是给热端散热片与TEC之间涂上一层薄薄的导热硅脂降温速度提升非常可观这一个小细节往往比换个更大功率的TEC更有效果。