基于STM32与MLX90614的红外测温系统设计与实现详解
2026/9/6 21:14:19 网站建设 项目流程

简介:一份基于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,引脚是PB6(SCL)和PB7(SDA)。用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_A)16位,×0.02K
0x0007目标温度(T_OBJ)16位,×0.02K
0x0008目标温度2(T_OBJ2)16位,×0.02K
0x04(EEPROM)发射率ε16位,0xFFFF=1.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接芯片PA13,SWCLK接PA14,GND必须共地。我犯过的错误是只接了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把温度和发射率数据传给ESP8266,ESP8266连上路由器,用MQTT协议上报到服务器或者手机上的MQTT客户端。STM32端只需要把温度数据打包成结构体,通过串口DMA发送;ESP8266端用AT指令或Arduino固件都行。我自己用的方式是ESP8266刷了Arduino固件,写了一个简单的MQTT publisher,手机用MQTT Dash App订阅主题,延迟大概几百毫秒,完全够用。要注意的是,两个模块之间的电平要匹配,ESP8266是3.3V,和STM32直接串口连接没问题。@来自南京邮电大学电子系统设计课程的同学,如果想把“智能测温终端”做出区分度,无线数据记录是最容易实现又最能展示效果的模块。

5.2 加身份联动:K210摄像头识别之后才测温

最近不少人问“K210和STM32怎么通讯”,这个组合用在测温上确实很有画面感。K210负责摄像头人脸检测,检测到人脸后通过串口发一个“测”命令给STM32,STM32收到命令后才触发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模块把数据读出来,再逐步加滤波、显示、按键,最后才画板子。每一步都验证过,再往下走,整体调试会顺很多。按照这路子,从零开始做到一个稳定可用的系统,一周时间是足够的。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询