基于ESP32-C6与MLX90614的红外测温枪DIY全流程解析
1. 项目概述与设计思路
作为一名长期混迹于硬件开源社区的开发者,我手头总缺不了几件趁手的测量工具。前段时间,我那把用了好些年的福禄克测温枪突然罢工,送修周期不短,手头的几个电子项目和3D打印机调试工作又不能停。市面上的替代品要么精度存疑,要么价格不菲,这让我萌生了自己动手做一个的念头。毕竟,核心的红外测温传感器模块已经很成熟,微控制器和显示单元更是我们玩嵌入式开发的“老熟人”。于是,就有了这个“TempGun Pro”项目——一个基于ESP32-C6和MLX90614传感器的开源手持红外测温枪。
这个项目的目标很明确:打造一个成本可控、精度可靠、完全开源且便于复制的非接触式测温工具。它主要服务于像我一样的电子爱好者、创客以及需要快速进行设备表面温度检测的工程师,应用场景包括但不限于测量3D打印热床温度、检查电路板元器件发热、评估散热器效能,甚至是日常中测量一杯咖啡的表面温度。整个方案的核心是利用MLX90614传感器感知物体发出的红外辐射,通过ESP32-C6进行数据处理,最终在1.47英寸的LCD屏幕上直观显示温度值。整个构建过程涉及硬件电路设计、PCB打样、嵌入式编程以及3D打印外壳制作,是一个典型的、涵盖“软硬结合”全流程的DIY项目。
选择ESP32-C6和MLX90614这个组合,是经过一番权衡的。ESP32-C6作为乐鑫新一代的Wi-Fi 6 + Bluetooth 5 (LE) MCU,其性能对于本项目而言绰绰有余,更重要的是,我手头正好有基于该芯片的Waveshare开发板,它集成了显示屏和锂电池充电管理,极大地简化了系统集成。MLX90614则是经过市场长期检验的红外测温芯片,其I2C接口简单易用,精度(±0.5°C)和量程(-70°C至+380°C)完全满足业余乃至多数专业场景的需求。整个系统的设计哲学是“复用与简化”,我复用了之前一个医疗诊断设备项目(Medic Mini)的主板设计,仅对其按钮布局和传感器接口做了最小化修改,这大大缩短了从构思到原型的时间。
2. 核心硬件解析与选型考量
2.1 主控与显示单元:Waveshare ESP32-C6开发板
在这个项目中,我选择了成品的Waveshare ESP32-C6 1.47英寸LCD开发模块作为核心。这个选择基于几个关键考量。首先,它极大地降低了入门门槛和焊接难度。该模块已经将ESP32-C6 MCU、SPI接口的ST7789驱动LCD屏幕、Type-C充电/编程接口以及必要的电源滤波电路集成在了一块小巧的板子上。对于DIY项目而言,使用这种高度集成的模块能避免在高速数字信号布线(如显示接口)、射频电路布局(ESP32的Wi-Fi/蓝牙天线)上踩坑,让我们能更专注于应用功能本身。
其次,该模块预留了丰富的GPIO引脚,方便我们接入外部传感器和按钮。其引脚排列通常兼容常见的ESP32开发板布局,使得编程和调试环境非常熟悉。最后,模块自带的锂电池充电管理功能(虽然具体芯片未标明,但此类模块通常集成)是不可或缺的,它让我们可以直接连接一块3.7V的锂聚合物电池,实现设备的真正便携化。如果你手头没有这款特定模块,任何带有足够GPIO和SPI接口用于驱动屏幕的ESP32系列开发板(如ESP32-S3)都可以作为替代,但你需要自行解决屏幕驱动和电池管理问题。
2.2 传感核心:MLX90614红外测温传感器
MLX90614是整个设备的“眼睛”,其工作原理基于所有高于绝对零度的物体都会向外辐射红外能量的物理定律,即黑体辐射原理。传感器内部有一个称为热电堆的检测元件,它能捕捉到目标物体发射的红外能量,并将其转换为微弱的电压信号。这个模拟信号经过传感器内部集成的低噪声放大器、模数转换器以及一个强大的DSP单元进行处理,最终通过I2C数字接口输出计算出的物体温度和环境温度。
这里有几个关键点需要理解。第一是测量距离与视场角(FOV)。MLX90614标准版通常有一个约90°的视场角。这意味着在距离传感器较远时,它检测到的是一片较大区域的平均温度。为了获得准确的、针对某一点的温度,我们必须让传感器靠近目标,通常建议距离在2-5厘米。这就是为什么我们的测温枪设计会将传感器头部突出,并引导用户近距离测量。第二是发射率(Emissivity)。MLX90614的出厂校准是针对发射率约为0.95的物体(接近大多数有机材料和氧化表面)。对于光亮金属等低发射率物体,读数会显著偏低,需要进行软件补偿。不过对于大多数日常电子维修和创客场景,这个默认值已经足够可靠。第三是I2C通信。这是一个双线(SDA数据线,SCL时钟线)的同步串行协议,非常适合微控制器与各种传感器通信。我们需要在代码中正确初始化I2C总线,并处理与MLX90614的寄存器读写。
2.3 电源管理:IP5306芯片的作用
为了实现单锂电池供电并稳定运行整个系统,一个高效的电源管理芯片是必需的。在原Medic Mini项目中使用的IP5306就是这样一款专为单节锂电池应用设计的集成化电源管理IC(PMIC)。它的核心功能是升压(Boost),能将锂电池的放电电压(约3.0V-4.2V)稳定提升到5V,以供给ESP32开发板和显示屏(它们通常需要5V或3.3V输入)。同时,它集成了完整的锂电池充电管理功能,可以通过Type-C口直接对电池充电,并具备充电状态指示(LED闪烁/常亮)、过充保护、过放保护、短路保护等,极大地增强了设备的耐用性和安全性。
在PCB设计时,围绕IP5306的电路布局需要特别注意。其用于升压的电感(1uH)和输入输出电容(如10uF)应尽可能靠近芯片引脚,走线要短而粗,以减少开关噪声和保证大电流输出能力(宣称2A)。电池连接端必须考虑防反接措施,虽然IP5306内部可能有部分保护,但一个好的习惯是在电池正极输入串联一个肖特基二极管或使用MOS管防反接电路,以防误接损坏芯片。
2.4 人机交互:按钮与机械设计
设备的人机交互被极致简化:一个按钮控制测温。在硬件上,这表现为一个连接到GPIO18的轻触开关,并通过一个10KΩ的上拉电阻确保引脚在未按下时处于确定的高电平状态。当按钮按下,引脚被拉低到GND,MCU检测到这个低电平信号即触发一次测温流程。
机械设计围绕这个简单的交互展开。外壳需要为这个按钮提供一个舒适、耐用的按压手感,因此设计了专门的椭圆形按钮帽和内部的导向柱(actuator),确保每次按压都能准确触发微动开关。同时,外壳还需要精密地固定Waveshare模块、MLX90614传感器和电池。传感器需要“看向”前方,且其透镜前方不能有障碍物(如亚克力板)严重阻挡红外线,因此外壳前端设计了专门的传感器舱室和开孔。整个结构通过前后壳合并,并用M2螺丝锁紧,保证了设备的整体强度和美观。
3. 电路设计与PCB制作实战
3.1 原理图设计:在现有项目上做减法
我的策略不是从零开始,而是基于成熟的“Medic Mini”项目进行修改。这就像在已有的乐高套件上更换一个模块。首先,我分析了原项目的原理图,其核心是Waveshare ESP32-C6模块与三个按钮(GPIO9, 18, 19)的连接,以及IP5306的电源电路。
对于TempGun Pro,我们只需要保留一个按钮(GPIO18)。因此,在原理图修改上,我移除了连接到GPIO9和GPIO19的按钮及其相关上拉电阻网络。GPIO18的电路保持不变,作为测温触发键。接着,需要添加MLX90614的接口。找到ESP32-C6模块上未被占用的I2C引脚,通常是GPIO4(SDA)和GPIO5(SCL)。在原理图中,从这两个引脚引出网络,连接到一个4Pin的排母或焊盘,用于连接MLX90614。同时,从3.3V和GND网络也引线至此,为传感器供电。至此,核心的功能修改就完成了。
注意:务必查阅你所使用的ESP32-C6开发板的引脚定义图。不同厂商的板子,其GPIO4和GPIO5可能已被用于其他功能(如连接内置SPI Flash)。确保你选择的I2C引脚是“干净”的,并且支持硬件I2C。Waveshare的这块板子,GPIO4和GPIO5是明确可用的。
3.2 PCB布局:在有限空间内合理规划
PCB布局是在给定的外壳尺寸内进行的“俄罗斯方块”游戏。首先,导入3D外壳模型或精确的尺寸图到PCB设计软件(我用的KiCad),将其作为板框(Board Outline)的依据。然后,开始放置关键器件:
- 结构件优先:放置Type-C接口(对齐外壳开孔)、四个按钮(位置必须与外壳的按钮柱精确对应)、四个固定孔(与外壳支柱对应)。这些器件的位置几乎没有调整余地。
- 核心模块定位:放置Waveshare ESP32-C6模块。它的位置通常由外壳的屏幕窗口和内部结构决定,需要确保屏幕正对外壳窗口,且模块的焊盘或插针不会与外壳干涉。
- 电源芯片布局:放置IP5306及其外围器件(电感、电容)。这是布局的重中之重。输入电容应尽可能靠近芯片的VIN和GND引脚。功率电感应靠近芯片的SW引脚,且其下方的PCB各层最好做挖空处理,避免开关噪声干扰其他信号。输出电容靠近VOUT引脚。所有这些功率回路的走线要短、宽,以减小寄生电感和电阻。
- 传感器接口放置:将用于连接MLX90614的4Pin排母放在PCB边缘,方便走线和传感器安装。其位置应靠近外壳为传感器预留的舱室。
- 走线与敷铜:完成信号线连接。I2C信号线(SDA, SCL)最好能并行等长走线,并远离高频或大电流线路(如电感附近)。在PCB的顶层和底层进行大面积敷铜,并连接到GND网络,这能提供良好的屏蔽和散热。记得在敷铜上多打一些过孔,连接顶层和底层的地平面,形成完整的地平面。
3.3 PCB打样与焊接
设计完成后,导出Gerber文件(包含各层铜箔、丝印、阻焊、钻孔等信息)和钻孔文件。我这次选择了PCBWay的打样服务,尝试了他们的紫色阻焊油配白色丝印,效果非常出色。一周左右收到板子后,需要进行焊接:
- 物料准备:对照BOM清单清点所有元器件:IP5306芯片(QFN封装,需热风枪)、1uH功率电感(屏蔽电感为佳)、0402或0603封装的电容电阻、轻触开关、Type-C座、排母等。
- 焊接顺序:建议先焊接高度最低的器件,如贴片电阻电容。可以使用焊锡膏和热风枪进行回流焊接,或者用烙铁逐个焊接。然后焊接IP5306这类QFN芯片,对好位后用热风枪均匀加热直至焊锡融化归位。接着焊接功率电感和Type-C座。最后焊接通孔器件,如按钮和排母。
- 检查与测试:焊接完成后,先用肉眼和放大镜检查有无虚焊、短路。然后,不要急于接电池和主控。先用万用表测量:
- 电源输入:在Type-C口测量是否有5V输入。
- 电池接口:确认正负极无误,电压为0(因为没接电池)。
- 关键电源点:测量IP5306的5V输出端对地是否短路。确认无误后,可以接上锂电池,测量5V输出是否正常稳定。
- 按钮电路:测量按钮一端是否接地,另一端是否通过上拉电阻接到3.3V,且与对应GPIO引脚连通。
4. 嵌入式软件实现详解
4.1 开发环境与库依赖
代码在Arduino IDE或PlatformIO中开发。需要预先安装以下库,这些库可以通过Arduino的库管理器或PlatformIO的lib_deps轻松添加:
- Arduino_GFX_Library:一个强大且高效的显示屏驱动库,支持多种控制器,包括我们使用的ST7789。它比Adafruit的库在某些情况下更轻量、更快。
- Wire:Arduino核心库的一部分,用于I2C通信。
- Adafruit_MLX90614 Library:Adafruit出品的MLX90614传感器驱动库,封装了读取温度的简单函数。
在PlatformIO的platformio.ini中,依赖配置可能如下所示:
4.2 代码结构与状态机设计
整个程序的核心是一个简单的状态机(State Machine),它使程序逻辑清晰,易于理解和维护。我们定义了三种状态:
状态流转逻辑如下:
- 上电后,进入
STATE_READY,屏幕显示待机界面(如“Ready”或一个瞄准图标)。 - 当检测到有效的按钮按下事件(经过消抖处理),状态切换至
STATE_MEASURING。此时屏幕可以显示一个动态的测量动画(如闪烁的圆点或进度条),同时程序开始一个短暂的延时(例如500ms),这是为了让传感器有足够的时间稳定读数,也模拟了真实测温枪的测量过程。 - 延时结束后,通过I2C读取MLX90614的数据,获取物体温度(
mlx.readObjectTempC())和环境温度(mlx.readAmbientTempC())。状态切换至STATE_DISPLAY_RESULT,在屏幕上以大字体显示物体温度值,并保持显示几秒钟(例如5秒)。 - 结果显示时间结束后,状态自动跳转回
STATE_READY,等待下一次测量。
这种状态机设计避免了在loop()函数中使用复杂的延时和标志位,让每一帧循环只处理当前状态该做的事情,代码结构非常干净。
4.3 关键代码段剖析
引脚定义与对象初始化:
这里根据实际硬件连接定义了所有引脚。Arduino_GFX库的初始化方式比较灵活,需要根据屏幕驱动芯片和连接方式创建对应的总线对象和显示对象。
按钮消抖逻辑: 这是确保每次按压只触发一次的关键。简单的消抖代码如下:
温度读取与显示:
在STATE_MEASURING状态延时结束后,执行读取和显示:
displayTemperature()函数负责在屏幕上绘制温度数值,可以使用gfx->setTextSize()设置大字体,gfx->setCursor()定位,gfx->print()输出。
4.4 显示优化与用户体验
为了获得更好的视觉体验,可以做以下优化:
- 自定义字体:使用
gfx->loadFont()加载一个更大的点阵字体来显示温度数字,会比默认字体更醒目。 - 测量动画:在
STATE_MEASURING状态,可以在屏幕中央绘制一个逐渐放大的圆圈或一个跳动的点,给用户一个明确的“正在工作”的反馈。 - 单位切换:可以通过长按按钮或其他方式,在摄氏度和华氏度之间切换。代码上只需在显示前做一个转换:
fahrenheit = celsius * 9.0 / 5.0 + 32。 - 低电量指示:ESP32-C6有ADC引脚可以连接电池电压分压电路,实时监测电池电压。当电压低于阈值(如3.3V)时,在屏幕角落显示一个电池图标或提示。
5. 外壳3D打印与组装工艺
5.1 模型设计与修改要点
我基于原有Medic Mini的外壳进行修改。使用Fusion 360或SolidWorks等CAD软件,主要改动有两处:
- 前壳按钮布局:将原来的三个按钮孔修改为一个更大的椭圆形按钮孔。需要设计一个与之匹配的按钮帽(Button Cap),其下部应有导向柱,确保能准确按压到PCB上的微动开关。
- 后壳传感器舱室:在后壳前端设计一个圆柱形或方形的腔体,用于固定MLX90614传感器。腔体尺寸需与传感器模块严丝合缝,可以采用卡扣或预留打胶槽的方式固定。腔体前端必须开一个与传感器透镜大小匹配的圆孔,确保无遮挡。同时,后壳还需要为电池预留空间。
设计时务必考虑拔模斜度,以便于从3D打印机平台上取下模型。所有螺丝柱内部应添加热熔螺母或自攻螺丝的导向孔。如果使用M2自攻螺丝,柱子内径建议在1.6mm左右;如果预埋热熔螺母(更牢固),则需设计对应的沉孔。
5.2 打印材料与参数设置
- 材料选择:外壳主体使用PLA+ 或PETG。PLA+强度更高,打印成功率高;PETG则更耐热、有一定韧性,抗冲击性更好。按钮帽可以使用透明PLA或柔性材料(如TPU)打印,以获得更好的光扩散效果(如果内部有LED)或按压手感。
- 打印机校准:确保打印机的第一层附着良好,XY轴尺寸准确。这对于需要组装的两个零件之间的配合至关重要。
- 打印参数:
- 层高:0.2mm(平衡精度与速度)。
- 壁厚:至少2-3条轮廓线(约0.8-1.2mm),保证强度。
- 填充密度:15%-20%的网格填充通常足够。
- 支撑:对于按钮孔、传感器腔室内部的悬空部分,需要生成支撑。记得在切片软件中仔细检查支撑结构。
5.3 精密组装步骤
组装顺序直接影响效率和成品质量:
- 传感器固定:将MLX90614传感器插入后壳的专用舱室。从后方观察,确保其透镜正对前方开孔。使用少量热熔胶或环氧树脂在传感器侧面点胶固定。注意胶水不要污染透镜或溢出到电气引脚上。
- 前壳预装:将按钮帽安装到前壳的按钮孔中。将PCB板对准前壳内部的定位柱和螺丝柱,轻轻放平。将电源开关的拨杆或按钮帽也安装到对应位置。
- 电路连接:
- 将MLX90614的4Pin杜邦线(或焊接的排线)连接到PCB上的对应插座(VCC, GND, SDA, SCL)。
- 将锂电池的插头连接到PCB的电池接口(务必确认正负极!)。
- 将Waveshare ESP32-C6模块插入PCB的排母(如果设计为插接)。
- 合壳与紧固:将后壳小心地扣合到已安装PCB的前壳上,确保所有按钮帽、开关拨杆都对准位置,传感器线材没有受到挤压。使用4颗M2螺丝,从后壳的螺丝孔穿入,拧入前壳的螺丝柱中。采用对角线顺序逐步拧紧,确保外壳受力均匀,闭合严密。
- 功能测试:合壳后,先不要完全拧紧所有螺丝,先连接Type-C线充电并开机测试。按下按钮,观察屏幕显示和测温是否正常。一切正常后,再完全拧紧螺丝。
6. 校准、测试与性能优化
6.1 基础功能测试
组装完成后,需要进行系统测试:
- 电源测试:插入Type-C线,观察充电指示灯是否正常(常亮/闪烁)。开机后,用万用表测量PCB上5V和3.3V网络电压是否稳定。
- 显示与按键测试:开机后屏幕应点亮并显示就绪界面。按压测温按钮,应能感觉到清晰的触感,屏幕状态应随之变化。
- I2C通信测试:在代码初始化阶段加入调试信息,通过串口监视器查看是否能成功检测到MLX90614的I2C地址(默认是0x5A)。如果检测失败,检查接线、电源,以及代码中的引脚定义。
- 温度读数比对:这是最关键的测试。准备两个已知温度的参考源:
- 低温参考:一杯冰水混合物,其表面温度应稳定在0°C左右。
- 高温参考:一个恒温加热台,设定在某个固定温度(如50°C),用热电偶温度计测量其表面实际温度作为基准。 将测温枪传感器对准参考源表面(距离2-3厘米),记录读数。与基准温度对比,计算误差。
6.2 软件校准与补偿
MLX90614出厂已校准,但在不同安装条件(如外壳透镜的轻微遮挡)或测量特定材料时,可能存在系统误差。可以在软件中加入一个简单的偏移量校准。
- 获取偏移量:在测量一个已知准确温度
T_known(如上述冰水混合物0°C)的物体时,记录传感器的原始读数T_raw。计算偏移量Offset = T_known - T_raw。 - 应用补偿:在代码中,每次读取物体温度后,都加上这个偏移量:CPPfloat calibratedTemp = mlx.readObjectTempC() + OFFSET_VALUE; // OFFSET_VALUE是你计算出的值
- 高级补偿:如果误差在不同温度段不一致,可以建立一个简单的线性补偿公式:
T_calibrated = a * T_raw + b。通过测量两个不同温度点的基准值,解出系数a和b。
6.3 测量精度与稳定性提升技巧
- 测量距离:严格遵守2-5厘米的最佳测量距离。距离越远,传感器视场覆盖的面积越大,读数是该区域内温度的平均值,可能无法反映你真正想测的那个点。
- 环境温度补偿:MLX90614本身会输出环境温度(Ambient Temperature)。在代码中,可以读取这个值。虽然传感器内部DSP已经进行了一定补偿,但在环境温度剧烈变化时,关注这个值有助于判断读数的可靠性。例如,刚从寒冷的室外进入室内,传感器自身需要时间与环境温度平衡。
- 读数平滑:由于红外测温易受微小气流、目标表面发射率波动影响,单次读数可能有微小跳动。可以在软件中实现一个移动平均滤波器。例如,连续读取5次温度,去掉最高和最低值,然后取中间3次的平均值作为最终输出。这能有效平滑数据,使显示更稳定。CPPconst int numReadings = 5;float readings[numReadings];int readIndex = 0;float total = 0;float average = 0;// 在测量循环中readings[readIndex] = mlx.readObjectTempC();readIndex = (readIndex + 1) % numReadings;// 计算平均值(这里简化了排序去极值的过程,实际可更复杂)total = 0;for (int i = 0; i < numReadings; i++) {total += readings[i];}average = total / numReadings;
- 发射率考虑:对于非常光亮或反射性强的表面(如抛光铝、不锈钢),读数会严重偏低。这不是传感器故障,而是物理原理限制。对于这类物体,需要查找其发射率值(可通过网络或材料手册),并在专业测温仪中设置补偿。我们的DIY测温枪未内置此功能,因此对这类物体的测量结果应定性参考而非定量依赖。
6.4 功耗优化与续航提升
对于便携设备,续航很重要。ESP32-C6本身支持深度睡眠,但我们的设备需要随时响应按钮唤醒,且屏幕常亮,深度睡眠不适用。但我们可以进行其他优化:
- 屏幕背光控制:在
STATE_READY待机状态,可以将屏幕背光(通过TFT_BL引脚控制)调暗,例如设置为最大亮度的30%。当按下按钮进入测量状态时,再将背光调至100%。这能显著降低功耗。 - Wi-Fi/蓝牙关闭:我们的功能完全不需要无线连接。在
setup()函数中,确保调用WiFi.mode(WIFI_OFF)和btStop()来关闭ESP32的无线射频模块,这能节省大量电流。 - CPU频率:如果测温逻辑不复杂,可以考虑在
setup()中调用setCpuFrequencyMhz(80)将CPU主频从160MHz降至80MHz,也能降低一些功耗。 - 电池选择:选择容量更大的锂电池,如1000mAh或2000mAh,但需考虑外壳空间。一个600mAh的电池在屏幕常亮、间歇测量的情况下,连续工作几小时到十几小时是可行的。
经过以上步骤,你就能获得一个功能完整、性能可靠的自制红外测温枪。它不仅解决了临时替代专业工具的燃眉之急,其开源特性也允许你在此基础上继续扩展,例如增加数据记录、蓝牙传输到手机、或更换更高分辨率的MLX90640传感器矩阵来实现简易热成像功能。整个项目从电路设计到代码编写,再到机械组装,是一次对嵌入式系统开发全链路的绝佳实践。