基于STM32与MLX90614的红外测温系统设计与实现详解

发布时间:2026/9/6 21:14:27
基于STM32与MLX90614的红外测温系统设计与实现详解 简介一份基于STM32的红外测温系统设计文档面向嵌入式学习者和工程技术人员系统讲解从课题背景、方案论证到硬件软件实现的完整流程。文档选用STM32F103作为主控搭配MLX90614红外传感器、DS18B20辅助测温、LCD1602显示并涵盖按键、复位、电源及报警电路既适合课程设计参考也适合项目开发借鉴。包体为单个docx文件大小约2.09MB内容包含系统方案、硬件原理、软件流程和调试过程结构完整便于直接阅读和二次编辑。已有175人学习下载可作为STM32应用与红外测温技术结合的典型案例。全文从数字测温和红外测温的发展现状入手对比不同传感器选型给出硬件设计框图和程序流程图并记录软硬件调试方法。读者可从中获取一套可复用的测温系统设计思路包括电路连接、代码逻辑和排错经验对理解嵌入式测温产品的实际开发很有帮助。 大二下学期开始接触电子系统设计那会儿实验室里一半人做温湿度采集另一半做超声波测距真正把“基于STM32的红外测温系统设计”当题目的人不算多。我当初选这个方向纯粹是因为非接触测温听起来很酷——不用贴上去拿着板子对着一杯热水按一下屏幕上就能跳出温度。等真正上手才发现题目里每个字都有门道STM32只算最省心的部分真正的坑集中在传感器选型、硬件布局、发射率修正和标定这几个环节。这篇文章就把我整套做下来的思路、电路、代码和踩坑记录完整写一遍给准备做类似课设、毕设或者单纯想入坑红外测温的朋友一个可复现的参考。先交代一下做完之后的系统规格主控用STM32F103C8T6传感器用迈来芯Melexis的MLX90614红外测温模块显示走0.96寸OLED带两个按键用来调发射率和报警阈值超过阈值蜂鸣器会响。整体测量范围是-40℃到125℃这个取决于传感器型号分辨率0.02℃通电实测在25℃环境下手持测量人体额头与医用测温枪误差在±0.3℃以内。这个精度对课设和多数非医疗场景完全够用。下面从原理一路讲到联调按我做项目的顺序来。1. 红外测温的底层逻辑黑体辐射、热电堆与传感器选型1.1 为什么不用热敏电阻要绕这么大一圈测红外接触式测温NTC热敏电阻、DS18B20、热电偶之所以在很多场景被嫌弃是因为它必须和被测物体接触而且需要时间达到热平衡。你总不能拿个热敏电阻去贴一千米外的变压器接头也不能每次测体温都等三分钟。红外测温的思路是完全不接触靠接收物体自身辐射出来的红外线来推算温度。物理学基础是斯特藩-玻尔兹曼定律物体单位面积辐射的总功率 E ε·σ·T⁴。其中ε是发射率σ是斯特藩-玻尔兹曼常数T是热力学温度。也就是说物体温度越高辐射出来的红外能量按四次方关系猛增。探测器只要测到辐射功率反推就能得到温度。这里有个非常容易被忽略的概念发射率ε。真实物体并不是理想黑体ε在0到1之间代表它“辐射能力”和黑体的比值。抛光金属表面ε可能只有0.05而人体皮肤、黑胶布这种表面ε高达0.95左右。如果传感器默认按ε1计算测抛光金属时读数会严重偏低——因为金属把周围环境的红外辐射反射了一部分进探测器探测器分不清哪些是目标自己发的、哪些是反射别人的。后面我会专门讲发射率修正的具体操作这是红外测温能不能做得准的分水岭。1.2 热电堆传感器红外测温的核心探测器件红外测温传感器里最主流的探测结构是热电堆thermopile。原理可以这么理解在一片MEMS硅片上用微加工工艺做出几十上百对串联的热电偶热端覆盖一层能吸收红外辐射的薄膜冷端保持在传感器自身温度。目标物体辐射来的红外线照到热端热端温度升高热端和冷端之间就产生温差根据塞贝克效应温差会转化成电压。电压只有微伏到毫伏级别经过片内高精度运放放大再进行模数转换和温度计算最终输出数字信号。消费级和工业级最常见的成品就是MLX90614它把热电堆探头、信号调理电路、ADC、数字信号处理、PWM/SMBus接口全部集成在一颗TO-39金属封装里。使用体验就是一个词省事。你不需要设计微伏级信号放大电路不用担心运放失调电压直接I2C严格说是SMBus读寄存器温度值就出来了。1.3 数字传感器方案和模拟调理电路方案到底选哪个很多课程设计要求“展示信号处理链路”会有老师暗示你别用一体化的MLX90614模块要用裸热电堆探头搭模拟放大电路。我两种方案都试过把特点列出来供选择对比项MLX90614数字方案裸热电堆放大电路方案硬件复杂度极低I2C直接读数据高需要仪表放大器、滤波、ADC开发时间1-2天跑通1-2周调通还要标定精度出厂校准典型±0.5℃依赖你的电路和标定水平成本模块约20-60元元器件约10-30元教学/展示效果偏应用原理黑盒能讲清楚完整信号链踩坑风险低高容易被50Hz工频干扰折磨我的建议很明确如果目标是做一个“能用、够准”的系统闭眼选MLX90614。如果是为了课程要求必须展示模拟链路那再考虑裸探头方案并且做好花两三倍时间调零漂和干扰的心理准备。下面整篇的硬件、软件说明都基于MLX90614数字方案。2. 硬件电路搭建从最小系统到测温通道的细节2.1 STM32F103C8T6最小系统够用、便宜、生态好主控选择STM32F103C8T6一颗蓝色Pill开发板大约十块钱出头Flash 64KB、RAM 20KB跑一个红外测温加显示绰绰有余。就算以后想加无线模块、加语音播报资源也够。它的I2C外设、ADC、定时器、PWM该有的都有而且网上教程储量巨大哪个引脚什么功能遇到问题一搜就有答案。用最小系统板的话晶振、复位、LDO稳压、USB转串口全都是现成的直接插面包板或者画个扩展板就能开始调。如果是自己画完整原理图注意这几点8MHz主晶振要靠近MCU负载电容用12pF到20pF都行复位脚NRST上拉10k电阻加100nF电容到地防止复位不稳BOOT0和BOOT1都通过10k电阻下拉到地保证从主Flash启动。我自己后来画板子习惯在VDD每个引脚旁边放一个100nF去耦电容电源入口放一个10μF钽电容这个习惯帮我少追了很多莫名其妙的复位问题。2.2 MLX90614外围电路看似简单实则三个地方容易错MLX90614总共就几个引脚SDA、SCL、VCC、GND还有电源和地外围看似只接两个上拉电阻。但我在这个“简单”上栽过跟头说三个关键点。第一SDA和SCL都必须接上拉电阻到VCC。STM32的I2C引脚虽然是开漏模式但内部上拉很弱总线电容一上来波形就变差。MLX90614的SMBus协议要求上拉电阻典型值4.7kΩ到10kΩ。我用的是4.7kΩ1.8V逻辑电平时可能要用更小的但3.3V系统用4.7kΩ稳定得很。第二MLX90614的VCC要放一个0.1μF和一个10μF的去耦电容位置尽量靠近传感器引脚。它内部有一个小功率加热器用于温度参考补偿供电纹波大会直接影响内部ADC的测量精度。第三MLX90614的SMBus地址是7位0x5A写入时的8位地址是0xB4读取是0xB5这个没有地址引脚可改多颗传感器挂同一条总线就需要用PWM模式或者额外设计本项目只挂一颗不用纠结。2.3 显示、按键、报警模块够用就好别盲目堆料显示模块我选0.96寸I2C接口的SSD1306 OLED。理由很简单I2C只占用两个引脚显示内容多功耗低不会像LCD1602那样需要一堆数据线还得自己焊对比度电位器。四针VCC、GND、SCL、SDA一插I2C地址默认0x3C配上u8g2库或者自己写SSD1306驱动半小时内能点亮。按键用了三个独立按键一个进入设置模式一个加一个减。功能是调整发射率ε从0.10到1.00步进0.01和超温报警阈值。按键输入我强烈建议别在while循环里用delay消抖这样会影响测温的实时刷新。用5ms定时中断去扫描按键状态加一个简单的状态机消抖代码不复杂体验完全不同。报警输出我用了有源蜂鸣器。注意有源蜂鸣器是给高电平就响、给低电平就不响而且工作电流有几十毫安不能直接接在GPIO上中间加一个S8050三极管或者直接用NPN三极管驱动基极串1kΩ电阻接到MCU引脚。这个细节看着小但直接决定你的蜂鸣器能不能把声音推响。2.4 PCB布局里最容易翻车的热干扰问题如果你要画PCB而不是用开发板飞线下面这条请重点记住红外传感器要尽量远离板上的发热器件。MLX90614探测的是目标辐射但它内部还有一个环境温度传感器用来做参考补偿。板上的STM32芯片、LDO稳压芯片、蜂鸣器在工作时都会发热如果这些热量传导到MLX90614的封装上内部环境温度读数就会漂移目标温度也跟着出错。实际的系统设计里漂移个3到5℃都是可能的。我自己的布局经验是把MLX90614放在PCB一角周围不要铺大块铜皮因为铜是良导热体LDO放在对角位置如果板上空间允许传感器正下方PCB不铺铜、甚至掏空蜂鸣器尽量远离传感器它工作的时候发热量不小。要是只做开发板飞线版本这个问题的严重性没那么高因为空气流通会带走热量但一做成封闭外壳自热问题立刻放大。我就见过一个师兄把整个板子塞进3D打印的密闭壳子里测温漂了6℃查了半天才发现是电源芯片的热量憋在里面出不去。3. 软件实现驱动、滤波、发射率修正和状态控制3.1 I2C底层配置和MLX90614寄存器读写STM32的I2C外设有两个I2C1和I2C2我用的I2C1引脚是PB6SCL和PB7SDA。用HAL库配置成标准模式100kHz就行MLX90614的SMBus最高支持100kHz别贪快。重点来了读MLX90614的RAM寄存器时寄存器地址是16位的这是最多人踩的坑。具体来说要读目标温度寄存器地址不是0x07而是0x0007。如果按8位地址去读设备会返回NACK或者读到乱码。用HAL库的代码长这样uint8_t buf[3]; uint16_t reg 0x0007; // T_OBJ目标温度16位地址 if (HAL_I2C_Mem_Read(hi2c1, 0x5A 1, reg, I2C_MEMADD_SIZE_16BIT, buf, 3, 100) ! HAL_OK) { return -999.0f; } // 数据格式低字节在前高字节在后最后一个字节是PEC校验 uint16_t raw (buf[1] 8) | buf[0]; float temp_k raw * 0.02f; float temp_c temp_k - 273.15f;buf接收三个字节前两个是16位温度数据第三个是PEC校验字节。我们在Lab里就只读前两个字节PEC校验没做因为I2C本身的ACK机制已经能发现大部分传输错误实际跑起来很稳。但如果你是做正经产品或者毕设要求严谨PEC校验建议加上MLX90614数据手册附录里有CRC-8算法。寄存器地址再列一遍做个速查寄存器含义数据格式0x0006环境温度T_A16位×0.02K0x0007目标温度T_OBJ16位×0.02K0x0008目标温度2T_OBJ216位×0.02K0x04EEPROM发射率ε16位0xFFFF1.00环境温度在0x0006目标温度在0x0007两个都读出来后面有用。OLED部分就是标准的SSD1306驱动我用的是自己精简过的底层函数只保留画字符串和画字符的功能然后做了一组6x8和12x16的字库显示一行标题、三行数据、一个状态图标足够用了。3.2 温度滤波别用移动平均一棍子打死MLX90614的输出本身已经经过内部滤波稳定度不错但直接读原始值还是会看到末位跳动——毕竟红外测温是测量极其微弱的辐射信号外部环境的微小扰动都会造成波动。我在实际测试中测一个30℃的恒温发热片原始读数会在29.8℃到30.4℃之间来回跳。最简单的滑动平均就能压住大部分波动窗口取10次很合适。太小了压不住太大了响应变慢测量移动目标时会拖尾。我用的滤波代码#define FILTER_LEN 10 float filter_buf[FILTER_LEN] {0}; uint8_t filter_idx 0; uint8_t filter_count 0; float filter_sum 0.0f; float temp_filter(float new_value) { filter_sum - filter_buf[filter_idx]; filter_buf[filter_idx] new_value; filter_sum new_value; filter_idx (filter_idx 1) % FILTER_LEN; if (filter_count FILTER_LEN) filter_count; return filter_sum / filter_count; }比滑动平均更好一点的做法是限幅平均滤波先判断当前值和上一秒的滤波值的差是否超过一个阈值比如3℃超过就认为是粗大误差丢弃这一次的数据。这个方法在有人从传感器前快速走过、导致一瞬间读到背景墙温度时非常有效。我的代码里两个都用粗大误差剔除在前滑动平均在后。3.3 发射率修正直接改传感器的EEPROM还是软件补偿前面反复提到发射率现在说实操。MLX90614在出厂时默认发射率寄存器是0xFFFF也就是ε1.0。如果被测物体不是理想黑体直接读出来的温度就会偏低。两个处理办法。第一个办法是改传感器内部EEPROM的0x04寄存器把它设置成目标实际的发射率。用SMBus写命令的方式往0x04写入对应的16位值比如ε0.95对应十六进制0xFF0C计算公式是ε×0xFFFF。注意写EEPROM需要给MLX90614的VCC瞬间升到7V以上这在正常电路里根本做不到得单独做写保护电路。我不推荐大家折腾这个因为传感器里的出厂校准数据在EEPROM里写错地址可能搞坏校准参数。第二个办法简单可靠传感器读出的数据按照ε1.0算出来的我们在软件里根据目标的真实ε做二次修正。修正公式是T_real pow( (pow(T_obj_k, 4) - (1 - eps) * pow(T_amb_k, 4)) / eps, 0.25 ) - 273.15其中T_obj_k是MLX90614读出的目标温度开尔文T_amb_k是同时读出的环境温度开尔文eps是用户设置的发射率。这个公式的物理含义是传感器把一部分来自周围环境的反射辐射也当成了目标辐射我们要把它减掉。实际验证下来用这个方法测抛光金属表面ε从1.0改成0.3读数能从偏差十几度修正到偏差两三度以内。精度仍然有限因为真实表面的发射率不是单一常数还和波长、温度有关但日常场景已经够用。3.4 主循环状态机不要写成一块大饼系统功能可以拆成几个状态正常测温显示、配置发射率、配置报警阈值、报警输出。我用一个简单的枚举型状态机来管理代码结构比全堆在主循环里清晰很多。typedef enum { STATE_MEASURE 0, STATE_SET_EPS, STATE_SET_THRESHOLD, } sys_state_t;默认是STATE_MEASURE每秒刷新一次温度并显示。短按设置键进入STATE_SET_EPS加减键调发射率OLED第二行会显示当前的ε值和你用这个ε修正后的实时温度这样调ε的时候立刻能看到效果。再次短按进入STATE_SET_THRESHOLD加减键调报警阈值。第三次短按回到STATE_MEASURE。报警判断放在主循环里一旦当前测温值超过阈值蜂鸣器响OLED状态图标闪烁温度回落阈值以下2℃后再解除报警这个回差电压的处理方式是为了避免蜂鸣器在阈值附近反复通断。4. 联调阶段的三个硬骨头连接失败、数据漂移、标定精度4.1 调试器连不上芯片从“No target found”到正常烧录的排查过程第一次把程序烧进板子就收到报错error: no stm32 target found! 这个错误提示在Keil和STM32CubeProgrammer里都见过原因五花八门。我把我踩过的和帮别人排查的路径整理出来按顺序排查最快。第一查供电。用万用表量STM32的3.3V引脚没电压看LDO输出再看USB转串口很多时候是杜邦线松了一根芯片压根没上电。第二查SWD接线。ST-Link的SWDIO接芯片PA13SWCLK接PA14GND必须共地。我犯过的错误是只接了SWDIO、SWCLK和3.3V忘了GND调试器当然找不到目标。第三按住复位键不放点击下载松开复位。这招处理“程序把SWD引脚复用成普通GPIO”引起的问题特别有效——芯片上电时SWD默认可用程序运行后引脚才被改成GPIO在复位瞬间抢时间完成擦除。第四用STM32CubeProgrammer连接它会尝试连接并显示当前RDP等级。如果读保护是Level 1需要先执行解除读保护代价是Flash被全片擦除。第五降低SWD速度。把Keil里Debug选项卡的SWD时钟从4MHz改成1MHz甚至100kHz长杜邦线或者接触不良时高速容易失败。这一套流程走下来绝大多数“No target found”都能解决。4.2 温度读数莫名漂移把传感器和发热源物理隔离系统刚组装完放在桌上测量一个恒温目标发现温度会在两三分钟内慢慢升高1℃到2℃然后稳定在高位。第一反应是传感器坏了后来才意识到是板子上STM32和LDO的热量在传导。做了一组对照实验传感器悬空放在离板子5cm的地方读数稳定传感器紧贴板子安装开机10分钟后读数漂了近3℃。解决办法就是前面硬件章节提到的布局原则因为已经画完板子没法动PCB了只能让传感器通过排线引出固定在远离板子的支架上。如果是重新画板传感器区域和功率器件距离至少2cm以上且传感器下方不要铺完整的地铜皮。如果你测的目标本身是变化的比如人体这种漂移可能被误判成“目标温度变化”在验证红外测温可靠性时尤其要警惕。4.3 标定精度没有黑体炉也能把手头误差压到±0.5℃MLX90614出厂精度已经达到±0.5℃理论上是“即插即用”的。但实际安装位置、外壳遮挡、光学窗口的透过率都会引入额外误差。我用一个行之有效的低成本方法做了整体标定用一个可调温的热水杯把一支精度0.1℃的工业级PT100探头贴在杯壁同时用MLX90614对准同一点。从40℃到70℃区间每隔5℃记录一次红外读数。将“传感器读数减去PT100真值”的偏差拟合出一条二次多项式曲线然后在软件里用这条曲线做输出补偿。标定关键点和PT100探头完全同步采样杯壁温度会缓慢下降同一个时刻的读数才有可比性。测的时候让温度先自然下降到一个稳定段再记录不要边降温边手忙脚乱地记数据。实测下来补偿前最大偏差1.2℃补偿后所有标定点偏差都落在±0.3℃内。5. 项目还能往哪走从课设到智能测温终端的扩展思路5.1 加无线功能ESP8266/ESP32上报数据到手机这是被问得最多的扩展方向。核心思路是STM32通过串口或SPI把温度和发射率数据传给ESP8266ESP8266连上路由器用MQTT协议上报到服务器或者手机上的MQTT客户端。STM32端只需要把温度数据打包成结构体通过串口DMA发送ESP8266端用AT指令或Arduino固件都行。我自己用的方式是ESP8266刷了Arduino固件写了一个简单的MQTT publisher手机用MQTT Dash App订阅主题延迟大概几百毫秒完全够用。要注意的是两个模块之间的电平要匹配ESP8266是3.3V和STM32直接串口连接没问题。来自南京邮电大学电子系统设计课程的同学如果想把“智能测温终端”做出区分度无线数据记录是最容易实现又最能展示效果的模块。5.2 加身份联动K210摄像头识别之后才测温最近不少人问“K210和STM32怎么通讯”这个组合用在测温上确实很有画面感。K210负责摄像头人脸检测检测到人脸后通过串口发一个“测”命令给STM32STM32收到命令后才触发MLX90614采集同时OLED显示测温结果。整套联动逻辑不复杂难点在K210的人脸检测模型训练和双MCU之间的通信协议设计。我建议通信协议这样做帧头0xAA、命令字、数据长度、数据、校验和STM32端用状态机解析这样比在循环里等固定长度数组要健壮得多。5.3 加记录功能把温度历史存进Flash或SD卡测温系统最实际的痛点是没有历史记录测完看一眼就没了。在STM32F103上扩展一个SPI Flash或者直接上SD卡文件系统把每次测量的时间戳、温度、发射率一起追加写入配合一个简单的上位机Python的PySerial读串口导出CSV就能在后端做温度趋势分析。如果以后结合RK3588这类高性能主控做视频监控再把红外测温叠加到视频画面上那就完全是另一个量级的项目了。不过前期一张STM32F103的板子、一颗MLX90614、一块OLED先把测温链路跑通比什么花哨功能都重要。5.4 工程化经验版本管理、文档记录和留足调试接口做系统的过程里我自己最大的教训是一开始没有做版本管理。东加一个功能西修一个bug代码很快改得一团糟。后来开了个Git仓库每次稳定版本打一个tag调试接口串口打印、GPIO测试点全部预留出来改什么地方都记录一下排查问题的速度快了不止一倍。文档方面原理图导出的PDF、传感器数据手册、自己的调试笔记都放在项目文件夹里命名成“20240115_temp_ok_v1.1.sch”这种格式回头找资料再也没翻过车。我的个人体会是红外测温这类系统设计的价值不在于把某个库调通而在于整个链路环环相扣——物理原理决定了测量上限硬件布局决定了有没有系统误差软件滤波决定了读数稳不稳标定决定了最终准不准。每一步单独看都不难但把它们串起来以后你会发现一个看似简单的“拿起来测一下温度”的动作背后有这么多设计决策要做。如果你打算从零复现这个系统我建议按照本文的顺序来先用手头的STM32开发板接上MLX90614模块把数据读出来再逐步加滤波、显示、按键最后才画板子。每一步都验证过再往下走整体调试会顺很多。按照这路子从零开始做到一个稳定可用的系统一周时间是足够的。本文还有配套的精品资源点击获取