手把手教你用STM32F103驱动LU90614红外测温模块(附完整代码与避坑指南)

发布时间:2026/6/30 17:32:12

手把手教你用STM32F103驱动LU90614红外测温模块(附完整代码与避坑指南) STM32F103与LU90614红外测温模块实战从硬件对接到数据解析全攻略在智能硬件和物联网项目中非接触式温度测量需求日益增多。LU90614作为一款性价比较高的红外测温模块通过串口输出数据非常适合与STM32系列单片机配合使用。本文将完整呈现如何从零开始在STM32F103C8T6BluePill开发板上实现LU90614模块的稳定驱动包含硬件连接、协议解析、模式切换等关键环节的避坑指南。1. 硬件准备与连接LU90614模块通常采用4Pin接口VCC、GND、TX、RX工作电压为3.3V。与STM32F103连接时需特别注意电源处理虽然模块内置HT7533稳压芯片但仍建议使用独立LDO供电避免串口通信时电流波动影响测量精度串口选择任意USART接口均可示例使用USART2PA2-TX、PA3-RX电平匹配确保STM32的IO电压与模块一致均为3.3V推荐连接方式LU90614引脚STM32F103连接点备注VCC3.3V建议独立电源轨GNDGND共地至关重要TXPA3 (USART2_RX)模块TX接MCU RXRXPA2 (USART2_TX)模块RX接MCU TX注意部分廉价模块可能省略了ESD保护器件建议在信号线上串联100Ω电阻并添加对地TVS二极管。2. 开发环境配置使用Keil MDK-ARM开发环境进行项目搭建新建STM32F103C8T6工程选择正确芯片型号启用USART2外设配置参数波特率115200数据位8bit停止位1bit无校验位开启USART2全局中断NVIC配置关键初始化代码片段// USART2初始化结构体 USART_InitTypeDef USART_InitStruct { .USART_BaudRate 115200, .USART_WordLength USART_WordLength_8b, .USART_StopBits USART_StopBits_1, .USART_Parity USART_Parity_No, .USART_Mode USART_Mode_Rx | USART_Mode_Tx, .USART_HardwareFlowControl USART_HardwareFlowControl_None }; // 时钟使能 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // GPIO配置 GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Pin GPIO_Pin_2; // TX GPIO_InitStruct.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStruct); GPIO_InitStruct.GPIO_Pin GPIO_Pin_3; // RX GPIO_InitStruct.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, GPIO_InitStruct); // USART初始化 USART_Init(USART2, USART_InitStruct); USART_Cmd(USART2, ENABLE); // 使能接收中断 USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); NVIC_EnableIRQ(USART2_IRQn);3. 通讯协议深度解析LU90614采用简单的串口协议但实际应用中存在几个关键细节需要特别注意3.1 数据帧结构模块主动上传的温度数据帧为8字节固定格式[0x55][0xAA][DATA_H][DATA_L][TEMP_H][TEMP_L][CHECKSUM][0x0D]其中DATA_H/DATA_L保留字段通常为0TEMP_H/TEMP_L温度值大端格式CHECKSUM校验和从0x55开始到TEMP_L所有字节的累加和温度值转换公式float temperature ((TEMP_H 8) | TEMP_L) / 100.0f;3.2 模式切换命令模块支持两种测量模式切换体温模式发送0x55 0xAA 0x00 0x01 0x00 0x56 0x0D物温模式发送0x55 0xAA 0x00 0x01 0x01 0x57 0x0D模式切换代码实现void LU90614_SetMode(uint8_t mode) { uint8_t cmd[7] {0x55, 0xAA, 0x00, 0x01, mode, 0x00, 0x0D}; cmd[5] 0x56 mode; // 计算校验和 for(int i0; i7; i) { USART_SendData(USART2, cmd[i]); while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) RESET); } }3.3 数据校验与过滤实际测试发现原始数据可能存在跳变必须实现校验机制uint8_t LU90614_CheckSum(uint8_t *data, uint8_t len) { uint8_t sum 0; for(uint8_t i0; ilen; i) { sum data[i]; } return sum; } float LU90614_ParseData(uint8_t *buf) { // 检查帧头和校验和 if(buf[0]!0x55 || buf[1]!0xAA || buf[7]!0x0D) return -1; if(LU90614_CheckSum(buf, 6) ! buf[6]) return -1; // 提取温度值 int16_t temp_raw (buf[4] 8) | buf[5]; return temp_raw / 100.0f; }4. 完整驱动实现与优化结合上述知识点构建稳定可靠的驱动程序4.1 中断接收处理采用环形缓冲区管理串口数据#define BUF_SIZE 128 typedef struct { uint8_t buffer[BUF_SIZE]; uint16_t head; uint16_t tail; } RingBuffer; RingBuffer rx_buf {0}; void USART2_IRQHandler(void) { if(USART_GetITStatus(USART2, USART_IT_RXNE) ! RESET) { uint8_t data USART_ReceiveData(USART2); uint16_t next (rx_buf.head 1) % BUF_SIZE; if(next ! rx_buf.tail) { // 缓冲区未满 rx_buf.buffer[rx_buf.head] data; rx_buf.head next; } USART_ClearITPendingBit(USART2, USART_IT_RXNE); } }4.2 主处理逻辑实现状态机解析数据帧typedef enum { STATE_IDLE, STATE_HEAD1, STATE_HEAD2, STATE_DATA } ParserState; float LU90614_GetTemperature(void) { static ParserState state STATE_IDLE; static uint8_t frame[8], pos 0; float temp -1; while(rx_buf.head ! rx_buf.tail) { uint8_t data rx_buf.buffer[rx_buf.tail]; rx_buf.tail (rx_buf.tail 1) % BUF_SIZE; switch(state) { case STATE_IDLE: if(data 0x55) state STATE_HEAD1; break; case STATE_HEAD1: if(data 0xAA) state STATE_HEAD2; else state STATE_IDLE; break; case STATE_HEAD2: frame[0] 0x55; frame[1] 0xAA; frame[2] data; pos 3; state STATE_DATA; break; case STATE_DATA: frame[pos] data; if(pos 8) { temp LU90614_ParseData(frame); state STATE_IDLE; } break; } } return temp; }4.3 温度采样优化策略针对数据波动问题可采用以下方法提升稳定性移动平均滤波#define SAMPLE_SIZE 5 float temp_history[SAMPLE_SIZE]; uint8_t sample_index 0; float GetFilteredTemperature(void) { float raw LU90614_GetTemperature(); if(raw 0) return -1; // 无效数据 temp_history[sample_index] raw; if(sample_index SAMPLE_SIZE) sample_index 0; float sum 0; for(int i0; iSAMPLE_SIZE; i) { sum temp_history[i]; } return sum / SAMPLE_SIZE; }异常值剔除记录历史数据当新数据偏离平均值超过阈值时丢弃环境温度补偿结合DS18B20等接触式传感器进行校准5. 实际应用中的问题排查根据实测经验以下是常见问题及解决方案5.1 数据不稳定或全零检查电源质量示波器观察3.3V电源纹波建议增加100μF电解电容验证接线可靠性特别是GND连接必须保证共地良好确认模块模式有些模块需要先发送模式命令才开始输出数据5.2 温度值明显偏差测量距离影响LU90614的最佳测量距离为3-5cm发射率设置多数情况下默认值0.95适用但对高反光表面需要调整环境温度补偿模块内部补偿可能不足需外部校准5.3 通信完全无响应逻辑分析仪验证检查STM32是否正常发送模式切换命令波特率校准虽然标称115200但部分模块可能需要微调波特率硬件流控冲突确保USART的硬件流控已禁用6. 扩展应用实例将LU90614与OLED显示结合创建便携式测温仪// 在main循环中添加 float temp GetFilteredTemperature(); if(temp 0) { char disp_str[16]; sprintf(disp_str, Temp: %.2fC, temp); OLED_ShowString(0, 2, (uint8_t*)disp_str); // 温度趋势指示 static float last_temp 0; if(temp last_temp 0.5) { OLED_ShowString(0, 4, (uint8_t*)↑ Rising); } else if(temp last_temp - 0.5) { OLED_ShowString(0, 4, (uint8_t*)↓ Falling); } else { OLED_ShowString(0, 4, (uint8_t*)- Stable); } last_temp temp; }通过按键切换测量模式// 按键初始化 GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Pin GPIO_Pin_0; // 假设按键接PA0 GPIO_InitStruct.GPIO_Mode GPIO_Mode_IPU; GPIO_InitStruct.GPIO_Speed GPIO_Speed_2MHz; GPIO_Init(GPIOA, GPIO_InitStruct); // 在main循环中检测 static uint8_t current_mode 0; if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) 0) { Delay_ms(50); // 消抖 if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) 0) { current_mode !current_mode; LU90614_SetMode(current_mode); while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) 0); // 等待释放 } }7. 进阶开发建议低功耗优化间隔采样如每秒1次采样间隙关闭模块电源使用STM32的STOP模式降低功耗多模块组网通过USART的地址识别功能管理多个LU90614或采用IO口切换片选信号云端监控结合ESP8266上传数据至云平台实现温度异常报警功能机械结构设计3D打印专用支架固定传感器添加激光瞄准辅助定位// 示例通过WiFi上传数据 void UploadToCloud(float temp) { char cmd[64]; sprintf(cmd, ATCIPSTART\TCP\,\api.thingspeak.com\,80); ESP8266_SendCommand(cmd); sprintf(cmd, GET /update?api_keyYOUR_KEYfield1%.2f HTTP/1.1\r\n Host: api.thingspeak.com\r\n\r\n, temp); ESP8266_SendData(cmd); }在完成基础驱动后建议使用标准黑体辐射源或高精度红外测温枪进行校准建立温度补偿曲线。实际测试中发现在10-40℃范围内LU90614的误差可控制在±0.5℃内但在高温段80℃可能需要额外的补偿系数。

相关新闻