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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 55013|回復: 113
打印 上一主題 下一主題
收起左側

max30100血氧心率制作stm32源碼 OLED顯示

  [復制鏈接]
跳轉到指定樓層
樓主
ID:244405 發表于 2017-10-31 12:09 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
使用模擬iic_MAX30100,簡易血氧心率制作,可用正電原子mini板,OLED顯示。整套資料提供給大家學習。主函數部分代碼


50Hz每采集一次數據集時間0.02s,共采集800次,用時16s
脈搏每跳動一次對應一個波形的峰值,上圖共有20處峰值
計算(20/16)*60=75,可知心跳為每分鐘75次

50Hz采集心率數據:


血氧檢測數據處理:


stm32單片機源程序如下:
  1. #include "stm32f10x.h"
  2. #include "usart.h"
  3. #include "ultrasonic.h"
  4. #include "stm32f10x_gpio.h"
  5. #include "stm32f10x_i2c.h"
  6. #include "delay.h"        //延時函數 1
  7. #include "delayl.h"        //延時函數 2
  8. #include <stdio.h>
  9. #include <math.h>
  10. #include "bsp_i2c_gpio.h"
  11. #include "oled.h"

  12. #define SAMPLE_50   //如果定義此宏就是50采樣率   否則是100


  13. /*************************************************
  14. 函數: fputc(int ch, FILE *f)
  15. 功能: 重定向c庫函數printf到USART1
  16. 參數: 無
  17. 返回: 無
  18. **************************************************/
  19. int fputc(int ch, FILE *f)
  20. {
  21.         USART_SendData(USART1, (unsigned char) ch);
  22.         while (!(USART1->SR & USART_FLAG_TXE));
  23.         return (ch);
  24. }


  25. #define USR_I2C_USED I2C1

  26. void I2C1_Configuration(void)
  27. {
  28.         I2C_InitTypeDef  I2C_InitStructure;
  29.         GPIO_InitTypeDef  GPIO_InitStructure;

  30.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
  31.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
  32.    

  33.         /* PB6,7 SCL and SDA */
  34.         GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
  35.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  36.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
  37.         GPIO_Init(GPIOB, &GPIO_InitStructure);
  38.         
  39.     I2C_DeInit(I2C1);
  40.     I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
  41.     I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
  42.     I2C_InitStructure.I2C_OwnAddress1 = 0x30;
  43.     I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
  44.     I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
  45.     I2C_InitStructure.I2C_ClockSpeed = 100000;//100K速度
  46.    
  47.         I2C_Cmd(I2C1, ENABLE);
  48.         I2C_Init(I2C1, &I2C_InitStructure);
  49.         /*允許1字節1應答模式*/
  50.         I2C_AcknowledgeConfig(I2C1, ENABLE);

  51.     printf("I2C1_Configuration----\n\r");
  52. }

  53. void I2C2_Configuration(void)
  54. {
  55.         I2C_InitTypeDef  I2C_InitStructure;
  56.         GPIO_InitTypeDef  GPIO_InitStructure;

  57.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);
  58.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
  59.    

  60.         /* PB10,11 SCL and SDA */
  61.         GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_10 | GPIO_Pin_11;
  62.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  63.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
  64.         GPIO_Init(GPIOB, &GPIO_InitStructure);
  65.         
  66.     I2C_DeInit(I2C2);
  67.     I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
  68.     I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
  69.     I2C_InitStructure.I2C_OwnAddress1 = 0x30;
  70.     I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
  71.     I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
  72.     I2C_InitStructure.I2C_ClockSpeed = 100000;//100K速度
  73.    
  74.         I2C_Cmd(I2C2, ENABLE);
  75.         I2C_Init(I2C2, &I2C_InitStructure);
  76.         /*允許1字節1應答模式*/
  77.         I2C_AcknowledgeConfig(I2C2, ENABLE);

  78.     printf("I2C2_Configuration----\n\r");
  79. }

  80. void I2C1_GPIO_Config(void)
  81. {

  82.         GPIO_InitTypeDef GPIO_InitStructure; //GPIO結構體定義
  83.         
  84.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能I2C的IO口

  85.                 /* 使能與 I2C1 有關的時鐘 */
  86.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
  87.         
  88.         /* PB6-I2C1_SCL、PB7-I2C1_SDA*/
  89.         
  90.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;

  91.         
  92.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  93.         
  94.         //PIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // 開漏輸出
  95.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  96.         
  97.         GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化結構體配置

  98. }

  99. /* I2C 工作模式配置 */

  100. void I2C1_Mode_config(void)
  101. {
  102.                 /*定義I2C結構體*/
  103.         I2C_InitTypeDef  I2C_InitStructure;



  104.                
  105.         /*配置為I2C模式*/
  106.         I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
  107.         
  108.         /*該參數只有在I2C 工作在快速模式(時鐘工作頻率高于 100KHz)下才有意義。*/
  109.         I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
  110.         
  111.         /*設置第一個設備自身地址*/
  112.         I2C_InitStructure.I2C_OwnAddress1 =0x30;
  113.         
  114.         /*使能應答*/
  115.         I2C_InitStructure.I2C_Ack = I2C_Ack_Enable ;
  116.         
  117.         /*AT24C02地址為7位所以設置7位就行了*/
  118.         I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; /*時鐘速率,以HZ為單位的,最高為400khz*/
  119.         
  120.         I2C_InitStructure.I2C_ClockSpeed = 20000;

  121.         /* 使能 I2C1 */
  122.         I2C_Cmd(I2C1, ENABLE);
  123.         
  124.         /* I2C1 初始化 */
  125.         I2C_Init(I2C1, &I2C_InitStructure);
  126.         
  127.         
  128. }

  129. void I2C2_GPIO_Config(void)
  130. {

  131.         GPIO_InitTypeDef GPIO_InitStructure; //GPIO結構體定義
  132.         
  133.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能I2C的IO口

  134.                 /* 使能與 I2C1 有關的時鐘 */
  135.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);
  136.         
  137.         /* PB10-I2C2_SCL、PB11-I2C2_SDA*/
  138.         
  139.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;

  140.         
  141.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  142.         
  143.         //PIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // 開漏輸出
  144.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  145.         
  146.         GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化結構體配置

  147. }

  148. /* I2C 工作模式配置 */

  149. void I2C2_Mode_config(void)
  150. {
  151.                 /*定義I2C結構體*/
  152.         I2C_InitTypeDef  I2C_InitStructure;

  153.         /*配置為I2C模式*/
  154.         I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
  155.         
  156.         /*該參數只有在I2C 工作在快速模式(時鐘工作頻率高于 100KHz)下才有意義。*/
  157.         I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
  158.         
  159.         /*設置第一個設備自身地址*/
  160.         I2C_InitStructure.I2C_OwnAddress1 =0x30;
  161.         
  162.         /*使能應答*/
  163.         I2C_InitStructure.I2C_Ack = I2C_Ack_Enable ;
  164.         
  165.         /*AT24C02地址為7位所以設置7位就行了*/
  166.         I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; /*時鐘速率,以HZ為單位的,最高為400khz*/
  167.         
  168.         I2C_InitStructure.I2C_ClockSpeed = 100000;

  169.         /* 使能 I2C1 */
  170.         I2C_Cmd(I2C2, ENABLE);
  171.         
  172.         /* I2C1 初始化 */
  173.         I2C_Init(I2C2, &I2C_InitStructure);
  174.         
  175.         
  176. }


  177. /*************************************************
  178. 函數: void main_init(void)
  179. 功能: main初始化
  180. 參數: 無
  181. 返回: 無
  182. **************************************************/
  183. void main_init(void)
  184. {
  185.         Usart_Init();
  186.         //I2C1_GPIO_Config();
  187.         //I2C1_Mode_config();
  188.         //I2C1_Configuration();
  189.         bsp_InitI2C();
  190.         delay_init(72);            //延時初始化
  191. }

  192. extern void test_max30100_fun(void);
  193. extern u8 max10300_Bus_Read(u8 Register_Address);
  194. extern void max10300_init(void);

  195. /*************************************************
  196. 函數: int main(void)
  197. 功能: main主函數
  198. 參數: 無
  199. 返回: 無
  200. **************************************************/
  201. int main(void)
  202. {
  203.         u8 temp_num=0;
  204.          
  205.         main_init();
  206.         
  207.         max10300_init();
  208.         printf("\r\n stm32 init runing \r\n");
  209.         
  210.         delayl_init();                     //延時函數初始化         
  211.          
  212.         OLED_Init();                        //初始化OLED     

  213.         OLED_ShowString(0,0, "SpO2:",16);  
  214.                   
  215.         OLED_ShowString(0,30,"Heart Rate:",16);  
  216.                   
  217.         OLED_Refresh_Gram();//更新顯示到OLED
  218.         
  219.         
  220.         
  221.         
  222.         
  223.         /*
  224. while(1)
  225. {
  226.         delay_ms(1000);            
  227.         max10300_init();
  228.         temp_num = max10300_Bus_Read(0x16);
  229.         printf("當前溫度 = %d\r\n",temp_num);
  230. }*/
  231.         while(1)
  232.         {        
  233.                 test_max30100_fun();
  234.                
  235.                
  236.                         
  237.                
  238.                
  239.                
  240.         }
  241. }




  242. #define max10300_WR_address 0xAE

  243. u8 max10300_Bus_Write(u8 Register_Address, u8 Word_Data)
  244. {

  245.         /* 采用串行EEPROM隨即讀取指令序列,連續讀取若干字節 */

  246.         /* 第1步:發起I2C總線啟動信號 */
  247.         i2c_Start();

  248.         /* 第2步:發起控制字節,高7bit是地址,bit0是讀寫控制位,0表示寫,1表示讀 */
  249.         i2c_SendByte(max10300_WR_address | I2C_WR);        /* 此處是寫指令 */

  250.         /* 第3步:發送ACK */
  251.         if (i2c_WaitAck() != 0)
  252.         {
  253.                 goto cmd_fail;        /* EEPROM器件無應答 */
  254.         }

  255.         /* 第4步:發送字節地址 */
  256.         i2c_SendByte(Register_Address);
  257.         if (i2c_WaitAck() != 0)
  258.         {
  259.                 goto cmd_fail;        /* EEPROM器件無應答 */
  260.         }
  261.         
  262.         /* 第5步:開始寫入數據 */
  263.         i2c_SendByte(Word_Data);

  264.         /* 第6步:發送ACK */
  265.         if (i2c_WaitAck() != 0)
  266.         {
  267.                 goto cmd_fail;        /* EEPROM器件無應答 */
  268.         }

  269.         /* 發送I2C總線停止信號 */
  270.         i2c_Stop();
  271.         return 1;        /* 執行成功 */

  272. cmd_fail: /* 命令執行失敗后,切記發送停止信號,避免影響I2C總線上其他設備 */
  273.         /* 發送I2C總線停止信號 */
  274.         i2c_Stop();
  275.         return 0;
  276. }



  277. u8 max10300_Bus_Read(u8 Register_Address)
  278. {
  279.         u8  data;


  280.         /* 第1步:發起I2C總線啟動信號 */
  281.         i2c_Start();

  282.         /* 第2步:發起控制字節,高7bit是地址,bit0是讀寫控制位,0表示寫,1表示讀 */
  283.         i2c_SendByte(max10300_WR_address | I2C_WR);        /* 此處是寫指令 */

  284.         /* 第3步:發送ACK */
  285.         if (i2c_WaitAck() != 0)
  286.         {
  287.                 goto cmd_fail;        /* EEPROM器件無應答 */
  288.         }

  289.         /* 第4步:發送字節地址, */
  290.         i2c_SendByte((uint8_t)Register_Address);
  291.         if (i2c_WaitAck() != 0)
  292.         {
  293.                 goto cmd_fail;        /* EEPROM器件無應答 */
  294.         }
  295.         

  296.         /* 第6步:重新啟動I2C總線。下面開始讀取數據 */
  297.         i2c_Start();

  298.         /* 第7步:發起控制字節,高7bit是地址,bit0是讀寫控制位,0表示寫,1表示讀 */
  299.         i2c_SendByte(max10300_WR_address | I2C_RD);        /* 此處是讀指令 */

  300.         /* 第8步:發送ACK */
  301.         if (i2c_WaitAck() != 0)
  302.         {
  303.                 goto cmd_fail;        /* EEPROM器件無應答 */
  304.         }

  305.         /* 第9步:讀取數據 */
  306.         {
  307.                 data = i2c_ReadByte();        /* 讀1個字節 */

  308.                 i2c_NAck();        /* 最后1個字節讀完后,CPU產生NACK信號(驅動SDA = 1) */
  309.         }
  310.         /* 發送I2C總線停止信號 */
  311.         i2c_Stop();
  312.         return data;        /* 執行成功 返回data值 */

  313. cmd_fail: /* 命令執行失敗后,切記發送停止信號,避免影響I2C總線上其他設備 */
  314.         /* 發送I2C總線停止信號 */
  315.         i2c_Stop();
  316.         return 0;
  317. }

  318. static void i2c_Delay(void)
  319. {
  320.         uint8_t i;

  321.         /* 
  322.                 CPU主頻168MHz時,在內部Flash運行, MDK工程不優化。用臺式示波器觀測波形。
  323.                 循環次數為5時,SCL頻率 = 1.78MHz (讀耗時: 92ms, 讀寫正常,但是用示波器探頭碰上就讀寫失敗。時序接近臨界)
  324.                 循環次數為10時,SCL頻率 = 1.1MHz (讀耗時: 138ms, 讀速度: 118724B/s)
  325.                 循環次數為30時,SCL頻率 = 440KHz, SCL高電平時間1.0us,SCL低電平時間1.2us

  326.                 上拉電阻選擇2.2K歐時,SCL上升沿時間約0.5us,如果選4.7K歐,則上升沿約1us

  327.                 實際應用選擇400KHz左右的速率即可
  328.         */
  329.         for (i = 0; i < 30; i++);
  330. }
  331. #if 1
  332. void max10300_FIFO_Read(u8 Register_Address,u16  Word_Data[][2],u8 count)
  333. {
  334.         u8 i=0;
  335.         u8 no = count;
  336.         u8 data1, data2;
  337.         /* 第1步:發起I2C總線啟動信號 */
  338.         i2c_Start();

  339.         /* 第2步:發起控制字節,高7bit是地址,bit0是讀寫控制位,0表示寫,1表示讀 */
  340.         i2c_SendByte(max10300_WR_address | I2C_WR);        /* 此處是寫指令 */

  341.         /* 第3步:發送ACK */
  342.         if (i2c_WaitAck() != 0)
  343.         {
  344.                 goto cmd_fail;        /* EEPROM器件無應答 */
  345.         }

  346.         /* 第4步:發送字節地址, */
  347.         i2c_SendByte((uint8_t)Register_Address);
  348.         if (i2c_WaitAck() != 0)
  349.         {
  350.                 goto cmd_fail;        /* EEPROM器件無應答 */
  351.         }
  352.         

  353.         /* 第6步:重新啟動I2C總線。下面開始讀取數據 */
  354.         i2c_Start();

  355.         /* 第7步:發起控制字節,高7bit是地址,bit0是讀寫控制位,0表示寫,1表示讀 */
  356.         i2c_SendByte(max10300_WR_address | I2C_RD);        /* 此處是讀指令 */

  357.         /* 第8步:發送ACK */
  358.         if (i2c_WaitAck() != 0)
  359.         {
  360.                 goto cmd_fail;        /* EEPROM器件無應答 */
  361.         }

  362.         /* 第9步:讀取數據 */
  363.         while (no)
  364.         {
  365.                 data1 = i2c_ReadByte();        
  366.                 i2c_Ack();
  367.                 data2 = i2c_ReadByte();
  368.                 i2c_Ack();
  369.                 Word_Data[i][0] = (((u16)data1 << 8) | data2);  //

  370.                
  371.                 data1 = i2c_ReadByte();        
  372.                 i2c_Ack();
  373.                 data2 = i2c_ReadByte();
  374.                 if(1==no)
  375.                         i2c_NAck();        /* 最后1個字節讀完后,CPU產生NACK信號(驅動SDA = 1) */
  376.                 else
  377.                         i2c_Ack();
  378.                 Word_Data[i][1] = (((u16)data1 << 8) | data2);

  379.                 no--;        
  380.                 i++;
  381.         }
  382.         /* 發送I2C總線停止信號 */
  383.         i2c_Stop();

  384. cmd_fail: /* 命令執行失敗后,切記發送停止信號,避免影響I2C總線上其他設備 */
  385.         /* 發送I2C總線停止信號 */
  386.         i2c_Stop();
  387. }
  388. #else

  389. void max10300_FIFO_Read(u8 Register_Address,u16  Word_Data[][2],u8 count)
  390. {
  391.         u8 i=0;
  392.         u8 no = count;
  393.         u8 data1, data2;
  394.         

  395.         while(I2C_GetFlagStatus(USR_I2C_USED, I2C_FLAG_BUSY))
  396.                 ; //調用庫函數檢測I2C器件是否處于BUSY狀態
  397.                

  398.         I2C_AcknowledgeConfig(USR_I2C_USED, ENABLE);   /*允許1字節1應答模式*/


  399.         I2C_GenerateSTART(USR_I2C_USED, ENABLE);
  400.          while(!I2C_CheckEvent(USR_I2C_USED, I2C_EVENT_MASTER_MODE_SELECT))
  401.                  ; //清除EV5
  402.         
  403.         I2C_Send7bitAddress(USR_I2C_USED, max10300_WR_address, I2C_Direction_Transmitter);
  404.         while(!I2C_CheckEvent(USR_I2C_USED,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
  405.                 ; //ADDR=1,清除EV6
  406.                
  407.         I2C_SendData(USR_I2C_USED, Register_Address);
  408.          while(! I2C_CheckEvent(USR_I2C_USED, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
  409.                  ;//移位寄存器非空,數據寄存器已經空,產生EV8,發送數據到DR既可清除該事件

  410.         I2C_GenerateSTART(USR_I2C_USED, ENABLE);
  411.          while(!I2C_CheckEvent(USR_I2C_USED, I2C_EVENT_MASTER_MODE_SELECT))
  412.                  ; //清除EV5
  413.         
  414.         I2C_Send7bitAddress(USR_I2C_USED, max10300_WR_address, I2C_Direction_Receiver);
  415.         while(!I2C_CheckEvent(USR_I2C_USED, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));


  416.          while (no)
  417.     {        
  418.         
  419.                 while(!I2C_CheckEvent(USR_I2C_USED, I2C_EVENT_MASTER_BYTE_RECEIVED)); // EV7
  420.             data1 = I2C_ReceiveData(USR_I2C_USED);

  421.                 while(!I2C_CheckEvent(USR_I2C_USED, I2C_EVENT_MASTER_BYTE_RECEIVED)); // EV7
  422.             data2 = I2C_ReceiveData(USR_I2C_USED);

  423.             Word_Data[i][0] = (((u16)data1 << 8) | data2);  //



  424.        while(!I2C_CheckEvent(USR_I2C_USED, I2C_EVENT_MASTER_BYTE_RECEIVED)); // EV7
  425.                 data1 = I2C_ReceiveData(USR_I2C_USED);

  426.             if(no==1)
  427.                 {
  428.                      I2C_AcknowledgeConfig(I2C1, DISABLE);        //最后一位后要關閉應答的
  429.                     I2C_GenerateSTOP(I2C1, ENABLE);                        //發送停止位
  430.                
  431.                 }

  432.                 while(!I2C_CheckEvent(USR_I2C_USED, I2C_EVENT_MASTER_BYTE_RECEIVED)); // EV7
  433.                 data2 = I2C_ReceiveData(USR_I2C_USED);

  434.                 Word_Data[i][1] = (((u16)data1 << 8) | data2);
  435.                 i++;

  436.                
  437.             /* Decrement the read bytes counter */
  438.             no--;
  439.     }
  440.         
  441.         I2C_AcknowledgeConfig(USR_I2C_USED, ENABLE);//將應答位使能回去,等待下次通信
  442.         I2C_GenerateSTOP(I2C1, ENABLE);                        //發送停止位

  443. }

  444. #endif
  445. #define INTERRUPT_REG                                          0X00
  446. #define INTERRUPT_REG_A_FULL                          (0X01<<7)
  447. #define INTERRUPT_REG_TEMP_RDY                  (0X01<<6)
  448. #define INTERRUPT_REG_HR_RDY                          (0X01<<5)
  449. #define INTERRUPT_REG_SPO2_RDY                  (0X01<<4)
  450. #define INTERRUPT_REG_PWR_RDY                          (0X01<<0)



  451. void max10300_init()
  452. {
  453.         max10300_Bus_Write(0x06, 0x0b);  //mode configuration : temp_en[3]      MODE[2:0]=010 HR only enabled    011 SP02 enabled
  454.         //max10300_Bus_Write(0x06, 0x0a);  //MODE[2:0]=010 HR only enabled     when used is mode ,the red led is not used.
  455.         max10300_Bus_Write(0x01, 0xF0); //open all of interrupt
  456.         max10300_Bus_Write(INTERRUPT_REG, 0x00); //all interrupt clear
  457.         max10300_Bus_Write(0x09, 0x33); //r_pa=3,ir_pa=3

  458. #ifdef SAMPLE_50
  459.         max10300_Bus_Write(0x07, 0x43); //SPO2_SR[4:2]=000   50 per second    LED_PW[1:0]=11  16BITS
  460. #else
  461.         max10300_Bus_Write(0x07, 0x47); //SPO2_SR[4:2]=001  100 per second    LED_PW[1:0]=11  16BITS
  462. #endif
  463.         
  464.         max10300_Bus_Write(0x02, 0x00);   //set FIFO write Pointer reg = 0x00 for clear it
  465.         max10300_Bus_Write(0x03, 0x00);        //set Over Flow Counter  reg = 0x00 for clear it
  466.         max10300_Bus_Write(0x04, 0x0f);        //set FIFO Read Pointer  reg = 0x0f for   
  467.                                                                                         //waitting  write pointer eq read pointer   to   interrupts  INTERRUPT_REG_A_FULL
  468. }

  469. double my_floor(double x)
  470. {
  471.    double y=x;
  472.     if( (*( ( (int *) &y)+1) & 0x80000000)  != 0) //或者if(x<0)
  473.         return (float)((int)x)-1;
  474.     else
  475.         return (float)((int)x);
  476. }

  477. double my_fmod(double x, double y)
  478. {
  479.    double temp, ret;
  480.   
  481.    if (y == 0.0)
  482.       return 0.0;
  483.    temp = my_floor(x/y);
  484.    ret = x - temp * y;
  485.    if ((x < 0.0) != (y < 0.0))
  486.       ret = ret - y;
  487.    return ret;
  488. }


  489. #define XPI            (3.1415926535897932384626433832795)
  490. #define XENTRY        (100)
  491. #define XINCL        (XPI/2/XENTRY)

  492.   static const double XSinTbl[] = {
  493.         0.00000000000000000  , 0.015707317311820675 , 0.031410759078128292 , 0.047106450709642665 , 0.062790519529313374 ,
  494.         0.078459095727844944 , 0.094108313318514325 , 0.10973431109104528  , 0.12533323356430426  , 0.14090123193758267  ,
  495.         0.15643446504023087  , 0.17192910027940955  , 0.18738131458572463  , 0.20278729535651249  , 0.21814324139654256  ,
  496.         0.23344536385590542  , 0.24868988716485479  , 0.26387304996537292  , 0.27899110603922928  , 0.29404032523230400  ,
  497.         0.30901699437494740  , 0.32391741819814940  , 0.33873792024529142  , 0.35347484377925714  , 0.36812455268467797  ,
  498.         0.38268343236508978  , 0.39714789063478062  , 0.41151435860510882  , 0.42577929156507272  , 0.43993916985591514  ,
  499.         0.45399049973954680  , 0.46792981426057340  , 0.48175367410171532  , 0.49545866843240760  , 0.50904141575037132  ,
  500.         0.52249856471594880  , 0.53582679497899666  , 0.54902281799813180  , 0.56208337785213058  , 0.57500525204327857  ,
  501.         0.58778525229247314  , 0.60042022532588402  , 0.61290705365297649  , 0.62524265633570519  , 0.63742398974868975  ,
  502.         0.64944804833018377  , 0.66131186532365183  , 0.67301251350977331  , 0.68454710592868873  , 0.69591279659231442  ,
  503.         0.70710678118654757  , 0.71812629776318881  , 0.72896862742141155  , 0.73963109497860968  , 0.75011106963045959  ,
  504.         0.76040596560003104  , 0.77051324277578925  , 0.78043040733832969  , 0.79015501237569041  , 0.79968465848709058  ,
  505.         0.80901699437494745  , 0.81814971742502351  , 0.82708057427456183  , 0.83580736136827027  , 0.84432792550201508  ,
  506.         0.85264016435409218  , 0.86074202700394364  , 0.86863151443819120  , 0.87630668004386369  , 0.88376563008869347  ,
  507.         0.89100652418836779  , 0.89802757576061565  , 0.90482705246601958  , 0.91140327663544529  , 0.91775462568398114  ,
  508.         0.92387953251128674  , 0.92977648588825146  , 0.93544403082986738  , 0.94088076895422557  , 0.94608535882754530  ,
  509.         0.95105651629515353  , 0.95579301479833012  , 0.96029368567694307  , 0.96455741845779808  , 0.96858316112863108  ,
  510.         0.97236992039767667  , 0.97591676193874743  , 0.97922281062176575  , 0.98228725072868872  , 0.98510932615477398  ,
  511.         0.98768834059513777  , 0.99002365771655754  , 0.99211470131447788  , 0.99396095545517971  , 0.99556196460308000  ,
  512.         0.99691733373312796  , 0.99802672842827156  , 0.99888987496197001  , 0.99950656036573160  , 0.99987663248166059  ,
  513.         1.00000000000000000  };

  514. double XSin( double x )
  515. {
  516.     int s = 0 , n;
  517.     double dx , sx , cx;
  518.     if( x < 0 )
  519.         s = 1 , x = -x;
  520.     x = my_fmod( x , 2 * XPI );
  521.     if( x > XPI )
  522.         s = !s , x -= XPI;
  523.     if( x > XPI / 2 )
  524.         x = XPI - x;
  525.     n = (int)( x / XINCL );
  526.     dx = x - n * XINCL;
  527.     if( dx > XINCL / 2 )
  528.         ++n , dx -= XINCL;
  529.     sx = XSinTbl[n];
  530.     cx = XSinTbl[XENTRY-n];
  531.     x = sx + dx*cx - (dx*dx)*sx/2
  532.         - (dx*dx*dx)*cx/6
  533.         + (dx*dx*dx*dx)*sx/24
  534.         ;
  535.      
  536.     return s ? -x : x;
  537. }

  538. double XCos( double x )
  539. {
  540.     return XSin( x + XPI/2 );
  541. }


  542. /*********************************FFT*************************************
  543.                          快速傅里葉變換C函數
  544. 函數簡介:此函數是通用的快速傅里葉變換C語言函數,移植性強,以下部分不依
  545.           賴硬件。此函數采用聯合體的形式表示一個復數,輸入為自然順序的復
  546.           數(輸入實數是可令復數虛部為0),輸出為經過FFT變換的自然順序的
  547.           復數
  548. 使用說明:使用此函數只需更改宏定義FFT_N的值即可實現點數的改變,FFT_N的
  549.           應該為2的N次方,不滿足此條件時應在后面補0
  550. 函數調用:FFT(s);
  551. 時    間:2010-2-20
  552. 版    本:Ver1.0
  553. 參考文獻:     
  554. **********************************************************************/

  555. #define PI 3.1415926535897932384626433832795028841971               //定義圓周率值
  556. #define FFT_N 1024                                                  //定義福利葉變換的點數

  557. struct compx     //定義一個復數結構
  558.         {
  559.                 float real;
  560.                 float imag;
  561.         };                  

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


  564. /*******************************************************************
  565. 函數原型:struct compx EE(struct compx b1,struct compx b2)  
  566. 函數功能:對兩個復數進行乘法運算
  567. 輸入參數:兩個以聯合體定義的復數a,b
  568. 輸出參數:a和b的乘積,以聯合體的形式輸出
  569. *******************************************************************/
  570. struct compx EE(struct compx a,struct compx b)      
  571. {
  572.          struct compx c;
  573.          c.real=a.real*b.real-a.imag*b.imag;
  574.          c.imag=a.real*b.imag+a.imag*b.real;
  575.          return(c);
  576. }

  577. /*****************************************************************
  578. 函數原型:void FFT(struct compx *xin,int N)
  579. 函數功能:對輸入的復數組進行快速傅里葉變換(FFT)
  580. 輸入參數:*xin復數結構體組的首地址指針,struct型
  581. *****************************************************************/
  582. void FFT(struct compx *xin)
  583. {
  584.         int f,m,nv2,nm1,i,k,l,j=0;
  585.         struct compx u,w,t;

  586.         nv2=FFT_N/2;                  //變址運算,即把自然順序變成倒位序,采用雷德算法
  587.         nm1=FFT_N-1;  
  588.         for(i=0;i<nm1;i++)        
  589.         {
  590.                 if(i<j)                    //如果i<j,即進行變址
  591.                 {
  592.                         t=xin[j];           
  593.                         xin[j]=xin[i];
  594.                         xin[i]=t;
  595.                 }
  596.                 k=nv2;                    //求j的下一個倒位序
  597.                
  598.                 while(k<=j)               //如果k<=j,表示j的最高位為1   
  599.                 {           
  600.                         j=j-k;                 //把最高位變成0
  601.                         k=k/2;                 //k/2,比較次高位,依次類推,逐個比較,直到某個位為0
  602.                 }
  603.                
  604.                 j=j+k;                   //把0改為1
  605.         }
  606.          
  607.         {  //FFT運算核,使用蝶形運算完成FFT運算
  608.                 int le,lei,ip;                           
  609.                 f=FFT_N;
  610.                 for(l=1;(f=f/2)!=1;l++)                  //計算l的值,即計算蝶形級數
  611.                         ;
  612.                 for(m=1;m<=l;m++)                           // 控制蝶形結級數
  613.                 {                                           //m表示第m級蝶形,l為蝶形級總數l=log(2)N
  614.                         le=2<<(m-1);                            //le蝶形結距離,即第m級蝶形的蝶形結相距le點
  615.                         lei=le/2;                               //同一蝶形結中參加運算的兩點的距離
  616.                         u.real=1.0;                             //u為蝶形結運算系數,初始值為1
  617.                         u.imag=0.0;
  618.                         w.real=XCos(PI/lei);                     //w為系數商,即當前系數與前一個系數的商
  619.                         w.imag=-XSin(PI/lei);
  620.                         for(j=0;j<=lei-1;j++)                   //控制計算不同種蝶形結,即計算系數不同的蝶形結
  621.                         {
  622.                                 for(i=j;i<=FFT_N-1;i=i+le)            //控制同一蝶形結運算,即計算系數相同蝶形結
  623.                                 {
  624.                                         ip=i+lei;                           //i,ip分別表示參加蝶形運算的兩個節點
  625.                                         t=EE(xin[ip],u);                    //蝶形運算,詳見公式
  626.                                         xin[ip].real=xin[i].real-t.real;
  627.                                         xin[ip].imag=xin[i].imag-t.imag;
  628.                                         xin[i].real=xin[i].real+t.real;
  629.                                         xin[i].imag=xin[i].imag+t.imag;
  630.                                 }
  631.                                 u=EE(u,w);                           //改變系數,進行下一個蝶形運算
  632.                         }
  633.                 }
  634.         }

  635. }

  636. u16 g_fft_index=0;

  637. u16 qsqrt(u32 a)
  638. {
  639.   u32 rem = 0, root = 0, divisor = 0;
  640.   u16 i;
  641.   for(i=0; i<16; i++)
  642.   {
  643.     root <<= 1;
  644.     rem = ((rem << 2) + (a>>30));
  645.     a <<= 2;
  646.     divisor = (root << 1) + 1;
  647.     if(divisor <= rem)
  648.     {
  649.       rem -= divisor;
  650.       root++;
  651.     }
  652.   }
  653.   return root;
  654. }

  655. #define START_INDEX    10   //濾出低頻干擾
  656. u16 find_max_num_index(struct compx *data,u16 count)
  657. {
  658.         u16 i=START_INDEX;
  659.         u16 max_num_index = i;
  660.         //struct compx temp=data[i];
  661.         float temp = data[i].real;
  662.         for(i=START_INDEX;i<count;i++)
  663.         {
  664.                 if(temp < data[i].real)
  665.                 {
  666.                         temp = data[i].real;
  667.                         max_num_index = i;
  668.                 }
  669.         }
  670.         printf("max_num_index=%d\r\n",max_num_index);
  671.         return max_num_index;
  672.         
  673. }

  674. #define CORRECTED_VALUE        50   //粗略標定血液氧氣含量   ,精準數據需要大量測量

  675. void sp02_treated_fun(u16 max_index)
  676. {
  677.         float sp02_num=0;
  678.          
  679.         delayl_init();                     //延時函數初始化           
  680.         OLED_Init();                        //初始化OLED     
  681.    
  682.          printf("\r\n zhiliu s1=%f,s2=%f \r\n",s1[0].real,s2[0].real);
  683.         printf("\r\n s1=%f,s2=%f \r\n",s1[max_index].real,s2[max_index].real);
  684.         if((s1[max_index].real*s2[0].real)>(s2[max_index].real*s1[0].real))  //if   ir>red      sp02>75%
  685.         {
  686.                 sp02_num = (s2[max_index].real*s1[0].real)/(s1[max_index].real*s2[0].real);
  687.                 printf("\r\nsp02_num  : %f\r\n",sp02_num*100);
  688.                 printf("\r\n血氧含量為: %f\r\n",(1-sp02_num)*100+CORRECTED_VALUE);
  689.                
  690.                 OLED_ShowString(0,0, "SpO2:",16);
  691.                 if((1-sp02_num)*100+CORRECTED_VALUE>99)
  692.                         OLED_ShowString(40,0, "99",16);
  693.                 else
  694.                         OLED_ShowNum(40,0,(1-sp02_num)*100+CORRECTED_VALUE,4,16);

  695.                 OLED_ShowString(80,0,"%",16);
  696.                 OLED_ShowString(0,30,"Heart Rate:",12);   
  697.                 OLED_Refresh_Gram();//更新顯示到OLED         
  698.                
  699.         }
  700.         else   // sp02<75%
  701.         {
  702.                 printf("\r\n 嚴重缺氧! \r\n");
  703.                
  704.                 OLED_ShowString(0,0, "SpO2:",16);
  705.                 OLED_ShowString(40,0,"ANOXIA!",16);
  706.                 OLED_ShowString(0,30,"Heart Rate:",12);   
  707.                 OLED_Refresh_Gram();//更新顯示到OLED
  708.         }        
  709. }

  710. void test_max30100_fun(void)
  711. {
  712.         u16 temp_num=0;
  713.         u16 fifo_word_buff[15][2];
  714.         u16 Heart_Rate=0;
  715.         u16 s1_max_index=0;
  716.         u16 s2_max_index=0;
  717.         
  718. ……………………

  719. …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼

所有資料51hei提供下載:
血氧心率.7z (4.33 MB, 下載次數: 1349)


評分

參與人數 7黑幣 +52 收起 理由
wait_wait_ + 12 很給力!
mettie + 5 很給力!
lqzhappy + 5 很給力!
kat5566 + 5
蘭木滄溟 + 5 很給力!
fhx97 + 15 很給力!
hei1043218814 + 5 很給力!

查看全部評分

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

使用道具 舉報

沙發
ID:246166 發表于 2017-11-8 18:39 | 只看該作者
樓主太強了,學習學習
回復

使用道具 舉報

板凳
ID:249501 發表于 2017-11-14 22:52 | 只看該作者
不錯啊  學習一個
回復

使用道具 舉報

地板
ID:249504 發表于 2017-11-15 10:45 | 只看該作者
樓主,你有兩個I2C函數,都用了 PB6和PB7引腳,一個是復用開漏,一個是復用推挽,請問為什么這樣寫呢?謝謝
回復

使用道具 舉報

5#
ID:245513 發表于 2017-11-18 16:48 來自手機 | 只看該作者
伊森一亨特 發表于 2017-11-15 10:45
樓主,你有兩個I2C函數,都用了 PB6和PB7引腳,一個是復用開漏,一個是復用推挽,請問為什么這樣寫呢?謝謝

模擬iic的。應該是sclk和sda。肯定要用不同gpio配置方式。自己看看iic協議吧。
回復

使用道具 舉報

6#
ID:252080 發表于 2017-11-22 16:17 | 只看該作者
學習學習
回復

使用道具 舉報

7#
ID:254920 發表于 2017-11-28 21:36 | 只看該作者
厲害厲害
回復

使用道具 舉報

8#
ID:249501 發表于 2017-12-21 10:02 | 只看該作者
請問讀FIFO是怎么讀?讀到中斷標志位就一直讀嗎?還是讀到中斷就只讀4個樣本?
回復

使用道具 舉報

9#
ID:180844 發表于 2018-1-15 16:37 | 只看該作者
請問數據處理方面的算法在哪部分
回復

使用道具 舉報

10#
ID:284715 發表于 2018-2-22 10:56 | 只看該作者
學習了~
回復

使用道具 舉報

11#
ID:284715 發表于 2018-2-22 14:07 | 只看該作者
求教樓主,為什么我采集到的數據是這樣的,數據值一直在變小啊

1519279446(1).png (40.56 KB, 下載次數: 203)

1519279446(1).png
回復

使用道具 舉報

12#
ID:288809 發表于 2018-3-8 10:05 | 只看該作者
想學習一下,分不夠了
回復

使用道具 舉報

13#
ID:292418 發表于 2018-3-15 18:18 來自手機 | 只看該作者
樓主流弊,學習學習
回復

使用道具 舉報

14#
ID:239244 發表于 2018-3-19 21:12 | 只看該作者
helloapy 發表于 2018-2-22 14:07
求教樓主,為什么我采集到的數據是這樣的,數據值一直在變小啊

兄弟,咱倆遇到的問題一樣啊,不知道你解決了沒有
回復

使用道具 舉報

15#
ID:296605 發表于 2018-3-25 09:23 | 只看該作者
你好,請問你所用的iic-max30100模塊可以發我一下淘寶鏈接嗎?找不到帶LCD顯示屏的30100模塊,麻煩了。
回復

使用道具 舉報

16#
ID:289262 發表于 2018-3-29 09:44 | 只看該作者
好東西,學習下。
回復

使用道具 舉報

17#
ID:299299 發表于 2018-4-3 23:36 | 只看該作者
請問樓主這個算法有一些資料文檔嗎,可以分享一下嗎,謝謝
回復

使用道具 舉報

18#
ID:299299 發表于 2018-4-5 09:49 | 只看該作者
請問樓主這個可以用來放在手腕上測量嗎,我調試了你的代碼發現在手指測量可以得出想要得到的波形,但手腕上卻不太一樣
回復

使用道具 舉報

19#
ID:273296 發表于 2018-4-13 11:03 | 只看該作者
學習了
回復

使用道具 舉報

20#
ID:198849 發表于 2018-4-13 15:53 | 只看該作者
樓主,我參考你的移植到F4上,接上線沒反應怎么回事?燈都不亮
回復

使用道具 舉報

21#
ID:198849 發表于 2018-4-14 09:54 | 只看該作者
我一直測出來心率為29
回復

使用道具 舉報

22#
ID:314754 發表于 2018-4-23 19:39 | 只看該作者
學習了
回復

使用道具 舉報

23#
ID:314857 發表于 2018-4-23 21:38 | 只看該作者
樓主厲害
回復

使用道具 舉報

24#
ID:315693 發表于 2018-4-24 20:45 | 只看該作者

樓主太給力啦
回復

使用道具 舉報

25#
ID:317239 發表于 2018-4-27 11:36 | 只看該作者
附件掛了,樓主能在傳一份嗎
回復

使用道具 舉報

26#
ID:319881 發表于 2018-5-1 15:24 | 只看該作者
樓主很強
回復

使用道具 舉報

27#
ID:319881 發表于 2018-5-1 15:29 | 只看該作者
樓主很強
回復

使用道具 舉報

28#
ID:195609 發表于 2018-5-2 10:22 | 只看該作者
請問樓主用的MAX30100長什么樣子 有鏈接嗎
回復

使用道具 舉報

29#
ID:313051 發表于 2018-5-2 19:26 | 只看該作者
學習了
回復

使用道具 舉報

30#
ID:321333 發表于 2018-5-3 16:18 | 只看該作者
厲害厲害 學習學習
回復

使用道具 舉報

31#
ID:321333 發表于 2018-5-3 16:56 | 只看該作者
樓主用的是什么采集軟件
回復

使用道具 舉報

32#
ID:280272 發表于 2018-5-3 21:29 | 只看該作者
厲害厲害 學習學習
回復

使用道具 舉報

33#
ID:322057 發表于 2018-5-4 15:28 | 只看該作者
資料下載了不能用,是什么原因?
回復

使用道具 舉報

34#
ID:322057 發表于 2018-5-4 15:29 | 只看該作者
nandyku 發表于 2018-4-13 15:53
樓主,我參考你的移植到F4上,接上線沒反應怎么回事?燈都不亮

請問,你的問題解決了嗎?
回復

使用道具 舉報

35#
ID:322057 發表于 2018-5-4 16:49 | 只看該作者
有可以用的代碼嗎?可以發一下嗎?
回復

使用道具 舉報

36#
ID:334304 發表于 2018-5-20 16:56 | 只看該作者
分不夠下載啊
回復

使用道具 舉報

37#
ID:337583 發表于 2018-5-25 11:13 | 只看該作者
樓主,為什么我下載不了這個壓縮包?按下載顯示服務器錯誤?
回復

使用道具 舉報

38#
ID:117866 發表于 2018-6-3 23:58 | 只看該作者
謝謝樓主!
回復

使用道具 舉報

39#
ID:344516 發表于 2018-6-4 11:17 | 只看該作者
感謝分享
回復

使用道具 舉報

40#
ID:345398 發表于 2018-6-5 14:30 | 只看該作者
謝謝樓主分享,樓主制作和上傳辛苦了
回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 91精品国产一区二区三区 | 伊人国产精品 | 亚洲91 | 成人中文字幕在线 | 午夜成人免费视频 | 亚洲二区在线观看 | 欧美日一区二区 | 粉嫩一区二区三区四区公司1 | 欧美日韩亚洲视频 | 国产在线一区二区三区 | 97在线超碰 | 欧美精品一区二区三区在线播放 | 一级片在线观看 | 美女国内精品自产拍在线播放 | 亚洲欧美综合 | 男女爱爱网站 | 国产成人综合亚洲欧美94在线 | 自拍偷拍第一页 | www亚洲精品 | 国产精品久久久久久久久久99 | 黄色在线免费观看视频网站 | 97人人澡人人爽91综合色 | 男人久久天堂 | 日韩一区二区视频 | 国产精品日韩欧美一区二区三区 | 在线免费观看欧美 | 久久久国产精品 | 欧洲一区二区视频 | 久久久精| 亚洲一区 中文字幕 | 91视视频在线观看入口直接观看 | 国产精品午夜电影 | 精品一区二区三区在线观看 | 亚洲精品视频免费观看 | 欧美黑人一级爽快片淫片高清 | 免费在线观看成年人视频 | 欧美成人一区二区 | 亚洲色片网站 | 国产精品久久久久久久久免费樱桃 | 亚洲精品色 | 四虎最新地址 |