手把手教你用STM32F103驱动LU90614红外测温模块(附完整代码与避坑指南)
STM32F103与LU90614红外测温模块实战:从硬件对接到数据解析全攻略
在智能硬件和物联网项目中,非接触式温度测量需求日益增多。LU90614作为一款性价比较高的红外测温模块,通过串口输出数据,非常适合与STM32系列单片机配合使用。本文将完整呈现如何从零开始,在STM32F103C8T6(BluePill开发板)上实现LU90614模块的稳定驱动,包含硬件连接、协议解析、模式切换等关键环节的避坑指南。
1. 硬件准备与连接
LU90614模块通常采用4Pin接口(VCC、GND、TX、RX),工作电压为3.3V。与STM32F103连接时需特别注意:
- 电源处理:虽然模块内置HT7533稳压芯片,但仍建议使用独立LDO供电,避免串口通信时电流波动影响测量精度
- 串口选择:任意USART接口均可,示例使用USART2(PA2-TX、PA3-RX)
- 电平匹配:确保STM32的IO电压与模块一致(均为3.3V)
推荐连接方式:
| LU90614引脚 | STM32F103连接点 | 备注 |
|---|---|---|
| VCC | 3.3V | 建议独立电源轨 |
| GND | GND | 共地至关重要 |
| TX | PA3 (USART2_RX) | 模块TX接MCU RX |
| RX | PA2 (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:保留字段(通常为0)
- TEMP_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 i=0; i<7; 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 i=0; i<len; 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 i=0; i<SAMPLE_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, "AT+CIPSTART=\"TCP\",\"api.thingspeak.com\",80"); ESP8266_SendCommand(cmd); sprintf(cmd, "GET /update?api_key=YOUR_KEY&field1=%.2f HTTP/1.1\r\n" "Host: api.thingspeak.com\r\n\r\n", temp); ESP8266_SendData(cmd); }在完成基础驱动后,建议使用标准黑体辐射源或高精度红外测温枪进行校准,建立温度补偿曲线。实际测试中发现,在10-40℃范围内LU90614的误差可控制在±0.5℃内,但在高温段(>80℃)可能需要额外的补偿系数。
