單片機源程序如下:- #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)
2024-4-28 14:42 上傳
點擊文件名下載附件
程序源碼 下載積分: 黑幣 -5
|