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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 7057|回復(fù): 1
打印 上一主題 下一主題
收起左側(cè)

STM32+MAX30100心率血氧的算法與源程序

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:450941 發(fā)表于 2021-5-11 15:00 | 只看該作者 |只看大圖 回帖獎勵 |倒序瀏覽 |閱讀模式
MAX30100 心率血氧的算法和硬件設(shè)計
GPIO連接圖:


單片機源程序如下:
  1. /**
  2.   ******************************************************************************
  3.   * @file    blood.c
  4.   * @version V1.0.0
  5.   * @brief   血氧圖示儀主程序部分
  6.   ******************************************************************************
  7.   */
  8. /*--Include-start-------------------------------------------------------------*/
  9. #include "blood.h"
  10. #include "MAX30100.h"
  11. #include "algorithm.h"
  12. #include "math.h"
  13. #include "gui.h"
  14. #include "stdio.h"
  15. #include "ST7735.h"
  16. #include "beep.h"
  17. /*Global data space ----------------------------------------------------------*/
  18. uint16_t g_fft_index = 0;                          //fft輸入輸出下標

  19. struct compx s1[FFT_N+16];                   //FFT輸入和輸出:從S[1]開始存放,根據(jù)大小自己定義
  20. struct compx s2[FFT_N+16];                   //FFT輸入和輸出:從S[1]開始存放,根據(jù)大小自己定義

  21. struct
  22. {
  23.         float         Hp        ;                        //血紅蛋白       
  24.         float         HpO2;                        //氧合血紅蛋白
  25.        
  26. }g_BloodWave;//血液波形數(shù)據(jù)

  27. BloodData g_blooddata = {0};                                        //血液數(shù)據(jù)存儲

  28. #define CORRECTED_VALUE                        47                           //標定血液氧氣含量

  29. /*funcation start ------------------------------------------------------------*/


  30. /*Sensor func -----------------------------------------------------------------*/
  31. //血液檢測信息更新
  32. void blood_data_update(void)
  33. {
  34.         uint16_t temp_num=0;
  35.         uint16_t fifo_word_buff[1][2];
  36.        
  37.         temp_num = max30100_Bus_Read(INTERRUPT_REG);
  38.        
  39.         //標志位被使能時 讀取FIFO
  40.         if (INTERRUPT_REG_A_FULL&temp_num)
  41.         {
  42.                 HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,1);
  43.                 //讀取FIFO
  44.                 max30100_FIFO_Read(0x05,fifo_word_buff,1); //read the hr and spo2 data form fifo in reg=0x05
  45.                
  46.                 //將數(shù)據(jù)寫入fft輸入并清除輸出
  47.                 for(int i = 0;i < 1;i++)
  48.                 {
  49.                         if(g_fft_index < FFT_N)
  50.                         {
  51.                                 s1[g_fft_index].real = fifo_word_buff[i][0];
  52.                                 s1[g_fft_index].imag= 0;
  53.                                 s2[g_fft_index].real = fifo_word_buff[i][1];
  54.                                 s2[g_fft_index].imag= 0;
  55.                                 g_fft_index++;
  56.                         }
  57.                 }
  58.                 //信息更新標志位
  59.                 g_blooddata.update++;
  60.         }
  61.         else
  62.         {
  63.                 HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,0);
  64.         }
  65. }
  66. //血液信息轉(zhuǎn)換
  67. void blood_data_translate(void)
  68. {       
  69.         //緩沖區(qū)寫入結(jié)束
  70.         if(g_fft_index>=FFT_N)
  71.         {
  72.                 //開始變換顯示
  73.                 Gui_DrawFont_GBK16(102,2,BLACK,GREEN,"FFT");
  74.                
  75.                 g_fft_index = 0;
  76.                
  77.                 //數(shù)據(jù)更新標志位
  78.                 g_blooddata.display = 1;
  79.                
  80.                 //快速傅里葉變換
  81.                 FFT(s1);
  82.                 FFT(s2);
  83.                
  84.                 //解平方
  85.                 for(int i = 0;i < FFT_N;i++)
  86.                 {
  87.                         s1[i].real=sqrtf(s1[i].real*s1[i].real+s1[i].imag*s1[i].imag);
  88.                         s2[i].real=sqrtf(s2[i].real*s2[i].real+s2[i].imag*s2[i].imag);
  89.                 }
  90.                
  91.                 //讀取峰值點 結(jié)果的物理意義為
  92.                 uint16_t s1_max_index = find_max_num_index(s1, 60);
  93.                 uint16_t s2_max_index = find_max_num_index(s2, 60);
  94.                
  95.                 //檢查HbO2和Hb的變化頻率是否一致
  96.                 if(s1_max_index == s2_max_index)
  97.                 {
  98.                         //心率計算
  99.                         uint16_t Heart_Rate = 60 * SAMPLES_PER_SECOND *
  100.                                                                                                                 s2_max_index / FFT_N;
  101.                        
  102.                         g_blooddata.heart = Heart_Rate - 10;
  103.                        
  104.                         //血氧含量計算
  105.                         float sp02_num = (s2[s1_max_index].real * s1[0].real)
  106.                                                                                         /(s1[s1_max_index].real * s2[0].real);
  107.                        
  108.                         sp02_num = (1 - sp02_num) * SAMPLES_PER_SECOND + CORRECTED_VALUE;
  109.                        
  110.                         g_blooddata.SpO2 = sp02_num;
  111.                        
  112.                         //狀態(tài)正常
  113.                         g_blooddata.state = BLD_NORMAL;
  114.                 }
  115.                 else //數(shù)據(jù)發(fā)生異常
  116.                 {
  117.                         g_blooddata.heart = 0;
  118.                         g_blooddata.SpO2         = 0;
  119.                         g_blooddata.state = BLD_ERROR;
  120.                 }
  121.                 //結(jié)束變換顯示
  122.                 Gui_DrawFont_GBK16(102,2,GREEN,BLACK,"FFT");
  123.         }
  124. }

  125. //血液數(shù)據(jù)更新
  126. void blood_wave_update(void)
  127. {
  128.         static DC_FilterData hbdc = {.w = 0,.init = 0,.a = 0};
  129.         static DC_FilterData hbodc = {.w = 0,.init = 0,.a = 0};
  130.        
  131.         float hbag = 0;
  132.         float hboag = 0;
  133.        
  134.         float hbag_d = 0;
  135.         float hboag_d = 0;
  136.        
  137.         //前8次求平均值
  138.         for(int i = 0;i < 8;i++)
  139.         {
  140.                 hbag  += s1[g_fft_index - 8 + i].real;
  141.                 hboag += s2[g_fft_index - 8 + i].real;
  142.         }
  143.                
  144.         //直流濾波
  145.         hbag_d = dc_filter(hbag,&hbdc) / 8;
  146.         hboag_d = dc_filter(hboag,&hbodc) / 8;
  147.        
  148.         //高度數(shù)據(jù)
  149.         float hbhight  = 0;
  150.         float hbohight = 0;
  151.        
  152.         //比例與偏置
  153.         hbhight  = (-hbag_d / 40.0) + 5;
  154.         hbohight  = (-hboag_d / 40.0) + 5;
  155.        
  156.         //高度數(shù)據(jù)幅度限制
  157.         hbhight = (hbhight > 27) ? 27 : hbhight;
  158.         hbhight = (hbhight < 0) ?  0 : hbhight;
  159.        
  160.         hbohight = (hbohight > 27) ? 27 : hbohight;
  161.         hbohight = (hbohight < 0) ?  0 : hbohight;
  162.        
  163.         //將數(shù)據(jù)發(fā)布到全局
  164.         g_BloodWave.Hp = hbhight;
  165.         g_BloodWave.HpO2 = hbohight;
  166.        
  167.         //血液狀態(tài)檢查
  168.         if(hbag < 5000 ||hbag < 5000)
  169.         {
  170.                 //清空數(shù)據(jù)
  171.                 g_blooddata.heart = 0;
  172.                 g_blooddata.SpO2         = 0;
  173.                
  174.                 //刪除數(shù)據(jù)
  175.                 g_fft_index -= 7;
  176.                
  177.                 if(g_blooddata.state != BLD_ERROR)
  178.                 {
  179.                         g_blooddata.state = BLD_ERROR;
  180.                         g_blooddata.display = 1;
  181.                 }
  182.         }
  183.         else
  184.         {
  185.                 if(g_blooddata.state == BLD_ERROR)
  186.                 {
  187.                         g_blooddata.state = BLD_NORMAL;
  188.                         g_blooddata.display = 1;
  189.                 }
  190.         }
  191. }
  192. /*tft display ---------------------------------------------------------------*/

  193. //測試顯示血液信息
  194. void tft_test_display(void)
  195. {
  196.         uint8_t str[50];

  197.         if (g_blooddata.display == 1)
  198.         {
  199.                 g_blooddata.display = 0;
  200.                
  201.                 //顯示血氧信息
  202.                 sprintf((char *)str,"heart = %3d",g_blooddata.heart);
  203.                 Gui_DrawFont_GBK16(8,8,0x00FF,BLACK,str);
  204.                
  205.                 //顯示心率信息
  206.                 sprintf((char *)str,"SpO2 = %3.1f",g_blooddata.SpO2);
  207.                 Gui_DrawFont_GBK16(8,26,0x00FF,BLACK,str);
  208.                
  209.                 //顯示狀態(tài)信息
  210.                 if(g_blooddata.state)
  211.                 {
  212.                         sprintf((char *)str,"ERROR     ");
  213.                         Gui_DrawFont_GBK16(8,44,0xF000,BLACK,str);
  214.                 }
  215.                 else
  216.                 {
  217.                         sprintf((char *)str,"NORMAL    ");
  218.                         Gui_DrawFont_GBK16(8,44,0x07E0,BLACK,str);
  219.                 }
  220.         }
  221. }

  222. //繪制邊框
  223. void tft_draw_frame(uint16_t color)
  224. {
  225.         gui_draw_square(0,1,127,127,color);
  226.         gui_draw_square(0,1,127,18,color);
  227.         gui_draw_square(0,1,100,18,color);
  228.         gui_draw_square(0,57,127,127,color);
  229. }

  230. //狀態(tài)信息顯示
  231. void tft_draw_State(uint8_t st)
  232. {
  233.         switch(st)
  234.         {
  235.                 case BLD_NORMAL:
  236.                 {
  237.                         tft_draw_frame(GRAY1);
  238.                         Gui_DrawFont_GBK16(3,2,0x001F,GRAY3,"Normal    ");
  239.                         break;
  240.                 }
  241.                 case BLD_ERROR:
  242.                 {
  243.                         tft_draw_frame(RED);
  244.                         Gui_DrawFont_GBK16(3,2,0xF000,GRAY3,"Caution   ");
  245.                         break;
  246.                 }
  247.         }
  248. }

  249. //繪制波形線段
  250. void tft_draw_wave_line(uint8_t p,uint8_t n,uint16_t h0,uint16_t h1,uint16_t color)
  251. {
  252.         uint16_t x = 4;                                                                                // x 起始坐標
  253.         uint16_t y = (p == 0) ? 122 : 89; // y 起始坐標
  254.        
  255.         //擦除線
  256.         if((n + 1) < 82)
  257.         {
  258.                 Gui_DrawLine((x + n + 2),y - 28,(x + n + 2),y + 1,GRAY2);
  259.                 Gui_DrawLine((x + n + 1),y - 28,(x + n + 1),y + 1,BLACK);
  260.         }
  261.         //繪制線
  262.         Gui_DrawLine((x + n),(y - h0),(x + n + 1),(y - h1),color);
  263.        
  264. }

  265. //繪制波形圖表
  266. void tft_draw_wave(void)
  267. {
  268.         static uint16_t hist_n  = 0;        //同步歷史序號
  269.        
  270.         static uint16_t hbhist_h  = 0;//血紅蛋白歷史數(shù)值
  271.         static uint16_t hbohist_h = 0;//氧合血紅蛋白歷史數(shù)值

  272.         //繪制線
  273.         tft_draw_wave_line(1, hist_n, hbhist_h , g_BloodWave.Hp, 0x8FF0);
  274.         tft_draw_wave_line(0, hist_n, hbohist_h, g_BloodWave.HpO2, 0xFC1F);
  275.        
  276.         //移動下標
  277.         hist_n = (hist_n < 81) ? (hist_n + 1) : 0;
  278.        
  279.         //保存歷史
  280.         hbhist_h = g_BloodWave.Hp;
  281.         hbohist_h = g_BloodWave.HpO2;
  282. }

  283. //心率血氧數(shù)據(jù)刷新
  284. void tft_draw_hrsp(void)
  285. {
  286.         uint8_t str[50];

  287.         //心率信息顯示
  288.         sprintf((char *)str,"%3d  ",g_blooddata.heart);
  289.         Gui_DrawFont_GBK16(40,20,0xffe0,GRAY3,str);
  290.         //血氧飽和度顯示
  291.         g_blooddata.SpO2 = (g_blooddata.SpO2 > 99.99) ? 99.99:g_blooddata.SpO2;
  292.         sprintf((char *)str," %2.2f%%  ",g_blooddata.SpO2);
  293.         Gui_DrawFont_GBK16(40,38,0x07ff,GRAY3,str);
  294. }


  295. //顯示窗口繪制
  296. void tft_draw_windows(void)
  297. {
  298.         Lcd_Clear(GRAY3);
  299.        
  300.         //繪制窗口邊線
  301.         tft_draw_frame(GRAY1);

  302.        
  303.         //繪制區(qū)塊 h31 w84
  304.         gui_draw_Block(3,60,87,91,GRAY2,BLACK);
  305.         gui_draw_Block(3,93,87,124,GRAY2,BLACK);
  306.        
  307.         gui_draw_Block(89,60,125,91,GRAY2,BLACK);
  308.         gui_draw_Block(89,93,125,124,GRAY2,BLACK);
  309.        
  310.         //繪制字符串
  311.         Gui_DrawFont_GBK16(3,20,0xffe0,GRAY3,"HR  :");
  312.         Gui_DrawFont_GBK16(3,38,0x07ff,GRAY3,"SpO2:");
  313.        
  314.         Gui_DrawFont_GBK16(91,67,0x8FF0,BLACK," Hb");
  315.         Gui_DrawFont_GBK16(91,100,0xFC1F,BLACK,"HbO2");
  316.        
  317.         Gui_DrawFont_GBK16(102,2,GREEN,BLACK,"FFT");
  318.        
  319.         Gui_DrawFont_GBK16(3,2,0x001F,GRAY3,"Normal    ");
  320. }

  321. //tft顯示刷新
  322. void tft_display_update(void)
  323. {
  324.         //圖表更新
  325.         if(g_blooddata.update >= 8)
  326.         {
  327.                 //清除圖標更新標志位
  328.                 g_blooddata.update = 0;
  329.                 //血液波形數(shù)據(jù)更新
  330.                 blood_wave_update();
  331.                 //繪制波形
  332.                 tft_draw_wave();
  333.         }
  334.        
  335.         //轉(zhuǎn)換后的數(shù)據(jù)更新
  336.         if(g_blooddata.display >= 1)
  337.         {
  338.                 //清除更新標志位
  339.                 g_blooddata.display = 0;
  340.                 //顯示血液狀態(tài)信息
  341.                 tft_draw_State(g_blooddata.state);
  342.                 //心率血氧數(shù)據(jù)刷新
  343.                 tft_draw_hrsp();
  344.         }
  345. }
  346. /*Beep and LED func -------------------------------------------------------*/

  347. //LED和蜂鳴器狀態(tài)更新
  348. void Led_beep_update(void)
  349. {
  350.         static uint32_t errorStartTick = 0;                        //錯誤發(fā)生點
  351.         static BloodState blhist = BLD_NORMAL;        //歷史狀態(tài)
  352.         static uint8_t beepstate = 0;                                                //蜂鳴器狀態(tài)
  353.        
  354.        
  355.         switch(g_blooddata.state)
  356.         {
  357.                 case BLD_NORMAL:
  358.                 {
  359.                         //LED指示燈
  360.                         Led_Control((g_BloodWave.Hp > 10) * 20);
  361.                         //蜂鳴器
  362.                         Beep_Control((g_BloodWave.HpO2 > 10) * 50);
  363.                         break;
  364.                 }
  365.                 case BLD_ERROR:
  366.                 {
  367.                         if(blhist == BLD_NORMAL)
  368.                         {
  369.                                 errorStartTick = HAL_GetTick();
  370.                         }
  371.                        
  372.                         //錯誤前0-3秒 快速閃爍
  373.                         if((HAL_GetTick() - errorStartTick) < 3000)
  374.                         {
  375.                                 if(( (HAL_GetTick() / 100) %
  376.                                                  (4-(HAL_GetTick() - errorStartTick) / 1000)
  377.                                    ) == 0)
  378.                                 {
  379.                                         Led_Control(20);
  380.                                         Beep_Control(50);
  381.                                 }
  382.                                 else
  383.                                 {
  384.                                         Led_Control(0);
  385.                                         Beep_Control(0);
  386.                                 }
  387.                                
  388.                         }
  389.                         //錯誤前3-6秒 常亮
  390.                         else if(3000 < (HAL_GetTick() - errorStartTick) &&
  391.                                                         6000 > (HAL_GetTick() - errorStartTick))
  392.                         {
  393.                                 Led_Control(20);
  394.                                 Beep_Control(50);
  395.                         }
  396.                         //錯誤到6秒結(jié)束
  397.                         else if((HAL_GetTick() - errorStartTick) > 6000)
  398.                         {
  399.                                 Led_Control(0);
  400.                                 Beep_Control(0);
  401.                         }
  402.                         break;
  403.                 }
  404.                 default:break;
  405.         }
  406.        
  407.         blhist = g_blooddata.state;
  408. }


  409. /*Setup and loop func -----------------------------------------------------*/

  410. void blood_Setup(void)
  411. {
  412.         //初始化血液信息
  413.         g_blooddata.heart = 0;
  414.         g_blooddata.SpO2 = 0;
  415.         g_blooddata.display = 1;
  416.        
  417.         //繪制窗口
  418.         tft_draw_windows();
  419.        
  420.         //初始化指示燈和蜂鳴器
  421.         settone(14);
  422. }

  423. void blood_Loop(void)
  424. {
  425.         //血液信息獲取
  426.         blood_data_update();
  427.         //血液信息轉(zhuǎn)換
  428.         blood_data_translate();
  429.         //tft顯示刷新
  430.        
  431.         tft_display_update();
  432.         //LED 蜂鳴器信息更新
  433.         Led_beep_update();
  434.        
  435. }

  436. void blood_Interrupt(void)
  437. {
  438.         static int16_t div = 0;
  439.         static int16_t div2 = 0;
  440.         div++;
  441.         if(div > 10)
  442.         {
  443.                 div = 0;
  444.                 //更新血液信息
  445.                 //blood_data_update();
  446.         }
  447.        
  448.         div2++;
  449.         if(div > 50)
  450.         {
  451.                 div2 = 0;
  452.                 //tft顯示刷新
  453.                 //tft_display_update();
  454.         }
  455. }

復(fù)制代碼

所有代碼51hei提供下載:
MAX30100.7z (5.56 MB, 下載次數(shù): 125)

評分

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

查看全部評分

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

使用道具 舉報

沙發(fā)
ID:1094211 發(fā)表于 2023-11-17 11:15 | 只看該作者
遇到報錯HeartBeat\HeartBeat.axf: error: L6002U: Could not open file heartbeat\port.o: No such file or directory
回復(fù)

使用道具 舉報

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

本版積分規(guī)則

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

Powered by 單片機教程網(wǎng)

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 天堂在线91 | 亚洲精品国产电影 | 欧美激情精品久久久久久 | 国产精品久久二区 | 国产精品一区二区三区久久 | 欧美精品久久久 | 国产精品性做久久久久久 | 另类二区| 国产精品视频网址 | 亚洲成人免费观看 | 日本久久久久久久久 | 国产视频中文字幕在线观看 | 国产亚洲日本精品 | 日韩黄a | 久产久精国产品 | 视频一区二区中文字幕 | 色婷婷影院 | 国产成人99久久亚洲综合精品 | 亚洲国产精品一区 | 青青久在线视频 | 欧美一级艳情片免费观看 | 成年人国产在线观看 | 欧美日韩国产免费 | 免费在线看黄 | 在线色网站 | 欧美一级电影免费观看 | 日本不卡免费新一二三区 | 国产亚洲欧美另类一区二区三区 | 奇米av| 日韩精品一区在线观看 | 午夜性色a√在线视频观看9 | 北条麻妃99精品青青久久主播 | 日韩在线一区二区 | 一级毛片视频在线 | 91av视频在线观看 | av一级 | 久久亚洲一区二区三区四区 | 国产精品久久久久久久久久久免费看 | 国产精品一区在线播放 | 四虎永久 | 精品电影 |