news 2026/9/2 14:52:10

MLX90614红外测温实战:I2C寄存器级读取与稳定滤波

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MLX90614红外测温实战:I2C寄存器级读取与稳定滤波

简介:这是一份基于STM32与MLX90614的红外无接触测温工程源码,面向嵌入式开发者、电子设计竞赛学生以及需要快速搭建非接触体温检测方案的工程师,适用于人体体温监测、工业自动化和智能家居等场景。工程已实测通过,MLX90614通过I2C接口与STM32通信,硬件连接为SCK接PB6、SDA接PB7,串口1持续输出实时温度值,便于直接观察和二次开发;非接触测量方式还能降低交叉污染风险,在医疗健康与工业巡检等场景中更具优势。压缩包共110个文件,大小约992KB,以C源文件、H头文件为主体,同时包含编译生成的o、d、hex、map及Keil工程配置文件,可完整还原项目并用于烧录调试,也方便对照外设库理解驱动实现。目前已有1076人学习下载,适合需要快速参考I2C驱动、红外测温数据读取或STM32串口输出流程的开发者使用。整套资源目录结构清晰,包含标准外设库文件与构建脚本,能节省环境搭建时间,帮助上手实测与排错。 前阵子把 MLX90614 红外无接触测温项目调通了,数据读得稳、误差也控制在可接受范围内,测试通过后顺手把工程文件打包发到了交流群。不少朋友问源码和接线图,干脆把整个实现过程拆开写一写。这个方案不依赖现成的 Adafruit 库,直接从 I2C 寄存器底层把温度算出来,搞清楚了传感器内部到底在干什么。如果你也准备做测温小工具、手势检测或者非接触式温度采集,这篇文章应该能帮你省掉不少踩坑时间。

1. 项目背景与整体思路

1.1 为什么选 MLX90614 做无接触测温

测温方案其实不少,但做非接触测温时,热电阻、热电偶这类接触式传感器基本可以直接排除。它们响应慢,而且必须贴在被测物体上,很多场景根本没法用。热像仪效果最好,可一块入门级热像模块动辄上千元,个人项目实在没必要为一个小功能花这个钱。MLX90614 是 Melexis 推出的红外测温芯片,利用物体表面的红外辐射能量来计算温度,不需要物理接触,响应时间只有几十毫秒,分辨率能做到 0.02℃,量程覆盖 -70℃ 到 380℃,日常项目绰绰有余。更关键的是它走 I2C 接口,主控随便接,整个方案非常简单。

我手上这块是 GY-906 模块,板上带了 LDO 稳压管和 I2C 上拉电阻,不会出现直接贴裸芯片那种难伺候的情况。模块上一共四个引脚,VCC、GND、SDA、SCL,接线难度基本为零。项目核心就三件事:初始化 I2C、读取传感器 RAM 区原始数据、把原始值换算成物理温度。听起来简单,但真正调通的过程中还是有不少小细节,下面逐个讲。

1.2 项目包内容拆解

压缩包里主要几个文件:main.ino是 Arduino 主程序,包含初始化、循环读取和串口输出;MLX90614.cppMLX90614.h是自己封装的最小驱动库,没有依赖第三方库,方便移植到其他平台;Readme.txt写了接线说明和常见问题;还有一张Schematic.png,是接线示意图。整个项目在 Arduino Uno 上测试通过,但代码里我用的是软件 I2C,所以可以自由选择引脚,如果你用 ESP32、STM32 这类主控,也只要改一下引脚映射和延时函数即可。

2. 硬件准备与接线细节

2.1 物料清单

物料型号/规格数量
红外测温模块GY-906(MLX90614)1
主控板Arduino Uno / Nano1
杜邦线母对母,20cm4
面包板(可选)标准面包板1
电容(可选)100nF 陶瓷电容1

面包板不是必须的,如果模块直接插在 Arduino 排针上,省掉面包板更稳。建议多备几根杜邦线,很多时候数据线接触不良是导致 I2C 通信失败的元凶。

2.2 接线方式与注意事项

接线表非常直接:模块 VCC 接 Arduino 5V,GND 接 GND,SDA 接 A4,SCL 接 A5。如果你的主控是 3.3V 逻辑电平,比如部分 ESP32 板子的某些引脚,也可以直接用 3.3V 给模块供电,因为 GY-906 板载的 LDO 支持 3.3V 输入,I2C 引脚同样是开漏结构,配合上拉电阻不会有电平冲突。

实际接线时有几个坑必须提醒:

  • 供电线不要太长,超过 20cm 的杜邦线会带来压降和干扰,导致读数偶尔跳变。
  • 模块的 VCC 和 GND 之间并联一个 100nF 陶瓷电容,能明显减少电源纹波干扰。
  • 如果项目中还有继电器、电机这类大功率设备,一定要把传感器电源和它们隔开,共用一个电源时读数经常会乱飘。
  • 模块上的上拉电阻一般默认焊接到 3.3V,如果你的模块是二手或定制板,上拉电阻被拆了,需要自己补两个 4.7k-10k 电阻,否则 I2C 信号没有上拉,读不到任何数据。

2.3 软件 I2C 与硬件 I2C 的选择

I2C 分硬件和软件两种方式。硬件 I2C 是用单片机内部的专用外设,速度快,不占用 CPU;软件 I2C 则是用 GPIO 模拟时序,好处是任意引脚都能用。这个项目里我选了软件 I2C,因为测试时 A4/A5 被一个 OLED 占用了,不想重新插线,就把 MLX90614 接到了 A0/A1,用 SoftWire 库模拟。实测下来通信稳定,唯一区别是每次读取需要约 2ms 的时序延迟,测温本来就要求慢节奏读取,所以完全够用。

3. 核心代码实现与解析

3.1 I2C 通信与寄存器地址

MLX90614 内部有两个 RAM 地址最常用:0x07存放物体温度原始值,0x06存放环境温度原始值,都是 16 位有符号数。除了 RAM,它还有一块 EEPROM 区域,专门存放发射率(0x04)、温度偏移(0x24)等配置,出厂默认值已经适配大多数场景,普通使用不需要修改。

I2C 读取寄存器的时序比普通读器件多一个步骤。大致流程是:先给从机地址加写位,写入要读取的寄存器地址,然后重新发送 Start 信号,再给从机地址加读位,之后连续读三个字节,前两个是数据低位和高位,第三个是 PEC 校验字节。如果第三个字节不读,下次通信可能出问题,因为从机会一直等主机把剩余数据读走。默认从机地址是0x5A,这个值已经在芯片内部写死,没有特殊焊接的话不需要改。

3.2 温度读取与换算方法

直接用 Wire 库写一个最小读取函数,核心代码大概长这样:

#include <Wire.h> #define MLX90614_ADDR 0x5A #define MLX90614_TA 0x06 #define MLX90614_TOBJ 0x07 double readTemperature(uint8_t reg) { Wire.beginTransmission(MLX90614_ADDR); Wire.write(reg); Wire.endTransmission(false); Wire.requestFrom(MLX90614_ADDR, 3); if (Wire.available() < 3) return -273.15; uint16_t raw = Wire.read() | (Wire.read() << 8); uint8_t pec = Wire.read(); // PEC 校验字节,这里只读取并丢弃 return raw * 0.02 - 273.15; } void setup() { Wire.begin(); Serial.begin(115200); } void loop() { double objectTemp = readTemperature(MLX90614_TOBJ); double ambientTemp = readTemperature(MLX90614_TA); Serial.print("Obj: "); Serial.print(objectTemp); Serial.print(" C, Amb: "); Serial.print(ambientTemp); Serial.println(" C"); delay(200); }

换算的原理其实很简单:传感器输出的原始值是一个 16 位整数,每一位代表 0.02℃,所以原始值乘以 0.02 就得到开尔文温度,再减去 273.15 就是摄氏温度。注意这里需要转换成有符号数,如果高位为 1 就代表负数,但日常测物温不会出现负到离谱的情况,所以用uint16_t读出来也没问题,只要知道温度低于 -273.15℃ 时肯定不正常即可。

3.3 数据滤波与稳定性优化

直接把readTemperature的值用起来,串口监视器里会看到温度小数点末尾一直在跳,个别时刻还会冒出一个明显偏离的值。这是因为红外传感器对热噪声十分敏感,尤其是周围有风吹动或者目标物体表面有反射时。我加了一个 10 点滑动平均滤波,效果很明显。

#define FILTER_SIZE 10 float history[FILTER_SIZE]; uint8_t historyIndex = 0; float smoothRead(uint8_t reg) { history[historyIndex] = readTemperature(reg); historyIndex = (historyIndex + 1) % FILTER_SIZE; float sum = 0; for (uint8_t i = 0; i < FILTER_SIZE; i++) { sum += history[i]; } return sum / FILTER_SIZE; }

如果对实时性要求高,窗口可以缩短到 5;如果目标是剔除瞬时干扰,建议用中值滤波,把窗口内的最大值和最小值丢弃,再求平均值。实测下来 10 点滑动平均滞后感轻微,温度读取周期 200ms,窗口覆盖 2 秒,动态响应还能接受。

4. 标定与精度优化

4.1 发射率设置

发射率(Emissivity)是红外测温里最容易被忽略的参数。不同材料表面向外辐射红外能量的能力不同,黑体辐射率是 1.0,而人体皮肤大约 0.98,普通塑料在 0.85-0.95 之间,抛光金属只有 0.2 甚至更低。如果传感器默认内部发射率是 1.0,遇到低发射率目标,读数会严重偏低。

MLX90614 的发射率存放在 EEPROM 的0x04地址,默认值为0xFFFF(即 1.0)。如果要修改成 0.95,需要把0.95 * 65535 = 62258.25取整为62258,转换成 16 进制写入 EEPROM。写入命令有点特殊,不是普通写寄存器的流程,需要打开 EEPROM 访问模式,执行 Erase 命令再写数据。实际做项目时不建议频繁修改发射率,因为 EEPROM 擦写次数有限,反复写容易把配置搞坏。我的做法是代码里保留发射率变量,做软件补偿,这样不改硬件也能修正读数。

4.2 环境温度补偿

MLX90614 内部虽然带了环境温度补偿,但芯片本身测的是自身封装附近的温度,如果环境温度和被测物体温度差距过大,补偿效果会打折扣。我实测过一次,把传感器放在 60℃ 热水杯旁边,再测手温,读数会比正常值偏低不少,因为传感器被热辐射干扰了。

在代码里可以把环境温度也读出来,做简单逻辑判断。我设了一个阈值,当ambientTemp > 50时输出警告,说明传感器工作环境已超出可靠范围。普通室温场景基本不需要额外补偿,但一定要让传感器远离发热源和阳光直射,否则误差可能超过 ±2℃。

4.3 距离与视场角影响

MLX90614 的视场角有 35° 和 90° 两种规格,模块侧面会打标。视场角越大,传感器能接收到的目标区域越宽,但同时也会混入更多背景环境温度。距离系数大概在 1:1 左右,意思是测量距离每增加 1cm,传感器识别到的目标直径也增加 1cm。所以测额头或手背温度时,距离尽量控制在 2-3cm,太近会受传感器外壳自身热传导影响,太远测到的就是一块混合区域的平均温度,根本不准。

5. 常见问题与排查技巧

5.1 温度一直读成 -273.15 或 0

遇到这种情况,第一个要查的是寄存器地址和从机地址。有些代码示例里写Wire.beginTransmission(0xB4),这是把左移一位后的地址写进去了,会导致通信失败。正常在 Wire 库里应该写0x5A。其次是 PEC 校验字节,如果requestFrom只收两个字节,不读第三个 PEC 字节,部分模块会认为主机没有读完整,导致后续通信状态异常。最后还有一个常见坑:传感器刚上电的第一次读取可能返回异常值,简单delay(50)后重读一次即可解决。

5.2 测量值明显偏低或偏高

先检查发射率设置,这是最大嫌疑。如果你没有改过 EEPROM,默认是 1.0,测人体会略微偏低 0.5℃ 左右。其次是距离和视场角,测温目标如果小于传感器能覆盖的最小区域,读数会偏向背景。再就是遮挡问题,很多人习惯在传感器前面加透明塑料罩,红外线会被阻挡,测到的是罩子的温度,误差一下就拉开了。最好的办法是不加任何遮挡,或者用专门的红外窗口透镜。

5.3 I2C 通信时好时坏

这种现象多半是硬件问题。检查 SDA/SCL 是否松动,杜邦线换新的一组试试;如果模块和主控距离较远,缩短连接线长度;如果总线上同时挂了其他 I2C 设备,确认地址没有冲突。还有一个细节:MLX90614 的 I2C 引脚是开漏输出,必须有上拉电阻才能正常通信。模块上默认有上拉电阻,但某些定制板可能没有,我遇到过一块"精简版"模块,读不到数据,补了两颗 10k 电阻后才正常。

5.4 读取周期太频繁导致数据乱跳

很多人为了实时显示,把delay改得很短,比如 10ms 读一次,结果数据不仅没有更平滑,反而开始剧烈跳变。原因是传感器内部 ADC 需要时间来刷新热堆电压,读取间隔太短时,两次读到的原始数据可能来自同一次采样,或者采样尚未完成导致读取值波动。我的经验是每 200ms 读一次,既能保证数据稳定,也不会带来明显延迟。

6. 测试过程与个人体会

6.1 实测数据记录

我在室温 25℃ 环境下做了几组对比测试,参考值用的是水银温度计和热电偶,距离控制在 3cm,滑动平均窗口 10 点:

测试目标MLX90614 读数参考温度误差
手掌29.2℃29.5℃-0.3℃
陶瓷杯热水54.6℃54.3℃+0.3℃
桌面25.3℃25.0℃+0.3℃
暖风机出风口38.8℃39.2℃-0.4℃

整体误差在 ±0.5℃ 以内,符合标称精度。如果做体温检测建议测额头,并提前静置 5-10 分钟让传感器和环境温度保持一致,数据会更准。

6.2 个人调试心得与扩展建议

这个项目让我印象最深的一点是:红外测温模块本身精度并不差,但能不能测准,很大程度上取决于使用方式。发射率、距离、环境温度、供电稳定性,每一项都影响最终结果。如果只是把模块插上,读一个数字就发布,很容易被测量误差坑到。我的建议是,做任何测温项目都要多备几种参考源做对比,至少要有水银温度计或热电偶作为标定基准。

扩展方向上,可以给模块加一块 OLED 屏幕,按键切换物温/体温模式;或者把数据通过串口发到上位机,做温度曲线记录;再进一步可以用 ESP32 连接 WiFi,做成一个居家环境温度监测节点。这个模块的 I2C 接口注定了它非常容易接入各种主控,整套代码稍微改改就能移植到 STM32 或树莓派 Pico 上。最后分享一个自己的习惯:每次调试测温项目都会在串口输出里同时打印环境温度和物体温度,这样能快速判断环境因素是否干扰了测量结果,能少走很多弯路。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/2 14:51:17

Czkawka 深度上手:用 Rust 写成的重复文件与相似图片扫描器

Czkawka 深度上手&#xff1a;用 Rust 写成的重复文件与相似图片扫描器 【免费下载链接】czkawka Multi functional app to find duplicates, empty folders, similar images etc. 项目地址: https://gitcode.com/GitHub_Trending/cz/czkawka 硬盘越来越满&#xff0c;可…

作者头像 李华
网站建设 2026/9/2 14:50:05

RDP Wrapper 完整实战:Windows 远程桌面多用户并发连接三步搞定

RDP Wrapper 完整实战&#xff1a;Windows 远程桌面多用户并发连接三步搞定 【免费下载链接】surrealdb A scalable, distributed, collaborative, document-graph database, for the realtime web 项目地址: https://gitcode.com/GitHub_Trending/su/surrealdb 你肯定遇…

作者头像 李华
网站建设 2026/9/2 14:44:27

Python应用打包实战:从PyInstaller到企业级EXE交付全流程

简介&#xff1a;这是一套开箱即用的Python企业管理系统实战资源&#xff0c;面向初学者与中小型企业管理者&#xff0c;解决人力资源、库存及基础业务流程数字化管理需求。资源已打包为Windows可执行程序&#xff08;exe&#xff09;&#xff0c;双击即可运行&#xff0c;无需…

作者头像 李华
网站建设 2026/9/2 14:43:48

用编程游戏网站自学Python:环境配置、入门实操到小项目路线

如果你觉得 Python 入门教材翻几页就困&#xff0c;那可以试试编程游戏网站。这类网站把练习题包装成闯关、解谜、对战任务&#xff0c;让你在完成一关又一关的过程中&#xff0c;顺手把变量、循环、函数、数据结构这些基础概念过一遍。这篇文章不打算堆一个长长的网站合集&…

作者头像 李华
网站建设 2026/9/2 14:43:47

基于C8051F350的高精度称重系统设计与实现

简介&#xff1a;一份基于C8051F350单片机实现的完整称重系统设计资料&#xff0c;面向需要掌握混合信号处理器应用与称重测量技术的嵌入式工程师、电子竞赛参赛者和高年级学生。资料包共包含4个文件&#xff0c;整体压缩后仅222KB&#xff0c;其中包括C语言主程序与对应头文件…

作者头像 李华