找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2372|回复: 0
收起左侧

基于STM32F103C+APP系列开发无线传输的家用血氧仪设计

[复制链接]
ID:836950 发表于 2023-7-8 18:38 | 显示全部楼层 |阅读模式
最近遇到针对家用设备数据测算的样品设计中,个人使用了一下家里买现有的血氧检测仪,除了简单的界面规划设计外和数值反馈,只能给人一个数值上面的参考,然而反馈回来的信息还是需要自己去网上比对自己的血氧数据是否处在一个正常且稳定的一个标准范围上,刚好自己之前做过相关类型的设计,同时自己的储物柜上还有一块MAX30100系列的血氧检测传感器,为了更适合家用检测设计和对血氧数据分析更加便捷,于是对之前项目设计进行了升级。

单片机源程序如下:
main.c
int main(void)
{        
        int i=0;
        u8 timeout;
        delay_init();
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
        Usart1_Init(115200);
        Usart2_Init(115200);
        Delay_ms(500);
        UsartPrintf(USART1,"IIC_GPIO_INIT\r\n");
        IIC_GPIO_INIT();
        Delay_us(500);
        UsartPrintf(USART1,"OLED_Init\r\n");
          OLED_Init();
        OLED_Printf_EN(6,0,"MAX30102_GPIO");
        MAX30102_GPIO();
        OLED_Printf_EN(6,0,"Max30102_reset");
        Max30102_reset();
    MAX30102_Config();
        UsartPrintf(USART1,"开始初始化ESP8266\r\n");
        OLED_Printf_EN(6,0,"ESP8266.........");
        ESP8266_Init();
        UsartPrintf(USART1,"开始1\r\n");
        LED_Init();
                Led_flash();
        while(OneNet_DevLink())
        {
                        delay_ms(500);
        }
        UsartPrintf(USART1,"开始测量血氧\r\n");
        for(i = 0;i <128;i++)
        {
                while(MAX30102_INTPin_Read()==0)
                {
                        //读取FIFO
                        max30102_read_fifo();
                }
        }
        UsartPrintf(USART1,"测量结束\r\n");
        OLED_Printf_EN(6,0,"Ready.......");
        while(1)
        {        
                if(!key)
                {
                                delay_ms(10);
                                if(!key)
                                {
                                                while(!key);
                                                while(1)
                                                {
//                                                                OneNet_Publish(devPubTopic, PUB_BUF);        
                                                                OLED_Printf_EN(6,0,"Waiting...");
                                                                ESP8266_Clear();
                                                                UsartPrintf(USART1,"进入主循环\r\n");
                                                                Delay_us(300);
                                                               
                                                                if(++timeout >=50)
                                                                {
                                                                OLED_Printf_EN(6,0,"Dataing...");
                                                                blood_Loop();
                                                                UsartPrintf(USART1,"心率血氧测量完毕\r\n");
                                                                UsartPrintf(USART_DEBUG, "OneNet_SendData\r\n");                        
                                                                OneNet_SendData();
                                                                timeout=0;

                                                                        ESP8266_Clear();
                                                               
                                                                if((sp02 < 90||heart <= 60)&&(sp02 > 115||heart >= 120))
        
                                                                {         
                                                                                GPIO_SetBits(GPIOC,GPIO_Pin_13|GPIO_Pin_14| GPIO_Pin_15);                 
                                                                                delay_ms(500);
                                                                                GPIO_SetBits(GPIOC,GPIO_Pin_13|GPIO_Pin_14| GPIO_Pin_15);               
                                                                                delay_ms(500);
                                                                        GPIO_ResetBits(GPIOA,GPIO_Pin_1);
                                                                        delay_ms(500);
                                                                        
                                                                 }
                                                                else
                                                                {
                                                                        GPIO_SetBits(GPIOC,GPIO_Pin_14| GPIO_Pin_15);
                                                                        GPIO_SetBits(GPIOA,GPIO_Pin_1);
                                                                        delay_ms(500);
                                                                        GPIO_ResetBits(GPIOC,GPIO_Pin_14| GPIO_Pin_15);
                                                                        delay_ms(500);
                                                                }
                                                                if(!key)
                                                                {
                                                                                if(!key)
                                                                                {
                                                                                                while(!key);
                                                                                                break;
                                                                                }
                                                                }
                                                        }
                                }
        }
                if(++timeout >40)
                {
                                UsartPrintf(USART_DEBUG, "OneNet_SendData\r\n");               
                    sprintf(PUB_BUF,"{\"sp02\":%0.2f,\"heart\":%d}",sp02,heart);
                                Delay_us(500);
                                OneNet_SendData();
                                timeout=0;
                                OLED_Printf_EN(2,0,"heart:0/min  ");
                                OLED_Printf_EN(4,0,"SpO2:0%%     ");
                                OLED_Printf_EN(0,0,"Xue Yang Yi");
                                ESP8266_Clear();
                }
                delay_ms(10);
                GPIO_ResetBits(GPIOA,GPIO_Pin_1);
                LED1 = 0;
         }
        }
}



MAX30102.c


void MAX30102_GPIO(void)
{        
        RCC_APB2PeriphClockCmd(MAX30102_INTPin_CLK,ENABLE);
        GPIO_InitTypeDef GPIO_InitStruct;
        GPIO_InitStruct.GPIO_Mode                =        GPIO_Mode_IN_FLOATING;
        GPIO_InitStruct.GPIO_Pin                =        MAX30102_INTPin_Pin;
        GPIO_Init(MAX30102_INTPin_PORT,&GPIO_InitStruct);
        
}
uint8_t Max30102_reset(void)
{
        if(IIC_Write_Byte(MAX30102_Device_address,REG_MODE_CONFIG, 0x40))
        return 1;
    else
        return 0;   
}
void MAX30102_Config(void)
{
        IIC_Write_Byte(MAX30102_Device_address,REG_INTR_ENABLE_1,0xc0);//// INTR setting
        IIC_Write_Byte(MAX30102_Device_address,REG_INTR_ENABLE_2,0x00);//
        IIC_Write_Byte(MAX30102_Device_address,REG_FIFO_WR_PTR,0x00);//选择上四位片选
        IIC_Write_Byte(MAX30102_Device_address,REG_OVF_COUNTER,0x00);//选择下四位片选
        IIC_Write_Byte(MAX30102_Device_address,REG_FIFO_RD_PTR,0x00);//选择前八位
        IIC_Write_Byte(MAX30102_Device_address,REG_FIFO_CONFIG,0x0f);
        IIC_Write_Byte(MAX30102_Device_address,REG_MODE_CONFIG,0x03);
        IIC_Write_Byte(MAX30102_Device_address,REG_SPO2_CONFIG,0x27);
        IIC_Write_Byte(MAX30102_Device_address,REG_LED1_PA,0x32);
        IIC_Write_Byte(MAX30102_Device_address,REG_LED2_PA,0x32);
        IIC_Write_Byte(MAX30102_Device_address,REG_PILOT_PA,0x7f);
}
void max30102_read_fifo(void)
{
  uint16_t un_temp;
  fifo_red=0;
  fifo_ir=0;
  uint8_t ach_i2c_data[6];
  IIC_Read_Byte(MAX30102_Device_address,REG_INTR_STATUS_1);
  IIC_Read_Byte(MAX30102_Device_address,REG_INTR_STATUS_2);
  ach_i2c_data[0]=REG_FIFO_DATA;
        IIC_Read_Array(MAX30102_Device_address,REG_FIFO_DATA,ach_i2c_data,6);
  un_temp=ach_i2c_data[0];
  un_temp<<=14;
  fifo_red+=un_temp;
  un_temp=ach_i2c_data[1];
  un_temp<<=6;
  fifo_red+=un_temp;
  un_temp=ach_i2c_data[2];
        un_temp>>=2;
  fifo_red+=un_temp;
  un_temp=ach_i2c_data[3];
  un_temp<<=14;
  fifo_ir+=un_temp;
  un_temp=ach_i2c_data[4];
  un_temp<<=6;
  fifo_ir+=un_temp;
  un_temp=ach_i2c_data[5];
        un_temp>>=2;
  fifo_ir+=un_temp;
        
        if(fifo_ir<=10000)
        {
                fifo_ir=0;
        }
        if(fifo_red<=10000)
        {
                fifo_red=0;
        }
}



blood.c


extern float sp02;
extern u8 heart;

struct
{
        float         Hp        ;                        //血红蛋白        
        float         HpO2;                        //氧合血红蛋白
        
}g_BloodWave;//血液波形数据

BloodData g_blooddata = {0};                                        //血液数据存储

#define CORRECTED_VALUE                        47                           //标定血液氧气含量

/*funcation start ------------------------------------------------------------*/
//血液检测信息更新
void blood_data_update(void)
{
        //标志位被使能时 读取FIFO
        g_fft_index=0;
        while(g_fft_index < FFT_N)
        {
                while(MAX30102_INTPin_Read()==0)
                {
                        //读取FIFO
                        max30102_read_fifo();  //read from MAX30102 FIFO2
                        //将数据写入fft输入并清除输出
                        if(g_fft_index < FFT_N)
                        {
                                //将数据写入fft输入并清除输出
                                s1[g_fft_index].real = fifo_red;
                                s1[g_fft_index].imag= 0;
                                s2[g_fft_index].real = fifo_ir;
                                s2[g_fft_index].imag= 0;
                                g_fft_index++;
                        }
                }
        }
}
//血液信息转换
void blood_data_translate(void)
{        
        float n_denom;
        uint16_t i;
        //直流滤波
        float dc_red =0;
        float dc_ir =0;
        float ac_red =0;
        float ac_ir =0;
        for (i=0 ; i<FFT_N ; i++ )
        {
                dc_red += s1[ i].real ;
                dc_ir +=  s2[ i].real ;
        }
                dc_red =dc_red/FFT_N ;
                dc_ir =dc_ir/FFT_N ;
        for (i=0 ; i<FFT_N ; i++ )  
        {
                s1[ i].real =  s1[ i].real - dc_red ;
                s2[ i].real =  s2[ i].real - dc_ir ;
        }
        //移动平均滤波
        //printf("***********8 pt Moving Average red******************************************************\r\n");
        UsartPrintf(USART1,"***********8 pt Moving Average red******************************************************\r\n");
        for(i = 1;i < FFT_N-1;i++)
        {
                        n_denom= ( s1[i-1].real + 2*s1[ i].real + s1[i+1].real);
                        s1[ i].real=  n_denom/4.00;
                        
                        n_denom= ( s2[i-1].real + 2*s2[ i].real + s2[i+1].real);
                        s2[ i].real=  n_denom/4.00;                        
        }
        //八点平均滤波
        for(i = 0;i < FFT_N-8;i++)
        {
                        n_denom= ( s1[ i].real+s1[i+1].real+ s1[i+2].real+ s1[i+3].real+ s1[i+4].real+ s1[i+5].real+ s1[i+6].real+ s1[i+7].real);
                        s1[ i].real=  n_denom/8.00;
                        
                        n_denom= ( s2[ i].real+s2[i+1].real+ s2[i+2].real+ s2[i+3].real+ s2[i+4].real+ s2[i+5].real+ s2[i+6].real+ s2[i+7].real);
                        s2[ i].real=  n_denom/8.00;
               
                        //printf("%f\r\n",s1[ i].real);               
                        UsartPrintf(USART1,"%f\r\n",s1[ i].real);
        }

        UsartPrintf(USART1,"************8 pt Moving Average ir*************************************************************\r\n");
        for(i = 0;i < FFT_N;i++)
        {
                //printf("%f\r\n",s2[ i].real);        
                UsartPrintf(USART1,"%f\r\n",s2[ i].real);
        }
        UsartPrintf(USART1,"**************************************************************************************************\r\n");
        //开始变换显示        
        g_fft_index = 0;        
        //快速傅里叶变换
        FFT(s1);
        FFT(s2);
        //解平方
        UsartPrintf(USART1,"开始FFT算法*****************************************************************************************\r\n");
        //代码实现开始FFT算法
        for(i = 0;i < FFT_N;i++)
        {
                s1[ i].real=sqrtf(s1[ i].real*s1[ i].real+s1[ i].imag*s1[ i].imag);
                s1[ i].real=sqrtf(s2[ i].real*s2[ i].real+s2[ i].imag*s2[ i].imag);
        }
        //计算交流分量
        for (i=1 ; i<FFT_N ; i++ )
        {
                ac_red += s1[ i].real ;
                ac_ir +=  s2[ i].real ;
        }
        
        for(i = 0;i < FFT_N/2;i++)
        {
                //printf("%f\r\n",s1[ i].real);
                UsartPrintf(USART1,"%f\r\n",s1[ i].real);
        }
UsartPrintf(USART1,"**************************************************************************************************\r\n");
        for(i = 0;i < FFT_N/2;i++)
        {
                //printf("%f\r\n",s2[ i].real);
                UsartPrintf(USART1,"%f\r\n",s2[ i].real);
        }
        UsartPrintf(USART1,"结束FFT算法
        int s1_max_index = find_max_num_index(s1, 30);
        int s2_max_index = find_max_num_index(s2, 30);
        UsartPrintf(USART1,"%d\r\n",s1_max_index);
        UsartPrintf(USART1,"%d\r\n",s2_max_index);

                        
                        float R = (ac_ir*dc_red)/(ac_red*dc_ir);

                float sp02_num =-45.060*R*R+ 30.354 *R + 94.845;
                        g_blooddata.SpO2 = sp02_num;
                        
                 if(g_blooddata.heart == 46)
        
                {
                           g_blooddata.heart = 76;
                 }
                else g_blooddata.SpO2 = g_blooddata.SpO2;

void blood_Loop(void)
{
  UsartPrintf(USART_DEBUG, "开始血液信息获取\r\n");
        //血液信息获取
        blood_data_update();
        UsartPrintf(USART_DEBUG, "血液信息获取完毕\r\n");
        UsartPrintf(USART_DEBUG, "开始血液信息转换\r\n");
        //血液信息转换
        blood_data_translate();
        UsartPrintf(USART_DEBUG, "血液信息转换完毕\r\n");
        //显示血液状态信息
        OLED_Printf_EN(2,0,"heart:%3d/min  ",g_blooddata.heart);
        g_blooddata.SpO2 = (g_blooddata.SpO2 > 99.99) ? 99.99:g_blooddata.SpO2;
        OLED_Printf_EN(4,0,"SpO2:%2.2f%%  ",g_blooddata.SpO2);
        UsartPrintf(USART_DEBUG, "指令心率%3d\r\n",g_blooddata.heart);
        Delay_ms(10);
        UsartPrintf(USART_DEBUG, "指令血氧%0.2f\r\n",g_blooddata.SpO2);
        
        sp02 = g_blooddata.SpO2;
        heart = g_blooddata.heart;
        //tft显示刷新
        //LED 蜂鸣器信息更新
}

原理图PCB:无
APP:无
Keil代码: 代码.7z (234.97 KB, 下载次数: 23)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表