风筝
发表于: 2022-11-8 13:58:00 | 显示全部楼层

MAX30102脉搏血氧和心率传感器是一款基于I2C的低功耗即插即用型生物识别传感器。想要将实时心率数据整合到项目中的学生、爱好者、工程师、创客以及游戏和移动开发人员可以使用它。


MAX30102模块硬件概述

该模块采用MAX30102(MAX30100的升级产品) - ADI公司的现代集成脉搏血氧计和心率传感器。它包含了两个LED、一个光电探测器、优化的光学器件和低噪声模拟信号处理来检测脉搏血氧饱和度 (SpO2) 和心率 (HR) 信号。

MAX30102-Module-Hardware-Overview-IC-and-LEDs.jpg


MAX30102有两个LED:红色LDE和红外LED。模块另一边是一个非常灵敏的光电探测器。当点亮LED时,检测反射回探测器的光量,然后根据特征,你可以测量血氧值和心率。


电源

MAX30102模块需要两种不同的电源电压:传感器为1.8V,红色LED和红外LED为3.3V。所以模块自带3.3V和1.8V稳压器。

MAX30102-Module-Hardware-Overview-Regulators.jpg


在电路板背面,您会发现一个焊接跳线,可用于在3.3V和1.8V逻辑电平之间进行选择。默认选择与 Arduino的逻辑电平兼容的3.3V逻辑电平。但您也可以根据需要选择1.8V逻辑电平。这允许您将模块连接到任何具有5V、3.3V甚至1.8V电平I/O的微控制器。

MAX30102-Module-Hardware-Overview-Solder-Jumper.jpg


MAX30102 最重要的特性之一是其低功耗:MAX30102在测量期间的功耗低于600μA。也可以将MAX30102置于待机模式,其功耗仅为0.7μA。这种低功耗允许在手机、可穿戴设备或智能手表等电池供电设备中实现。


片上温度传感器

MAX30102具有片上温度传感器,可用于补偿环境变化和校准测量值。


这是一款相当精确的温度传感器,可测量 -40˚C 至 +85˚C 范围内的芯片温度,精度为±1˚C。


I2C接口

该模块使用简单的两线I2C接口与微控制器通信。它有一个固定的I2C地址:0xAE(用于写操作)和 0xAF(用于读操作)。


FIFO缓冲器

MAX30102嵌入了一个FIFO缓冲器,用于存储数据样本。FIFO有一个32个样本的存储库,这意味着它可以容纳多达32个SpO2和心率样本。FIFO缓冲器可以减轻微控制器从传感器读取每个新数据样本的负担,从而节省系统功耗。


中断

MAX30102可以编程产生中断,允许主机微控制器在传感器收集数据的同时执行其他任务。可以为5个不同的源启用中断:

●    电源就绪:上电或掉电后触发。

●    新数据就绪:在收集每个SpO2和HR数据样本后触发。

●    环境光消除:当 SpO2/HR 光电二极管的环境光消除功能达到最大限制时触发,影响ADC的输出。

●    温度就绪:当内部芯片温度转换完成时触发。

●    FIFO已满:当FIFO已满且未来数据即将丢失时触发。

MAX30102-Module-Hardware-Overview-Interrupt-Pin.jpg

INT引脚是漏极开路,因此使用板载电阻拉高。当中断发生时,INT引脚变为低电平并保持低电平,直到中断被清除。


MAX30102脉搏血氧和心率传感器如何工作?

MAX30102或任何光学脉搏血氧和心率传感器由一对高强度LED(红色 和红外LED,均为不同波长)和一个光电探测器组成。这些LED的波长分别为660nm和880nm。

MAX30102-Pulse-Detection-Photoplethysmogram.jpg


MAX30102的工作原理是将两种光都照射到手指或耳垂上并使用光电探测器测量反射光量。这种通过光检测脉冲的方法称为光电体积描记图(Photoplethysmogram)。


MAX30102的工作可分为两部分:心率测量和脉搏血氧饱和度(测量血液中的氧含量)。


心率测量

动脉血中的氧合血红蛋白(HbO2)具有吸收红外光的特性。血液越红(血红蛋白越高),吸收的红外光越多。当血液随着每次心跳泵入手指时,反射光的量会发生变化,从而在光电探测器的输出端产生变化的波形。当您继续照射光并获取光电探测器读数时,您很快就会开始获得心跳 (HR) 脉搏读数。

Pulse-Detection-Heart-Rate-Sensor-Working-Photoplethysmogram.jpg


脉搏血氧

脉搏血氧(Pulse Oximetry)的原理是,吸收的红光和红外光量取决于血液中的氧气量。下图是含氧血红蛋白 (HbO2) 和脱氧血红蛋白 (Hb) 的吸收光谱。

Absorption-Spectrum-of-Hb-and-HbO2.jpg


从图中可以看出,脱氧血液吸收更多红光(660nm),而含氧血液吸收更多红外光(880nm)。通过测量光电探测器接收到的红外和红光的比率,可以计算出血液中的氧气水平 (SpO2)。


MAX30102模块引脚

MAX30102模块提供以下连接。

MAX30102-Module-Pinout.jpg


●    VIN 是电源引脚。您可以将其连接到Arduino的3.3V或5V输出。

●    SCL 是I2C时钟引脚,连接到Arduino的I2C时钟线。

●    SDA 是I2C数据引脚,连接到Arduino的I2C数据线。

●    INT MAX30102可以编程为每个脉冲产生一个中断。这条线是开漏的,所以使用板载电阻拉高。当中断发生时,INT引脚变为低电平并保持低电平,直到中断被清除。

●    IRD MAX30102集成了一个LED驱动器,用于驱动LED脉冲,用于SpO2和HR测量。

●    RD 引脚类似于IRD引脚,但用于驱动红色LED。如果您不想自己驱动红色 LED,请将其悬空。

●    GND 是接地引脚。


将MAX30102模块连接到Arduino

首先将VCC引脚连接到电源,3V-5V就可以了。使用与微控制器逻辑所基于的电压相同的电压。对于大多数 Arduino 来说,这是5V。对于3.3V逻辑器件,使用3.3V。现在将GND连接到公共地。


将SCL引脚连接到Arduino上的I2C时钟引脚,将SDA引脚连接到I2C数据引脚。请注意,每个Arduino开发板都有不同的I2C引脚,应相应地连接。下图显示了接线。

Arduino-Wiring-for-MAX30102-Pulse-Oximeter-Heart-Rate-Module.jpg


安装库

MAX30102传感器有多个库可用。 然而,在示例中,我们使用的是SparkFun Electronics提供的库。 该库公开了MAX30102的大部分特性,并提供简单易用的函数来计算脉率和SpO2。 您可以从Arduino IDE库管理器中下载此库。


要安装库,请导航到 Sketch > Include Library > Manage Libraries… 等待库管理器下载库索引并更新已安装库的列表。


输入MAX3010x筛选搜索结果。 查找SparkFun MAX3010x Pulse and Proximity Sensor Library。 单击该条目,然后选择安装。

MAX30102-Library-Installation.jpg

跳转到指定楼层
回复

使用道具 举报

风筝
发表于: 2022-11-8 14:34:20 | 显示全部楼层

MAX30102示例草图

SparkFun_MAX3010x库有许多示例草图。 您可以使用这些示例草图作为开发您自己的代码的基础。


要访问示例草图,请导航至File > Examples > SparkFun MAX3010x Pulse and Proximity Sensor Library。您将看到一系列示例草图。

MAX30102-Library-Examples.jpg


示例1 – 读取红灯和红外LED

第一个示例输出传感器读取的原始值(IR和红灯读数)。 将其上传到Arduino并打开串口终端查看打印值。

  1. #include <Wire.h>
  2. #include "MAX30105.h"

  3. MAX30105 particleSensor;

  4. void setup() {
  5.         Serial.begin(9600);

  6.         // Initialize sensor
  7.         if (particleSensor.begin() == false) {
  8.                 Serial.println("MAX30102 was not found. Please check wiring/power.");
  9.                 while (1);
  10.         }

  11.         particleSensor.setup(); //Configure sensor. Use 6.4mA for LED drive
  12. }

  13. void loop() {
  14.         Serial.print(" R[");
  15.         Serial.print(particleSensor.getRed());
  16.         Serial.print("] IR[");
  17.         Serial.print(particleSensor.getIR());
  18.         Serial.println("]");
  19. }
复制代码

使传感器朝上,在传感器上滑动手掌。当您的手反射不同数量的光时,您应该会看到值的变化。

MAX30102-Raw-Red-and-IR-Values-Output.jpg


如果您只查看值,串口数据可能很难可视化。如果您使用的是Arduino IDE v1.6.6+,则可以选择使用Arduino串口绘图仪(Serial Plotter)查看图表上的数据。


首先,将上面代码中的loop()函数替换为以下代码片段:

  1. void loop() {
  2.         Serial.print(particleSensor.getRed());
  3.         Serial.print(", ");
  4.         Serial.println(particleSensor.getIR());
  5. }
复制代码

在 Arduino IDE 中,选择Tools > Serial Plotter。当您将手滑过传感器时,您应该会看到类似于下图的波浪。

MAX30102-Output-on-Serial-Plotter.jpg


示例2 – 存在感测

我们的下一个实验展示了如何将MAX30102传感器用作通用接近传感器或反射传感器,并可作为更多实际实验和项目的基础。


此示例通过在设置期间获取少量读数并将它们平均在一起来工作。然后它使用这个平均值作为基线。如果传感器检测到与平均值相比有显着变化,则打印“Something is there!”。

  1. #include <Wire.h>
  2. #include "MAX30105.h"

  3. MAX30105 particleSensor;

  4. long samplesTaken = 0; //Counter for calculating the Hz or read rate
  5. long unblockedValue; //Average IR at power up
  6. long startTime; //Used to calculate measurement rate

  7. void setup() {
  8.   Serial.begin(9600);

  9.   // Initialize sensor
  10.   if (particleSensor.begin(Wire, I2C_SPEED_FAST) == false) { //Use default I2C port, 400kHz speed
  11.     Serial.println("MAX30102 was not found. Please check wiring/power. ");
  12.     while (1);
  13.   }

  14.   //Setup to sense up to 18 inches, max LED brightness
  15.   byte ledBrightness = 0xFF; //Options: 0=Off to 255=50mA
  16.   byte sampleAverage = 4; //Options: 1, 2, 4, 8, 16, 32
  17.   byte ledMode = 2; //Options: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green
  18.   int sampleRate = 400; //Options: 50, 100, 200, 400, 800, 1000, 1600, 3200
  19.   int pulseWidth = 411; //Options: 69, 118, 215, 411
  20.   int adcRange = 2048; //Options: 2048, 4096, 8192, 16384
  21.   
  22.   //Configure sensor with these settings
  23.   particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange);

  24.   particleSensor.setPulseAmplitudeRed(0); //Turn off Red LED
  25.   particleSensor.setPulseAmplitudeGreen(0); //Turn off Green LED

  26.   //Take an average of IR readings at power up
  27.   unblockedValue = 0;
  28.   for (byte x = 0 ; x < 32 ; x++) {
  29.     unblockedValue += particleSensor.getIR(); //Read the IR value
  30.   }
  31.   unblockedValue /= 32;

  32.   startTime = millis();
  33. }

  34. void loop() {
  35.   samplesTaken++;

  36.   Serial.print("IR[");
  37.   Serial.print(particleSensor.getIR());
  38.   Serial.print("] Hz[");
  39.   Serial.print((float)samplesTaken / ((millis() - startTime) / 1000.0), 2);
  40.   Serial.print("]");

  41.   long currentDelta = particleSensor.getIR() - unblockedValue;

  42.   Serial.print(" delta[");
  43.   Serial.print(currentDelta);
  44.   Serial.print("]");

  45.   if (currentDelta > (long)100) {
  46.     Serial.print(" Something is there!");
  47.   }

  48.   Serial.println();
  49. }
复制代码

再次在传感器上滑动手掌,您将在串口终端上看到Something is there!消息。 尝试测试传感器可以检测到某物的范围。

MAX30102-Presence-Sensing-Output.jpg


示例3 – 读取温度

我们的下一个示例以摄氏度和华氏度输出板载温度传感器的读数。虽然温度读数应用于校准HR和SpO2测量值,但如果您需要灵敏且响应快速的温度传感器,它会很有用。

  1. #include <Wire.h>

  2. #include "MAX30105.h"
  3. MAX30105 particleSensor;

  4. void setup() {
  5.   Serial.begin(9600);
  6.   Serial.println("Initializing...");

  7.   // Initialize sensor
  8.   if (particleSensor.begin(Wire, I2C_SPEED_FAST) == false) { //Use default I2C port, 400kHz speed
  9.     Serial.println("MAX30102 was not found. Please check wiring/power. ");
  10.     while (1);
  11.   }

  12.   //The LEDs are very low power and won't affect the temp reading much but
  13.   //you may want to turn off the LEDs to avoid any local heating
  14.   particleSensor.setup(0); //Configure sensor. Turn off LEDs

  15.   particleSensor.enableDIETEMPRDY(); //Enable the temp ready interrupt. This is required.
  16. }

  17. void loop() {
  18.   float temperature = particleSensor.readTemperature();

  19.   Serial.print("temperatureC=");
  20.   Serial.print(temperature, 4);

  21.   float temperatureF = particleSensor.readTemperatureF();

  22.   Serial.print(" temperatureF=");
  23.   Serial.print(temperatureF, 4);

  24.   Serial.println();
  25. }
复制代码

现在尝试用手指加热传感器或在传感器上轻轻吹气。您应该会看到类似下面的输出。

MAX30102-Internal-Temperature-Sensor-Output.jpg

回复

使用道具 举报

风筝
发表于: 2022-11-8 14:38:48 | 显示全部楼层

示例4 – 测量心率 (BPM)

在此示例中,我们将测量人的心率(每分钟节拍数或BPM)。

  1. #include <Wire.h>
  2. #include "MAX30105.h"
  3. #include "heartRate.h"

  4. MAX30105 particleSensor;

  5. const byte RATE_SIZE = 4; //Increase this for more averaging. 4 is good.
  6. byte rates[RATE_SIZE]; //Array of heart rates
  7. byte rateSpot = 0;
  8. long lastBeat = 0; //Time at which the last beat occurred

  9. float beatsPerMinute;
  10. int beatAvg;

  11. void setup() {
  12.   Serial.begin(115200);
  13.   Serial.println("Initializing...");

  14.   // Initialize sensor
  15.   if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) {
  16.     Serial.println("MAX30102 was not found. Please check wiring/power. ");
  17.     while (1);
  18.   }
  19.   Serial.println("Place your index finger on the sensor with steady pressure.");

  20.   particleSensor.setup(); //Configure sensor with default settings
  21.   particleSensor.setPulseAmplitudeRed(0x0A); //Turn Red LED to low to indicate sensor is running
  22.   particleSensor.setPulseAmplitudeGreen(0); //Turn off Green LED
  23. }

  24. void loop() {
  25.   long irValue = particleSensor.getIR();

  26.   if (checkForBeat(irValue) == true) {
  27.     //We sensed a beat!
  28.     long delta = millis() - lastBeat;
  29.     lastBeat = millis();

  30.     beatsPerMinute = 60 / (delta / 1000.0);

  31.     if (beatsPerMinute < 255 && beatsPerMinute > 20) {
  32.       rates[rateSpot++] = (byte)beatsPerMinute; //Store this reading in the array
  33.       rateSpot %= RATE_SIZE; //Wrap variable

  34.       //Take average of readings
  35.       beatAvg = 0;
  36.       for (byte x = 0 ; x < RATE_SIZE ; x++)
  37.         beatAvg += rates[x];
  38.       beatAvg /= RATE_SIZE;
  39.     }
  40.   }

  41.   Serial.print("IR=");
  42.   Serial.print(irValue);
  43.   Serial.print(", BPM=");
  44.   Serial.print(beatsPerMinute);
  45.   Serial.print(", Avg BPM=");
  46.   Serial.print(beatAvg);

  47.   if (irValue < 50000)
  48.     Serial.print(" No finger?");

  49.   Serial.println();
  50. }
复制代码

上传草图后,将手指尽可能稳定地放在传感器上,等待几秒钟让读数有意义。你会看到这样的结果。

MAX30102-Heart-Rate-Output.jpg


示例5 – 测量氧饱和度 (SpO2)

在我们的最后一个示例中,我们将测量人的血氧水平 (SpO2)。 继续尝试草图。

  1. #include <Wire.h>
  2. #include "MAX30105.h"
  3. #include "spo2_algorithm.h"

  4. MAX30105 particleSensor;

  5. #define MAX_BRIGHTNESS 255

  6. #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
  7. //Arduino Uno doesn't have enough SRAM to store 100 samples of IR led data and red led data in 32-bit format
  8. //To solve this problem, 16-bit MSB of the sampled data will be truncated. Samples become 16-bit data.
  9. uint16_t irBuffer[100]; //infrared LED sensor data
  10. uint16_t redBuffer[100];  //red LED sensor data
  11. #else
  12. uint32_t irBuffer[100]; //infrared LED sensor data
  13. uint32_t redBuffer[100];  //red LED sensor data
  14. #endif

  15. int32_t bufferLength; //data length
  16. int32_t spo2; //SPO2 value
  17. int8_t validSPO2; //indicator to show if the SPO2 calculation is valid
  18. int32_t heartRate; //heart rate value
  19. int8_t validHeartRate; //indicator to show if the heart rate calculation is valid

  20. byte pulseLED = 11; //Must be on PWM pin
  21. byte readLED = 13; //Blinks with each data read

  22. void setup()
  23. {
  24.   Serial.begin(115200); // initialize serial communication at 115200 bits per second:

  25.   pinMode(pulseLED, OUTPUT);
  26.   pinMode(readLED, OUTPUT);

  27.   // Initialize sensor
  28.   if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed
  29.   {
  30.     Serial.println(F("MAX30105 was not found. Please check wiring/power."));
  31.     while (1);
  32.   }

  33.   Serial.println(F("Attach sensor to finger with rubber band. Press any key to start conversion"));
  34.   while (Serial.available() == 0) ; //wait until user presses a key
  35.   Serial.read();

  36.   byte ledBrightness = 60; //Options: 0=Off to 255=50mA
  37.   byte sampleAverage = 4; //Options: 1, 2, 4, 8, 16, 32
  38.   byte ledMode = 2; //Options: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green
  39.   byte sampleRate = 100; //Options: 50, 100, 200, 400, 800, 1000, 1600, 3200
  40.   int pulseWidth = 411; //Options: 69, 118, 215, 411
  41.   int adcRange = 4096; //Options: 2048, 4096, 8192, 16384

  42.   particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); //Configure sensor with these settings
  43. }

  44. void loop()
  45. {
  46.   bufferLength = 100; //buffer length of 100 stores 4 seconds of samples running at 25sps

  47.   //read the first 100 samples, and determine the signal range
  48.   for (byte i = 0 ; i < bufferLength ; i++)
  49.   {
  50.     while (particleSensor.available() == false) //do we have new data?
  51.       particleSensor.check(); //Check the sensor for new data

  52.     redBuffer[i] = particleSensor.getRed();
  53.     irBuffer[i] = particleSensor.getIR();
  54.     particleSensor.nextSample(); //We're finished with this sample so move to next sample

  55.     Serial.print(F("red="));
  56.     Serial.print(redBuffer[i], DEC);
  57.     Serial.print(F(", ir="));
  58.     Serial.println(irBuffer[i], DEC);
  59.   }

  60.   //calculate heart rate and SpO2 after first 100 samples (first 4 seconds of samples)
  61.   maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);

  62.   //Continuously taking samples from MAX30102.  Heart rate and SpO2 are calculated every 1 second
  63.   while (1)
  64.   {
  65.     //dumping the first 25 sets of samples in the memory and shift the last 75 sets of samples to the top
  66.     for (byte i = 25; i < 100; i++)
  67.     {
  68.       redBuffer[i - 25] = redBuffer[i];
  69.       irBuffer[i - 25] = irBuffer[i];
  70.     }

  71.     //take 25 sets of samples before calculating the heart rate.
  72.     for (byte i = 75; i < 100; i++)
  73.     {
  74.       while (particleSensor.available() == false) //do we have new data?
  75.         particleSensor.check(); //Check the sensor for new data

  76.       digitalWrite(readLED, !digitalRead(readLED)); //Blink onboard LED with every data read

  77.       redBuffer[i] = particleSensor.getRed();
  78.       irBuffer[i] = particleSensor.getIR();
  79.       particleSensor.nextSample(); //We're finished with this sample so move to next sample

  80.       //send samples and calculation result to terminal program through UART
  81.       Serial.print(F("red="));
  82.       Serial.print(redBuffer[i], DEC);
  83.       Serial.print(F(", ir="));
  84.       Serial.print(irBuffer[i], DEC);

  85.       Serial.print(F(", HR="));
  86.       Serial.print(heartRate, DEC);

  87.       Serial.print(F(", HRvalid="));
  88.       Serial.print(validHeartRate, DEC);

  89.       Serial.print(F(", SPO2="));
  90.       Serial.print(spo2, DEC);

  91.       Serial.print(F(", SPO2Valid="));
  92.       Serial.println(validSPO2, DEC);
  93.     }

  94.     //After gathering 25 new samples recalculate HR and SP02
  95.     maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);
  96.   }
  97. }
复制代码

上传草图后,将手指尽可能稳定地放在传感器上,等待几秒钟让读数有意义。您会看到这样的结果。

MAX30102-Heart-Rate-and-Oxygen-Saturation-Output.jpg

回复

使用道具 举报

_viv
发表于: 2023-3-19 13:45:56 | 显示全部楼层

作者你好,我想问一下
byte pulseLED = 11; //Must be on PWM pin
byte readLED = 13; //Blinks with each data read
这是连接了Arduino uno板子的11、13口吗?
回复

使用道具 举报

_viv
发表于: 2023-3-19 13:49:22 | 显示全部楼层

作者你好,我想请问一下
测量氧饱和度 (SpO2)
pulseLED = 11;
byte readLED = 13
是连接板子的11、13IO口吗
回复

使用道具 举报

horsetail
发表于: 2023-4-18 15:03:46 | 显示全部楼层

不用
只需要连接四个引脚就行了
回复

使用道具 举报

风风
发表于: 2024-1-17 20:04:36 | 显示全部楼层

您好,用esp32控制时,串口监视器为什么一直显示复位呀
回复

使用道具 举报

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

本版积分规则

主题 700 | 回复: 1480



手机版|

GMT+8, 2024-4-19 04:49 , Processed in 0.143074 second(s), 6 queries , Gzip On, MemCache On. Powered by Discuz! X3.5

YiBoard一板网 © 2015-2022 地址:河北省石家庄市长安区高营大街 ( 冀ICP备18020117号 )

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