Общие сведения
Датчик пульсоксиметрии MAX30102 — плата с интегрированным сенсорным модулем, которая позволяет определять частоту сердечных сокращений, то есть пульс, а так же уровень насыщения крови кислородом (SpO2). Помимо этого, в сенсор встроен температурный датчик, с помощью которого вы можете получить значение температуры (в Цельсиях и Фаренгейтах) окружающей среды.
Видео
Характеристики
- Оптический модуль с возможностью измерения ЧСС (пульс), SpO2 (степень насыщения крови кислородом) и температуры среды;
- Адрес на шине I2C: 0x57;
- Входное напряжение: 5В;
- Габариты датчика: 15.5мм х 19.5мм х 2.5мм (без гребёнки);
- Рабочая температура: -40°С ... +85°С;
Подключение
Для удобства подключения к Arduino воспользуйтесь Trema Shield, Trema Power Shield, Motor Shield или Trema Set Shield.
Так как датчик работает по шине I2C, то его выводы подключаются следующим образом:

| MAX30102 | Trema Shield |
|---|---|
| VIN | Vcc |
| SDA | SDA |
| SCL | SCL |
| GND | Gnd |
Питание
Датчик питается от напряжения 5 В.
Подробнее о датчике
Датчик предназначен для создания портативных носимых приборов контроля сердечного ритма и насыщенности крови кислородом.
В состав самой микросхемы входят светодиоды (ИК- и красного цвета), а так же фотоприемник и оптические элементы. Важно так же отметить, что полученные сигналы имеют низкий уровень шума. В ходе измерений испускаемый красный и инфракрасный свет регулируется встроенными программными методами за счёт изменения интенсивности свечения и его (свечения) длительности.
Датчик может быть программно переведен в режим ожидания, а благодаря технологии сверхнизкого потребления энергии в режиме ожидания ток потребления будет практически нулевой.
Примеры
Во время измерения любых значений необходимо, чтобы палец находился в постоянном зафиксированном положении и давил на сенсор с постоянным неизменяющимся давлением (лёгкое нажатие), или же, в случае с расположением на запястье, находился в неподвижном положении всё время измерений. Для решения этой задачи предлагается воспользоваться обычной канцелярской резинкой или ремешком, которые стоит продеть в петли модуля и зафиксировать модуль на пальце или запястье. В противном случае точность измерений может существенно снизиться.
Вывод значений ЧСС в монитор порта.
#include "Wire.h" // Подключаем библиотеку для работы с шиной I2C
#include "MAX30105.h" // Подключаем библиотеку для работы с модулем
#include "heartRate.h" // Подключаем блок для работы с ЧСС (пульс)
MAX30105 PARTICLE_SENSOR; // Создаём объект для работы с библиотекой
//--------------------------//
const byte RATE_SIZE = 4; // Коэффициент усреднения. ЧЕм больше число, тем больше усреднение показаний.
byte rates[RATE_SIZE]; // Массив со значениями ЧСС
byte rateSpot = 0; // Переменная с порядковым номером значения в массиве
long lastBeat = 0; // Время последнего зафиксированного удара
float beatsPerMinute; // Создаём переменную для хранения значения ЧСС
int beatAvg; // Создаём переменную для хранения усреднённого значения ЧСС
//----------------------------------------------------//
void setup() {
Serial.begin(115200); // Инициируем работу с монитором последовательного порта на скорости 115200 бод
if (!PARTICLE_SENSOR.begin()) { // Инициируем работу с модулем. Если инициализация не прошла, то
Serial.println("MAX30105 was not found"); // выводим сообщение об этом в монитор последовательного порта
while (1); // и останавливаем дальнейшее выполнение скетча
}
Serial.println("Place your finger on the sensor"); // выводим сообщение "Положите палец сверху на сенсор"
PARTICLE_SENSOR.setup(); // Устанавливаем настройки для сенсора по умолчанию
PARTICLE_SENSOR.setPulseAmplitudeRed(0x0A); // Выключаем КРАСНЫЙ светодиод для того, чтобы модуль начал работу
PARTICLE_SENSOR.setPulseAmplitudeGreen(0); // Выключаем ЗЕЛЁНЫЙ светодиод
}
//------------------------------------------------------//
void loop() {
long irValue = PARTICLE_SENSOR.getIR(); // Считываем значение отражённого ИК-светодиода (отвечающего за пульс) и
if (checkForBeat(irValue) == true) { // если пульс был зафиксирован, то
long delta = millis() - lastBeat; // находим дельту по времени между ударами
lastBeat = millis(); // Обновляем счётчик
beatsPerMinute = 60 / (delta / 1000.0); // Вычисляем количество ударов в минуту
if (beatsPerMinute < 255 && beatsPerMinute > 20) { // Если количество ударов в минуту находится в промежутке между 20 и 255, то
rates[rateSpot++] = (byte)beatsPerMinute; // записываем это значение в массив значений ЧСС
rateSpot %= RATE_SIZE; // Задаём порядковый номер значения в массиве, возвращая остаток от деления и присваивая его переменной rateSpot
beatAvg = 0; // Обнуляем переменную и
for (byte x = 0 ; x < RATE_SIZE ; x++) { // в цикле выполняем усреднение значений (чем больше RATE_SIZE, тем сильнее усреднение)
beatAvg += rates[x]; // путём сложения всех элементов массива
}
beatAvg /= RATE_SIZE; // а затем деления всей суммы на коэффициент усреднения (на общее количество элементов в массиве)
}
}
Serial.print("IR="); // Выводим в монитор последовательного порта текст про значение ИК-светдиода
Serial.print(irValue); // Выводим в монитор последовательного порта значение с ИК-светодиода
Serial.print(", BPM="); // Выводим в монитор последовательного порта текст про значение ЧСС
Serial.print(beatsPerMinute); // Выводим в монитор последовательного порта значение ЧСС
Serial.print(", Avg BPM="); // Выводим в монитор последовательного порта текст про усреднённую ЧСС
Serial.print(beatAvg); // Выводим в монитор последовательного порта значение усреднённой ЧСС
if (irValue < 50000) Serial.print(" No finger?"); // Если значение ИК-светодиода меньше указанного, то выводим текст о том, что палец убран с датчика
Serial.println(); // Выводим в монитор последовательного порта переход на новую строку
}
Вывод значений температуры окружающей среды в монитор порта.
#include "Wire.h" // Подключаем библиотеку для работы с шиной I2C
#include "MAX30105.h" // Подключаем библиотеку для работы с модулем
MAX30105 PARTICLE_SENSOR; // Создаём объект для работы с библиотекой
void setup() {
Serial.begin(9600); // Инициируем работу с монитором последовательного порта на скорости 9600 бод
if (!PARTICLE_SENSOR.begin()) { // Инициируем работу с модулем. Если инициализация не прошла, то
Serial.println("MAX30105 was not found."); // выводим сообщение об этом в монитор последовательного порта
while (1); // и останавливаем дальнейшее выполнение скетча
}
// Встроенные светодиоды потребляют незначительный ток,
// однако, если вы хотите исключить их возможное влияние
// на результат, то используйте следующую строку:
PARTICLE_SENSOR.setup(0); // Настраиваем сенсор на работу с выключенными светодиодами
// Если же вы хотите запустить сенсор в стандартном
// режиме, то раскомментируйте следующую строку:
//PARTICLE_SENSOR.setup(); // Устанавливаем настройки для сенсора по умолчанию
PARTICLE_SENSOR.enableDIETEMPRDY(); // Включаем поддержку прерываний для датчика температуры. Это ОБЯЗАТЕЛЬНЫЙ параметр
}
void loop() {
float temperature = PARTICLE_SENSOR.readTemperature(); // Создаём переменную с плавающей точкой и записываем в неё полученное от датчика значение (в Цельсиях)
Serial.print("temperature C = "); // Выводим в монитор последовательного порта текст
Serial.print(temperature, 4); // Выводим в монитор последовательного порта значение температуры в Цельсиях
float temperatureF = PARTICLE_SENSOR.readTemperatureF(); // Создаём переменную с плавающей точкой и записываем в неё полученное от датчика значение (в Фаренгейтах)
Serial.print(" | temperature F = "); // Выводим в монитор последовательного порта текст
Serial.print(temperatureF, 4); // Выводим в монитор последовательного порта значение температуры в Фаренгейтах
Serial.println(); // Переходим на новую строку
}
Вывод значений
уровня SpO2
в монитор порта.
#define MAX_BRIGHTNESS 255 // Задаём переменную максимальной яркости свечения светодиода
//--------------------------------------------------//
#include "Wire.h" // Подключаем библиотеку для работы с шиной I2C
#include "MAX30105.h" // Подключаем библиотеку для работы с модулем
#include "spo2_algorithm.h" // Подключаем блок работы с насыщением крови кислородом
MAX30105 PARTICLE_SENSOR; // Создаём объект для работы с библиотекой
//--------------------------------------------------//
// 32-битная переменная занимает в памяти 4 байта. Дальше используется 2 массива, каждый из которых содержит 100 значений.
// Если эти переменные будут 32-х битные, то они займут 100*4*2 = 800 байт. Arduino UNO имеет всего 2 Килобайт (2048 байт) памяти,
// поэтому при создании всех остальных переменных её объёма памяти не хватит. В связи с этим при запуске скетча выполняется проверка
// типа платы. Если это Arduino UNO (имеющая на борту микроконтроллер ATmega328), то будут созданы 16-битные массивы, чтобы занимать
// в 2 раза меньше места. Так как данные с сенсора считываются в 32-битном формате, то при записи в 16-битный массив эти значения
// будут автоматически обрезаны.
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
uint16_t irBuffer[100]; // 16-битный массив данных от сенсора со значениями от ИК-светодиода
uint16_t redBuffer[100]; // 16-битный массив данных от сенсора со значениями от красного светодиода
#else
uint32_t irBuffer[100]; // 32-битный массив данных от сенсора со значениями от ИК-светодиода
uint32_t redBuffer[100]; // 32-битный массив данных от сенсора со значениями от красного светодиода
#endif
//--------------------------------------------------//
int32_t bufferLength; // длина буфера данных
int32_t spo2; // значение SpO2 (насыщенности крови кислородом)
int8_t validSPO2; // флаг валидности значений сенсора по SpO2
int32_t heartRate; // значение ЧСС
int8_t validHeartRate; // флаг валидности значений сенсора по ЧСС
//--------------------------------------------------//
void setup() {
Serial.begin(115200); // инициируем работу с монитором последовательного порта на скорости 115200 бод
if (!PARTICLE_SENSOR.begin()) { // инициируем работу с сенсором. Если этого не произошло, то
Serial.println(F("MAX30105 was not found.")); // Выводим сообщением об этом и
while (1); // останавливаем дальнейшее выполнение скетча
}
Serial.println(F("Press any key!")); // Прежде, чем переходить к считыванию, выводим в монитор порта сообщение и
while (Serial.available() == 0); // ждём отправки любого символа в монитор порта (нажмите Enter, находясь в строке отправки)
Serial.read(); // Если символ получен, то скетч будет выполнен дальше
//------------------------------------------------//
// Блок настроек сенсора для работы в режиме определения насыщенности крови кислородом и определения ЧСС:
byte ledBrightness = 60; // Задаём яркость работы светодиода, при этом потребление тока будет следующим: 0 - 0мА, 255 - 50 мА
byte sampleAverage = 4; // Устанавливаем коэффициент усреднения. Возможные варианты значений: 1, 2, 4, 8, 16, 32
byte ledMode = 2; // Устанавливаем режим работы светодиодов на сенсоре: 1 - только красный (Red only), 2 - красный и ИК (Red + IR), 3 - красный, ИК и зелёный (Red + IR + Green)
byte sampleRate = 100; // Устанавливаем частоту дискретизации (сглаживания сигнала). Варианты: 50, 100, 200, 400, 800, 1000, 1600, 3200
int pulseWidth = 411; // Устанавливаем ширину импульса. Варианты: 69, 118, 215, 411
int adcRange = 4096; // Устанавливаем диапазон значений с АЦП. Варианты: 2048(11 бит), 4096(12 бит), 8192(13 бит), 16384(14 бит)
//------------------------------------------------//
// Настраиваем сенсор согласно вышеуказанным настройкам
PARTICLE_SENSOR.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange);
}
//----------------------------------------------------//
void loop() {
bufferLength = 100; // Устанавливаем длину буфера равным 100 (куда будут записаны пакеты по 25 значений в течении 4 секунд)
// считываем первые 100 значений и определяем диапазон значений сигнала:
for (byte i = 0 ; i < bufferLength ; i++) { // проходим в цикле по буферу и
while (PARTICLE_SENSOR.available() == false) // отправляем сенсору запрос на получение новых данных
PARTICLE_SENSOR.check();
redBuffer[i] = PARTICLE_SENSOR.getRed(); // Записываем в массив значения сенсора, полученные при работе с КРАСНЫМ светодиодом
irBuffer[i] = PARTICLE_SENSOR.getIR(); // Записываем в массив значения сенсора, полученные при работе с ИК светодиодом
PARTICLE_SENSOR.nextSample(); // Как только в буфер было записано 100 значений - отправляем сенсору команду начать вычислять значения ЧСС и SpO2
Serial.print(F("red=")); // Выводим текст в монитор последовательного порта
Serial.print(redBuffer[i], DEC); // Выводим значение переменной redBuffer[i] в монитор последовательного порта
Serial.print(F(", ir=")); // Выводим текст в монитор последовательного порта
Serial.println(irBuffer[i], DEC); // Выводим значение переменной irBuffer[i] в монитор последовательного порта
}
// Вычисляем значения ЧСС и SpO2 по первым полученным 100 значениям:
maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);
// Непрерывно считываем значений с сенсора и вычисляем значения ЧСС и SpO2 каждую секунду
while (1) {
// Сбрасываем первые полученные 25 значений из буфера, а оставшиеся 75 сдвигаем влево в массиве
for (byte i = 25; i < 100; i++) {
redBuffer[i - 25] = redBuffer[i];
irBuffer[i - 25] = irBuffer[i];
}
// Получаем новые 25 значений прежде чем переходить к вычислению ЧСС
for (byte i = 75; i < 100; i++) {
while (PARTICLE_SENSOR.available() == false) { // Опрашиваем сенсор на предмет наличия новых значений
PARTICLE_SENSOR.check();
}
redBuffer[i] = PARTICLE_SENSOR.getRed(); // Записываем в массив значения сенсора, полученные при работе с КРАСНЫМ светодиодом
irBuffer[i] = PARTICLE_SENSOR.getIR(); // Записываем в массив значения сенсора, полученные при работе с ИК светодиодом
PARTICLE_SENSOR.nextSample(); // Как только в буфер было записано 100 значений - отправляем сенсору команду начать вычислять значения ЧСС и SpO2
Serial.print(F("red=")); // Выводим текст в монитор последовательного порта
Serial.print(redBuffer[i], DEC); // Выводим значение переменной redBuffer[i] в монитор последовательного порта
Serial.print(F(", ir=")); // Выводим текст в монитор последовательного порта
Serial.print(irBuffer[i], DEC); // Выводим значение переменной irBuffer[i] в монитор последовательного порта
Serial.print(F(", HR=")); // Выводим текст в монитор последовательного порта
Serial.print(heartRate, DEC); // Выводим значение переменной heartRate в монитор последовательного порта
Serial.print(F(", HRvalid=")); // Выводим текст в монитор последовательного порта
Serial.print(validHeartRate, DEC); // Выводим значение переменной validHeartRate в монитор последовательного порта
Serial.print(F(", SPO2=")); // Выводим текст в монитор последовательного порта
Serial.print(spo2, DEC); // Выводим значение переменной spo2 в монитор последовательного порта
Serial.print(F(", SPO2Valid=")); // Выводим текст в монитор последовательного порта
Serial.println(validSPO2, DEC); // Выводим значение переменной validSPO2 в монитор последовательного порта
}
// После получения очередного пакета из 25 значений повторно считаем значения ЧСС и SpO2
maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);
}
}
Вывод значений ЧСС на светодиодную матрицу 64х32 с анимацией:
#include "Wire.h" // Подключаем библиотеку для работы с шиной I2C
#include "MAX30105.h" // Подключаем библиотеку для работы с модулем
#include "heartRate.h" // Подключаем блок для работы с ЧСС (пульс)
#include "RGBmatrixPanel.h" // Подключаем библиотеку для работы с матрицей
//----------------------------//
// Используем эти выводы, если матрица подключена к Arduino UNO
//#define CLK 8
//#define OE 9
//#define LAT 10
// Используем эти выводы, если матрица подключена к Arduino MEGA
//#define CLK 11
//#define OE 9
//#define LAT 10
// Используем эти выводы, если матрица подключена к Piranha ULTRA
#define CLK 11 // Вывод Arduino, к которому подключён вывод CLK матрицы
#define OE 12 // Вывод Arduino, к которому подключён вывод OE матрицы
#define LAT 13 // Вывод Arduino, к которому подключён вывод LAT матрицы
#define A A0 // Вывод Arduino, к которому подключён вывод A матрицы
#define B A1 // Вывод Arduino, к которому подключён вывод B матрицы
#define C A2 // Вывод Arduino, к которому подключён вывод C матрицы
#define D A3 // Вывод Arduino, к которому подключён вывод D матрицы
#define RATE_SIZE 5 // Коэффициент усреднения, равный количеству элементов в массиве усреднения
#define ZUMMER 2 // Вывод, к которому подключен зуммер
#define OFF 0 // Переменная, имеющая значение LOW или 0
#define ON 1 // Переменная, имеющая значение HIGH или 1
MAX30105 PARTICLE_SENSOR; // Создаём объект для работы с библиотекой
//----------------------------//
// Объявляем объект MATRIX для работы с матрицей 64х32, включаем двойную буферизацию
RGBmatrixPanel MATRIX(A, B, C, D, CLK, LAT, OE, false, 64);
//----------------------------//
byte rates[RATE_SIZE]; // Массив со значениями ЧСС
byte rateSpot = 0; // Переменная с порядковым номером значения в массиве
bool no_finger_flag = true; // Флаг отсутствия приложенного к сенсору пальца
bool new_beat_flag = true; // Флаг считывания нового удара пульса
long lastBeat = 0; // Время последнего зафиксированного удара
float beatsPerMinute; // Создаём переменную для хранения значения ЧСС
int beatAvg; // Создаём переменную для хранения усреднённого значения ЧСС
//----------------------------//
// Указываем 2 массива с изображениями сердца - малого размера и большого, для создания анимации
static const unsigned char PROGMEM small_heart[] =
{ 0x03, 0xC0, 0xF0, 0x06, 0x71, 0x8C, 0x0C, 0x1B, 0x06, 0x18, 0x0E, 0x02, 0x10, 0x0C, 0x03, 0x10,
0x04, 0x01, 0x10, 0x04, 0x01, 0x10, 0x40, 0x01, 0x10, 0x40, 0x01, 0x10, 0xC0, 0x03, 0x08, 0x88,
0x02, 0x08, 0xB8, 0x04, 0xFF, 0x37, 0x08, 0x01, 0x30, 0x18, 0x01, 0x90, 0x30, 0x00, 0xC0, 0x60,
0x00, 0x60, 0xC0, 0x00, 0x31, 0x80, 0x00, 0x1B, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x04, 0x00,
};
static const unsigned char PROGMEM large_heart[] =
{ 0x01, 0xF0, 0x0F, 0x80, 0x06, 0x1C, 0x38, 0x60, 0x18, 0x06, 0x60, 0x18, 0x10, 0x01, 0x80, 0x08,
0x20, 0x01, 0x80, 0x04, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x02, 0xC0, 0x00, 0x08, 0x03,
0x80, 0x00, 0x08, 0x01, 0x80, 0x00, 0x18, 0x01, 0x80, 0x00, 0x1C, 0x01, 0x80, 0x00, 0x14, 0x00,
0x80, 0x00, 0x14, 0x00, 0x80, 0x00, 0x14, 0x00, 0x40, 0x10, 0x12, 0x00, 0x40, 0x10, 0x12, 0x00,
0x7E, 0x1F, 0x23, 0xFE, 0x03, 0x31, 0xA0, 0x04, 0x01, 0xA0, 0xA0, 0x0C, 0x00, 0xA0, 0xA0, 0x08,
0x00, 0x60, 0xE0, 0x10, 0x00, 0x20, 0x60, 0x20, 0x06, 0x00, 0x40, 0x60, 0x03, 0x00, 0x40, 0xC0,
0x01, 0x80, 0x01, 0x80, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x30, 0x0C, 0x00,
0x00, 0x08, 0x10, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x01, 0x80, 0x00
};
//--------------------------------------------//
void setup() {
PARTICLE_SENSOR.begin(); // Инициируем работу с сенсором
MATRIX.begin(); // Инициируем работу с матрицей
MATRIX.setTextWrap(false); // Отключаем перенос текста на следующую строку
MATRIX.setTextSize(1); // Устанавливаем размер текста равным 1 (6 пикселей на символ)
pinMode(ZUMMER, OUTPUT); // Настраиваем вывод, к которому подключен зуммер, работать в режиме ВЫХОДА
PARTICLE_SENSOR.setup(); // Запускаем сенсор с настройками по умолчанию
PARTICLE_SENSOR.setPulseAmplitudeRed(0x0A); // Выключаем КРАСНЫЙ светодиод для того, чтобы модуль начал работу
PARTICLE_SENSOR.setPulseAmplitudeGreen(0); // Выключаем ЗЕЛЁНЫЙ светодиод
}
//----------------------------------------------------------------------------//
void loop() {
long irValue = PARTICLE_SENSOR.getIR(); // Считываем значение отражённого ИК-светодиода (отвечающего за пульс) и
if (irValue > 50000) { // если был зафиксирован приложенный к сенсору палец, то
no_finger_flag = true; // устанавливаем флаг отсутствия пальца
if (new_beat_flag == true) { // Проверяем, если флаг нового удара пульса установлен, то
new_beat_flag = false; // сбрасываем флаг нового удара сердца
MATRIX.fillScreen(0); // Очищаем экран
MATRIX.drawBitmap(5, 5, small_heart, 24, 21, MATRIX.Color333(3, 0, 0)); // Выводим изображение сердца малого размера
MATRIX.setCursor(37, 5); // Устанавливаем курсор
MATRIX.print("BPM:"); // Выводим текст
MATRIX.setCursor(40, 20); // Устанавливаем курсор
MATRIX.print(beatAvg); // Выводим количество ударов в минуту
MATRIX.swapBuffers(false); // Выводим изображение из буфера на матрицу
}
if (checkForBeat(irValue) == true) { // Если зафиксирован новый удар пульса, то
new_beat_flag = true; // устанавливаем флаг нового удара
long delta = millis() - lastBeat; // вычисляем дельту по времени между 2 соседними ударами
lastBeat = millis(); // обновляем счётчик времени
beatsPerMinute = 60 / (delta / 1000.0); // вычисляем "сырое" количество ударов в минуту
if (beatsPerMinute < 255 && beatsPerMinute > 20) { // Дополнительно отфильтровываем значение ударов в минуту и если оно попадает в выборку, то
rates[rateSpot++] = (byte)beatsPerMinute; // записываем новое значение в массив усреднения
rateSpot %= RATE_SIZE; // Задаём порядковый номер значения в массиве, возвращая остаток от деления и присваивая его переменной rateSpot
beatAvg = 0; // Обнуляем переменную и
for (byte x = 0 ; x < RATE_SIZE ; x++) // в цикле выполняем усреднение значений (чем больше RATE_SIZE, тем сильнее усреднение)
beatAvg += rates[x]; // путём сложения всех элементов массива
beatAvg /= RATE_SIZE; // а затем деления всей суммы на коэффициент усреднения (на общее количество элементов в массиве)
}
digitalWrite(ZUMMER, ON); // Включаем зуммер
MATRIX.fillRect(0, 0, 32, 32, MATRIX.Color333(0, 0, 0)); // Выводим квадрат размером 32х32, закрашенный чёрным, чтобы затереть изображение сердца малого размера
MATRIX.drawBitmap(0, 0, large_heart, 32, 32, MATRIX.Color333(3, 0, 0)); // Выводим рисунок сердца большого размера
MATRIX.swapBuffers(false); // Выводим изображение из буфера на матрицу
delay(100); // Ждём 100мс, чтобы зуммер и матрица отобразили изменения и включились
digitalWrite(ZUMMER, OFF); // Выключаем зуммер
}
}
if (irValue < 50000 && no_finger_flag == true ) { // Если пале убран с сенсора, то
for (byte x = 0 ; x < RATE_SIZE ; x++) { // проходим в цикле по массиву усреднения и
rates[x] = 0; // обнуляем его
}
beatAvg = 0; // обнуляем переменную со значением усреднённой ЧСС
no_finger_flag = false; // сбрасываем флаг отсутствия пальца на сенсоре, чтобы не заходить в этот блок при каждом выполнении цикла
new_beat_flag = true; // Устанавливаем флаг обнаружения пальца, чтобы в следующий проход цикла зайти в блок определения пульса
MATRIX.fillScreen(0); // Очищаем экран
MATRIX.setTextColor(MATRIX.Color333(3, 3, 3)); // Устанавливаем цвет текста
MATRIX.setCursor(3, 12); // Устанавливаем крусор
MATRIX.println("No finger!"); // Выводим тект о том, что палец не приложен
MATRIX.swapBuffers(false); // Выводим изображение из буфера на матрицу
}
}
Комплектация
- 1x Датчик пульсоксиметрии MAX30102;
- 1x 4-контактная гребёнка;
Ссылки
- DataSheet;
- Библиотека SparkFun_MAX3010x_Sensor_Library;

















