找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

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

STM32單片機(jī)+MAX30102心率血氧檢測代碼

  [復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:1022289 發(fā)表于 2022-5-15 09:47 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
最近在做心率血氧檢測,用的是C8T6最小系統(tǒng)板和MAX30102代碼發(fā)送給大家
STM32F103-30102:
    VCC<->3.3V
    GND<->GND
    SCL<->PB7
    SDA<->PB8
    IM<->PB9
0.96inch OLED :
    VCC<->3.3V
    GND<->GND
    SCL<->PA5
    SDA<->PA6
    RST<->PA3
    DC<->PA4
    CS<->PA2
USB-TTL:
    5V<->5V
    GND<->GND
    RXD<->PA9
    TXD<->PA10
單片機(jī)源程序如下:
  1. #include "max30102.h"
  2. #include "myiic.h"
  3. #include "delay.h"

  4. u8 max30102_Bus_Write(u8 Register_Address, u8 Word_Data)
  5. {

  6.         /* 采用串行EEPROM隨即讀取指令序列,連續(xù)讀取若干字節(jié) */

  7.         /* 第1步:發(fā)起I2C總線啟動(dòng)信號(hào) */
  8.         IIC_Start();

  9.         /* 第2步:發(fā)起控制字節(jié),高7bit是地址,bit0是讀寫控制位,0表示寫,1表示讀 */
  10.         IIC_Send_Byte(max30102_WR_address | I2C_WR);        /* 此處是寫指令 */

  11.         /* 第3步:發(fā)送ACK */
  12.         if (IIC_Wait_Ack() != 0)
  13.         {
  14.                 goto cmd_fail;        /* EEPROM器件無應(yīng)答 */
  15.         }

  16.         /* 第4步:發(fā)送字節(jié)地址 */
  17.         IIC_Send_Byte(Register_Address);
  18.         if (IIC_Wait_Ack() != 0)
  19.         {
  20.                 goto cmd_fail;        /* EEPROM器件無應(yīng)答 */
  21.         }
  22.         
  23.         /* 第5步:開始寫入數(shù)據(jù) */
  24.         IIC_Send_Byte(Word_Data);

  25.         /* 第6步:發(fā)送ACK */
  26.         if (IIC_Wait_Ack() != 0)
  27.         {
  28.                 goto cmd_fail;        /* EEPROM器件無應(yīng)答 */
  29.         }

  30.         /* 發(fā)送I2C總線停止信號(hào) */
  31.         IIC_Stop();
  32.         return 1;        /* 執(zhí)行成功 */

  33. cmd_fail: /* 命令執(zhí)行失敗后,切記發(fā)送停止信號(hào),避免影響I2C總線上其他設(shè)備 */
  34.         /* 發(fā)送I2C總線停止信號(hào) */
  35.         IIC_Stop();
  36.         return 0;
  37. }



  38. u8 max30102_Bus_Read(u8 Register_Address)
  39. {
  40.         u8  data;


  41.         /* 第1步:發(fā)起I2C總線啟動(dòng)信號(hào) */
  42.         IIC_Start();

  43.         /* 第2步:發(fā)起控制字節(jié),高7bit是地址,bit0是讀寫控制位,0表示寫,1表示讀 */
  44.         IIC_Send_Byte(max30102_WR_address | I2C_WR);        /* 此處是寫指令 */

  45.         /* 第3步:發(fā)送ACK */
  46.         if (IIC_Wait_Ack() != 0)
  47.         {
  48.                 goto cmd_fail;        /* EEPROM器件無應(yīng)答 */
  49.         }

  50.         /* 第4步:發(fā)送字節(jié)地址, */
  51.         IIC_Send_Byte((uint8_t)Register_Address);
  52.         if (IIC_Wait_Ack() != 0)
  53.         {
  54.                 goto cmd_fail;        /* EEPROM器件無應(yīng)答 */
  55.         }
  56.         

  57.         /* 第6步:重新啟動(dòng)I2C總線。下面開始讀取數(shù)據(jù) */
  58.         IIC_Start();

  59.         /* 第7步:發(fā)起控制字節(jié),高7bit是地址,bit0是讀寫控制位,0表示寫,1表示讀 */
  60.         IIC_Send_Byte(max30102_WR_address | I2C_RD);        /* 此處是讀指令 */

  61.         /* 第8步:發(fā)送ACK */
  62.         if (IIC_Wait_Ack() != 0)
  63.         {
  64.                 goto cmd_fail;        /* EEPROM器件無應(yīng)答 */
  65.         }

  66.         /* 第9步:讀取數(shù)據(jù) */
  67.         {
  68.                 data = IIC_Read_Byte(0);        /* 讀1個(gè)字節(jié) */

  69.                 IIC_NAck();        /* 最后1個(gè)字節(jié)讀完后,CPU產(chǎn)生NACK信號(hào)(驅(qū)動(dòng)SDA = 1) */
  70.         }
  71.         /* 發(fā)送I2C總線停止信號(hào) */
  72.         IIC_Stop();
  73.         return data;        /* 執(zhí)行成功 返回data值 */

  74. cmd_fail: /* 命令執(zhí)行失敗后,切記發(fā)送停止信號(hào),避免影響I2C總線上其他設(shè)備 */
  75.         /* 發(fā)送I2C總線停止信號(hào) */
  76.         IIC_Stop();
  77.         return 0;
  78. }


  79. void max30102_FIFO_ReadWords(u8 Register_Address,u16 Word_Data[][2],u8 count)
  80. {
  81.         u8 i=0;
  82.         u8 no = count;
  83.         u8 data1, data2;
  84.         /* 第1步:發(fā)起I2C總線啟動(dòng)信號(hào) */
  85.         IIC_Start();

  86.         /* 第2步:發(fā)起控制字節(jié),高7bit是地址,bit0是讀寫控制位,0表示寫,1表示讀 */
  87.         IIC_Send_Byte(max30102_WR_address | I2C_WR);        /* 此處是寫指令 */

  88.         /* 第3步:發(fā)送ACK */
  89.         if (IIC_Wait_Ack() != 0)
  90.         {
  91.                 goto cmd_fail;        /* EEPROM器件無應(yīng)答 */
  92.         }

  93.         /* 第4步:發(fā)送字節(jié)地址, */
  94.         IIC_Send_Byte((uint8_t)Register_Address);
  95.         if (IIC_Wait_Ack() != 0)
  96.         {
  97.                 goto cmd_fail;        /* EEPROM器件無應(yīng)答 */
  98.         }
  99.         

  100.         /* 第6步:重新啟動(dòng)I2C總線。下面開始讀取數(shù)據(jù) */
  101.         IIC_Start();

  102.         /* 第7步:發(fā)起控制字節(jié),高7bit是地址,bit0是讀寫控制位,0表示寫,1表示讀 */
  103.         IIC_Send_Byte(max30102_WR_address | I2C_RD);        /* 此處是讀指令 */

  104.         /* 第8步:發(fā)送ACK */
  105.         if (IIC_Wait_Ack() != 0)
  106.         {
  107.                 goto cmd_fail;        /* EEPROM器件無應(yīng)答 */
  108.         }

  109.         /* 第9步:讀取數(shù)據(jù) */
  110.         while (no)
  111.         {
  112.                 data1 = IIC_Read_Byte(0);        
  113.                 IIC_Ack();
  114.                 data2 = IIC_Read_Byte(0);
  115.                 IIC_Ack();
  116.                 Word_Data[i][0] = (((u16)data1 << 8) | data2);  //

  117.                
  118.                 data1 = IIC_Read_Byte(0);        
  119.                 IIC_Ack();
  120.                 data2 = IIC_Read_Byte(0);
  121.                 if(1==no)
  122.                         IIC_NAck();        /* 最后1個(gè)字節(jié)讀完后,CPU產(chǎn)生NACK信號(hào)(驅(qū)動(dòng)SDA = 1) */
  123.                 else
  124.                         IIC_Ack();
  125.                 Word_Data[i][1] = (((u16)data1 << 8) | data2);

  126.                 no--;        
  127.                 i++;
  128.         }
  129.         /* 發(fā)送I2C總線停止信號(hào) */
  130.         IIC_Stop();

  131. cmd_fail: /* 命令執(zhí)行失敗后,切記發(fā)送停止信號(hào),避免影響I2C總線上其他設(shè)備 */
  132.         /* 發(fā)送I2C總線停止信號(hào) */
  133.         IIC_Stop();
  134. }

  135. void max30102_FIFO_ReadBytes(u8 Register_Address,u8* Data)
  136. {        
  137.         max30102_Bus_Read(REG_INTR_STATUS_1);
  138.         max30102_Bus_Read(REG_INTR_STATUS_2);
  139.         
  140.         /* 第1步:發(fā)起I2C總線啟動(dòng)信號(hào) */
  141.         IIC_Start();

  142.         /* 第2步:發(fā)起控制字節(jié),高7bit是地址,bit0是讀寫控制位,0表示寫,1表示讀 */
  143.         IIC_Send_Byte(max30102_WR_address | I2C_WR);        /* 此處是寫指令 */

  144.         /* 第3步:發(fā)送ACK */
  145.         if (IIC_Wait_Ack() != 0)
  146.         {
  147.                 goto cmd_fail;        /* EEPROM器件無應(yīng)答 */
  148.         }

  149.         /* 第4步:發(fā)送字節(jié)地址, */
  150.         IIC_Send_Byte((uint8_t)Register_Address);
  151.         if (IIC_Wait_Ack() != 0)
  152.         {
  153.                 goto cmd_fail;        /* EEPROM器件無應(yīng)答 */
  154.         }
  155.         

  156.         /* 第6步:重新啟動(dòng)I2C總線。下面開始讀取數(shù)據(jù) */
  157.         IIC_Start();

  158.         /* 第7步:發(fā)起控制字節(jié),高7bit是地址,bit0是讀寫控制位,0表示寫,1表示讀 */
  159.         IIC_Send_Byte(max30102_WR_address | I2C_RD);        /* 此處是讀指令 */

  160.         /* 第8步:發(fā)送ACK */
  161.         if (IIC_Wait_Ack() != 0)
  162.         {
  163.                 goto cmd_fail;        /* EEPROM器件無應(yīng)答 */
  164.         }

  165.         /* 第9步:讀取數(shù)據(jù) */
  166.         Data[0] = IIC_Read_Byte(1);        
  167.         Data[1] = IIC_Read_Byte(1);        
  168.         Data[2] = IIC_Read_Byte(1);        
  169.         Data[3] = IIC_Read_Byte(1);
  170.         Data[4] = IIC_Read_Byte(1);        
  171.         Data[5] = IIC_Read_Byte(0);
  172.         /* 最后1個(gè)字節(jié)讀完后,CPU產(chǎn)生NACK信號(hào)(驅(qū)動(dòng)SDA = 1) */
  173.         /* 發(fā)送I2C總線停止信號(hào) */
  174.         IIC_Stop();

  175. cmd_fail: /* 命令執(zhí)行失敗后,切記發(fā)送停止信號(hào),避免影響I2C總線上其他設(shè)備 */
  176.         /* 發(fā)送I2C總線停止信號(hào) */
  177.         IIC_Stop();

  178. //        u8 i;
  179. //        u8 fifo_wr_ptr;
  180. //        u8 firo_rd_ptr;
  181. //        u8 number_tp_read;
  182. //        //Get the FIFO_WR_PTR
  183. //        fifo_wr_ptr = max30102_Bus_Read(REG_FIFO_WR_PTR);
  184. //        //Get the FIFO_RD_PTR
  185. //        firo_rd_ptr = max30102_Bus_Read(REG_FIFO_RD_PTR);
  186. //        
  187. //        number_tp_read = fifo_wr_ptr - firo_rd_ptr;
  188. //        
  189. //        //for(i=0;i<number_tp_read;i++){
  190. //        if(number_tp_read>0){
  191. //                IIC_ReadBytes(max30102_WR_address,REG_FIFO_DATA,Data,6);
  192. //        }
  193.         
  194.         //max30102_Bus_Write(REG_FIFO_RD_PTR,fifo_wr_ptr);
  195. }

  196. void max30102_init(void)
  197. {
  198.         GPIO_InitTypeDef GPIO_InitStructure;

  199.          RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);        
  200.         GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_14;
  201.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  202.          GPIO_Init(GPIOB, &GPIO_InitStructure);
  203.         
  204.         IIC_Init();
  205.         
  206.         max30102_reset();
  207.         
  208. //        max30102_Bus_Write(REG_MODE_CONFIG, 0x0b);  //mode configuration : temp_en[3]      MODE[2:0]=010 HR only enabled    011 SP02 enabled
  209. //        max30102_Bus_Write(REG_INTR_STATUS_2, 0xF0); //open all of interrupt
  210. //        max30102_Bus_Write(REG_INTR_STATUS_1, 0x00); //all interrupt clear
  211. //        max30102_Bus_Write(REG_INTR_ENABLE_2, 0x02); //DIE_TEMP_RDY_EN
  212. //        max30102_Bus_Write(REG_TEMP_CONFIG, 0x01); //SET   TEMP_EN

  213. //        max30102_Bus_Write(REG_SPO2_CONFIG, 0x47); //SPO2_SR[4:2]=001  100 per second    LED_PW[1:0]=11  16BITS

  214. //        max30102_Bus_Write(REG_LED1_PA, 0x47);
  215. //        max30102_Bus_Write(REG_LED2_PA, 0x47);
  216.         
  217.         
  218.         
  219.         max30102_Bus_Write(REG_INTR_ENABLE_1,0xc0);        // INTR setting
  220.         max30102_Bus_Write(REG_INTR_ENABLE_2,0x00);
  221.         max30102_Bus_Write(REG_FIFO_WR_PTR,0x00);          //FIFO_WR_PTR[4:0]
  222.         max30102_Bus_Write(REG_OVF_COUNTER,0x00);          //OVF_COUNTER[4:0]
  223.         max30102_Bus_Write(REG_FIFO_RD_PTR,0x00);          //FIFO_RD_PTR[4:0]
  224.         max30102_Bus_Write(REG_FIFO_CONFIG,0x0f);          //sample avg = 1, fifo rollover=false, fifo almost full = 17
  225.         max30102_Bus_Write(REG_MODE_CONFIG,0x03);          //0x02 for Red only, 0x03 for SpO2 mode 0x07 multimode LED
  226.         max30102_Bus_Write(REG_SPO2_CONFIG,0x27);          // SPO2_ADC range = 4096nA, SPO2 sample rate (100 Hz), LED pulseWidth (400uS)  
  227.         max30102_Bus_Write(REG_LED1_PA,0x24);           //Choose value for ~ 7mA for LED1
  228.         max30102_Bus_Write(REG_LED2_PA,0x24);           // Choose value for ~ 7mA for LED2
  229.         max30102_Bus_Write(REG_PILOT_PA,0x7f);           // Choose value for ~ 25mA for Pilot LED


  230.         
  231. //        // Interrupt Enable 1 Register. Set PPG_RDY_EN (data available in FIFO)
  232. //        max30102_Bus_Write(0x2, 1<<6);

  233. //        // FIFO configuration register
  234. //        // SMP_AVE: 16 samples averaged per FIFO sample
  235. //        // FIFO_ROLLOVER_EN=1
  236. //        //max30102_Bus_Write(0x8,  1<<4);
  237. //        max30102_Bus_Write(0x8, (0<<5) | 1<<4);

  238. //        // Mode Configuration Register
  239. //        // SPO2 mode
  240. //        max30102_Bus_Write(0x9, 3);

  241. //        // SPO2 Configuration Register
  242. //        max30102_Bus_Write(0xa,
  243. //                        (3<<5)  // SPO2_ADC_RGE 2 = full scale 8192 nA (LSB size 31.25pA); 3 = 16384nA
  244. //                        | (1<<2) // sample rate: 0 = 50sps; 1 = 100sps; 2 = 200sps
  245. //                        | (3<<0) // LED_PW 3 = 411μs, ADC resolution 18 bits
  246. //        );

  247. //        // LED1 (red) power (0 = 0mA; 255 = 50mA)
  248. //        max30102_Bus_Write(0xc, 0xb0);

  249. //        // LED (IR) power
  250. //        max30102_Bus_Write(0xd, 0xa0);
  251.                                                                                        
  252. }

  253. void max30102_reset(void)
  254. {
  255.         max30102_Bus_Write(REG_MODE_CONFIG,0x40);
  256.         max30102_Bus_Write(REG_MODE_CONFIG,0x40);
  257. }






  258. void maxim_max30102_write_reg(uint8_t uch_addr, uint8_t uch_data)
  259. {
  260. //  char ach_i2c_data[2];
  261. //  ach_i2c_data[0]=uch_addr;
  262. //  ach_i2c_data[1]=uch_data;
  263. //        
  264. //  IIC_WriteBytes(I2C_WRITE_ADDR, ach_i2c_data, 2);
  265.         IIC_Write_One_Byte(I2C_WRITE_ADDR,uch_addr,uch_data);
  266. }

  267. void maxim_max30102_read_reg(uint8_t uch_addr, uint8_t *puch_data)
  268. {
  269. //  char ch_i2c_data;
  270. //  ch_i2c_data=uch_addr;
  271. //  IIC_WriteBytes(I2C_WRITE_ADDR, &ch_i2c_data, 1);
  272. //        
  273. //  i2c.read(I2C_READ_ADDR, &ch_i2c_data, 1);
  274. //  
  275. //   *puch_data=(uint8_t) ch_i2c_data;
  276.         IIC_Read_One_Byte(I2C_WRITE_ADDR,uch_addr,puch_data);
  277. }

  278. void maxim_max30102_read_fifo(uint32_t *pun_red_led, uint32_t *pun_ir_led)
  279. {
  280.         uint32_t un_temp;
  281.         unsigned char uch_temp;
  282.         char ach_i2c_data[6];
  283.         *pun_red_led=0;
  284.         *pun_ir_led=0;

  285.   
  286.   //read and clear status register
  287.   maxim_max30102_read_reg(REG_INTR_STATUS_1, &uch_temp);
  288.   maxim_max30102_read_reg(REG_INTR_STATUS_2, &uch_temp);
  289.   
  290.   IIC_ReadBytes(I2C_WRITE_ADDR,REG_FIFO_DATA,(u8 *)ach_i2c_data,6);
  291.   
  292.   un_temp=(unsigned char) ach_i2c_data[0];
  293.   un_temp<<=16;
  294.   *pun_red_led+=un_temp;
  295.   un_temp=(unsigned char) ach_i2c_data[1];
  296.   un_temp<<=8;
  297.   *pun_red_led+=un_temp;
  298.   un_temp=(unsigned char) ach_i2c_data[2];
  299.   *pun_red_led+=un_temp;
  300.   
  301.   un_temp=(unsigned char) ach_i2c_data[3];
  302.   un_temp<<=16;
  303.   *pun_ir_led+=un_temp;
  304.   un_temp=(unsigned char) ach_i2c_data[4];
  305.   un_temp<<=8;
  306.   *pun_ir_led+=un_temp;
  307.   un_temp=(unsigned char) ach_i2c_data[5];
  308.   *pun_ir_led+=un_temp;
  309.   *pun_red_led&=0x03FFFF;  //Mask MSB [23:18]
  310.   *pun_ir_led&=0x03FFFF;  //Mask MSB [23:18]
  311. }
復(fù)制代碼

Keil5代碼下載:
代碼.7z (214.85 KB, 下載次數(shù): 287)

評(píng)分

參與人數(shù) 2威望 +15 黑幣 +80 收起 理由
wpppmlah + 15 + 30 共享資料的黑幣獎(jiǎng)勵(lì)!
admin + 50 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

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

使用道具 舉報(bào)

沙發(fā)
ID:1039983 發(fā)表于 2022-8-19 17:09 | 只看該作者
7針OLED怎么改4針OLED啊
回復(fù)

使用道具 舉報(bào)

板凳
ID:1043634 發(fā)表于 2022-10-13 16:44 | 只看該作者
這么好的帖子,必須頂起,支持樓主
回復(fù)

使用道具 舉報(bào)

地板
ID:1043634 發(fā)表于 2022-10-30 15:16 | 只看該作者
這么好的帖子,必須頂起,支持樓主
回復(fù)

使用道具 舉報(bào)

5#
ID:875451 發(fā)表于 2023-2-3 17:30 | 只看該作者
這個(gè)可以下載進(jìn)C8T6嗎
回復(fù)

使用道具 舉報(bào)

6#
ID:504443 發(fā)表于 2023-3-8 07:38 | 只看該作者
請問定義的IM是接哪個(gè)引腳?
回復(fù)

使用道具 舉報(bào)

7#
ID:291668 發(fā)表于 2023-3-8 13:34 | 只看該作者
辛苦了。頂起
回復(fù)

使用道具 舉報(bào)

8#
ID:940352 發(fā)表于 2023-3-13 13:13 | 只看該作者
移植完成后 不出現(xiàn)心率值 一直顯示----- 的原因是什么 求解
回復(fù)

使用道具 舉報(bào)

9#
ID:1069607 發(fā)表于 2023-4-3 10:13 | 只看該作者
請問這個(gè)代碼下載了是不是直接能用了?
回復(fù)

使用道具 舉報(bào)

10#
ID:1069607 發(fā)表于 2023-4-3 12:26 | 只看該作者
543545 發(fā)表于 2022-8-19 17:09
7針OLED怎么改4針OLED啊

請問解決了嗎
回復(fù)

使用道具 舉報(bào)

11#
ID:291668 發(fā)表于 2023-4-3 13:51 | 只看該作者
好東西,頂起,太有幫助了
回復(fù)

使用道具 舉報(bào)

12#
ID:1073560 發(fā)表于 2023-4-25 14:48 來自手機(jī) | 只看該作者
請問有proteus仿真電路圖嗎?
回復(fù)

使用道具 舉報(bào)

13#
ID:948914 發(fā)表于 2023-5-4 10:01 | 只看該作者
543545 發(fā)表于 2022-8-19 17:09
7針OLED怎么改4針OLED啊

好xd,改成功了么
回復(fù)

使用道具 舉報(bào)

14#
ID:1074282 發(fā)表于 2023-5-10 14:22 | 只看該作者
悟道劍 發(fā)表于 2023-3-13 13:13
移植完成后 不出現(xiàn)心率值 一直顯示----- 的原因是什么 求解

我也是一致顯示----,兄弟解決了嗎
回復(fù)

使用道具 舉報(bào)

15#
ID:1073980 發(fā)表于 2023-11-22 14:24 | 只看該作者
帶顯示器嗎
回復(fù)

使用道具 舉報(bào)

16#
ID:1106925 發(fā)表于 2023-12-29 11:05 | 只看該作者
IM到底是什么引腳??
回復(fù)

使用道具 舉報(bào)

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

本版積分規(guī)則

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

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

快速回復(fù) 返回頂部 返回列表