
简介本资源是一套基于STM32F103系列的智能控温水杯完整嵌入式设计工程面向电子类本科生、嵌入式初学者及课程设计/毕业设计实践者解决多传感器融合控制、人机交互与蓝牙远程协同等典型物联网应用开发问题。压缩包共287个文件含57个C源文件如stm32f10x_adc.c、stm32f10x_i2c.c等底层驱动、58个编译中间文件.o/.d、39个头文件.h及Keil工程核心文件.uvprojx、.sct、.hex另有OLED显示、DS18B20温度采集、舵机杯盖控制、继电器加热/直流电机制冷等模块的完整实现代码与Proteus 8.15仿真工程.pdsprj整体大小23.88MB。已有152人学习下载配套包含可运行的.hex固件、详细功能说明文档.docx及系统工作原理WMV演示视频覆盖自动温控20–30℃区间调节、水质阈值报警300触发、按键可调饮水提醒倒计时、本地/蓝牙双模控制等全部功能点工程结构规范便于理解外设驱动整合与状态机逻辑设计。 做了这么久嵌入式我越来越发现一个规律真正让人觉得“有点意思”的项目往往是那些看起来不起眼、但日常高频使用的东西。比如这次要聊的智能控温水杯——听起来不就是个加热杯垫加个温度计吗但当你真的用STM32把整套系统跑起来从温度采集、加热控制到显示交互、低功耗管理每一个环节都踩得到真实的坑。这个项目很适合拿来练手既能覆盖单片机开发的常见外设又能逼着你把控制逻辑想清楚。我用的主控是STM32F103C8T6也就是大家常说的“蓝 pill”核心板。选它的原因很简单便宜、资料多、随便搜都是现成的工程模板。如果你想做低功耗版本用STM32L0或者G0系列也完全可以逻辑基本一致只是时钟和低功耗配置略有差异。这篇文章我尽量把设计思路、电路细节、代码框架和调试过程都摊开讲方便你直接照着搭一个能用的版本。1. 项目概览为什么用STM32做控温杯1.1 智能控温杯要解决的几个核心问题先想清楚这个产品到底要干什么。市面上那种普通保温杯只能物理隔热热水放进去慢慢变凉凉了想喝还得倒出来加热。智能控温杯的逻辑其实很直白让杯子里面的水恒定在你设定的温度比如你设45℃它就通过加热片把水温维持住随时拿起来喝都是刚好入口的温度。要实现这个目标至少要拆成四个事感知温度、控制加热、人机交互、供电续航。感知温度用NTC热敏电阻或者DS18B20都行控制加热用MOS管驱动加热片交互用OLED屏加按键供电用锂电池加充电管理。这四个模块听上去都不复杂但串在一起之后电源噪声、ADC采样跳变、加热开关瞬间电压跌落、温度控制过冲这些问题全都会冒出来。1.2 主控选型为什么是STM32而不是其他方案有人会问这玩意儿用个555定时器加运放是不是也能做确实能但那种方案只能实现简单的开关控制没法做到“设定温度、实时显示、温度曲线平滑”。用STM32的核心优势在于你可以用ADC连续采样温度用定时器输出PWM控制加热功率用I2C驱动OLED显示再用串口打印调试信息——所有事情都围绕一个主控展开调试起来非常舒服。我选STM32F103C8T6还有一个现实原因好买、好焊、好烧录。淘宝几块钱一片ST-Link下载器便宜量又足万一芯片烧了也不心疼。而且STM32的HAL库和标准库资料铺天盖地遇到问题搜一下基本都有答案。对于这种软硬件结合的小项目开发效率是第一位的。2. 整体方案设计与硬件选型2.1 系统架构与关键模块拆分整个系统的框图可以分成三层理解。最底下一层是电源系统锂电池经过充电芯片管理同时输出两路电压一路给加热片直接供电另一路经过LDO稳压到3.3V给单片机、传感器和屏幕供电。中间一层是感知与控制NTC温度传感器通过分压电路接到STM32的ADC引脚单片机根据温度数据输出PWM信号控制MOS管的导通占空比从而控制加热功率。最上面一层是交互OLED显示当前温度和设定温度按键用来调整目标温度值。这里有个很重要的设计原则加热回路和信号回路要尽量分开。加热片工作电流大瞬间电流可能到1A以上如果和传感器的地线走在同一条线上ADC采样值会被拉得乱七八糟。我在画PCB和接线时会把功率地的走线单独拉出去最后在电池负极的地方做单点汇接。2.2 传感器、加热片与电源方案的具体选择先聊温度传感器。我试用过DS18B20和NTC两种方案。DS18B20是数字输出直接用单总线协议读温度不需要ADC精度也可以做到0.5℃但问题在于它的测温速度偏慢默认12位分辨率下一次转换要750ms而且单总线时序在系统里有中断时容易被干扰。NTC的方案是模拟量输出通过分压电阻接到ADC引脚采样速度快响应也快配合软件滤波做出来的温度曲线非常平滑。我最终选了NTC 10K B3950也就是25℃时电阻10K、B值为3950的热敏电阻。分压电阻也用10K电源3.3V供电。这样在25℃时输出电压正好是1.65VADC采集值大约在2048左右落在中间位置动态范围比较合理。加热片用的是12V的PTC加热片但在锂电池供电场景下不能直接用12V所以我改用5V的PTC加热片大概8Ω左右电池3.7V供电时理论功率在1.7W左右够把一个300ml的水杯在合理时间内加热到设定温度。电源部分比较常规TP4056充电模块负责锂电池充电一个LDO把电池电压稳到3.3V给单片机供电。要注意的是不要用AMS1117-3.3直接接锂电池因为AMS1117的压差大电池电压掉到3.6V左右输出就稳不住了。我换成XC6206或者ME6211这类低压差LDO压差只有几百毫伏能用到电池电量基本放完续航会好很多。3. 核心硬件电路设计要点3.1 温度采集电路NTC分压与ADC采样NTC分压电路的接法看起来很基础但采样结果准不准很大程度上取决于你怎么接。传统接法是NTC从3.3V接电阻再到GND中间抽头进ADC引脚。我习惯把NTC放在高端也就是3.3V先经过NTC再经过固定电阻到GND这样在温度升高、NTC阻值下降时ADC引脚的电压是上升的对应关系更直观。实际测量时ADC引脚的高输入阻抗容易受到外界噪声干扰所以我会在ADC引脚与GND之间加一个0.1uF的滤波电容这个电容能滤掉大部分高频噪声。另外STM32的ADC是12位的输入范围0到3.3V我开发时用DMA循环采样每次连续采8个点取平均能有效减少随机抖动。温度换算这一步网上有各种查表法但我更推荐直接用公式算。先用ADC值算回电压V adc_value / 4096 * 3.3然后根据分压关系算NTC当前电阻值R R_fixed * (3.3 - V) / V。有了电阻值之后用B值公式就能算温度T 1 / (1/T0 ln(R/R0) / B) - 273.15其中T0取298.15K即25℃R0是10KB是3950。这个公式算出来的温度误差在±1℃以内对这个项目完全够用。如果你用的传感器不是10K B3950只要把参数换掉就行。3.2 加热驱动电路MOS管开关与PWM控制加热控制是另一个核心点。驱动加热片最简单的方式是用MOS管做低端开关加热片一端接电池正极另一端接MOS管的漏极MOS管源极接地栅极通过一个电阻接到单片机的PA1引脚。我选的是AO3400这是一颗很常用的N沟道MOS管Vgs阈值低3.3V就能完全导通导通电阻只有40毫欧左右1A电流下压降可以忽略。栅极电阻我也是经过考虑的。单片机引脚输出是数字信号驱动容性负载MOS管栅极时会有一个电流尖峰。串联一个10Ω到100Ω的电阻可以限制栅极充电电流既保护了单片机IO口也减少了开关噪声。为了避免MOS管意外导通我还在栅极和地之间并了一个10K的下拉电阻这样单片机复位期间加热片是断电状态更安全。控制策略上我承认自己一开始也想直接上PID试过之后才发现对这个系统来说用滞回控制或者简单的PWM固定占空比控制反而更实用。原因后面详细说。3.3 显示与人机交互OLED与按键设计显示模块我用的是0.96寸的I2C接口OLED屏SSD1306驱动芯片四根线搞定VCC、GND、SCL、SDA。STM32的硬件I2C用起来有点别扭很多老手都改用GPIO模拟I2C因为时序自己控制不会出现奇怪的总线卡死问题。我也走了模拟I2C路线代码简单可靠。屏幕显示内容分三块左上角实时温度右上角设定温度下方用进度条表示当前温度占设定温度的比例再加一个加热状态图标加热时显示实心块恒温时显示空心块。按键部分用了三个轻触开关模式键、加键、减键。模式键用来切换“保温模式”和“快速加热模式”在快速加热模式下目标温度默认是100℃但实际加热到85℃就停了防止水烧干加键和减键每按一次调整1℃长按自动连加。按键消抖不能在主循环里做delay我放在定时器中断里每10ms扫描一次连续3次采样值一致才确认按键有效这样既不阻塞主流程又很稳定。4. 软件逻辑与代码实现4.1 工程结构与初始化配置软件框架我选择使用标准库主要还是因为熟悉。现在ST官方主推HAL库但标准库的老工程在GitHub上一抓一把F103系列的标准库代码非常稳定外设寄存器的手册资料也齐全出了问题可以直接扒寄存器看。如果你是刚开始学STM32用标准库反而更容易理解底层运行的逻辑。初始化顺序很关键我的习惯是先配置系统时钟然后初始化GPIO、ADC、DMA、定时器、I2C、串口最后初始化OLED和按键。时钟用内部8MHz晶振倍频到72MHz这是F103最常用的主频。我在ADC配置上踩过一次坑如果不把ADC的采样周期调大一点采样值会偏小原因是ADC内部的采样电容没充满电。我在代码里把采样周期设为55.5个时钟周期比默认值大不少测出来的电压就准多了。4.2 温度采样与滤波算法前面提到用ADCDMA连续采样具体来说我让ADC在规则通道上循环扫描每次转换完成由DMA把结果搬到内存数组里。DMA传输长度我设了8即一次触发搬运8个16位数据采样完成后在主循环里对这8个数据做冒泡排序去掉最大最小值剩下的取平均。这种做法比单纯算术平均更能抗脉冲干扰。滤波之后就是温度换算。公式计算有浮点运算对F103来说完全没压力但如果你用的是低端的Cortex-M0单片机建议做一个对照表用二分查找的方式快速定位温度值省去浮点运算的时间。我自己的参考实现里还是保留了浮点版本因为代码可读性更好。采样周期需要注意不要一直在采也不要采太慢。我用定时器触发ADC采样频率设为10Hz即每100ms完成一次完整的换算。这个频率下温度显示不会有肉眼可见的滞后同时滤波窗口内的数据变化也不会太剧烈。4.3 温控策略滞回控制与PID控制这是整个项目最有嚼头的部分。最开始我天真地想用PID肯定比简单的开关控制高级。但跑起来之后发现不对劲加热惯性大、传感器离加热片距离远、散热条件不固定PID参数稍微调不对就会振荡温度在目标值附近来回穿反而很难看。后来我改成滞回控制。伪代码逻辑是当水温低于目标温度1.5℃时打开加热输出100%占空比当水温高于目标温度1.5℃时关闭加热在中间1.5℃范围内保持上一状态。这样做的好处是加热不会频繁通断温度波动范围也就3℃左右对喝水来说完全感觉不到。如果你想要更平滑的温度曲线另一个可用的方法是固定占空比PWM控制当温度低于目标值5℃时PWM占空比设80%全速加热距离目标值3℃到5℃时降到50%距离1℃到3℃时降到20%到了目标值就停止。这种分档控制本质上是一种查表法变体虽然不像PID那样理论上最优但胜在稳定不用反复调参数。我的经验是热水杯这种惯性大、响应慢的系统不要一上来就追求高精度的连续控制算法先把滞回控制跑稳再考虑要不要换成更复杂的策略。4.4 显示刷新与按键处理显示刷新我放在主循环里每200ms执行一次。OLED屏幕是I2C接口速度有限刷新太频繁反而闪烁而且会占用大量主循环时间。LCD显示内容如果在没有变化时不重绘能省电很多。我在代码里加了一个脏标记位温度变化超过0.5℃才更新温度数字按键状态改变才更新设定值这样大部分时间屏幕数据其实没有刷新静态画面由SSD1306内部RAM保持不需要外部干预。按键处理放在定时器中断里每10ms扫描一次按下和松开都记录时间通过比较按下时长区分短按和长按。加键短按一次加1℃长按500ms后进入连发模式每150ms自动加1℃这个交互逻辑在调整温度时非常顺手不用一下一下戳按键。中断里只做按键状态收集不做温度处理这样中断服务函数很短不会影响系统实时性。5. 调试过程与常见问题排查5.1 串口调试与参数观察硬件调通了之后软件调试是重头戏。我第一件事就是配置串口1把printf重定向到UART。调试时每隔500ms打印一次当前ADC原始值、计算出的电压、温度、目标温度、加热状态。串口输出的作用比你想象的还要大很多问题看屏幕是看不出来的但一旦打印出来数据一对比原因就很明显。比如我有一次发现温度跳到90℃多但触摸杯壁明显不烫一看串口数据才发现ADC值突然跳到4000多。查下来是加热片开关瞬间地线上的干扰把ADC引脚电压冲高了。后来加上滤波电容、调整采样时机问题才解决。这些都是靠串口日志一点点定位出来的。5.2 电源干扰、ADC跳动与地线处理这个项目最大的坑基本都集中在电源上。锂电池供电时电池电压从4.2V慢慢降到3.3V加热片功率也在慢慢变小。如果ADC的参考电压直接接在这个波动的电源上采样值就不准。好在STM32的ADC参考电压就是VDD而VDD经过LDO稳压后是稳定的3.3V所以影响不大。但要注意的是电池电压不稳会影响加热片的发热功率低温环境下尤其明显。ADC跳动这个问题我前后解决了两轮。第一轮是在硬件上加滤波电容第二轮是在软件上做多次采样取中位值平均。两个手段都有效但真正解决是在我把加热片的驱动MOS管和ADC采样引脚拉开距离、并且把采样时间安排在加热PWM的关断时段之后。也就是说我让温度采集不在MOS管导通的瞬间附近进行避开开关噪声。这个思路其实在很多工业控制里叫“同步采样”放在这么小的项目里是最有效的抗干扰手段。5.3 低功耗与续航优化最后说说续航。如果你只是拿这个杯子当桌面摆件一直插着USB电源那续航不用管。但如果你做的是便携版就必须考虑低功耗。STM32F103在正常运行模式下功耗大概在20mA到50mA之间但进入STOP模式后可以降到几十微安。我的做法是超过5分钟没有任何按键操作并且水温稳定在目标温度附近时系统进入STOP模式。OLED彻底断电只有定时器唤醒每5秒醒来一次快速采一次温度如果温度跌破阈值就立即唤醒主控加热。这样折腾下来一块1000mAh的锂电池每天正常使用2小时大概能撑两到三天。主动关屏省电效果最明显——OLED屏的驱动IC在工作时电流能有20mA比STM32本身还费电。另外一个值得注意的点是看门狗。低功耗和看门狗天然存在冲突因为低功耗模式会停止喂狗如果配置不好设备会不断复位。我用的方案是进入STOP模式前关闭独立看门狗醒来后重新初始化。虽然麻烦一点但能保证系统万一跑飞也能自己恢复不至于需要拆杯重启。6. 实测效果与心得扩展整机做出来后实测数据是这样的室温25℃环境下250ml常温水从25℃升温到45℃用时大概6分钟升温过程功率恒定温度曲线在滞回控制下波动不超过±2℃。设定45℃恒温杯环境温度变化时温度能稳定保持。这个性能对日常使用来说已经足够体感舒适了。我个人做完这个项目最大的收获不是学会了几句标准库的配置而是明白了做嵌入式项目一定要“先跑通、再优化”。很多初学者喜欢一上来就把原理图画得很复杂把算法调得很高端但最后往往卡在某个小问题上出不来。我这次的节奏是先用现有的模块搭一个雏形让温度能显示、加热能开启、按键能调整目标值然后再一步一步把手感做好把干扰干掉把功耗降下来。如果后续想继续扩展有几个方向我觉得挺有意思。一是加蓝牙模块用手机App远程查看温度和调整目标值STM32出BLE数据透传是经典玩法二是换成STM32G0系列利用它更低功耗的特性做真正的便携版本续航能做到一周以上三是加一个水流传感器实现喝水提醒功能。总而言之这个项目的框架是很标准的“传感器控制交互电源”四层结构换一个产品方向比如智能花盆、孵蛋器、宠物暖垫思路完全可以直接迁移。本文还有配套的精品资源点击获取