1. 项目缘起与整体设计思路
夏天喝饮料最怕什么?不是买不到,是刚倒出来的冰可乐,接个电话回来就变温吞水了。市面上带制冷的杯子要么贵得离谱,要么制冷片功率小得可怜,基本属于“心理安慰型”产品。我去年夏天就琢磨着自己攒一个真正能打的智能制冷杯,要求很明确:半导体制冷片直接贴着杯壁干活,ESP32-C3做主控负责调温逻辑和人机交互,OLED小屏实时显示当前温度和设定温度,供电用Type-C口走PD诱骗拿12V,整体塞进一个普通保温杯大小的壳子里。
这个项目在立创EDA上从原理图到PCB打样前后折腾了差不多三周,中间踩了不少坑,也积累了一些在常规教程里看不到的经验。整杯的核心逻辑其实不复杂:制冷片冷面贴铝制导冷块,导冷块伸进杯体内壁,热面接散热鳍片加风扇往外排热。ESP32-C3通过NTC热敏电阻采集杯内温度,用PWM驱动MOS管控制制冷片功率,同时用另一路PWM调速风扇。OLED走I2C,两个按键负责调温和开关。听起来简单,但实际做起来,制冷片的功率匹配、MOS管的散热、PWM频率的选择、I2C上拉电阻的取值,每一个细节都能让你多打一次样。
适合谁来参考这个项目?如果你已经玩过ESP32或者STM32的基础开发,会用立创EDA画简单的双层板,想找一个综合了模拟采样、PWM功率控制、I2C显示和电源管理的练手项目,那这个制冷杯非常合适。它不像纯软件项目那样只调代码就行,也不像纯硬件项目那样焊完就完事,软硬结合的部分才是最有意思的地方。下面我把整个设计思路、关键参数计算、实操步骤和踩坑记录全部摊开讲,你照着做基本能少走八成弯路。
2. 核心器件选型与关键参数计算
2.1 半导体制冷片到底选多大功率
半导体制冷片(TEC)的选型直接决定了这个杯子是“真制冷”还是“假把式”。市面上常见的TEC规格有TEC1-12706、TEC1-12710、TEC1-12715等,数字越大代表制冷功率越高,但同时发热量和电流也越大。我一开始想用TEC1-12715,觉得功率大制冷快,后来算了一下账就放弃了。
TEC1-12706在12V下的典型工作电流约6A,功耗72W,制冷量大约50-60W。TEC1-12715在12V下电流能到15A,功耗180W,制冷量约120W。看起来12715猛得多,但问题是:你的散热系统能不能把180W的热量排出去?如果热面散热跟不上,冷面温度反而会升高,因为热量会从热面倒灌回冷面。对于杯子这种小体积设备,散热鳍片的面积和风扇的风量都是有限的,我实测用12706配一个40×40×20mm的铝鳍片加5V小风扇,热面温度稳定在45-50度左右,已经比较理想了。换成12715,热面直接飙到70度以上,制冷效果反而变差。
所以最终选型是TEC1-12706,12V供电,实际运行时通过PWM把平均功率控制在50%-80%之间,既保证制冷效果又留出散热余量。这里有个经验:TEC的冷热面温差越大,制冷效率越低。也就是说,如果你想把一杯30度的水降到5度,最后那段从10度降到5度的过程会非常慢,因为温差大了之后TEC的泵热能力急剧下降。所以实际使用中,设定温度不要低于环境温度15度以上,否则等待时间会让你怀疑人生。
2.2 MOS管驱动电路与PWM频率选择
ESP32-C3的GPIO输出是3.3V电平,驱动电流最大也就几十毫安,直接驱动TEC肯定不行,必须用MOS管做功率开关。我选的是IRLZ44N,这是一颗逻辑电平N沟道MOS管,Vgs(th)最低只要1V就能导通,3.3V驱动完全没问题。如果是用普通的IRF540N,3.3V下根本导不通,这是新手最容易踩的坑之一。
PWM频率的选择也有讲究。频率太低(比如100Hz),TEC会因为电流断续而产生噪音,而且温度波动明显;频率太高(比如100kHz),MOS管的开关损耗会急剧增加,发热严重。我试过1kHz、5kHz、20kHz三档,最终定在20kHz。原因有两个:一是20kHz刚好在人耳听觉范围的上限附近,TEC基本听不到啸叫声;二是IRLZ44N在20kHz下的开关损耗还可以接受,配合一个小铝片散热器,MOS管温度在50度左右。
PWM占空比和制冷功率的关系不是线性的。TEC的等效电阻约2欧姆,12V下满功率电流6A。但PWM斩波时,TEC两端的平均电压下降,电流也跟着下降,实际功率大约是占空比的平方关系。也就是说,50%占空比下,实际制冷功率只有满功率的25%左右。这个特性在调温算法里要考虑进去,不能简单地用线性映射。
2.3 NTC温度采样与分压电阻计算
温度采样用的是10kΩ的NTC热敏电阻,B值3950。分压电路很简单:NTC一端接3.3V,另一端接一个10kΩ的固定电阻到GND,中点接到ESP32-C3的ADC引脚。25度时NTC阻值10kΩ,中点电压正好是1.65V。ESP32-C3的ADC是12位的,参考电压3.3V,理论上分辨率是3.3V/4096≈0.8mV。但实际用下来,ESP32-C3的ADC线性度一般,特别是在接近0V和3.3V的两端误差较大。所以分压电阻选10kΩ是合理的,让工作点落在ADC的中间区域。
NTC的阻值和温度关系是指数型的,公式是Rt = R0 * exp(B * (1/T - 1/T0)),其中R0是25度时的阻值10kΩ,T0是298.15K,B是3950。反过来求温度就是T = 1 / (1/T0 + ln(Rt/R0)/B)。在代码里我直接用查表加线性插值的方式,比每次算浮点对数快得多,也更省电。表格每隔5度一个点,从0度到100度共21个点,插值误差在0.2度以内,完全够用。
2.4 OLED显示与I2C上拉电阻
OLED用的是0.96寸SSD1306,128×64分辨率,I2C接口。这个屏在3.3V下工作很稳定,但有一个细节要注意:I2C总线的上拉电阻。很多模块自带上拉电阻,通常是4.7kΩ或10kΩ。如果你用的模块已经带了,就不需要额外加;如果没带,必须在SDA和SCL上各接一个4.7kΩ到3.3V。我一开始用了一个没带上拉的裸屏,死活点不亮,查了半天才发现是上拉电阻的问题。
I2C的速率我设在400kHz,刷一屏大概需要20ms左右,对于温度显示这种低频刷新完全够用。SSD1306的显存是1KB,ESP32-C3的RAM有400KB,随便挥霍。显示内容我做了三行:第一行显示当前温度,第二行显示设定温度,第三行显示PWM占空比和制冷片状态。字体用的是6×8和8×16两种,当前温度用大字体,看着清楚。
3. 立创EDA原理图与PCB设计实操
3.1 原理图绘制中的网络联动与星型接地
立创EDA专业版的原理图绘制体验比标准版好很多,特别是网络联动功能。在原理图里选中一个网络,PCB里对应的走线会高亮,这个在检查连接时非常有用。设置方法是在原理图界面按快捷键“T”然后选“网络联动”,或者在右侧属性面板里勾选“同步选中”。我画这个项目的时候,电源网络和地网络是最容易出问题的,因为TEC的电流有6A,地线上的压降如果太大,会影响ADC采样的精度。
星型接地在这个项目里不是可选项,是必须项。所谓星型接地,就是所有需要接地的点都单独走一根线到电源入口的接地点,而不是手拉手串在一起。具体到我的板子上,TEC的功率地、MOS管的源极地、ESP32-C3的模拟地、OLED的数字地,这四路地线分别走线,最后汇聚到Type-C接口的GND焊盘。这样做的目的是避免大电流在地线上产生的压降干扰小信号采样。我第一版没注意这个,ADC读出来的温度跳变能有正负3度,改成星型接地后跳变控制在0.5度以内。
立创EDA里实现星型接地的方法是:在PCB界面用“铺铜”功能,但不要整板铺一个大地,而是分区域铺铜,每个区域单独打过孔连接到背面的大地平面。或者更直接一点,手动走线,每路地线宽度至少1mm(约40mil),TEC的功率地线宽2mm以上。我实测1mm线宽走6A电流,温升大概10度左右,可以接受,但2mm更稳妥。
3.2 PCB布局与散热通孔设计
PCB布局的核心原则是:大电流路径最短,模拟信号远离功率区域。我的布局是这样的:Type-C接口在板子左侧,12V输入后先经过一个保险丝和TVS管,然后分两路,一路给TEC的MOS管,一路经过降压芯片给ESP32-C3和OLED供电。TEC的MOS管放在板子右侧靠近TEC接线端子的位置,走线又短又粗。ESP32-C3和OLED放在板子中间偏左,远离MOS管和TEC的功率走线。
散热通孔是另一个关键点。IRLZ44N的封装是TO-220,我把它平贴在PCB上,漏极和源极的焊盘下面打了9个过孔(3×3阵列),过孔直径0.3mm,间距1mm。这些过孔把热量从顶层铜皮传导到底层铜皮,相当于一个免费的散热器。实测有散热通孔的情况下,MOS管表面温度比没有通孔时低了15度左右。如果你用贴片MOS管,比如AO3400,那散热通孔就更重要了,因为贴片封装的散热能力本来就差。
TEC的接线端子我用的是KF128-2P,间距5.08mm,能过10A电流。接线时注意正负极,TEC反接的话冷热面会对调,制冷变制热。我在端子上标了“+”和“-”,但打样回来发现丝印有点小,后来用红色记号笔又描了一遍。这种细节看着不起眼,但实际用的时候能省很多事。
3.3 打样前的DRC检查与位号图导出
立创EDA的DRC检查能查出大部分低级错误,比如线宽不够、间距太小、焊盘重叠等。但有几个它查不出来的,需要你自己确认:一是TEC的功率走线宽度,DRC默认的规则可能只要求0.5mm,但你需要2mm;二是MOS管的散热焊盘有没有正确连接到铜皮;三是I2C的上拉电阻有没有漏掉。我打样前专门用立创EDA的“设计规则”功能把电源网络的线宽单独设成2mm,信号线设成0.3mm,这样DRC就能帮你检查了。
位号图导出是为了焊接时方便找元件。立创EDA专业版导出位号图的方法是:在PCB界面点“导出”→“位号图”,选PDF格式,然后勾选“显示位号”和“显示封装”。导出的PDF里每个元件的位置和位号都标得清清楚楚,焊接的时候对着图找,比在板子上一个个看丝印快得多。我一般还会在位号图旁边打印一份BOM表,焊接一个划掉一个,避免漏焊。
4. 固件开发与PWM温控逻辑实现
4.1 ESP32-C3的ADC采样与温度换算
ESP32-C3的ADC用起来有几个坑。首先是ADC的参考电压,官方文档说是1.1V,但实际上芯片内部的参考电压有偏差,每颗芯片都不一样。我试过用1.1V算出来的温度比实际低了5度多。解决办法是用一个已知电压去校准,比如用3.3V的LDO输出直接接到ADC引脚,读出来的值反推参考电压。我实测那颗芯片的参考电压是1.08V,校准后温度就准了。
ADC的采样代码用Arduino框架写很简单,analogRead()读原始值,然后套公式算电阻,再查表得温度。但要注意ESP32-C3的ADC引脚有衰减设置,默认是0dB衰减,输入范围0-1.1V。如果分压后的电压超过1.1V,读出来就一直是4095。所以要么设置衰减为11dB(输入范围0-3.3V),要么调整分压电阻让中点电压不超过1.1V。我选的是设置11dB衰减,这样分压电阻还是10kΩ对10kΩ,中点1.65V,在范围内。
温度换算的代码我贴一下核心部分:
float readTemperature() { int adcValue = analogRead(NTC_PIN); float voltage = adcValue / 4095.0 * 3.3; float resistance = 10000.0 * voltage / (3.3 - voltage); // 查表插值 for (int i = 0; i < TABLE_SIZE - 1; i++) { if (resistance >= ntcTable[i].res && resistance < ntcTable[i+1].res) { float ratio = (resistance - ntcTable[i].res) / (ntcTable[i+1].res - ntcTable[i].res); return ntcTable[i].temp + ratio * (ntcTable[i+1].temp - ntcTable[i].temp); } } return -99; // 错误值 }这段代码每100ms跑一次,连续读8次取平均,进一步降低噪声。实测温度显示稳定在正负0.3度以内,对于喝水来说完全够用。
4.2 PWM输出与MOS管驱动逻辑
ESP32-C3的LEDC外设可以输出PWM,最多支持6个通道。我用两个通道,一个给TEC的MOS管,一个给风扇的MOS管。TEC的PWM频率设20kHz,分辨率设10位(0-1023),风扇的PWM频率设25kHz,分辨率8位(0-255)。为什么风扇频率高一点?因为风扇电机对PWM频率更敏感,频率太低会有明显的嗡嗡声,25kHz基本听不见。
驱动逻辑是这样的:设定温度通过按键调整,范围5度到30度。当前温度高于设定温度时,PWM占空比逐渐增加;低于设定温度时,占空比逐渐减小。为了防止频繁启停,我加了一个2度的回差,比如设定10度,当前温度降到8度才停,升到12度才重新启动。这个回差在代码里就是一个if判断,但实际体验差别很大,没有回差的话TEC会一直处于启停循环,又吵又费电。
PWM占空比的计算我用的是增量式PI控制,比例系数Kp=20,积分系数Ki=2。每200ms调整一次,每次调整幅度不超过50(10位分辨率下)。这样温度超调能控制在1度以内,稳定后波动在正负0.5度。参数是我试出来的,不同的杯子结构可能需要微调,但大方向就是这个范围。
4.3 OLED显示驱动与界面布局
OLED驱动我用的是U8g2库,这个库对SSD1306的支持很完善,I2C地址默认0x3C,如果点不亮就换成0x3D试试。初始化的时候要设置I2C的SDA和SCL引脚,ESP32-C3的默认I2C引脚是GPIO8和GPIO9,但我为了布线方便改成了GPIO4和GPIO5。改引脚的方法是在U8g2的构造函数里指定:
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE, 5, 4);最后一个参数是SCL,倒数第二个是SDA。注意顺序别搞反了,我一开始写反了,屏幕一直不亮,查了半天才发现。
界面布局我做了三行:第一行用8×16字体显示当前温度,比如“Now: 12.5C”;第二行用6×8字体显示设定温度“Set: 10.0C”;第三行显示PWM占空比和状态“PWM: 75% ON”。刷新率设在10Hz,也就是每100ms刷一次,肉眼看着很流畅,也不会占用太多CPU时间。U8g2的Full Buffer模式需要1KB RAM,ESP32-C3完全够用,用起来比Page Buffer模式简单。
5. 常见问题排查与避坑经验实录
5.1 制冷片不工作或制冷效果差
这是最常见的问题,原因通常有三个。第一个是MOS管没导通,用万用表量一下MOS管漏极和源极之间的电压,如果接近12V说明没导通。检查GPIO有没有输出PWM信号,用示波器或者LED串电阻接在GPIO上看亮度。如果GPIO有信号但MOS管不导通,大概率是MOS管选错了,普通IRF540N在3.3V下导通电阻很大,换IRLZ44N或AO3400就好了。
第二个原因是TEC接反了。TEC有正负极,反接的话冷面变热面,你会感觉杯子在加热。判断方法很简单:通电几秒钟后摸一下TEC的两面,一面热一面冷,如果两面都热说明散热没做好,如果一面热一面温说明可能接反了。我在TEC接线端子上用红色标了正极,黑色标了负极,但还是有一次焊反了,因为线材颜色搞混了。后来我养成习惯,焊之前先用万用表量一下TEC的电阻,正常应该在1.5-2.5欧姆之间,如果开路就是坏了。
第三个原因是散热跟不上。TEC的热面如果散热不好,热量会通过陶瓷基板传导回冷面,导致冷面温度降不下去。判断方法是摸散热鳍片,如果烫手(超过60度)说明散热不够。解决办法是换更大的鳍片或者更强的风扇。我试过用5V 0.2A的小风扇,散热明显不够,换成12V 0.5A的风扇后热面温度从65度降到48度,制冷效果立竿见影。
5.2 OLED点不亮或显示乱码
OLED点不亮的原因按概率排序:第一是I2C地址不对,0x3C和0x3D都试一下;第二是上拉电阻没接,SDA和SCL各接4.7kΩ到3.3V;第三是引脚定义搞反了,SDA和SCL对调一下试试;第四是供电不足,OLED在3.3V下工作电流约20mA,如果从ESP32-C3的3.3V引脚取电,同时WiFi又在工作,可能会掉电重启。解决办法是单独用一个LDO给OLED供电,或者把WiFi关掉。
显示乱码通常是I2C速率太高或者线太长。I2C的默认速率是100kHz,我设成400kHz后线长超过10cm就开始出问题。解决办法是把速率降回100kHz,或者缩短走线。我在PCB上OLED的走线控制在5cm以内,400kHz下很稳定。如果是用杜邦线连接,建议降到100kHz,杜邦线的分布电容比较大,高速下波形会变形。
还有一个隐蔽的问题:OLED的复位引脚。有些模块有RES引脚,需要先拉低再拉高才能初始化。如果模块上没有RES引脚,SSD1306内部有上电复位电路,一般没问题。但如果你的模块有RES引脚又没接,可能一直处于复位状态。我用的模块没有RES引脚,省了一根线,但如果你遇到点不亮的情况,可以检查一下这个。
5.3 PWM控制TEC时的噪音与干扰
PWM驱动TEC时,如果频率落在音频范围内,TEC的陶瓷基板会像扬声器一样振动发出声音。我试过1kHz的时候,声音大得像个蜂鸣器。解决办法是把频率提到20kHz以上,超出人耳听觉范围。但频率太高MOS管发热会增加,所以20kHz是一个平衡点。
另一个问题是PWM对ADC采样的干扰。TEC的PWM电流在地线上产生的压降会耦合到NTC的分压电路里,导致温度读数跳动。我第一版的时候,PWM一开,温度读数就跳正负3度。解决办法有三个:一是星型接地,前面说过了;二是在NTC分压中点加一个0.1uF的电容到地,滤掉高频干扰;三是ADC采样时避开PWM的开关时刻,比如在PWM周期的中点采样。我三个方法都用了,温度跳动降到0.3度以内。
还有一个经验:TEC的PWM走线不要和NTC的走线平行走,如果必须交叉,尽量垂直交叉。平行走线会产生容性耦合,垂直交叉的耦合最小。我在PCB上把NTC的走线放在顶层,TEC的PWM走线放在底层,中间隔着地平面,干扰就很小了。
5.4 常见问题速查表
| 现象 | 可能原因 | 排查方法 | 解决办法 |
|---|---|---|---|
| TEC不制冷 | MOS管未导通 | 量MOS管D-S电压 | 换逻辑电平MOS管 |
| TEC不制冷 | TEC接反 | 摸冷热面 | 调换接线 |
| TEC不制冷 | 散热不足 | 摸散热鳍片温度 | 换大鳍片或强风扇 |
| OLED不亮 | I2C地址错 | 试0x3C和0x3D | 改代码地址 |
| OLED不亮 | 无上拉电阻 | 量SDA/SCL电压 | 加4.7kΩ上拉 |
| 温度跳动大 | 地线干扰 | 示波器看地线 | 星型接地+滤波电容 |
| PWM有噪音 | 频率太低 | 听声音 | 提到20kHz以上 |
| MOS管发热 | 开关损耗大 | 摸MOS管温度 | 降频率或加散热片 |
6. 外壳装配与整机调试心得
6.1 导冷块与杯体的热耦合处理
导冷块是连接TEC冷面和杯内水的关键零件,我用的是6061铝合金,导热系数约167 W/(m·K),比纯铜差一点但加工容易、重量轻。导冷块的形状是一个圆柱体,直径比杯口小2mm,高度约30mm,底部加工成平面和TEC的冷面贴合。贴合面涂一层导热硅脂,厚度控制在0.1mm左右,太厚反而影响导热。
杯体我用的是一个不锈钢保温杯,把底部切开一个方孔,导冷块从孔里伸进去,周围用硅胶密封。这里有个坑:硅胶要选耐温-40到200度的中性硅胶,酸性硅胶会腐蚀铝块。我第一版用了普通玻璃胶,两周后导冷块表面就发黑了。换成中性硅胶后用了半年都没问题。
TEC的冷面贴着导冷块底部,热面贴着散热鳍片。三者用M3螺丝夹紧,压力要均匀,太松接触不良,太紧可能压裂TEC的陶瓷基板。我用的方法是弹簧垫片加螺母,拧到弹簧垫片压平即可,不要死拧。TEC的陶瓷基板很脆,我拧裂过一片,直接报废。
6.2 整机功耗测试与续航估算
整机功耗分三部分:TEC满功率72W,风扇约6W(12V 0.5A),ESP32-C3加OLED约0.5W。总功耗约78W。如果用12V 6A的电源适配器,刚好够用。如果用PD诱骗器从充电宝取电,需要充电宝支持PD 12V档位,且输出电流至少5A。我试过一个10000mAh的充电宝,PD 12V 3A输出,TEC只能跑到50%占空比,制冷效果打折扣。
续航估算:10000mAh充电宝在12V下的能量是10000mAh × 3.7V / 12V ≈ 3083mAh,也就是约3Ah。TEC在50%占空比下平均电流约3A,加上风扇和主控约0.5A,总电流3.5A。3Ah / 3.5A ≈ 0.86小时,也就是大约50分钟。实际用下来,从30度降到10度大约需要20分钟,然后维持10度大约能撑30分钟,总共50分钟左右,和估算基本吻合。
如果想延长续航,可以把TEC的PWM占空比限制在30%以下,这样平均电流约1.8A,续航能到1.5小时,但制冷速度会慢很多。我的建议是:如果追求快速制冷,就用大功率电源;如果追求便携,就降低功率预期,或者带一个更大的充电宝。
6.3 温度校准与长期稳定性测试
温度校准我用的是冰水混合物法。把导冷块浸在冰水混合物里(0度),等温度读数稳定后,记录ADC值,然后调整代码里的偏移量,让显示温度等于0度。然后再用温水(约40度)校准一次,用温度计做参考。两点校准后,整个量程内的误差在0.5度以内。
长期稳定性方面,我连续跑了72小时,设定温度10度,环境温度28度。前2小时温度从28度降到10度,之后一直稳定在9.8到10.3度之间波动。MOS管温度稳定在52度,散热鳍片温度45度,TEC冷面温度5度左右。这个数据说明散热系统设计是合理的,长时间运行没有热积累问题。
唯一需要注意的是冷凝水。杯内温度低于环境露点时,杯壁外侧会结露。我的解决办法是在杯体外侧贴了一层薄海绵,既能保温又能吸水。如果你在潮湿环境使用,建议在PCB上也涂一层三防漆,防止冷凝水导致短路。
7. 项目扩展方向与个人体会
这个制冷杯做完之后,我发现可扩展的地方还挺多的。比如加一个蓝牙模块,用手机App调温度;或者加一个陀螺仪,杯子倒了自动断电;再或者加一个太阳能板,户外用的时候能补一点电。我最近在试的是把OLED换成1.3寸的彩屏,显示温度曲线,看着更直观。不过彩屏的功耗比OLED高不少,对电源是个考验。
另一个方向是优化温控算法。我现在用的是PI控制,超调大概1度。如果换成模糊控制或者模型预测控制,理论上能把超调降到0.3度以内。但说实话,对于喝水来说,1度的超调根本感觉不出来,所以这个优化的优先级不高。倒是制冷速度可以再压榨一下,比如在初始阶段用100%占空比猛冲,等接近设定温度再切回PI控制。我试了一下,从30度降到10度的时间从22分钟缩短到18分钟,效果还是有的。
最后分享一个焊接时的小技巧:TEC的引脚很粗,散热很快,用普通60/40焊锡很难焊。我换成含银焊锡(Sn96.5/Ag3.0/Cu0.5),熔点217度,配合大功率烙铁(60W以上),焊接时间控制在3秒以内,焊点光亮饱满。焊完用万用表量一下TEC电阻,确认没有虚焊。这个细节看着小,但TEC的电流有6A,虚焊的话接触电阻发热会很严重,甚至烧毁焊盘。我第一版就是虚焊了,用了两天焊点就发黑了,重新焊过才稳定。