久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 2349|回復: 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)
手冊: MAX30102數據手冊.7z (1.97 MB, 下載次數: 10)

評分

參與人數 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂 踩
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 韩日三级 | www97影院 | 狠狠的干狠狠的操 | 国产成人综合网 | 久久久久久久久国产成人免费 | 一区二区三区视频 | 91免费版在线观看 | 国外激情av| 欧美成人激情 | 日韩在线观看一区 | 亚洲网站免费看 | h视频在线播放 | 亚洲精品一区在线观看 | 综合久 | 在线小视频 | 国产午夜视频 | 国产一区二区激情视频 | 精品一区二区三区不卡 | 九色综合网| 午夜亚洲 | 亚洲国产精品99久久久久久久久 | 性欧美hd| 中文字幕在线一区 | 欧美日韩国产一区二区 | 日韩一二区 | 国产精品免费视频一区 | 久久精品久久久久久 | 久久久久国产 | 天天干天天操天天看 | 在线观看的av | 伊人伊成久久人综合网站 | 婷婷色国产偷v国产偷v小说 | 黄色大片网站 | 国产精品久久国产精品久久 | 久久久国产一区二区三区 | 日韩中文一区二区三区 | 一级一级毛片免费看 | 国产成人精品久久二区二区91 | 久久免费精品视频 | 中文字幕一区在线观看视频 | 日韩精品区 |