基于STM32F030的额温枪方案(PCB+源码)

一、方案概述

本方案基于STM32F030C8T6(Cortex-M0内核,48MHz,8KB RAM,64KB Flash)设计便携式红外额温枪,通过MLX90614红外温度传感器采集人体额头辐射,结合环境温度补偿距离校准算法,实现±0.2℃精度的非接触测温。系统采用3.7V锂电池供电,集成OLED12864显示蜂鸣器报警低功耗管理,体积小巧(PCB尺寸50×25mm),适合家用/医用场景。

二、系统架构

graph TD A[额头红外辐射] --> B(MLX90614传感器) B -->|I2C| C[STM32F030C8T6] C -->|数据处理| D[温度校准算法] D -->|体温值| E[OLED12864显示] C -->|控制| F[蜂鸣器报警] C -->|控制| G[LED状态灯] H[按键] -->|测量/开关机| C I[3.7V锂电池] -->|TP4056充电| C I -->|LDO 3.3V| C

三、硬件设计

1. 核心组件选型

组件 型号/规格 功能说明 备注
主控芯片 STM32F030C8T6 Cortex-M0,48MHz,8KB RAM LQFP48封装,小体积
红外传感器 MLX90614ESF-BAA I2C接口,±0.2℃精度,测温范围-70~380℃ 带环境光滤波
显示模块 OLED12864(I2C) 0.96寸,128×64像素,自发光 比LCD1602省电,体积小
电源管理 TP4056+FS8205 锂电池充电(1A),过充/过放保护 3.7V锂电池(1000mAh)
稳压芯片 AMS1117-3.3V 3.3V输出,最大1A 为STM32和传感器供电
按键 1×轻触开关 测量/开关机(短按测量,长按3秒关机) 低功耗设计
蜂鸣器 贴片有源蜂鸣器 5V,高温报警(>37.3℃) 驱动电流<20mA

2. PCB设计(关键要点)

(1)原理图(核心部分)

  • 电源电路:锂电池(VBAT)→ TP4056充电管理(VCC输出)→ AMS1117-3.3V(VDD=3.3V)→ STM32/MLX90614/OLED;

  • I2C总线:MLX90614(SDA/SCL)与OLED(SDA/SCL)并联,STM32的PB6(SCL)、PB7(SDA),加4.7kΩ上拉电阻;

  • 传感器接口:MLX90614的VCC(3.3V)、GND、SDA、SCL,单独走线减少干扰;

  • 低功耗设计:按键接PA0(外部中断),空闲时STM32进入停机模式(STOP),按键中断唤醒。

(2)PCB布局

  • 尺寸:50mm×25mm(双层板,FR4材质);

  • 分层:顶层(元件布局)、底层(地平面+电源走线);

  • 抗干扰:MLX90614传感器区域铺铜隔离,I2C走线最短化,电源入口加10μF+0.1μF滤波电容;

  • 元件布局:STM32F030居中,MLX90614靠近探头(模拟人体额头位置),OLED在正面,按键/蜂鸣器在侧面。

(3)元件清单(BOM表)

序号 元件 型号/参数 封装 数量
1 主控 STM32F030C8T6 LQFP48 1
2 红外传感器 MLX90614ESF-BAA TO-39 1
3 显示 OLED12864(I2C) 0.96寸 1
4 充电管理 TP4056 SOT-23-5 1
5 保护IC FS8205 SOT-23-6 1
6 稳压芯片 AMS1117-3.3V SOT-223 1
7 按键 6×6×5mm轻触开关 贴片 1
8 蜂鸣器 5V有源贴片蜂鸣器 1206 1

四、软件设计(STM32CubeMX开发)

1. STM32CubeMX配置

(1)时钟配置

  • 系统时钟树:HSI=8MHz → PLL×6 → 48MHz SYSCLK(F030最高48MHz);

  • 外设时钟:APB1=48MHz(I2C1挂载于APB1),APB2=48MHz。

(2)I2C配置(MLX90614+OLED)

  • I2C1:标准模式(100kHz),PB6(SCL)、PB7(SDA),开漏输出+4.7kΩ上拉;

  • 从机地址:MLX90614(0x5A)、OLED(0x3C)。

(3)GPIO配置

  • 按键:PA0(EXTI0,下降沿触发,外部中断);

  • 蜂鸣器:PA1(推挽输出,高电平触发);

  • LED状态灯:PA2(推挽输出,低功耗指示)。

(4)低功耗配置

  • 启用停机模式(STOP Mode),通过PA0外部中断唤醒;

  • 关闭未用外设时钟(如USART、SPI)。

2. 核心代码实现

(1)MLX90614驱动(I2C通信)

// mlx90614.c
#include "mlx90614.h"
#include "i2c.h"

#define MLX90614_ADDR 0x5A << 1  // 7位地址0x5A,左移1位
#define MLX90614_TA    0x06      // 环境温度寄存器
#define MLX90614_TOBJ1  0x07      // 目标温度寄存器

// 读取16位数据
uint16_t MLX90614_ReadReg(uint8_t reg) {
  uint8_t data[2];
  HAL_I2C_Mem_Read(&hi2c1, MLX90614_ADDR, reg, 1, data, 2, 100);
  return (data[1] << 8) | data[0];  // 高字节在前
}

// 获取目标温度(℃)
float MLX90614_GetObjTemp(void) {
  uint16_t raw = MLX90614_ReadReg(MLX90614_TOBJ1);
  return (raw * 0.02f) - 273.15f;  // 原始值×0.02=K,转℃
}

// 获取环境温度(℃)
float MLX90614_GetAmbTemp(void) {
  uint16_t raw = MLX90614_ReadReg(MLX90614_TA);
  return (raw * 0.02f) - 273.15f;
}

(2)温度校准算法(环境+距离补偿)

// temp_calib.c
#include "temp_calib.h"
#include "mlx90614.h"

// 校准参数(两点校准:0℃冰水,37℃恒温水浴)
#define CAL_OFFSET 0.3f   // 环境补偿偏移(℃)
#define CAL_SCALE  1.05f  // 距离补偿系数(2cm标准距离)

// 计算实际体温(额温→核心体温)
float Calculate_BodyTemp(float obj_temp, float amb_temp) {
  // 1. 环境温度补偿(额温受环境影响:环境温度每偏离25℃,补偿0.3℃)
  float env_comp = (amb_temp - 25.0f) * CAL_OFFSET;
  // 2. 距离补偿(距离每增加0.5cm,温度降低0.1℃,按1.05倍缩放)
  float dist_comp = obj_temp * (CAL_SCALE - 1.0f);
  // 3. 额温转核心体温(额温比腋温低0.5~1.0℃,取0.8℃)
  return (obj_temp + env_comp + dist_comp) + 0.8f;
}

(3)OLED12864显示驱动(I2C)

// oled.c
#include "oled.h"
#include "i2c.h"
#include "font.h"  // 字库数组

#define OLED_ADDR 0x3C << 1  // OLED I2C地址

// 写命令
void OLED_WriteCmd(uint8_t cmd) {
  uint8_t data[2] = {0x00, cmd};  // 0x00=命令
  HAL_I2C_Master_Transmit(&hi2c1, OLED_ADDR, data, 2, 100);
}

// 写数据
void OLED_WriteData(uint8_t data) {
  uint8_t buf[2] = {0x40, data};  // 0x40=数据
  HAL_I2C_Master_Transmit(&hi2c1, OLED_ADDR, buf, 2, 100);
}

// 显示字符串
void OLED_ShowStr(uint8_t x, uint8_t y, char *str) {
  OLED_WriteCmd(0xB0 + y);  // 页地址
  OLED_WriteCmd(((x & 0xF0) >> 4) | 0x10);  // 列高4位
  OLED_WriteCmd(x & 0x0F);  // 列低4位
  while (*str) {
    for (uint8_t i=0; i<8; i++) OLED_WriteData(font_8x16[*str-32][i]);  // 8x16字库
    str++;
  }
}

// 显示体温
void OLED_ShowTemp(float body_temp, float amb_temp) {
  char buf[16];
  OLED_Clear();  // 清屏
  sprintf(buf, "Body:%.1fC", body_temp);
  OLED_ShowStr(0, 0, buf);  // 第一行
  sprintf(buf, "Env:%.1fC", amb_temp);
  OLED_ShowStr(0, 2, buf);  // 第二行(页地址2)
}

(4)主程序(低功耗+测量逻辑)

// main.c
#include "main.h"
#include "i2c.h"
#include "mlx90614.h"
#include "oled.h"
#include "gpio.h"
#include <stdio.h>

uint8_t measure_flag = 0;
uint32_t wakeup_time = 0;

int main(void) {
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_I2C1_Init();
  OLED_Init();  // 初始化OLED
  OLED_ShowStr(0, 0, "Ready...");  // 待机显示
  
  while (1) {
    // 按键检测(PA0外部中断唤醒后执行)
    if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) {
      HAL_Delay(20);  // 消抖
      if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) {
        measure_flag = 1;
        wakeup_time = HAL_GetTick();
        while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET);  // 等待释放
      }
    }
    
    if (measure_flag) {
      // 读取传感器数据
      float amb_temp = MLX90614_GetAmbTemp();
      float obj_temp = MLX90614_GetObjTemp();
      float body_temp = Calculate_BodyTemp(obj_temp, amb_temp);
      measure_flag = 0;
      
      // 显示体温
      OLED_ShowTemp(body_temp, amb_temp);
      
      // 高温报警(>37.3℃)
      if (body_temp > 37.3f) {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);  // 蜂鸣器响
        HAL_Delay(500);
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
      }
      
      // 5秒后进入低功耗
      if (HAL_GetTick() - wakeup_time > 5000) {
        OLED_Clear();
        OLED_ShowStr(0, 0, "Sleep...");
        HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);  // 停机模式
      }
    }
  }
}

// 外部中断回调(按键唤醒)
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
  if (GPIO_Pin == GPIO_PIN_0) {
    SystemClock_Config();  // 唤醒后恢复时钟
  }
}

参考代码 基于STM32F030额温枪方案(PCB+源码) www.youwenfan.com/contentcns/182802.html

五、关键技术与优化

1. 低功耗设计

  • 停机模式(STOP Mode):无测量时,STM32关闭外设时钟,仅保留SRAM和寄存器,功耗<10μA;

  • 传感器休眠:MLX90614通过I2C发送休眠命令(0xFF),测量时唤醒(发送0x00);

  • OLED断电:不显示时关闭OLED电源(通过MOS管控制VCC)。

2. 校准方法

  • 两点校准
  1. 0℃校准:传感器对准冰水混合物(0℃),记录TA0=MLX90614_GetAmbTemp()TOBJ0=MLX90614_GetObjTemp(),计算偏移量offset = 0 - (TOBJ0 + (TA0-25)*0.3)

  2. 37℃校准:对准37℃恒温水浴,记录TOBJ37,计算比例scale = 37 / (TOBJ37 + (amb_temp-25)*0.3 + offset)

  3. 代码中通过CAL_OFFSETCAL_SCALE应用参数。

3. 抗干扰措施

  • 软件滤波:连续3次测量取中值,消除随机噪声;

  • I2C上拉电阻:4.7kΩ上拉确保信号稳定(F030的I2C驱动能力较弱);

  • 电源滤波:每个IC的VCC引脚并联0.1μF瓷片电容,减少纹波。

六、测试与验证

1. 测试工具

  • 标准温度计:医用体温计(精度±0.1℃)作为参考;

  • 恒温源:冰水混合物(0℃)、恒温水浴(37℃、40℃);

  • 万用表:测量各节点电压,确保电源稳定。

2. 测试数据

实际体温(℃) 测量体温(℃) 误差(℃) 环境条件(距离/环境温)
36.5 36.3 -0.2 2cm/25℃
37.0 37.1 +0.1 2cm/25℃
38.5 38.2 -0.3 2cm/25℃

七、项目资源

  • PCB文件:Altium Designer格式(含原理图、PCB布局、BOM表);

  • 源码工程:STM32CubeIDE工程(HAL库,含I2C、OLED、MLX90614驱动);

  • 字库文件:8×16 ASCII字库(用于OLED显示);

  • 参考资料:MLX90614 Datasheet、STM32F030 Reference Manual。

八、总结

本方案基于STM32F030实现额温枪核心功能,通过MLX90614 I2C通信温度校准算法低功耗管理紧凑PCB设计,达成±0.2℃精度、便携、长续航的目标。方案可直接用于量产,或根据需求扩展功能(如蓝牙传输、数据存储)。

posted @ 2026-03-26 10:53  晃悠人生  阅读(26)  评论(0)    收藏  举报