ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

STM32与MLX90614红外测温系统设计:从选型到代码实现

2026/9/6 21:15:52 拓冰建站 浏览量
STM32与MLX90614红外测温系统设计:从选型到代码实现 简介一份基于STM32的红外测温系统设计文档面向嵌入式系统初学者、电子竞赛参赛者及毕业设计学生系统阐述了从课题背景、技术现状、方案论证到硬件/软件设计、系统调试与总结的完整流程。文档选用STM32F103作为主控搭配MLX90614红外测温模块、DS18B20辅助校准、LCD1602显示并给出复位、电源、报警等电路设计细节同时涵盖主程序流程图、部分程序实现及软硬件调试思路有助于读者掌握非接触测温设备的设计方法。压缩包为单个DOCX格式文件大小约2.09MB总计1个文件内容组织结构清晰目录完整可直接作为课设或毕设的参考资料。目前已有175人学习浏览适合需要快速了解STM32红外测温系统整体架构与关键技术的读者。 做嵌入式这几年红外测温这个方向几乎每年都会被拿出来翻新一次。这两年医疗电子、智能家居和工业设备里非接触测温依然是刚需——电机堵转检测、厨电防干烧、母婴护理、人车感应都能见到它的身影。我自己用手头最常规的STM32F103C8T6主控配MLX90614红外测温传感器完整搭过一套红外测温系统从传感器选型、I2C通信、数据定标到OLED显示和超温报警整个流程都走了一遍。这篇就把设计过程、核心代码和踩过的坑一次性整理出来给正在做STM32相关毕业设计或想在工控、物联网项目里加测温模块的朋友一个可直接参考的方案。1. 方案选型为什么是STM32加MLX906141.1 主控选型背后的三个理由STM32这个系列在测温项目里几乎是默认答案尤其是F1系列成本低、资料全、上手门槛也低。我在这个项目里用的是STM32F103C8T672MHz主频、20KB SRAM、64KB Flash对红外测温这种纯数据采集加显示的任务来说完全够用。选它的第一个理由是I2C外设齐全。MLX90614默认走SMBus协议本质上兼容I2CSTM32F103有硬件I2C外设可以直接挂上去用。第二个理由是生态成熟HAL库、标准库的例程遍地都是出问题网上基本都能搜到答案这对学生党做毕业设计非常友好。第三个理由是后续扩展空间大同一个主控以后还能加WiFi模块、蓝牙模块、LCD屏、语音播报哪怕整个项目从测温扩展到全屋环境监测也不用换芯片。有朋友可能会问为什么不用ArduinoArduino写起来确实更快但STM32能让你真正理解寄存器操作、时钟树、外设中断这些底层逻辑而且工业环境和毕业设计答辩对这一块的认可度更高。我个人建议如果纯粹为了验证测温功能Arduino可以如果想把系统做成一个完整的产品级方案STM32是更好的选择。1.2 红外测温传感器怎么选红外测温传感器市面上最常见的无非几种MLX90614、MLX90640、AMG8833、TMP006。其中MLX90614是综合性价比最高的单点测温方案自带DSP处理出厂校准过直接读寄存器就能拿温度数据不需要自己做复杂的温度补偿。MLX90614的核心是一颗热电堆传感器它接收被测物体辐射的红外线通过内部算法换算成温度。它有两个关键指标一是测量精度典型在±0.5°C体温范围内足够满足绝大多数非接触测温场景二是视场角常见的有35°和90°两种型号型号后缀一般会标注比如MLX90614ESF-BCI就是90°视场角度适合近距离大范围测温MLX90614ESF-DCI则是35°视场角适合远距离小目标测温。我在项目里选的是90°视场角的BCC型号方便在室内环境下对桌面、设备面板这类目标快速测温。如果你是要做人体额头测温建议用SMB系列加金属网罩并额外做距离校准因为D:S比距离与目标直径的比例直接决定你在多远的距离测到的温度是准的。注意MLX90614是“红外辐射测温”和那个用NEC协议传数据的红外遥控是完全两码事。前者读的是物体自身辐射的热量后者只是用红外光做载波通信。别把这两者混在一起选型这是很多新手容易犯的第一个概念错误。1.3 系统架构一句话讲清楚整个系统说白了就是四条线。传感器负责把物体辐射的红外信号变成数字量STM32通过I2C把数字量读回来内部换算成摄氏温度再送给屏幕显示同时按键设置报警阈值温度超限就驱动蜂鸣器报警LED指示灯同步闪烁。如果还想加功能串口留出来随时接个ESP8266或蓝牙模块就能把温度数据上传到云端。这就是一个非常典型的传感器加主控加执行器的闭环结构不复杂但对硬件设计、通信协议、数据处理这套嵌入式基本功的考察很全面所以特别适合做课程设计或毕业设计。2. 硬件设计与接线细节2.1 主控最小系统和引脚规划STM32F103C8T6要做的事情很明确上电初始化、读传感器、刷屏幕、响报警所以最小系统只要保证电源、复位、时钟三样东西不出问题就行。我用的是现成的核心板USB供电5V经过板载AMS1117稳压到3.3V外部接了一个8MHz晶振由内部PLL倍频到72MHz。引脚分配这里给出我实际用的方案你可以直接照抄功能模块引脚说明MLX90614 SCLPB6I2C1_SCL硬I2CMLX90614 SDAPB7I2C1_SDA硬I2COLED SCLPB8软件模拟I2COLED SDAPB9软件模拟I2C蜂鸣器PA6高电平触发LED指示灯PA7高电平点亮按键1报警阈值PA0外部中断/轮询按键2报警阈值-PA1外部中断/轮询这里有个设计经验OLED我故意没有复用硬件I2C而是用软件模拟。原因很简单MLX90614的SMBus时序和标准I2C有点差异用硬件I2C调试比较麻烦而且OLED屏幕刷新频率高如果和温度读取共用一条I2C总线会产生相互等待导致屏幕卡顿或读温度超时。分开用两路I2C软件和硬件各管一路逻辑清晰代码也更好写。2.2 MLX90614接线最容易踩的坑MLX90614模块本身引脚不多VCC、GND、SCL、SDA四个脚接法看起来很简单。但这里有一个非常关键的细节I2C总线必须接上拉电阻STM32的PB6和PB7内部虽然可以开启上拉但有些MLX90614模块板上已经带了4.7k上拉电阻有些则没有。我在第一版接线时用的是一块没上拉电阻的裸传感器模块直接接硬件I2C结果SCL线上的波形完全是乱的传感器偶尔能读到数据大多数时候直接超时。后来用万用表量了一下SCL电平发现高电平只有1.6V左右明显偏弱。解决办法是在SCL和SDA各加一个4.7k电阻到3.3V波形立刻正常了。提示买了MLX90614模块先看一下板子背面有没有印着472的贴片电阻有就说明上拉已经集成不需要额外加没有的话自己必须补两个4.7k电阻否则I2C通信就是玄学时好时坏。另外模块的VCC我接的是3.3V没有接5V。虽然MLX90614支持3.3V和5V两种供电但接5V时SDA和SCL的高电平也是5V如果STM32这边是3.3V系统直连会有电平不匹配的问题需要电平转换。直接统一用3.3V供电省事且电平兼容实测工作稳定。2.3 显示、报警和电源的整体匹配OLED屏我用的是一块0.96寸128x64的I2C屏幕这种屏在STC、STM32、ESP32项目里几乎人手一个驱动芯片是SSD1306支持3.3V供电引脚直接接主控的软件I2C引脚就行。唯一要注意的是OLED的I2C地址默认是0x788位或0x3C7位在写驱动时要和实际对应上这个后面代码部分会说。报警部分用的是有源蜂鸣器低电平触发还是高电平触发取决于模块上有没有三极管驱动我买的模块是低电平触发所以代码里引脚默认拉低报警时输出高电平驱动一个NPN三极管导通蜂鸣器。LED指示灯则串联一个330欧电阻接到PA7电流大概10mA亮度足够也不会超IO口最大电流。电源部分要额外提醒MLX90614在工作时需要稳定的供电如果使用电池供电且电池电压掉到3.0V以下传感器读出来的温度会出现很大的漂移。实测在锂电池电压从4.2V降到3.5V的过程中显示温度会有约0.8°C的跳变这个是传感器内部基准电压跟随电源变化导致的。解决办法是加一颗3.3V的LDO稳压或者用AMS1117-3.3单独给传感器供电。3. 核心代码实现与参数解读3.1 初始化流程与I2C通信细节我的代码基于STM32标准库开发初始化顺序是系统时钟72MHz、GPIO复用、I2C1主机模式、软件I2C引脚、按键GPIO、蜂鸣器和LED的GPIO最后初始化OLED并显示开机画面。整个流程不长但顺序有讲究I2C外设的时钟一定要在GPIO配置之前使能否则复用功能配置会失败。硬件I2C1的配置如下void I2C1_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; I2C_InitTypeDef I2C_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); GPIO_InitStructure.GPIO_Pin GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_OD; // 开漏复用 GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOB, GPIO_InitStructure); I2C_InitStructure.I2C_Mode I2C_Mode_I2C; I2C_InitStructure.I2C_DutyCycle I2C_DutyCycle_2; // 2:1占空比高速模式 I2C_InitStructure.I2C_OwnAddress2 0x00; I2C_InitStructure.I2C_Ack I2C_Ack_Enable; I2C_InitStructure.I2C_ClockSpeed 100000; // 100kHz标准模式 I2C_Init(I2C1, I2C_InitStructure); I2C_Cmd(I2C1, ENABLE); }这里有个细节GPIO模式必须是开漏复用GPIO_Mode_AF_OD不能是推挽输出。I2C协议本身设计就是开漏加外部上拉这样才能实现线与功能和电平仲裁。如果你配成推挽两设备同时拉低总线时可能损坏IO口而且波形也不对。时钟速度这里我特意设成了100kHz没有用400kHz快速模式。原因在于MLX90614的SMBus从机时序比较挑剔400kHz下对信号质量要求高接线稍长就容易丢ACK。100kHz虽然慢一点但每次只是读两字节数据实际测试一秒钟刷新20次温度完全没问题稳定压倒一切。3.2 读取MLX90614温度的完整操作MLX90614内部最核心的寄存器有两个0x06是物体温度TOBJ0x07是环境温度TA。读取时序是主机先发送从机地址加写位0x00然后发送寄存器地址再发重复起始位最后发送从机地址加读位0x01从机返回两个字节的数据和一个PEC校验字节。完整读取代码#define MLX90614_ADDR 0x5A #define MLX90614_TOBJ 0x07 uint8_t MLX90614_ReadBytes(uint8_t reg, uint8_t *data, uint8_t len) { uint8_t i; I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(I2C1, MLX90614_ADDR, I2C_Direction_Transmitter); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_SendData(I2C1, reg); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(I2C1, MLX90614_ADDR, I2C_Direction_Receiver); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); for(i 0; i len; i) { if(i len - 1) I2C_AcknowledgeConfig(I2C1, DISABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); data[i] I2C_ReceiveData(I2C1); } I2C_AcknowledgeConfig(I2C1, ENABLE); I2C_GenerateSTOP(I2C1, ENABLE); return 0; }读取到的原始数据是16位无符号整数分辨率0.02°C存的是开尔文温度。换算公式很简单float MLX90614_GetObjectTemp(void) { uint8_t buf[3]; uint16_t raw; float temp_k, temp_c; MLX90614_ReadBytes(MLX90614_TOBJ, buf, 3); raw (uint16_t)(buf[0] | (buf[1] 8)); temp_k (float)raw * 0.02f; temp_c temp_k - 273.15f; return temp_c; }第三个字节是PEC校验码我这里没有做校验而是直接忽略因为实测正常环境下误码率极低。如果项目运行环境有强电磁干扰建议把PEC校验加上方法是对从机地址、寄存器地址、读地址和数据字节做一个CRC-8计算和收到的PEC字节比对不一致就丢弃这一帧。3.3 数据处理发射率、滤波和定标MLX90614出厂默认发射率是0.5左右写在内部EEPROM的0x04寄存器里。但现实世界被测物的发射率基本都在0.85到0.98之间比如人体皮肤约0.98黑色电路板约0.90抛光金属表面只有0.1左右。用默认发射率测人体额温读数会明显偏低。所以使用前必须把发射率改成和目标匹配的值。写EEPROM的代码void MLX90614_SetEmissivity(float emis) { uint8_t val (uint8_t)(emis * 256.0f); MLX90614_WriteEEPROM(0x04, val); }0.98的发射率对应十六进制0x62写入后传感器内部就会按这个系数计算温度。注意EEPROM写次数有限虽然MLX90614官方没给具体次数但最好只在初始化时写一次不要每次开机都写否则容易把EEPROM写坏。温度数据出来之后还有一个痛点就是跳动。MLX90614在静止环境下读出来的数值本身比较稳定但人拿着设备手抖、环境有气流扰动数值就会有正负0.3°C的跳变。我在这里加了一个5点滑动平均滤波就是保留最近5次采样取平均值输出。这个滤波在代码里实现最简单用一个循环队列就行复杂度低效果肉眼可见。实操心得如果你测的目标是自己烙铁头这类发射率很低的金属会发现读数怎么都不准这时候别怀疑代码先测一块黑色电工胶带。把胶带贴在金属表面温度读数会立刻变得合理因为胶带的发射率接近0.95。这是做红外测温必须知道的一个小技巧。3.4 OLED显示和超温报警的实现OLED显示我用的是开源的SSD1306驱动核心就是初始化配置寄存器列表然后通过软件I2C把显存数据推送到屏幕。这里建议在内存里开一个128x8字节的显存缓冲所有绘制操作先在缓冲里改数据最后一次性刷新到屏幕这样可以避免频繁I2C通信导致屏幕闪烁。显示的布局我分了三个区域第一行显示实时温度第二行显示报警阈值第三行显示状态正常/超温。温度整数部分和小数部分分开绘制用大号字体突出显示。报警逻辑比较简单if (temp_c alarm_threshold) { alert_flag 1; GPIO_SetBits(GPIOA, GPIO_Pin_6); GPIO_SetBits(GPIOA, GPIO_Pin_7); } else { alert_flag 0; GPIO_ResetBits(GPIOA, GPIO_Pin_6); GPIO_ResetBits(GPIOA, GPIO_Pin_7); }蜂鸣器这里我没有加延时函数来做间歇报警而是用了一个全局变量timestamp在主循环里通过时间戳判断是否到翻转时刻。这样避免delay卡死主循环保证OLED刷新和按键扫描都不被打断。有些人在微博上问“stm32延时函数delay卡死”多半就是因为在中断里调用了阻塞式延时中断嵌套时导致死循环这个习惯一定要改掉。4. 常见问题与排查实录4.1 I2C读取超时、读不到设备地址这是刚把传感器焊上板子后最容易遇到的问题。排查顺序我是这么走的先量VCC和GND有没有3.3V再用示波器或逻辑分析仪看SCL有没有方波最后用扫描程序遍历I2C地址看从机有没有ACK。如果扫描不到0x5A地址80%是上拉电阻缺失导致的信号太弱剩下20%是SDA和SCL接反了。我当时犯过一个低级错误把SCL和SDA在杜邦线上接反了扫描不到回执检查了半小时才发现。另外MLX90614有一个SMBus的从机地址引脚有些模块引出有些没有不要随意去拉高拉低这个引脚否则地址会偏移导致主机找不到设备。现象可能原因处理方式I2C扫描无0x5A上拉电阻缺失补4.7k上拉SCL无波形引脚配置错误检查GPIO配置为开漏复用偶尔读到偶尔超时接线过长/供电不稳缩短杜邦线加稳压电容地址不是0x5A地址引脚被拉高确认地址引脚接GND4.2 温度数据跳变剧烈或者明显不对如果数据在正常范围内来回乱跳先软后硬排查。软件上确认是不是每一次读取都发了正确的寄存器地址有些代码会把0x06和0x07搞混把环境温度当物体温度读出来数值自然会随着室温波动。硬件上MLX90614的视场角决定了它测的是一个区域的平均温度不是点温度。如果你的目标物体很小而周围环境背景温度差异很大读数就会飘。解决方法是让传感器尽量靠近目标并保证目标填满视场。D:S比这个参数要记住以90°FOV型号为例距离被测物5cm时测量区域直径约5cm如果目标只有2cm宽就必须拉近到2cm以内才准确。还有一点传感器本身会有自发热长时间通电后外壳温度升高会影响精度。所以我在产品结构设计时给传感器加了一个小的散热孔避免热量堆积。裸板测试时用手捏着传感器外壳几秒钟温度读数就会漂移这都是正常现象。4.3 OLED显示乱码、刷新卡顿OLED乱码优先检查I2C地址和波特率。SSD1306默认7位地址是0x3C如果初始化时写成了0x3D显示就是雪花点。另外软件模拟I2C的延时不能太短我之前把I2C时钟时序参数调得非常快结果OLED偶尔显示错乱放慢到标准速率后问题解决。刷新卡顿则多半是因为主循环里频繁调用全屏刷新128x64的分辨率一次要送1024字节走软件I2C大概需要几十毫秒。解决办法就是用显存缓冲只在数据变化时局部刷新温度小数点的位置基本只有下半屏变化完全没必要整屏刷新。我把显示刷新频率控制在20Hz肉眼看起来非常流畅又不占CPU。4.4 后续扩展方向这套系统做完后扩展空间其实很大。喜欢功能叠加的可以挂ESP8266把温度数据用MQTT上报到Home Assistant想做低功耗的可以把主控切到STOP模式用定时唤醒采一次温度再接着睡电池供电能撑很久想提升测量精度的可以换MLX90640做热成像显示网格化温度分布配合伪彩色算法效果直接把项目档次拉高一个级别。如果还想继续深入建议去研究一下HAL库版本的I2C中断和非阻塞读取方式以及DMA配合I2C读取。这个项目里我用的标准库阻塞方式能保证结果正确但想把实时性做好还得靠中断加状态机。最后再分享一个我自己的实操习惯调试这类传感器项目时我习惯先在串口调试助手上打印原始寄存器值而不是直接打印换算后的温度。因为原始寄存器值能直接反映通信链路是否正常如果原始值在乱跳说明是通信问题如果原始值稳定但温度不对才需要去检查和发射率、定标相关的逻辑。这样做排查问题会快很多。这套基于STM32的红外测温系统硬件成本大概在40块左右代码量也不大但对从选型到调试的完整流程训练非常到位。如果你正在为毕业设计发愁或者想在项目里快速塞进去一个可靠的测温模块照着这条路走基本能少走一半弯路。本文还有配套的精品资源点击获取