标题:
STM32F103单片机使用MAX30102测量心率血氧源程序
[打印本页]
作者:
嗡嗡嗡顶顶顶
时间:
2024-4-28 10:15
标题:
STM32F103单片机使用MAX30102测量心率血氧源程序
单片机源程序如下:
#include "stm32f10x.h" // Device header
#include "software_IIC.h"
#include "MAX30102.h"
#include "MAX30102_algorithm.h"
#include "OLED.h"
#include "Key.h"
#include "Delay.h"
#define MAX_BRIGHTNESS 255
uint16_t fifo_red;
uint16_t fifo_ir;
void MAX30102_Init(void)
{
IIC_GPIO_Init(); //先初始化底层的I2C
/*MAX30102寄存器初始化,需要对照MAX30102手册的寄存器描述配置,此处仅配置了部分重要的寄存器*/
IIC_WriteReg(MAX30102_ADDRESS,REG_MODE_CONFIG, 0x40); //将RESET位设置为1,所有配置、阈值和数据寄存器通过上电复位复位复位到其上电状态。
IIC_WriteReg(MAX30102_ADDRESS,REG_INTR_ENABLE_1, 0x00); //不使用中断
IIC_WriteReg(MAX30102_ADDRESS,REG_INTR_ENABLE_2, 0x00);
IIC_WriteReg(MAX30102_ADDRESS,REG_FIFO_WR_PTR,0x00); //FIFO写入指针为0
IIC_WriteReg(MAX30102_ADDRESS,REG_OVF_COUNTER,0x00); //溢出数据计数器为0
IIC_WriteReg(MAX30102_ADDRESS,REG_FIFO_RD_PTR,0x00); //FIFO读取指针为0
IIC_WriteReg(MAX30102_ADDRESS,REG_FIFO_CONFIG,0x0f); //0x0f设置平均取样为4,当FIFO完全充满数据时,FIFO地址滚动到零并且FIFO继续填充新数据。
IIC_WriteReg(MAX30102_ADDRESS,REG_MODE_CONFIG,0x03); //SpO2模式
IIC_WriteReg(MAX30102_ADDRESS,REG_SPO2_CONFIG,0x27); //0x45ADC量程为8192,采样率为100/s,LED占空比118us,对应采样精度16bit
IIC_WriteReg(MAX30102_ADDRESS,REG_LED1_PA,0x20);
IIC_WriteReg(MAX30102_ADDRESS,REG_LED2_PA,0x20);
IIC_WriteReg(MAX30102_ADDRESS,REG_PILOT_PA,0x7F);
}
void MAX30102_IIC_ReadReg(uint8_t slave_ID,uint8_t RegAddress) //读取6个字节
{
fifo_red=0;
fifo_ir=0;
uint16_t Data1,Data2,Data3,Data4,Data5,Data6;
IIC_Start(); //I2C起始
IIC_SendByte(slave_ID); //发送从机地址,读写位为0,表示即将写入
IIC_ReceiveAck(); //接收应答
IIC_SendByte(RegAddress); //发送寄存器地址
IIC_ReceiveAck(); //接收应答
IIC_Start(); //I2C重复起始
IIC_SendByte(slave_ID | 0x01); //发送从机地址,读写位为1,表示即将读取
IIC_ReceiveAck(); //接收应答
Data1 = IIC_ReceiveByte(); //接收指定寄存器的数据
IIC_SendAck(0); //发送应答,给从机非应答,终止从机的数据输出
Data2 = IIC_ReceiveByte();
IIC_SendAck(0);
Data3 = IIC_ReceiveByte();
IIC_SendAck(0);
Data4 = IIC_ReceiveByte(); //接收指定寄存器的数据
IIC_SendAck(0); //发送应答,给从机非应答,终止从机的数据输出
Data5 = IIC_ReceiveByte();
IIC_SendAck(0);
Data6 = IIC_ReceiveByte();
IIC_SendAck(1);
IIC_Stop();
//I2C终止
Data1 <<= 14;
fifo_red+=Data1;
Data2 <<= 6;
fifo_red+=Data2;
Data3 >>= 2;
fifo_red+=Data3;
Data4 <<= 14;
fifo_ir+=Data4;
Data5 <<= 6;
fifo_ir+=Data5;
Data6 >>= 2;
fifo_ir+=Data6;
if(fifo_ir<=10000)
{
fifo_ir=0;
}
if(fifo_red<=10000)
{
fifo_red=0;
}
}
int8_t menu_Back_event(void)//菜单返回
{
return Key_Back_Get();; //返回键接到PA2;
}
void SPO2_function(void)
{
OLED_Clear();
OLED_ShowChinese(46,0,"血");
OLED_ShowChinese(62,0,"氧");
OLED_ShowChinese(78,0,"检");
OLED_ShowChinese(94,0,"测");
MAX30102_Init(); //初始化MAX30102
OLED_ShowImage(0,0,22,8,qipaoup); //显示左上方固定的石头块
OLED_ShowImage(0,56,22,8,qipaodown); //显示左下方固定的石头块
OLED_Update();
uint8_t j=128; //定义鱼的起始X坐标
uint8_t ave_Count = 1; //为了获取10个最终得到的血氧值,设置计数器,(可以更改,值越大测量时间越长,获取数据越多)
uint16_t cal_ave[10]; //定义长度为10的数组存储10个检测数据
uint16_t ave_Sum = 0; //存储10个数据的和
uint8_t cal_Sum_lock = 0; //总和计算器锁
while(1)
{
/*-------------------------移动气泡的程序逻辑------------------------------*/
uint8_t i;
for(i = 0;i <= 16;i++)
{
OLED_ClearArea(0,8,22,48);
OLED_ShowImage(1,49-i,7,7,qipao);
OLED_ShowImage(1,33-i,7,7,qipao);
if(i<17)
{
OLED_ShowImage(1,17-i,7,7,qipao);
OLED_ShowImage(0,0,22,8,qipaoup);
}
OLED_ShowImage(13,56-i,7,7,qipao);
OLED_ShowImage(13,40-i,7,7,qipao);
OLED_ShowImage(13,24-i,7,7,qipao);
/*-------------------------移动鱼的程序逻辑------------------------------*/
if(j<=0)
{
j = 128;
OLED_ClearArea(22,49,106,15); //清除小鱼游过后的全屏尾迹
}
OLED_ShowImage(j,49,15,15,Fish);
OLED_ClearArea(j+15,49,106,15); //解除注释可以实时清除小鱼尾迹
OLED_ShowImage(0,56,22,8,qipaodown); //刷新左下角石头块,让小鱼从石头快后边游过,注释后会从石头块前方游过
j--;
Delay_ms(5); //控制动画移动速度
OLED_Update();
}
if(ave_Count<=10)
{
blood_Loop();
if(SPO2dataResult != 0)
{
OLED_ClearArea(22,16,106,32);
OLED_ShowChinese(54,17,"检");
OLED_ShowChinese(70,17,"测");
OLED_ShowChinese(86,17,"中");
cal_ave[ave_Count-1] = SPO2dataResult;
ave_Count++;
}else{
OLED_ClearArea(22,16,106,32);
OLED_ShowChinese(54,16,"请");
OLED_ShowChinese(70,16,"正");
OLED_ShowChinese(86,16,"确");
OLED_ShowChinese(54,32,"佩");
OLED_ShowChinese(70,32,"戴");
OLED_ShowChar(90,32,'!',OLED_8X16);
}
}else
{
ave_Count = 11; //得到10个数据后将计数器值固定到11防止溢出
uint8_t i;
uint16_t min;
for(i = 0;i<9;i++) //取出最小值
{
if(i == 0){min = cal_ave[0];} //
if(cal_ave[i+1]<min)
{
min = cal_ave[i+1];
}
}
if(cal_Sum_lock == 0)
{
for(i = 0;i<10;i++)
{
ave_Sum += cal_ave[i]; //计算0个数据的和
}
cal_Sum_lock = 1; //和计算一次后打开锁,防止多次累加
}
OLED_ClearArea(22,17,106,32);
OLED_ShowNum(49,17,(ave_Sum-min)/9 + 3,3,OLED_15X24); //显示最终结果
OLED_ShowChar(96,17,0x3A,OLED_15X24);
}
if(menu_Back_event()) //检测按键按下
{
break;
}
}
}
void Heart_function(void)
{
OLED_Clear();
OLED_ShowChinese(32,0,"心");
OLED_ShowChinese(48,0,"率");
OLED_ShowChinese(64,0,"检");
OLED_ShowChinese(80,0,"测");
OLED_Update();
MAX30102_Init();
uint8_t ave_Count = 1; //为了获取10个最终得到的心率,设置计数器
uint16_t cal_ave[10]; //定义长度为10的数组存储测量的10个心率数据
uint16_t ave_Sum = 0; //存储10个数据的和
uint8_t cal_Sum_lock = 0; //总和计算器锁
while(1)
{
OLED_ClearArea(0,20,64,44);
OLED_ShowImage(0,20,54,49,Heart1);
OLED_Update();
Delay_ms(10);
OLED_ClearArea(0,20,64,44);
OLED_ShowImage(0,20,54,49,Heart2);
OLED_Update();
Delay_ms(10);
OLED_ClearArea(0,20,64,44);
OLED_ShowImage(0,20,54,49,Heart3);
OLED_Update();
Delay_ms(10);
OLED_ClearArea(0,20,64,44);
OLED_ShowImage(0,20,54,49,Heart4);
OLED_Update();
Delay_ms(10);
OLED_ClearArea(0,20,64,44);
OLED_ShowImage(0,20,54,49,Heart5);
OLED_Update();
Delay_ms(10);
OLED_ClearArea(0,20,64,44);
OLED_ShowImage(0,20,54,49,Heart6);
OLED_Update();
Delay_ms(10);
OLED_ClearArea(0,20,64,44);
OLED_ShowImage(0,20,54,49,Heart7);
OLED_Update();
Delay_ms(10);
OLED_ClearArea(0,20,64,44);
OLED_ShowImage(0,20,54,49,Heart8);
OLED_Update();
Delay_ms(10);
OLED_ClearArea(0,20,64,44);
OLED_ShowImage(0,20,54,49,Heart7);
OLED_Update();
Delay_ms(10);
OLED_ClearArea(0,20,64,44);
OLED_ShowImage(0,20,54,49,Heart6);
OLED_Update();
Delay_ms(10);
OLED_ClearArea(0,20,64,44);
OLED_ShowImage(0,20,54,49,Heart5);
OLED_Update();
Delay_ms(10);
OLED_ClearArea(0,20,64,44);
OLED_ShowImage(0,20,54,49,Heart4);
OLED_Update();
Delay_ms(10);
OLED_ClearArea(0,20,64,44);
OLED_ShowImage(0,20,54,49,Heart3);
OLED_Update();
Delay_ms(10);
OLED_ClearArea(0,20,64,44);
OLED_ShowImage(0,20,54,49,Heart2);
OLED_Update();
Delay_ms(10);
OLED_ClearArea(0,20,64,44);
OLED_ShowImage(0,20,54,49,Heart1);
OLED_Update();
//blood_Loop();
OLED_ClearArea(64,20,64,44);
if(ave_Count<=10)
{
blood_Loop();
if(SPO2dataResult != 0)
{
OLED_ClearArea(64,16,64,44);
OLED_ShowChinese(64,17,"测");
OLED_ShowChinese(80,17,"量");
OLED_ShowChinese(96,17,"中");
//OLED_ShowNum(64,17,HeartdataResult,3,OLED_13X24);
cal_ave[ave_Count-1] = HeartdataResult;
ave_Count++;
}
else
{
OLED_ClearArea(64,16,64,44);
OLED_ShowChinese(64,16,"请");
OLED_ShowChinese(80,16,"正");
OLED_ShowChinese(96,16,"确");
OLED_ShowChinese(64,32,"佩");
OLED_ShowChinese(80,32,"戴");
OLED_ShowChar(100,32,'!',OLED_8X16);
}
}
else
{
ave_Count = 11; //得到10个数据后将计数器固定到11防止溢出
uint8_t i;
uint16_t max;
for(i = 0;i<9;i++) //取出最大值
{
if(i == 0){max = cal_ave[0];} //
if(cal_ave[i+1]>max)
{
max = cal_ave[i+1];
}
}
if(cal_Sum_lock == 0)
{
for(i = 0;i<10;i++)
{
ave_Sum += cal_ave[i]; //计算10个数据的和
}
cal_Sum_lock = 1; //和计算一次后打开锁,防止多次计算
}
OLED_ClearArea(22,17,106,32);
OLED_ShowNum(64,17,(ave_Sum-max)/9,3,OLED_15X24); //显示最终结果
Delay_ms(200);
}
if(menu_Back_event()) //检测按键按下
{
break;
}
}
}
复制代码
原理图: 无
仿真: 无
代码:
心率血氧检测.7z
(198.14 KB, 下载次数: 30)
2024-4-28 14:42 上传
点击文件名下载附件
程序源码
下载积分: 黑币 -5
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1