单片机源程序如下:- #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)
|