STM32 驱动心率血氧传感器--GH3020

GH3020 是一款低成本、低功耗的心率 / 血氧(SpO2)传感器,核心通信方式为I2C,以下以 STM32F103(最常用的入门款)为例,提供完整的驱动代码和硬件 / 软件说明,新手可直接复用。

一、硬件连接说明

STM32 引脚 GH3020 引脚 说明
PB6 SCL I2C 时钟线(上拉 10KΩ)
PB7 SDA I2C 数据线(上拉 10KΩ)
3.3V VDD 电源(请勿接 5V)
GND GND 接地
PA0(可选) INT 数据就绪中断(低电平有效)

二、软件驱动代码(STM32 标准库)

1. 头文件定义(gh3020.h)
复制代码
#ifndef __GH3020_H
#define __GH3020_H
#include "stm32f10x.h"
// GH3020 I2C地址(7位地址为0x2F,左移1位后写0x5E,读0x5F)
#define GH3020_I2C_ADDR    0x5E  
// GH3020核心寄存器地址
#define GH3020_REG_ID      0x00  // 设备ID寄存器(固定值0x30)
#define GH3020_REG_CTRL1   0x01  // 控制寄存器1(模式配置)
#define GH3020_REG_CTRL2   0x02  // 控制寄存器2(采样率配置)
#define GH3020_REG_HR_DATA 0x03  // 心率数据寄存器(低字节)
#define GH3020_REG_SPO2_DATA 0x05 // 血氧数据寄存器(低字节)
#define GH3020_REG_RED_ADC 0x07  // 红光ADC值(低字节)
#define GH3020_REG_IR_ADC  0x09  // 红外光ADC值(低字节)
// 数据结构体(存储传感器数据)
typedef struct {
    uint8_t  device_id;   // 设备ID
    uint16_t heart_rate;  // 心率值(bpm)
    uint16_t spo2;        // 血氧值(%)
    uint16_t red_adc;     // 红光ADC原始值
    uint16_t ir_adc;      // 红外光ADC原始值
} GH3020_Data_TypeDef;
// 函数声明
void GH3020_I2C_Init(void);                  // 初始化STM32的I2C外设
uint8_t GH3020_Check_ID(void);               // 检测GH3020是否存在
void GH3020_Init(void);                      // 初始化GH3020传感器
uint8_t GH3020_Read_Reg(uint8_t reg_addr);   // 读取单个寄存器
void GH3020_Write_Reg(uint8_t reg_addr, uint8_t data); // 写入单个寄存器
void GH3020_Read_Data(GH3020_Data_TypeDef *data); // 读取心率/血氧数据
#endif
2. 源文件实现(gh3020.c)
复制代码
#include "gh3020.h"
#include "delay.h"  // 需自行实现延时函数(us/ms级)
// 初始化STM32的I2C1外设(标准模式,100KHz)
void GH3020_I2C_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    I2C_InitTypeDef I2C_InitStruct;
    // 使能时钟:I2C1 + GPIOB
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    // 配置PB6(SCL)、PB7(SDA)为复用开漏输出
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;  // 复用开漏
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStruct);
    // 初始化I2C1
    I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2; // 占空比2:1
    I2C_InitStruct.I2C_OwnAddress1 = 0x00; // 自身地址(无需设置)
    I2C_InitStruct.I2C_Ack = I2C_Ack_Enable; // 使能应答
    I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; // 7位地址
    I2C_InitStruct.I2C_ClockSpeed = 100000; // 100KHz
    I2C_Init(I2C1, &I2C_InitStruct);
    // 使能I2C1
    I2C_Cmd(I2C1, ENABLE);
}
// 读取GH3020单个寄存器值
uint8_t GH3020_Read_Reg(uint8_t reg_addr)
{
    uint8_t reg_data = 0;
    // 等待I2C总线空闲
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
    // 发送起始信号
    I2C_GenerateSTART(I2C1, ENABLE);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
    // 发送设备写地址
    I2C_Send7bitAddress(I2C1, GH3020_I2C_ADDR, I2C_Direction_Transmitter);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    // 发送寄存器地址
    I2C_SendData(I2C1, reg_addr);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
    // 发送重复起始信号
    I2C_GenerateSTART(I2C1, ENABLE);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
    // 发送设备读地址
    I2C_Send7bitAddress(I2C1, GH3020_I2C_ADDR, I2C_Direction_Receiver);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
    // 关闭应答,准备接收数据
    I2C_AcknowledgeConfig(I2C1, DISABLE);
    I2C_GenerateSTOP(I2C1, ENABLE); // 发送停止信号
    // 读取寄存器数据
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
    reg_data = I2C_ReceiveData(I2C1);
    // 恢复应答使能
    I2C_AcknowledgeConfig(I2C1, ENABLE);
    return reg_data;
}
// 写入GH3020单个寄存器值
void GH3020_Write_Reg(uint8_t reg_addr, uint8_t data)
{
    // 等待I2C总线空闲
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
    // 发送起始信号
    I2C_GenerateSTART(I2C1, ENABLE);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
    // 发送设备写地址
    I2C_Send7bitAddress(I2C1, GH3020_I2C_ADDR, I2C_Direction_Transmitter);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    // 发送寄存器地址
    I2C_SendData(I2C1, reg_addr);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
    // 发送要写入的数据
    I2C_SendData(I2C1, data);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
    // 发送停止信号
    I2C_GenerateSTOP(I2C1, ENABLE);
    delay_ms(1); // 短延时,确保写入完成
}
// 检测GH3020是否存在(读取设备ID,正确值为0x30)
uint8_t GH3020_Check_ID(void)
{
    uint8_t dev_id = GH3020_Read_Reg(GH3020_REG_ID);
    if(dev_id == 0x30)
    {
        return 1; // 检测成功
    }
    return 0; // 检测失败
}
// 初始化GH3020传感器(配置为心率+血氧模式,采样率50Hz)
void GH3020_Init(void)
{
    // 先检测设备是否存在
    if(!GH3020_Check_ID())
    {
        return; // 检测失败,直接返回
    }
    // 配置控制寄存器1:0x07 = 心率+血氧模式,使能传感器
    GH3020_Write_Reg(GH3020_REG_CTRL1, 0x07);
    // 配置控制寄存器2:0x01 = 采样率50Hz(可选:0x00=25Hz,0x02=100Hz)
    GH3020_Write_Reg(GH3020_REG_CTRL2, 0x01);
    delay_ms(100); // 传感器启动延时
}
// 读取心率、血氧、ADC原始数据
void GH3020_Read_Data(GH3020_Data_TypeDef *data)
{
    uint8_t hr_h, hr_l;
    uint8_t spo2_h, spo2_l;
    uint8_t red_h, red_l;
    uint8_t ir_h, ir_l;
    // 读取设备ID
    data->device_id = GH3020_Read_Reg(GH3020_REG_ID);
    // 读取心率数据(16位:低字节+高字节)
    hr_l = GH3020_Read_Reg(GH3020_REG_HR_DATA);
    hr_h = GH3020_Read_Reg(GH3020_REG_HR_DATA + 1);
    data->heart_rate = (hr_h << 8) | hr_l;
    // 读取血氧数据(16位:低字节+高字节)
    spo2_l = GH3020_Read_Reg(GH3020_REG_SPO2_DATA);
    spo2_h = GH3020_Read_Reg(GH3020_REG_SPO2_DATA + 1);
    data->spo2 = (spo2_h << 8) | spo2_l;
    // 读取红光ADC值(16位)
    red_l = GH3020_Read_Reg(GH3020_REG_RED_ADC);
    red_h = GH3020_Read_Reg(GH3020_REG_RED_ADC + 1);
    data->red_adc = (red_h << 8) | red_l;
    // 读取红外光ADC值(16位)
    ir_l = GH3020_Read_Reg(GH3020_REG_IR_ADC);
    ir_h = GH3020_Read_Reg(GH3020_REG_IR_ADC + 1);
    data->ir_adc = (ir_h << 8) | ir_l;
}
3. 主函数调用示例(main.c)
复制代码
#include "stm32f10x.h"
#include "gh3020.h"
#include "delay.h"
int main(void)
{
    GH3020_Data_TypeDef gh3020_data;
    // 初始化延时函数
    delay_init();
    // 初始化GH3020的I2C外设
    GH3020_I2C_Init();
    // 初始化GH3020传感器
    GH3020_Init();
    while(1)
    {
        // 读取传感器数据
        GH3020_Read_Data(&gh3020_data);
        // 打印数据(需自行实现串口打印函数,如USART_SendString)
        // 示例:心率=gh3020_data.heart_rate,血氧=gh3020_data.spo2
        delay_ms(500); // 500ms读取一次
    }
}

三、关键代码解释

  1. I2C 初始化

    配置 PB6/PB7 为复用开漏输出(I2C 总线要求),I2C 时钟设为 100KHz(GH3020 支持的速率)。

  2. 寄存器读写

    • 写寄存器:先发送设备写地址→寄存器地址→要写入的数据→停止信号。

    • 读寄存器:先发送设备写地址→寄存器地址→重复起始信号→设备读地址→读取数据→停止信号。

  3. 传感器配置

    • GH3020_REG_CTRL1 = 0x07

      开启心率 + 血氧检测模式。

    • GH3020_REG_CTRL2 = 0x01

      设置采样率 50Hz(平衡精度和功耗)。

  4. 数据读取

    心率 / 血氧 / ADC 值均为 16 位数据,需读取低字节 + 高字节拼接。

四、使用注意事项

  1. 电源

    GH3020 仅支持 3.3V 供电,接 5V 会烧毁传感器。

  2. 上拉电阻

    SDA/SCL 引脚必须接 10KΩ 上拉电阻(I2C 总线要求)。

  3. 数据有效性

    首次上电后需等待 1~2 秒,传感器完成初始化后再读取数据。

  4. 中断使用(可选)

    若使用 INT 引脚,可配置 STM32 外部中断,当 INT 引脚拉低时读取数据(减少轮询功耗)。

总结

  1. 核心通信

    GH3020 与 STM32 通过 I2C 总线通信,设备 7 位地址为 0x2F(写 0x5E / 读 0x5F)。

  2. 关键步骤

    初始化 I2C→检测设备 ID→配置传感器工作模式→读取 16 位心率 / 血氧数据。

  3. 数据解析

    心率值范围为 0~250 bpm,血氧值范围为 0~100 %,ADC 值为原始光电信号(可用于自定义算法)。

相关推荐
FreakStudio7 天前
W55MH32L-EVB 上手测评:硬件 TCP/IP 加持的以太网单片机,MicroPython 零门槛开发
python·单片机·嵌入式·大学生·面向对象·并行计算·电子diy·电子计算机
✎ ﹏梦醒͜ღ҉繁华落℘12 天前
单片机基础知识---stm32单片机的优先级
stm32·单片机·mongodb
u1521096484912 天前
S.S.Audio PRO A2音频隔离器
嵌入式硬件·音视频·实时音视频·视频编解码·视频
zd84510150013 天前
RS485 总线详解
单片机·嵌入式硬件
半条-咸鱼13 天前
【STM32】I2C协议原理、HAL读写与OLED显示操作
嵌入式硬件·c·信息与通信
牛根生同志13 天前
SPI数据收发的时候 TXE与RXNE标志位置位的时机
stm32·spi·transfer
wohoo_wangzi13 天前
苏州晟雅泰电子:关于W25Q128JVSIQ这个芯片物料的参数,规格及应用领域
嵌入式硬件
goldenrolan13 天前
学习型红外控制系统稳定性挂测工装专项总结
软件测试·python·stm32·嵌入式·红外
✎ ﹏梦醒͜ღ҉繁华落℘13 天前
编程基础 --高内聚,低耦合
c语言·单片机
科芯创展13 天前
1A,1MHz,30VIN,XZ4115,降压恒流LED驱动芯片
单片机·嵌入式硬件