找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 94|回复: 0
打印 上一主题 下一主题
收起左侧

STM32F103单片机使用MAX30102测量心率血氧源程序

[复制链接]
跳转到指定楼层
楼主
ID:910507 发表于 2024-4-28 10:15 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
单片机源程序如下:
  1. #include "stm32f10x.h"                  // Device header
  2. #include "software_IIC.h"
  3. #include "MAX30102.h"
  4. #include "MAX30102_algorithm.h"
  5. #include "OLED.h"
  6. #include "Key.h"
  7. #include "Delay.h"
  8. #define MAX_BRIGHTNESS 255

  9. uint16_t fifo_red;
  10. uint16_t fifo_ir;



  11. void MAX30102_Init(void)
  12. {
  13.         IIC_GPIO_Init();                                                                        //先初始化底层的I2C
  14.        
  15.         /*MAX30102寄存器初始化,需要对照MAX30102手册的寄存器描述配置,此处仅配置了部分重要的寄存器*/
  16.         IIC_WriteReg(MAX30102_ADDRESS,REG_MODE_CONFIG, 0x40);   //将RESET位设置为1,所有配置、阈值和数据寄存器通过上电复位复位复位到其上电状态。
  17.         IIC_WriteReg(MAX30102_ADDRESS,REG_INTR_ENABLE_1, 0x00);        //不使用中断       
  18.         IIC_WriteReg(MAX30102_ADDRESS,REG_INTR_ENABLE_2, 0x00);               
  19.         IIC_WriteReg(MAX30102_ADDRESS,REG_FIFO_WR_PTR,0x00);        //FIFO写入指针为0               
  20.         IIC_WriteReg(MAX30102_ADDRESS,REG_OVF_COUNTER,0x00);    //溢出数据计数器为0
  21.         IIC_WriteReg(MAX30102_ADDRESS,REG_FIFO_RD_PTR,0x00);    //FIFO读取指针为0
  22.         IIC_WriteReg(MAX30102_ADDRESS,REG_FIFO_CONFIG,0x0f);    //0x0f设置平均取样为4,当FIFO完全充满数据时,FIFO地址滚动到零并且FIFO继续填充新数据。
  23.         IIC_WriteReg(MAX30102_ADDRESS,REG_MODE_CONFIG,0x03);    //SpO2模式
  24.         IIC_WriteReg(MAX30102_ADDRESS,REG_SPO2_CONFIG,0x27);    //0x45ADC量程为8192,采样率为100/s,LED占空比118us,对应采样精度16bit
  25.         IIC_WriteReg(MAX30102_ADDRESS,REG_LED1_PA,0x20);
  26.         IIC_WriteReg(MAX30102_ADDRESS,REG_LED2_PA,0x20);
  27.         IIC_WriteReg(MAX30102_ADDRESS,REG_PILOT_PA,0x7F);
  28.                
  29. }

  30. void MAX30102_IIC_ReadReg(uint8_t slave_ID,uint8_t RegAddress)  //读取6个字节
  31. {
  32.     fifo_red=0;
  33.     fifo_ir=0;
  34.         uint16_t Data1,Data2,Data3,Data4,Data5,Data6;
  35.        
  36.         IIC_Start();                                                //I2C起始
  37.         IIC_SendByte(slave_ID);        //发送从机地址,读写位为0,表示即将写入
  38.         IIC_ReceiveAck();                                        //接收应答
  39.         IIC_SendByte(RegAddress);                        //发送寄存器地址
  40.         IIC_ReceiveAck();                                        //接收应答
  41.        
  42.         IIC_Start();                                                //I2C重复起始
  43.         IIC_SendByte(slave_ID | 0x01);        //发送从机地址,读写位为1,表示即将读取
  44.         IIC_ReceiveAck();                                        //接收应答
  45.         Data1 = IIC_ReceiveByte();                        //接收指定寄存器的数据
  46.         IIC_SendAck(0);                                        //发送应答,给从机非应答,终止从机的数据输出
  47.         Data2 = IIC_ReceiveByte();
  48.         IIC_SendAck(0);       
  49.         Data3 = IIC_ReceiveByte();
  50.         IIC_SendAck(0);
  51.         Data4 = IIC_ReceiveByte();                        //接收指定寄存器的数据
  52.         IIC_SendAck(0);                                        //发送应答,给从机非应答,终止从机的数据输出
  53.         Data5 = IIC_ReceiveByte();
  54.         IIC_SendAck(0);       
  55.         Data6 = IIC_ReceiveByte();
  56.         IIC_SendAck(1);
  57.         IIC_Stop();       
  58.         //I2C终止
  59.         Data1 <<= 14;
  60.     fifo_red+=Data1;
  61.         Data2 <<= 6;
  62.     fifo_red+=Data2;
  63.         Data3 >>= 2;
  64.     fifo_red+=Data3;
  65.        
  66.         Data4 <<= 14;
  67.     fifo_ir+=Data4;
  68.         Data5 <<= 6;
  69.     fifo_ir+=Data5;
  70.         Data6 >>= 2;
  71.     fifo_ir+=Data6;
  72.        
  73.         if(fifo_ir<=10000)
  74.         {
  75.                 fifo_ir=0;
  76.         }
  77.         if(fifo_red<=10000)
  78.         {
  79.                 fifo_red=0;
  80.         }
  81. }

  82. int8_t menu_Back_event(void)//菜单返回
  83. {
  84.         return Key_Back_Get();;                                //返回键接到PA2;
  85. }

  86. void SPO2_function(void)
  87. {
  88.        
  89.         OLED_Clear();
  90.         OLED_ShowChinese(46,0,"血");
  91.         OLED_ShowChinese(62,0,"氧");
  92.         OLED_ShowChinese(78,0,"检");
  93.         OLED_ShowChinese(94,0,"测");
  94.         MAX30102_Init();                     //初始化MAX30102
  95.         OLED_ShowImage(0,0,22,8,qipaoup);    //显示左上方固定的石头块
  96.         OLED_ShowImage(0,56,22,8,qipaodown); //显示左下方固定的石头块
  97.         OLED_Update();
  98.         uint8_t j=128;                       //定义鱼的起始X坐标
  99.         uint8_t ave_Count = 1;               //为了获取10个最终得到的血氧值,设置计数器,(可以更改,值越大测量时间越长,获取数据越多)
  100.         uint16_t cal_ave[10];                //定义长度为10的数组存储10个检测数据
  101.         uint16_t ave_Sum = 0;                //存储10个数据的和
  102.         uint8_t cal_Sum_lock = 0;            //总和计算器锁
  103.     while(1)
  104.    {
  105.                         /*-------------------------移动气泡的程序逻辑------------------------------*/
  106.                 uint8_t i;
  107.                 for(i = 0;i <= 16;i++)
  108.                 {
  109.                         OLED_ClearArea(0,8,22,48);
  110.                         OLED_ShowImage(1,49-i,7,7,qipao);   
  111.                         OLED_ShowImage(1,33-i,7,7,qipao);
  112.         if(i<17)
  113.                 {
  114.                         OLED_ShowImage(1,17-i,7,7,qipao);
  115.                         OLED_ShowImage(0,0,22,8,qipaoup);
  116.                 }       
  117.                         OLED_ShowImage(13,56-i,7,7,qipao);
  118.                         OLED_ShowImage(13,40-i,7,7,qipao);
  119.                         OLED_ShowImage(13,24-i,7,7,qipao);
  120.                 /*-------------------------移动鱼的程序逻辑------------------------------*/
  121.                 if(j<=0)
  122.                 {
  123.                         j = 128;
  124.                         OLED_ClearArea(22,49,106,15);    //清除小鱼游过后的全屏尾迹
  125.                 }
  126.                         OLED_ShowImage(j,49,15,15,Fish);
  127.                         OLED_ClearArea(j+15,49,106,15);    //解除注释可以实时清除小鱼尾迹
  128.                         OLED_ShowImage(0,56,22,8,qipaodown); //刷新左下角石头块,让小鱼从石头快后边游过,注释后会从石头块前方游过
  129.                         j--;
  130.                         Delay_ms(5);        //控制动画移动速度
  131.                         OLED_Update();
  132.                 }
  133.                 if(ave_Count<=10)
  134.                 {
  135.                     blood_Loop();
  136.                         if(SPO2dataResult != 0)
  137.             {
  138.                         OLED_ClearArea(22,16,106,32);
  139.                         OLED_ShowChinese(54,17,"检");
  140.                 OLED_ShowChinese(70,17,"测");
  141.                     OLED_ShowChinese(86,17,"中");                               
  142.                         cal_ave[ave_Count-1] = SPO2dataResult;
  143.                         ave_Count++;
  144.                         }else{
  145.                                     OLED_ClearArea(22,16,106,32);
  146.                                     OLED_ShowChinese(54,16,"请");
  147.                             OLED_ShowChinese(70,16,"正");
  148.                             OLED_ShowChinese(86,16,"确");
  149.                             OLED_ShowChinese(54,32,"佩");
  150.                             OLED_ShowChinese(70,32,"戴");
  151.                             OLED_ShowChar(90,32,'!',OLED_8X16);
  152.                              }
  153.                 }else
  154.                 {
  155.                     ave_Count = 11;   //得到10个数据后将计数器值固定到11防止溢出
  156.                         uint8_t i;
  157.                         uint16_t min;
  158.                         for(i = 0;i<9;i++)                   //取出最小值
  159.                         {
  160.                                 if(i == 0){min = cal_ave[0];}    //
  161.                           if(cal_ave[i+1]<min)
  162.                           {
  163.                           min = cal_ave[i+1];
  164.                           }
  165.                         }
  166.                         if(cal_Sum_lock == 0)
  167.                         {
  168.                                  for(i = 0;i<10;i++)
  169.                                  {
  170.                                       ave_Sum += cal_ave[i];    //计算0个数据的和
  171.                                  }  
  172.                                          cal_Sum_lock = 1;          //和计算一次后打开锁,防止多次累加
  173.                     }
  174.                         OLED_ClearArea(22,17,106,32);
  175.                         OLED_ShowNum(49,17,(ave_Sum-min)/9 + 3,3,OLED_15X24);  //显示最终结果
  176.                         OLED_ShowChar(96,17,0x3A,OLED_15X24);
  177.                 }
  178.             
  179.                 if(menu_Back_event())   //检测按键按下
  180.         {
  181.                         break;
  182.                 }       
  183.    }
  184. }

  185. void Heart_function(void)
  186. {
  187.        
  188.         OLED_Clear();
  189.         OLED_ShowChinese(32,0,"心");
  190.         OLED_ShowChinese(48,0,"率");
  191.         OLED_ShowChinese(64,0,"检");
  192.         OLED_ShowChinese(80,0,"测");
  193.         OLED_Update();
  194.         MAX30102_Init();
  195.        
  196.         uint8_t ave_Count = 1;               //为了获取10个最终得到的心率,设置计数器
  197.         uint16_t cal_ave[10];                //定义长度为10的数组存储测量的10个心率数据
  198.         uint16_t ave_Sum = 0;                //存储10个数据的和
  199.         uint8_t cal_Sum_lock = 0;            //总和计算器锁
  200.         while(1)
  201.         {
  202.                 OLED_ClearArea(0,20,64,44);
  203.                 OLED_ShowImage(0,20,54,49,Heart1);
  204.                 OLED_Update();
  205.                 Delay_ms(10);
  206.                 OLED_ClearArea(0,20,64,44);
  207.                 OLED_ShowImage(0,20,54,49,Heart2);
  208.                 OLED_Update();
  209.                 Delay_ms(10);
  210.                 OLED_ClearArea(0,20,64,44);
  211.                 OLED_ShowImage(0,20,54,49,Heart3);
  212.                 OLED_Update();
  213.                 Delay_ms(10);
  214.                 OLED_ClearArea(0,20,64,44);
  215.                 OLED_ShowImage(0,20,54,49,Heart4);
  216.                 OLED_Update();
  217.                 Delay_ms(10);
  218.                 OLED_ClearArea(0,20,64,44);
  219.                 OLED_ShowImage(0,20,54,49,Heart5);
  220.                 OLED_Update();
  221.                 Delay_ms(10);
  222.                 OLED_ClearArea(0,20,64,44);
  223.                 OLED_ShowImage(0,20,54,49,Heart6);
  224.                 OLED_Update();
  225.                 Delay_ms(10);
  226.                 OLED_ClearArea(0,20,64,44);
  227.                 OLED_ShowImage(0,20,54,49,Heart7);
  228.                 OLED_Update();
  229.                 Delay_ms(10);
  230.                 OLED_ClearArea(0,20,64,44);
  231.                 OLED_ShowImage(0,20,54,49,Heart8);
  232.                 OLED_Update();
  233.                 Delay_ms(10);
  234.                 OLED_ClearArea(0,20,64,44);
  235.                 OLED_ShowImage(0,20,54,49,Heart7);
  236.                 OLED_Update();
  237.                 Delay_ms(10);
  238.                 OLED_ClearArea(0,20,64,44);
  239.                 OLED_ShowImage(0,20,54,49,Heart6);
  240.                 OLED_Update();
  241.                 Delay_ms(10);
  242.                 OLED_ClearArea(0,20,64,44);
  243.                 OLED_ShowImage(0,20,54,49,Heart5);
  244.                 OLED_Update();
  245.                 Delay_ms(10);
  246.                 OLED_ClearArea(0,20,64,44);
  247.                 OLED_ShowImage(0,20,54,49,Heart4);
  248.                 OLED_Update();
  249.                 Delay_ms(10);
  250.                 OLED_ClearArea(0,20,64,44);
  251.                 OLED_ShowImage(0,20,54,49,Heart3);
  252.                 OLED_Update();
  253.                 Delay_ms(10);
  254.                 OLED_ClearArea(0,20,64,44);
  255.                 OLED_ShowImage(0,20,54,49,Heart2);
  256.                 OLED_Update();
  257.                 Delay_ms(10);
  258.                 OLED_ClearArea(0,20,64,44);
  259.                 OLED_ShowImage(0,20,54,49,Heart1);
  260.                 OLED_Update();
  261.                 //blood_Loop();
  262.                 OLED_ClearArea(64,20,64,44);
  263.         if(ave_Count<=10)
  264.                 {
  265.                     blood_Loop();
  266.                         if(SPO2dataResult != 0)
  267.             {
  268.                         OLED_ClearArea(64,16,64,44);
  269.                         OLED_ShowChinese(64,17,"测");
  270.                 OLED_ShowChinese(80,17,"量");
  271.                     OLED_ShowChinese(96,17,"中");
  272.             //OLED_ShowNum(64,17,HeartdataResult,3,OLED_13X24);                               
  273.                         cal_ave[ave_Count-1] = HeartdataResult;
  274.                         ave_Count++;
  275.                         }
  276.                         else
  277.                         {
  278.                                     OLED_ClearArea(64,16,64,44);
  279.                                     OLED_ShowChinese(64,16,"请");
  280.                             OLED_ShowChinese(80,16,"正");
  281.                             OLED_ShowChinese(96,16,"确");
  282.                             OLED_ShowChinese(64,32,"佩");
  283.                             OLED_ShowChinese(80,32,"戴");
  284.                             OLED_ShowChar(100,32,'!',OLED_8X16);
  285.                          }
  286.                 }
  287.                 else
  288.                 {
  289.                     ave_Count = 11;   //得到10个数据后将计数器固定到11防止溢出
  290.                         uint8_t i;
  291.                         uint16_t max;
  292.                         for(i = 0;i<9;i++)                   //取出最大值
  293.                         {
  294.                                 if(i == 0){max = cal_ave[0];}    //
  295.                           if(cal_ave[i+1]>max)
  296.                           {
  297.                           max = cal_ave[i+1];
  298.                           }
  299.                         }
  300.                         if(cal_Sum_lock == 0)
  301.                         {
  302.                                  for(i = 0;i<10;i++)
  303.                                  {
  304.                                       ave_Sum += cal_ave[i];    //计算10个数据的和
  305.                                  }  
  306.                                          cal_Sum_lock = 1;          //和计算一次后打开锁,防止多次计算
  307.                     }
  308.                         OLED_ClearArea(22,17,106,32);
  309.                         OLED_ShowNum(64,17,(ave_Sum-max)/9,3,OLED_15X24);  //显示最终结果
  310.                         Delay_ms(200);
  311.       }
  312.                 if(menu_Back_event())   //检测按键按下
  313.         {
  314.                  break;
  315.                 }
  316.     }
  317. }
复制代码

原理图: 无
仿真: 无
代码: 心率血氧检测.7z (198.14 KB, 下载次数: 6)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 赞一个!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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