STM32CubeMX实战:基于HAL库驱动MLX90614实现非接触式体温监测 📅 发布时间:2026/7/4 6:26:06 👁️ 浏览次数: 1. 项目缘起为什么选择STM32CubeMX和MLX90614大家好我是老张一个在嵌入式领域摸爬滚打了十多年的老工程师。今天想和大家分享一个非常实用的小项目用STM32CubeMX和HAL库来驱动MLX90614红外测温传感器做一个非接触式的体温监测装置。这个项目听起来可能有点“硬核”但我保证只要你跟着我的步骤走哪怕你是个刚接触STM32的新手也能在半天内把它跑起来。为什么选这个组合呢首先MLX90614这款传感器在业内口碑非常好它是一款高精度的红外测温芯片测量范围从-40℃到125℃精度能达到±0.5℃在人体温度范围内。我们常见的GY-906模块就是基于这颗芯片的价格便宜十几块钱就能买到非常适合做原型开发。其次STM32CubeMX这个工具简直是ST单片机开发的“福音”。以前我们用标准库要手动配置时钟、外设、中断一堆寄存器看得人头大。现在有了CubeMX图形化点一点代码框架就生成了大大降低了入门门槛。最后HAL库是ST主推的硬件抽象层库虽然有些人吐槽它效率不如LL库或标准库但它的可移植性和易用性是真的强特别适合快速开发和教学。我这次选用的主控是大家最熟悉的STM32F103C8T6也就是我们常说的“蓝色小药丸”或者“最小系统板”性价比极高。整个项目的目标很明确通过CubeMX配置好I2C和串口然后编写驱动代码让单片机通过I2C总线读取MLX90614测得的物体温度再通过串口打印到电脑上。你可以把它看作一个温度计的“大脑”后续完全可以加上OLED屏幕显示或者通过蓝牙/Wi-Fi模块把数据传到手机做成一个无线体温监测仪。2. 硬件准备与电路连接别在第一步就踩坑动手写代码之前咱们先把硬件捋清楚。硬件连接是基础线接错了代码写得再漂亮也是白搭。我建议大家先准备好以下材料STM32F103C8T6 核心板一块。GY-906 (MLX90614) 模块一个。USB转TTL串口模块一个用于程序下载和串口通信。杜邦线若干。3.3V电源可以直接从STM32板子的3.3V引脚取。重点来了MLX90614的引脚和连接方式。GY-906模块通常有4个引脚VCC、GND、SCL、SDA。这里有一个非常关键的细节MLX90614的工作电压是3.3V绝对不要接到5V上否则很可能烧坏传感器我刚开始玩的时候就因为粗心用了一个5V的Arduino板子供电结果传感器瞬间发烫几十块钱就这么没了这都是血泪教训。连接电路非常简单参照下面的表格用杜邦线一一对应接好就行STM32F103C8T6引脚GY-906模块引脚说明3.3VVCC电源务必是3.3VGNDGND共地PB6SCLI2C1时钟线PB7SDAI2C1数据线为什么选PB6和PB7因为对于STM32F103C8T6来说I2C1的默认引脚就是PB6SCL和PB7SDA这样我们在CubeMX里配置起来最省事不需要重映射。当然你也可以用其他支持I2C的引脚但配置上会多一步。对于新手我强烈建议就用这个默认组合能减少很多不必要的麻烦。接好线后先别急着上电仔细检查一遍VCC是不是3.3VGND有没有共地SCL和SDA有没有接反确认无误后再把USB线插到电脑上给STM32板子供电。同时把USB转TTL串口模块的RX、TX分别接到STM32的PA9TX、PA10RX并将两者的GND连接在一起这样我们后面才能用串口助手看到温度数据。3. STM32CubeMX工程配置图形化点一点基础框架就有了硬件搞定现在打开STM32CubeMX软件开始我们的“画图”工作。CubeMX的版本我用的是6.0以上界面可能略有不同但核心步骤是一样的。第一步创建新工程选对芯片。打开软件点击“New Project”。在芯片选择器里输入“STM32F103C8”然后选择“STM32F103C8Tx”。认准这个型号别选错了。双击它工程就创建好了主界面会显示这颗芯片的引脚图。第二步配置系统核心SYS和时钟RCC。在左侧分类视图里找到“System Core”。点开SYS在“Debug”下拉菜单里选择“Serial Wire”。这是因为我们用的ST-Link下载器需要这个调试接口。点开RCC在“High Speed Clock (HSE)”选择“Crystal/Ceramic Resonator”。我们的板子外部通常有一个8MHz的晶振这里就是告诉单片机使用这个外部高速时钟。第三步配置I2C1外设。这是驱动MLX90614的关键。在左侧找到“Connectivity”点开I2C1。在“I2C Mode”里选择“I2C”。模式保持默认的“Standard”即可。下面的参数配置对于MLX90614来说默认的100kHz标准模式就完全够用了。如果你想追求更快的读取速度可以尝试调到400kHz的快速模式但初次调试建议先用默认值稳定第一。配置完成后回到主引脚图你会发现PB6和PB7已经被自动标记为I2C1_SCL和I2C1_SDA了这表示配置生效。第四步配置USART1串口。我们需要一个通道来输出数据。在“Connectivity”里找到USART1。将“Mode”设置为“Asynchronous”异步通信。基础参数波特率“115200”字长“8 Bits”停止位“1”校验位“None”流控制“None”。这是最常用的串口配置。此时引脚图上的PA9和PA10会被自动配置为USART1_TX和USART1_RX正好对应我们之前连接的串口模块。第五步配置时钟树。点击上方选项卡的“Clock Configuration”。这里的目标是把系统主频调到72MHz这是F103系列的最高频率。你会发现界面中间有个锁相环PLL的配置。在“Input frequency”输入框输入8对应外部8MHz晶振。将“PLL Source Mux”选择为“HSE”。将“PLLMUL”设置为9倍频8MHz * 9 72MHz。最后在“System Clock Mux”选择“PLLCLK”作为系统时钟源。此时右侧的“HCLK”应该显示为72MHz。如果显示红色说明配置有冲突检查一下各外设的时钟分频是否超限通常按上述步骤设置就不会有问题。第六步生成工程代码。点击上方“Project Manager”选项卡。给工程起个名字比如“MLX90614_Test”。“Project Location”选一个你找得到的路径。“Toolchain / IDE”选择你用的IDE我习惯用“MDK-ARM V5”Keil5。最关键的一步在“Code Generator”里勾选“Generate peripheral initialization as a pair of ‘.c/.h’ files per peripheral”。这会把每个外设的初始化代码生成独立的文件结构更清晰。最后点击右上角的“GENERATE CODE”。CubeMX会问你是否要打开工程选择“Open Project”它就会自动启动Keil MDK了。至此一个包含I2C和串口初始化代码的完整工程框架就生成了。整个过程我们一行代码都没写全是图形化操作是不是比想象中简单4. 移植与编写MLX90614驱动代码理解SMBus协议是关键工程框架有了现在需要把“灵魂”——MLX90614的驱动代码放进去。MLX90614使用的是SMBus协议你可以把它理解为I2C协议的一个子集在电气特性上完全兼容但在协议层有一些额外的规定比如超时、PEC包错误校验等。对于基础的温度读取我们可以暂时忽略SMBus的一些高级特性用标准的I2C读写流程也能工作。但为了代码的健壮性和学习价值我这里会实现一个包含PEC校验的完整驱动。首先在Keil工程里我们在“Src”和“Inc”文件夹下分别新建两个文件mlx90614.c和mlx90614.h。你也可以直接把原始文章里的代码复制过来但我会带你一行行理解并做一些优化和适配。头文件mlx90614.h的要点这个文件主要做三件事定义硬件连接、声明函数、定义传感器内部寄存器地址。#ifndef __MLX90614_H #define __MLX90614_H #include main.h // 包含HAL库和STM32的硬件定义 /* 硬件接口定义 - 这里我们使用HAL库的GPIO操作不再需要宏定义切换输入输出 */ #define MLX90614_I2C_HANDLE hi2c1 // 使用CubeMX生成的I2C句柄 #define MLX90614_I2C_ADDR (0x5A 1) // 传感器7位地址是0x5A左移1位后HAL库使用 /* 核心函数声明 */ uint8_t MLX90614_Init(void); float MLX90614_ReadTemp(void); uint8_t MLX90614_ReadTempRaw(uint16_t *raw_data); /* 传感器寄存器地址定义 (RAM访问) */ #define MLX90614_RAW_IR1 0x04 #define MLX90614_RAW_IR2 0x05 #define MLX90614_TA 0x06 // 环境温度寄存器 #define MLX90614_TOBJ1 0x07 // 物体1温度寄存器 (我们主要用这个) #endif这里我做了个重要改动放弃了原始的“软件模拟I2CGPIO模拟时序”转而使用CubeMX配置好的硬件I2C外设和HAL库函数。原因很简单硬件I2C更稳定不占用CPU资源去模拟时序而且HAL库的HAL_I2C_Master_Transmit和HAL_I2C_Master_Receive用起来非常方便。我们把I2C的句柄hi2c1和器件地址0x5A左移一位定义好后续函数直接调用即可。源文件mlx90614.c的实现驱动代码的核心是三个函数初始化、读取原始数据、计算温度值。#include mlx90614.h #include i2c.h // 包含HAL I2C驱动 #include math.h // 初始化函数主要是检查设备是否在线 uint8_t MLX90614_Init(void) { if (HAL_I2C_IsDeviceReady(MLX90614_I2C_HANDLE, MLX90614_I2C_ADDR, 3, 100) HAL_OK) { return 0; // 成功 } else { return 1; // 失败 } } // 读取指定寄存器的原始数据16位带PEC校验简化版 uint8_t MLX90614_ReadReg(uint8_t reg_addr, uint16_t *data) { uint8_t cmd reg_addr; uint8_t rx_buf[3]; // 接收缓冲区低字节、高字节、PEC // 1. 发送要读取的寄存器地址 if (HAL_I2C_Master_Transmit(MLX90614_I2C_HANDLE, MLX90614_I2C_ADDR, cmd, 1, 100) ! HAL_OK) { return 1; // 发送失败 } HAL_Delay(1); // 短暂延时等待传感器准备数据 // 2. 重新发起读请求读取3个字节数据低、数据高、PEC if (HAL_I2C_Master_Receive(MLX90614_I2C_HANDLE, MLX90614_I2C_ADDR, rx_buf, 3, 100) ! HAL_OK) { return 2; // 接收失败 } // 3. 组合数据注意MLX90614返回的低字节在前 *data (rx_buf[1] 8) | rx_buf[0]; // 4. 这里可以添加PEC校验计算为了教程清晰先跳过实际产品建议加上 // if (CalculatePEC(...) ! rx_buf[2]) { return 3; } return 0; // 成功 } // 读取物体温度并转换为摄氏度 float MLX90614_ReadTemp(void) { uint16_t raw_data; float temp; if (MLX90614_ReadReg(MLX90614_TOBJ1, raw_data) ! 0) { return -273.15; // 读取失败返回绝对零度作为错误标识 } // MLX90614的温度数据格式raw_data * 0.02 - 273.15 temp (float)raw_data * 0.02 - 273.15; return temp; }这段代码是驱动层的核心。MLX90614_ReadReg函数封装了标准的I2C读寄存器流程先写寄存器地址再读数据。这里我简化了PEC校验但注释标明了位置你可以后期完善。MLX90614_ReadTemp函数则调用读寄存器函数获取原始数据后按照芯片手册的公式原始值乘以0.02再减去273.15将其转换为摄氏度。这个转换公式是固定的所有MLX90614都一样。5. 主程序逻辑与串口输出让数据“说话”驱动写好了最后一步就是在主函数main.c里把它们串联起来形成一个完整的应用程序。思路很简单初始化所有外设 - 初始化传感器 - 在死循环里不断读取温度 - 通过串口发送到电脑。打开main.c文件找到/* USER CODE BEGIN Includes */和/* USER CODE END Includes */之间加入我们驱动文件的头文件/* USER CODE BEGIN Includes */ #include mlx90614.h #include stdio.h // 用于printf函数 /* USER CODE END Includes */接下来我们需要重定向printf函数到串口这样我们就能方便地用printf打印数据了。在/* USER CODE BEGIN 4 */和/* USER CODE END 4 */之间通常在文件末尾添加以下代码/* USER CODE BEGIN 4 */ // 重定向printf到串口1 #ifdef __GNUC__ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif PUTCHAR_PROTOTYPE { HAL_UART_Transmit(huart1, (uint8_t *)ch, 1, 1000); // huart1是CubeMX生成的串口句柄 return ch; } /* USER CODE END 4 */现在来到主函数main()中的/* USER CODE BEGIN 2 */区域这里是外设初始化后主循环开始前放置我们用户初始化代码的地方/* USER CODE BEGIN 2 */ printf(\r\n MLX90614 Non-contact Thermometer \r\n); printf(System Initializing...\r\n); if (MLX90614_Init() 0) { printf(MLX90614 Sensor OK!\r\n); } else { printf(Error: MLX90614 Not Found! Check Connection.\r\n); while (1); // 卡死提示错误 } HAL_Delay(1000); // 等待传感器稳定 printf(Start Reading Temperature...\r\n\r\n); /* USER CODE END 2 */最后在while (1)主循环里我们周期性地读取并打印温度/* USER CODE BEGIN WHILE */ while (1) { float object_temp MLX90614_ReadTemp(); float ambient_temp; // 如果需要也可以读取环境温度 // 读取环境温度可选 // uint16_t raw_amb; // if (MLX90614_ReadReg(MLX90614_TA, raw_amb) 0) { // ambient_temp (float)raw_amb * 0.02 - 273.15; // } printf(Object Temperature: %.2f C\r\n, object_temp); // printf(Ambient Temperature: %.2f C\r\n, ambient_temp); printf(-----------------------------\r\n); HAL_Delay(1000); // 每秒读取一次 /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */代码写完了点击Keil的“Rebuild”按钮编译。如果没有错误就用ST-Link或串口工具记得设置Boot0跳线把程序下载到STM32板子里。6. 调试实战与常见问题排查程序下载成功后打开电脑上的串口调试助手比如XCOM、SSCOM等设置波特率为115200数据位8停止位1无校验。给设备上电你应该能看到串口助手依次打印出初始化信息和每秒更新的温度值。如果什么都没收到或者显示“Sensor Not Found”别慌这是嵌入式开发的常态。我们可以按照以下步骤排查检查硬件连接最最最重要再用万用表量一遍VCC是不是3.3VSCL和SDA线是否连通STM32和传感器的GND是否接在一起我遇到过好几次都是杜邦线接触不良导致的。检查I2C地址MLX90614的默认7位地址是0x5A。但有些模块可能被改过地址或者你买到了不同版本的芯片。可以用I2C扫描代码来探测总线上存在的设备地址。在HAL库中可以写一个简单的循环用HAL_I2C_IsDeviceReady函数尝试从0x08到0x77的地址看看哪个有应答。检查上拉电阻I2C总线需要上拉电阻通常4.7kΩ到10kΩ才能正常工作。很多GY-906模块已经内置了上拉电阻但如果你用的是裸芯片或者某些简化模块可能需要在SCL和SDA线上各接一个4.7kΩ电阻到3.3V。检查代码配置确认CubeMX里I2C的模式是“I2C”而不是“SMBus”。虽然传感器用SMBus但HAL库的I2C模式兼容其基本读写。确认时钟速度配置正确标准模式100kHz。用逻辑分析仪抓波形终极武器如果以上都试了还不行逻辑分析仪就派上用场了。把探头接到SCL和SDA上看看单片机是否发出了正确的起始信号、地址帧和数据帧。这是定位I2C通信问题最直接的方法。当串口终于稳定地打印出温度数据时比如“Object Temperature: 36.52 C”那种成就感是无与伦比的。你可以用手靠近或远离传感器观察温度值的变化。需要注意的是MLX90614测量的是物体表面的红外辐射温度它受环境温度、测量距离、被测物体表面材质发射率影响很大。对于人体测温需要保持适当的距离通常建议3-5厘米并且避免有强风或热源干扰。7. 项目优化与进阶思路基础功能实现后这个项目还有很多可以玩和优化的地方提高测量稳定性在主循环里连续读取10次温度然后取平均值或中位数可以滤除偶然的跳动。添加温度报警功能在代码里设置一个阈值比如37.3℃当测量值超过时让STM32控制一个LED闪烁或者蜂鸣器鸣叫。本地显示接一个0.96寸的OLED屏幕同样使用I2C接口地址通常为0x78或0x7A将温度实时显示在屏幕上脱离电脑。无线传输接入一个ESP-01S WiFi模块或HC-05蓝牙模块将温度数据发送到手机APP或者云平台实现远程监控。低功耗设计MLX90614本身有睡眠模式。对于电池供电的设备可以让STM32间歇性唤醒传感器进行测量其他时间进入休眠大幅延长续航。校准与补偿如果你对精度要求极高可以针对特定的应用场景如人体额头测温进行软件校准。用一个高精度的接触式体温计作为参考记录MLX90614的读数建立一个简单的线性补偿公式。这个项目虽然小但它完整地走了一遍STM32开发的标准化流程硬件选型、CubeMX配置、HAL库驱动编写、功能实现、调试优化。掌握了这套方法你再面对其他I2C传感器比如温湿度传感器SHT30、气压计BMP280、陀螺仪MPU6050时就会觉得思路非常清晰无非就是换一下器件地址、读一下数据手册的寄存器定义和转换公式。嵌入式开发就是这样打通第一个项目之后后面的路会越走越宽。希望这篇长文能帮你少走些弯路如果实践中遇到问题欢迎随时交流讨论。
深入解析PLC四大定时器:从脉冲生成到延时控制的实战应用 1. 初识西门子S7-1200的四大定时器:你的工业时序控制工具箱 如果你刚开始接触西门子S7-1200 PLC编程,面对梯形图里那几个长得差不多的定时器方块,是不是有点懵?TP、TON、TOF、TONR,名字听起来就挺绕的。别担心… 2026/7/4 13:50:27
de4dot完全指南:.NET反混淆工具的技术原理与实战应用解析 de4dot完全指南:.NET反混淆工具的技术原理与实战应用解析 【免费下载链接】de4dot .NET deobfuscator and unpacker. 项目地址: https://gitcode.com/gh_mirrors/de/de4dot 理解.NET反混淆:从困境到解决方案 当你面对一个被混淆的.NET程序集时&a… 2026/5/17 8:09:55
深入解析PCA9306:I2C电平转换的实战应用与电路设计 1. 从一次尴尬的“翻车”说起:为什么我们需要PCA9306? 我刚开始捣鼓电路那会儿,踩过一个现在想起来都觉得脸红的坑。当时手头有个项目,主控芯片是1.8V供电的,但外挂的一个传感器模块是3.3V的。我寻思着,I2C… 2026/5/17 8:09:54
普通人如何科学选择大模型API与免费窗口 1. 普通人到底该选大模型API还是免费窗口?一个实操十年的老手掏心窝子说真话 你是不是也这样:看到ChatGPT Plus每月20美元、Claude Pro每月25美元、国内某大厂会员每月88元,心里直打鼓——我每天就问几个问题、写两段文案、帮孩子改改作文&am… 2026/7/4 13:51:32
分层分步精准创作:paperxie 开题 AI 工具直击学生选题写作各类痛点 paperxie-免费查重复率aigc检测/开题报告/毕业论文/智能排版/文献综述/科研绘图开题报告 - PaperXie智能写作PaperXieAi论文智能生成软件,10分钟生成万字毕业论文、期刊论文、文献综述、PPT,Aigc查重、降重报告、文献资料。只需一个标题,从开… 2026/7/4 13:51:32
Serverless数据分析的成本与性能优化实战 1. Serverless 数据分析的本质剖析Serverless架构这两年确实火得不行,各种云厂商都在鼓吹"零运维"、"按需付费"的优势。但作为一个在数据领域摸爬滚打多年的老司机,我必须说:Serverless不是银弹,特别是在数据… 2026/7/4 13:49:32
基于Si4731与STM32F745ZG的数字收音机开发指南 1. 项目概述:基于Si4731与STM32F745ZG的收音机开发 最近在整理工作室的元器件库存时,翻出了一块闲置的Si4731收音机芯片和STM32F745ZG开发板。这两者的组合让我想起了一个有趣的DIY项目——打造一台可编程的数字收音机。Si4731作为业界知名的单芯片AM/FM… 2026/7/4 13:47:31
加密数据模糊查询实战:从原理到工程实现 1. 项目概述:当数据安全遇上模糊查询 在数据驱动的业务场景里,我们常常面临一个看似矛盾的需求:既要对敏感数据(如用户手机号、地址、姓名)进行高强度加密存储以满足合规与安全要求,又要支持对这些加密数据… 2026/7/4 13:43:29
JMeter 2.13性能测试实战:从核心原理到分布式压测 1. 项目概述:为什么JMeter 2.13在今天依然值得深挖? 如果你在性能测试领域摸爬滚打过几年,大概率会听过一个说法:“JMeter 5.x都出来了,谁还用老掉牙的2.13?” 这话对,但也不全对。对的是&#… 2026/7/4 13:43:29
STM32F745VG与MC6470 IMU的高性能姿态控制系统设计 1. MC6470与STM32F745VG的黄金组合解析在工业自动化和机器人控制领域,传感器与微控制器的协同工作能力直接决定了系统的响应速度和定位精度。MC6470作为一款6自由度惯性测量单元(6DOF IMU),与STM32F745VG这款基于ARM Cortex-M7内核的高性能微控制器组合&… 2026/7/4 0:00:28
Playwright自动化测试实战:从零搭建现代Web测试框架 1. 项目概述:为什么是 Playwright?如果你正在为现代 Web 应用的自动化测试头疼,尤其是面对那些充斥着动态加载、复杂交互的单页应用(SPA),那么 Playwright 的出现,很可能就是你的解药。我接触过… 2026/7/4 0:00:28
终极指南:如何将JSXBIN二进制文件转换为可读JSX源代码 终极指南:如何将JSXBIN二进制文件转换为可读JSX源代码 【免费下载链接】jsxbin-to-jsx-converter JSXBin to JSX Converter written in C# 项目地址: https://gitcode.com/gh_mirrors/js/jsxbin-to-jsx-converter 你是否曾经面对过Adobe产品的JSXBIN文件感到… 2026/7/4 0:02:28