STM32--GY906体温检测传感器

目录

一、工作原理

二、接线方式

三、软件程序

总结

前言

最近用到了STM32驱动GY906体温检测传感器模块,我这里用的STM32是STM32F407IGT6,这个模块的精度能达到0.01℃,所以记录一下

一、工作原理

GY906 是一款基于MLX90614 芯片 的非接触式红外温度传感器模块,其工作原理基于红外辐射测温技术塞贝克效应(Seebeck Effect)。

核心原理:所有温度高于绝对零度 (-273.15℃) 的物体都会持续发射红外辐射,辐射强度与物体温度的四次方成正比 (斯特藩 - 玻尔兹曼定律)。GY906 通过检测目标物体发射的红外辐射能量,将其转换为电信号,经过处理后计算出物体表面温度。

GY906 通过I2C/SMBus 协议输出温度数据,也支持 PWM 输出模式:

  • I2C 模式:16 位数据 (高 8 位 + 低 8 位),包含物体温度和环境温度,分辨率 0.02℃
  • PWM 模式:SDA 引脚输出占空比代表温度的 10 位 PWM 信号

信号处理链

复制代码
热电堆微弱电压信号 → 低噪声放大器(LNA) → 带通滤波器 → 17位ADC → DSP处理 → 温度值

二、接线方式

|-----|-----|
| VIN | 5V |
| GND | GND |
| SCL | PB6 |
| SDA | PB7 |


三、软件程序

gy906.h

复制代码
#ifndef __GY906_H
#define __GY906_H

#include "stm32f1xx_hal.h"  // 替换为对应型号的HAL头文件(如stm32f4xx_hal.h)

// GY906(MLX90614)I2C地址(默认0x5A,若未配置EEPROM则为0x00)
#define MLX90614_ADDR        0x5A << 1  // I2C地址左移1位(HAL库要求包含读写位)

// MLX90614 寄存器地址
#define MLX90614_TA_REG      0x06  // 环境温度寄存器
#define MLX90614_TOBJ1_REG   0x07  // 目标物体温度寄存器(主要测量)

// 函数声明
void GY906_Init(I2C_HandleTypeDef *hi2c);  // 初始化(本质是I2C初始化,此处用于校验连接)
float GY906_ReadAmbientTemp(I2C_HandleTypeDef *hi2c);  // 读取环境温度(℃)
float GY906_ReadObjectTemp(I2C_HandleTypeDef *hi2c);   // 读取目标物体温度(℃)
uint8_t GY906_CheckDevice(I2C_HandleTypeDef *hi2c);    // 检测传感器是否在线

#endif

gy906.c

复制代码
#include "gy906.h"
#include "stdio.h"

/**
 * @brief  检测GY906是否在线
 * @param  hi2c: I2C句柄指针
 * @retval 0: 正常,1: 异常
 */
uint8_t GY906_CheckDevice(I2C_HandleTypeDef *hi2c)
{
    HAL_StatusTypeDef status;
    uint8_t dummy_data = 0x00;
    
    // 尝试向传感器发送地址,检测ACK
    status = HAL_I2C_Master_Transmit(hi2c, MLX90614_ADDR, &dummy_data, 1, 100);
    if (status == HAL_OK)
        return 0;  // 传感器响应正常
    else
        return 1;  // 传感器未连接或地址错误
}

/**
 * @brief  初始化GY906(校验I2C连接)
 * @param  hi2c: I2C句柄指针
 * @retval 无
 */
void GY906_Init(I2C_HandleTypeDef *hi2c)
{
    if (GY906_CheckDevice(hi2c) == 0)
        printf("GY906 Device OK!\r\n");
    else
        printf("GY906 Device Error!\r\n");
}

/**
 * @brief  读取MLX90614寄存器数据
 * @param  hi2c: I2C句柄指针
 * @param  reg_addr: 寄存器地址
 * @param  data: 接收数据缓冲区(2字节)
 * @retval HAL状态
 */
static HAL_StatusTypeDef MLX90614_ReadReg(I2C_HandleTypeDef *hi2c, uint8_t reg_addr, uint8_t *data)
{
    HAL_StatusTypeDef status;
    
    // 1. 发送寄存器地址
    status = HAL_I2C_Master_Transmit(hi2c, MLX90614_ADDR, &reg_addr, 1, 100);
    if (status != HAL_OK)
        return status;
    
    // 2. 重新发送起始信号,读取2字节数据(温度值+校验位)
    status = HAL_I2C_Master_Receive(hi2c, MLX90614_ADDR, data, 2, 100);
    return status;
}

/**
 * @brief  读取环境温度(℃)
 * @param  hi2c: I2C句柄指针
 * @retval 环境温度值(失败返回-273.15)
 */
float GY906_ReadAmbientTemp(I2C_HandleTypeDef *hi2c)
{
    uint8_t data[2];
    int16_t temp_raw;
    float temp_c;
    
    if (MLX90614_ReadReg(hi2c, MLX90614_TA_REG, data) != HAL_OK)
        return -273.15f;  // 读取失败返回绝对零度(标识错误)
    
    // 合并2字节数据(高8位+低8位)
    temp_raw = (data[0] << 8) | data[1];
    
    // 温度转换公式:原始值 * 0.02 - 273.15(MLX90614输出为绝对温度K)
    temp_c = (temp_raw * 0.02f) - 273.15f;
    
    return temp_c;
}

/**
 * @brief  读取目标物体温度(℃)
 * @param  hi2c: I2C句柄指针
 * @retval 目标温度值(失败返回-273.15)
 */
float GY906_ReadObjectTemp(I2C_HandleTypeDef *hi2c)
{
    uint8_t data[2];
    int16_t temp_raw;
    float temp_c;
    
    if (MLX90614_ReadReg(hi2c, MLX90614_TOBJ1_REG, data) != HAL_OK)
        return -273.15f;
    
    temp_raw = (data[0] << 8) | data[1];
    
    // 排除无效数据(MLX90614无效温度值为0xFFFF)
    if (temp_raw == 0xFFFF)
        return -273.15f;
    
    temp_c = (temp_raw * 0.02f) - 273.15f;
    
    return temp_c;
}

main.c

复制代码
#include "stm32f1xx_hal.h"
#include "gy906.h"
#include "stdio.h"

// 全局变量
I2C_HandleTypeDef hi2c1;
UART_HandleTypeDef huart1;

// 函数声明
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
static void MX_USART1_UART_Init(void);
int fputc(int ch, FILE *f);  // 重定向printf到串口

int main(void)
{
    HAL_Init();
    SystemClock_Config();  // 系统时钟配置(需根据实际硬件修改)
    MX_GPIO_Init();        // GPIO初始化
    MX_I2C1_Init();        // I2C1初始化
    MX_USART1_UART_Init(); // USART1初始化(用于打印)
    
    GY906_Init(&hi2c1);    // 初始化GY906(检测设备)
    
    while (1)
    {
        float ambient_temp = GY906_ReadAmbientTemp(&hi2c1);  // 读取环境温度
        float object_temp = GY906_ReadObjectTemp(&hi2c1);    // 读取目标温度
        
        // 打印温度数据(保留2位小数)
        printf("Ambient Temp: %.2f ℃\r\n", ambient_temp);
        printf("Object Temp  : %.2f ℃\r\n", object_temp);
        printf("-------------------------\r\n");
        
        HAL_Delay(1000);  // 1秒读取一次
    }
}

/**
 * @brief  I2C1初始化配置(标准模式100kHz)
 */
static void MX_I2C1_Init(void)
{
    hi2c1.Instance = I2C1;
    hi2c1.Init.ClockSpeed = 100000;  // I2C时钟频率100kHz
    hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
    hi2c1.Init.OwnAddress1 = 0;      // STM32作为主机,无需自身地址
    hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    hi2c1.Init.OwnAddress2 = 0;
    hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
    if (HAL_I2C_Init(&hi2c1) != HAL_OK)
    {
        Error_Handler();
    }
}

/**
 * @brief  USART1初始化(115200波特率,8N1)
 */
static void MX_USART1_UART_Init(void)
{
    huart1.Instance = USART1;
    huart1.Init.BaudRate = 115200;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    if (HAL_UART_Init(&huart1) != HAL_OK)
    {
        Error_Handler();
    }
}

/**
 * @brief  GPIO初始化(I2C1引脚:PB6=SCL,PB7=SDA)
 */
static void MX_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    // 使能GPIOB时钟
    __HAL_RCC_GPIOB_CLK_ENABLE();
    // 使能I2C1时钟
    __HAL_RCC_I2C1_CLK_ENABLE();
    // 使能USART1时钟
    __HAL_RCC_USART1_CLK_ENABLE();
    
    // I2C1 SCL(PB6)和SDA(PB7)配置:开漏输出、上拉、复用功能
    GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;  // 开漏复用模式
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Pull = GPIO_PULLUP;      // 上拉电阻(无需外接时可开启,建议外接)
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    
    // USART1 TX引脚(PA9)配置
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

/**
 * @brief  重定向printf到串口1
 */
int fputc(int ch, FILE *f)
{
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 100);
    return ch;
}

/**
 * @brief  系统时钟配置(需根据实际STM32型号修改,此处以STM32F103C8T6为例)
 */
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
    // 配置HSI作为时钟源(8MHz)
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }
    
    // 配置系统时钟:HSI→AHB→APB1/APB2
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;  // APB1最大36MHz
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    
    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
    {
        Error_Handler();
    }
}

/**
 * @brief  错误处理函数
 */
void Error_Handler(void)
{
    while (1)
    {
        // 错误时可点亮LED提示(需自行添加LED配置)
        HAL_Delay(500);
    }
}

#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
    printf("Assertion Failed: File %s, Line %d\r\n", file, line);
    while (1);
}
#endif

总结

本文介绍了STM32驱动GY906红外温度传感器的实现方法。GY906基于MLX90614芯片,采用I2C通信协议,精度达0.01℃。硬件连接使用PB6(SCL)和PB7(SDA)引脚,软件部分包含初始化、环境温度和目标温度读取函数,通过串口输出温度数据。程序采用HAL库开发,实现了1秒间隔的温度采集与显示功能,为嵌入式系统温度监测提供了完整解决方案。

相关推荐
cooldream20091 小时前
基于 RISC-V VisionFive 的桌面数字时钟项目实战
嵌入式硬件·risc-v·嵌入式开发
2401_853448231 小时前
Spieed micarray开发介绍
stm32·sk9822·sipeed mic
哄娃睡觉2 小时前
STM32 VBAT外围电路接法详解--备用电源(纽扣电池)
stm32
小李做物联网2 小时前
26.3基于stm32单片机毕业设计物联网软硬件智能遮阳棚设计
stm32·单片机·嵌入式硬件·物联网
D***y2012 小时前
SocketTool、串口调试助手、MQTT中间件基础
单片机·嵌入式硬件·中间件
易水寒陈2 小时前
使用1个定时器作为多个串口的超时计数器
stm32·单片机
三佛科技-187366133973 小时前
BP8501CH是什么芯片?BP8501CH(输出功率说明及典型电路图)
单片机·嵌入式硬件
Zeku3 小时前
20251125 - 韦东山Linux第三篇笔记【下】
linux·驱动开发·嵌入式硬件
芯联智造3 小时前
【stm32简单外设篇】- 水银开关
c语言·stm32·单片机·嵌入式硬件