1. 从一杯冰水说起:这个项目到底在做什么
夏天喝温水这件事,说大不大,说小也不小。办公室里空调开着,一杯水放半小时就温吞吞的,想喝口凉的要么去冰箱拿,要么加冰块,要么干脆忍了。市面上确实有制冷杯这种东西,但要么贵得离谱,要么制冷效率感人,要么就是纯粹靠一块半导体制冷片硬怼,连个像样的温控都没有。这个"小北极冰冰杯(夏)"项目,就是拿立创EDA从零画一块板子,用ESP32-C3做主控,驱动半导体制冷片,配一块OLED做交互显示,把一杯水从常温拉到能入口的凉度。
核心关键词其实就几个:立创EDA、ESP32-C3、半导体制冷、PWM、OLED。这几个词串起来就是一条完整的技术链路——用立创EDA完成原理图和PCB设计,ESP32-C3负责逻辑控制和PWM输出,半导体制冷片执行冷热转换,OLED承担人机交互。听起来不复杂,但真动手做的时候,从选型到布线到调参,每一步都有坑。
这篇文章适合谁看?如果你手上有立创EDA的基础操作能力,知道怎么画原理图、怎么拉线,但对"怎么把一块制冷片安全高效地驱动起来"没底,那这篇就是写给你的。如果你连ESP32-C3都没碰过,也没关系,我会把关键的配置逻辑和踩坑点讲清楚,你照着抄作业也能跑起来。整个项目的硬件成本控制在百元以内,PCB打样用嘉立创的免费额度基本不花钱,属于典型的"低成本高折腾价值"项目。
我先把整体架构说清楚,免得后面看细节的时候迷路。整块板子的功能模块划分是这样的:ESP32-C3作为主控,负责读取温度传感器(NTC或者DS18B20)、输出PWM控制制冷片的驱动电路、驱动OLED显示当前温度和目标温度、处理按键输入来调节目标温度。制冷片这边不能直接用IO口驱动,必须经过MOS管或者专用驱动芯片,因为制冷片的电流动辄两三安培,ESP32-C3的IO口最大也就几十毫安,直接接上去就是烧片的节奏。电源部分要考虑制冷片的大电流需求和ESP32-C3的3.3V需求,通常是12V输入,一路降压到3.3V给主控,另一路直接给制冷片驱动。
注意:半导体制冷片是电流驱动型器件,它的制冷量跟流过它的电流基本成正比,但发热量跟电流的平方成正比。这意味着你不能无脑加大电流,否则制冷没上去多少,热端先把板子烤了。
2. 为什么选ESP32-C3而不是STM32或者8051
2.1 主控选型的几个现实考量
选ESP32-C3做这个项目,不是因为它性能多强,而是因为它在"够用"和"省事"之间找到了一个很好的平衡点。ESP32-C3是乐鑫出的RISC-V架构芯片,单核160MHz,带WiFi和蓝牙,GPIO数量对于这个项目来说绰绰有余。最关键的是,它的开发环境成熟,Arduino IDE和ESP-IDF都能用,LEDC(LED Control)外设天然支持PWM输出,配置起来比STM32的定时器PWM要简单不少。
有人可能会问,STM32不香吗?香,但STM32F103C8T6这种经典款,你要配PWM得算预分频、算自动重装载值,还得处理定时器通道映射,对于一个小项目来说有点杀鸡用牛刀。而且STM32的最小系统板通常还要外挂USB转串口芯片,ESP32-C3直接内置USB Serial/JTAG,一根Type-C线就能烧录和调试,省事太多。
至于8051,用8051模拟16位PWM这种操作,属于学习原理的好方法,但真做产品级的东西,没必要给自己找麻烦。ESP32-C3的LEDC外设支持最高20位分辨率,频率和占空比都可以灵活配置,驱动制冷片这种对PWM频率要求不高的负载(通常1kHz到10kHz就够了),简直是降维打击。
2.2 LEDC外设的PWM配置逻辑
ESP32-C3的LEDC外设有6个通道,分成两组定时器。每个通道可以独立配置频率和占空比。配置的时候有几个参数需要搞清楚:
- 频率:制冷片驱动用1kHz到5kHz比较合适。频率太低会有可闻噪声,频率太高MOS管开关损耗会增加。
- 分辨率:8位到14位都行。8位就是0到255,14位是0到16383。分辨率越高,占空比调节越细腻,但频率上限会降低。
- 占空比:决定制冷功率的核心参数。占空比100%就是全功率运行,50%就是半功率。
在Arduino环境下配置LEDC的代码大概长这样:
// 配置LEDC通道 ledcSetup(0, 5000, 10); // 通道0,5kHz,10位分辨率 ledcAttachPin(3, 0); // GPIO3连接到通道0 ledcWrite(0, 512); // 占空比50%(10位分辨率下512/1023)这段代码的逻辑是:先把通道0配置成5kHz、10位分辨率,然后把GPIO3绑定到这个通道,最后设置占空比。10位分辨率下,占空比范围是0到1023,512就是50%。
提示:ESP32-C3的GPIO3是strapping引脚,上电时的电平会影响启动模式。如果你用GPIO3做PWM输出,确保驱动电路在上电瞬间不会把它拉低,否则芯片可能进不了正常启动模式。我建议换用GPIO4或者GPIO5这类普通IO。
2.3 为什么不用硬件PWM芯片
有人可能会想,用555做PWM电路或者用专用PWM芯片不是更简单吗?从纯硬件角度确实可以,但问题是这个项目需要根据温度动态调节PWM占空比,还要在OLED上显示状态,纯硬件方案做不到闭环控制。ESP32-C3的LEDC外设本质上就是一个硬件PWM发生器,配置好之后CPU不需要干预,PWM波形会持续输出,效率上跟专用芯片没区别,还省了额外元件。
3. 半导体制冷片的驱动电路:从原理到布线
3.1 制冷片的工作特性与驱动需求
半导体制冷片(TEC,Thermoelectric Cooler)的原理是帕尔帖效应:直流电流流过两种不同导体的结点时,一端吸热一端放热。制冷片通常标称的参数有额定电压(比如12V)、额定电流(比如3A)、最大温差(比如65摄氏度)。但实际使用中,你很少会跑到额定值,因为热端散热跟不上,冷端温度反而会反弹。
驱动制冷片的核心需求有三个:足够的电流能力、PWM调速能力、反向电压保护。电流能力靠MOS管或者驱动芯片解决,PWM调速靠ESP32-C3的LEDC外设解决,反向电压保护靠续流二极管解决。
我选的是AO3400A这款N沟道MOS管,SOT-23封装,导通电阻在Vgs=4.5V时大概28毫欧,持续电流可以到5.7A,驱动一块3A的制冷片绰绰有余。栅极驱动电压用3.3V直接驱动也可以,但为了降低导通电阻,最好用4.5V以上。ESP32-C3的IO口输出3.3V,AO3400A在3.3V驱动下导通电阻会大一些,大概40毫欧左右,3A电流下功耗是0.36W,SOT-23封装勉强能扛住,但会发热。如果你想让MOS管凉快点,可以在栅极加一级电平转换,把驱动电压拉到5V。
3.2 续流二极管和栅极电阻的选型
制冷片是感性负载吗?严格来说不是,但它的引线和内部结构存在寄生电感,PWM开关瞬间会产生反向电动势。如果不加续流二极管,这个反向电压可能击穿MOS管。我用的是一颗SS34肖特基二极管,反向耐压40V,正向电流3A,并联在制冷片两端,阴极接电源正极,阳极接MOS管漏极。
栅极电阻的作用是限制栅极充电电流,防止MOS管开关瞬间产生振铃。我用的是一颗10欧姆的电阻,串在ESP32-C3的IO口和MOS管栅极之间。这个值不能太大,否则开关速度变慢,MOS管在过渡区停留时间变长,发热会增加;也不能太小,否则栅极电流过大,可能损坏IO口。
下面这个表格总结了驱动电路的关键元件和参数:
| 元件 | 型号/参数 | 作用 | 注意事项 |
|---|---|---|---|
| MOS管 | AO3400A | 开关制冷片电流 | 栅极驱动电压建议4.5V以上 |
| 续流二极管 | SS34 | 吸收反向电动势 | 阴极接电源正极 |
| 栅极电阻 | 10Ω | 限制栅极电流 | 太大影响开关速度 |
| 栅极下拉电阻 | 10kΩ | 确保默认关断 | 防止上电误导通 |
| 电源滤波电容 | 470μF/25V | 平滑电流波动 | 靠近制冷片接口放置 |
3.3 星型接地在立创EDA里的实现
嘉立创EDA如何布线星型接地,这是热词里出现的问题,也是这个项目里很关键的一点。星型接地的核心思想是:大电流回路和小信号回路分开走,最后只在电源入口处单点汇合。制冷片的电流是安培级别的,如果它的回流路径经过ESP32-C3的GND引脚,地线上的压降会干扰主控的正常工作,严重时会导致复位或者ADC读数跳变。
在立创EDA专业版里实现星型接地,我的做法是:在原理图阶段就把GND网络分成两个——GND_POWER和GND_SIGNAL,然后用一个0欧姆电阻或者磁珠在电源入口处连接。PCB布局时,制冷片驱动电路的地线走粗线(至少40mil),单独走一条路径回到电源输入端的滤波电容负极;ESP32-C3和OLED的地线走细线,单独走另一条路径回到同一个点。两条路径不要交叉,不要形成环路。
注意:立创EDA专业版里可以通过"网络类"功能给不同GND网络设置不同的线宽规则。在"设计"->"规则"->"网络类"里新建一个类,把
GND_POWER加进去,最小线宽设成40mil,这样布线的时候会自动应用。
4. OLED交互界面的驱动与显示逻辑
4.1 IIC通信协议在OLED上的实际表现
OLED 0.96寸模块基本都是SSD1306驱动芯片,支持IIC和SPI两种接口。IIC的好处是接线少,两根线(SCL和SDA)就能搞定,坏处是速度慢,刷新率有限。对于显示温度、目标温度、PWM占空比这几个数字来说,IIC的速度完全够用。
IIC通信协议在OLED上的实际表现,有几个细节值得说。SSD1306的IIC地址通常是0x3C或者0x3D,具体看模块上的电阻配置。ESP32-C3的IIC引脚可以映射到任意GPIO,我习惯用GPIO8做SDA,GPIO9做SCL。上拉电阻用4.7kΩ,接3.3V。有些OLED模块自带上拉电阻,如果你不确定,用万用表量一下SCL和SDA对VCC的电阻,如果是10kΩ左右就说明自带了,不需要外加。
HAL库驱动OLED的代码在STM32上很常见,但ESP32-C3用Arduino框架的话,直接用U8g2库或者Adafruit_SSD1306库更省事。U8g2库的优势是支持多种字体和图形,缺点是内存占用大一些。Adafruit_SSD1306库更轻量,但字体选择少。我选的是U8g2,因为要显示中文"制冷中"和"待机"这几个字,U8g2的中文字体支持更好。
4.2 显示内容的布局与刷新策略
OLED屏幕只有128x64像素,能显示的内容有限。我的布局是这样的:第一行显示当前温度,大字体;第二行显示目标温度,小字体;第三行显示PWM占空比和制冷片状态;第四行显示运行时间。刷新策略上,不要每次循环都全屏刷新,那样屏幕会闪。我的做法是只刷新变化的区域,用U8g2的updateDisplayArea函数,只更新温度那一行的区域。
// 只刷新温度显示区域 u8g2.setDrawColor(0); u8g2.drawBox(0, 0, 128, 20); // 清除温度区域 u8g2.setDrawColor(1); u8g2.setFont(u8g2_font_logisoso16_tf); u8g2.setCursor(0, 18); u8g2.print(currentTemp, 1); u8g2.updateDisplayArea(0, 0, 16, 3); // 只更新前3页这段代码的逻辑是:先用背景色清除温度区域,然后画上新温度,最后只更新那几页的显示缓存。这样屏幕不会闪,刷新率也上去了。
4.3 OLED 0.96批量点不亮的排查思路
热词里有个"oled 0.96批量点不亮",这个问题我在项目里也遇到过。批量点不亮通常不是模块坏了,而是以下几个原因:
- IIC地址不对:有些模块是0x3C,有些是0x3D。用IIC扫描程序扫一下就知道。
- 上拉电阻缺失:如果模块没自带上拉,SDA和SCL都是开漏输出,没有上拉电阻就没有高电平,通信直接失败。
- 电源电压不对:SSD1306支持3.3V和5V,但有些模块只支持3.3V,接5V会烧。
- 初始化序列不对:不同批次的SSD1306可能固件版本不同,初始化序列需要微调。U8g2库通常能自动处理,但如果用的是自己写的驱动,就要注意。
我的排查步骤是:先用IIC扫描程序确认地址,然后用示波器看SCL和SDA有没有波形,最后换一个确认能用的模块交叉验证。三步下来基本能定位问题。
5. 温度采集与闭环控制的实现细节
5.1 NTC热敏电阻的线性化处理
温度采集我用的是一颗10kΩ的NTC热敏电阻,B值3950,配合一个10kΩ的上拉电阻分压,接到ESP32-C3的ADC引脚。NTC的阻值和温度是非线性的,直接读ADC值只能得到电压,要转换成温度得用Steinhart-Hart方程或者查表法。
Steinhart-Hart方程是这样的:
1/T = A + B*ln(R) + C*(ln(R))^3其中T是开尔文温度,R是NTC阻值,A、B、C是常数。对于B值3950的10k NTC,常用的简化公式是:
1/T = 1/T0 + (1/B) * ln(R/R0)T0是25摄氏度(298.15K),R0是10kΩ。这个公式在0到100摄氏度范围内精度够用,误差大概在1摄氏度以内。
在代码里实现的时候,先读ADC值,算出NTC阻值,再代入公式算温度。ESP32-C3的ADC是12位的,但实际有效位数大概10位左右,所以读数会有跳动。我的做法是连续读10次取平均值,再做滑动滤波,这样温度显示基本能稳定在0.5摄氏度以内。
5.2 PWM占空比的PID调节逻辑
闭环控制的核心是:根据当前温度和目标温度的差值,动态调节PWM占空比。最简单的做法是比例控制:差值越大,占空比越大。但纯比例控制会有稳态误差,温度永远差那么一点点到不了目标值。所以我加了一个简单的积分项,做成PI控制器。
float error = currentTemp - targetTemp; integral += error * dt; float output = Kp * error + Ki * integral; output = constrain(output, 0, 1023); // 限制在0到1023 ledcWrite(0, output);Kp和Ki的值需要根据实际系统调。我的经验是Kp从50开始试,Ki从0.5开始试。如果温度震荡,减小Kp;如果温度到不了目标值,增大Ki。制冷片的响应有延迟,所以积分时间不能太短,否则会过冲。
提示:制冷片有个特性,断电之后冷端温度会迅速回升,因为热端的热量会通过制冷片本身传导过来。所以如果你要做精确温控,最好在达到目标温度后保持一个较小的PWM占空比(比如10%到20%),而不是完全关断。
5.3 温度传感器的安装位置
温度传感器贴在哪里,直接影响控制效果。贴在制冷片冷端,测的是制冷片本身的温度,不是水温。贴在水杯壁上,测的是杯壁温度,跟水温也有差距。我的做法是用导热硅胶把NTC贴在一个铝制小片上,再把铝片贴在水杯外壁,这样测到的温度更接近水温。如果你追求更精确的水温,可以用防水封装的DS18B20直接插进水里,但那样清洗杯子就麻烦了。
6. 立创EDA从原理图到PCB的实操要点
6.1 原理图阶段的关键网络命名
在立创EDA里画原理图,网络命名是个容易被忽视但很重要的细节。我的习惯是给所有关键网络加前缀:PWR_表示电源,SIG_表示信号,GND_表示地。比如PWR_12V、PWR_3V3、SIG_PWM、GND_POWER、GND_SIGNAL。这样做的好处是,在PCB布线的时候,你可以通过网络类快速筛选,给不同网络设置不同的线宽和间距规则。
嘉立创EDA原理图选择网络联动PCB如何设置,这个问题在热词里也出现了。在立创EDA专业版里,原理图和PCB是实时联动的,你在原理图里选中一个网络,PCB里对应的走线会高亮。如果没联动,检查一下"工具"->"交叉选择"有没有打开。有时候工程文件多了,联动会失效,重启一下软件就好。
6.2 PCB布局的优先级排序
PCB布局我遵循一个原则:先放接口,再放核心器件,最后放辅助电路。接口包括Type-C电源口、制冷片接线端子、OLED排针。核心器件是ESP32-C3模组和MOS管。辅助电路是NTC分压电阻、按键、指示灯。
制冷片接线端子要靠近MOS管,MOS管要靠近电源输入电容,这样大电流回路的面积最小。ESP32-C3模组要远离MOS管和制冷片接线端子,避免热干扰和电磁干扰。OLED排针放在板子边缘,方便接线。NTC分压电阻靠近ESP32-C3的ADC引脚,走线尽量短。
6.3 布线时的线宽计算与过孔处理
线宽的计算依据是电流和允许的温升。IPC-2221标准给出的公式是:
I = k * ΔT^0.44 * A^0.725其中I是电流(安培),ΔT是温升(摄氏度),A是截面积(平方密耳),k是常数(外层走线取0.048)。对于3A电流,允许10摄氏度温升,算下来截面积大概需要60平方密耳,对应1盎司铜厚的话,线宽大概40mil。所以我给PWR_12V和GND_POWER设置的线宽是40mil,其他信号线10mil就够了。
过孔的处理也有讲究。大电流路径上的过孔,不要只放一个,放两到三个并联,降低过孔电阻。过孔孔径用0.3mm,外径0.6mm,这是嘉立创的常规工艺,不加钱。如果电流更大,可以考虑用0.5mm孔径的过孔。
6.4 导出位号图和装配图
立创EDA导出位号图,在"制造"->"装配图"里可以生成。位号图的作用是手工焊接的时候对照元件位置,特别是0402、0603这种小封装,没有位号图很容易焊错。我通常导出PDF格式,打印出来放在手边。装配图里还可以标注元件的极性,比如二极管的方向、电解电容的正负极,这些在焊接的时候很关键。
7. 实测中的几个意外与解决过程
7.1 MOS管发热问题的排查
第一次打样回来,焊好之后跑起来,制冷片确实凉了,但MOS管烫得不敢摸。用热成像仪看了一下,MOS管表面温度到了80多摄氏度。排查过程是这样的:先量栅极电压,发现只有3.1V,因为ESP32-C3的IO口输出高电平大概是3.1V到3.2V,AO3400A在这个电压下导通电阻偏大。然后量电流,制冷片实际电流2.8A,MOS管功耗是2.82.80.04=0.31W,SOT-23封装的热阻大概250摄氏度每瓦,算下来温升确实有70多度。
解决方案有两个:一是换用低阈值电压的MOS管,比如AO3402,Vgs=2.5V时导通电阻就很小了;二是在栅极加一级电平转换,用一颗小NPN三极管把3.3V拉到5V再驱动MOS管。我选了第二个方案,因为手头有现成的三极管,改起来也快。
7.2 OLED在PWM开启后花屏
这个问题比较隐蔽。单独跑OLED显示没问题,一旦开启PWM驱动制冷片,OLED就花屏或者闪屏。一开始以为是IIC通信被干扰了,加了屏蔽线也没用。后来用示波器看电源纹波,发现12V电源在PWM开关瞬间有大概500mV的尖峰,这个尖峰通过降压电路耦合到了3.3V上,导致OLED的复位或者通信异常。
解决办法是在12V输入端加一个LC滤波,电感用10μH,电容用470μF,把尖峰压下去。同时在3.3V稳压器的输入端加一个100μF的电解电容和一个0.1μF的陶瓷电容,进一步滤除高频噪声。改完之后OLED就稳定了。
7.3 温度读数跳变的软件滤波
NTC的ADC读数跳动是正常的,但跳变幅度超过2摄氏度就不正常了。我一开始以为是ADC的问题,后来发现是PWM开关噪声耦合到了NTC的走线上。NTC的走线跟PWM走线平行了一段,长度大概5mm,就这一段就足够把噪声耦合进去。
改板的时候把NTC走线远离PWM走线,中间加了一条地线做隔离。软件上也加了中值滤波,连续读5次,去掉最大最小值,取中间3个的平均值。这样处理后,温度读数稳定在0.3摄氏度以内。
8. 这个项目还能怎么玩
硬件跑通之后,软件上还有很多可以折腾的地方。比如加一个蓝牙功能,用手机APP调目标温度;或者加一个定时功能,设定制冷时长;再或者加一个屏幕休眠功能,没人操作的时候自动熄屏省电。ESP32-C3自带WiFi和蓝牙,这些功能都是现成的,只需要写代码。
硬件上也可以扩展。比如加一个风扇给制冷片热端散热,散热效果好了,冷端温度能更低。风扇的PWM控制可以跟制冷片共用一个定时器,用不同通道输出不同频率。再比如加一个Type-C接口的PD诱骗芯片,让充电头输出12V,这样就不需要外接电源适配器了。
我个人在实际操作中的体会是,半导体制冷这个东西,散热比制冷更重要。你把热端散热做好了,冷端自然就凉了。散热做不好,再大的电流也是白搭。所以如果你要复现这个项目,我建议在散热上多花点心思,散热片面积尽量大,风扇尽量选风量大的,导热硅脂不要省。
最后再分享一个小技巧:调试PWM的时候,先用一个LED灯珠代替制冷片,看看PWM波形和占空比调节是否正常。LED灯珠的电流小,不会烧东西,等逻辑调通了再接制冷片。这个习惯帮我省了好几次烧MOS管的钱。