Точный мониторинг пульса и SpO₂ с MAX30102 и Arduino: OLED-дисплей и звуковой индикатор
Компоненты и материалы
| Компонент | Количество |
|---|---|
| Arduino UNO | 1 |
| OLED-дисплей 128×32 (Adafruit SSD1306, I²C) | 1 |
| Пьезопищалка (buzzer) | 1 |
| Модуль MAX30102 (пульсоксиметр/сердечный ритм) | 1 |
О проекте
Введение
В этом уроке подключаем модуль MAX30102 (пульсоксиметрия и измерение частоты сердечных сокращений) к Arduino UNO, добавляем OLED-дисплей и пьезопищалку для визуального и звукового индицирования пульса.
BPM (ударов в минуту) в покое у здорового человека 65–75, у спортсменов — ниже. SpO₂ (насыщение кислородом) норма — выше 95%. Модули MAX30102 бывают разными производителями (у меня WAVGAT) — важна только сама микросхема MAX30102.
Компоненты
На фото: модуль MAX30102, OLED 128×32, пьезопищалка, Arduino UNO.
Тестирование
Использованы примеры из библиотеки SparkFun_MAX3010x. Модифицированный скетч «HeartRate» просит приложить палец к датчику. Нужно постоять неподвижно, пока пищалка не начнёт бипнуть в такт пульсу (или анимация на OLED не синхронизируется). Затем отображается средний BPM (усреднение по 4 измерениям — точнее).
Создание битмапов для OLED
Анимация сердечка: при обнаружении пальца рисуется маленькое сердечко, при регистрации удара — большое на короткое время. Два битмапа (32×32 и 24×21 пиксель) хранятся в массивах logo2_bmp и logo3_bmp.
Как сделать свои битмапы:
- Найти чёрно-белую картинку нужного размера (меньше 128×32).
- Скачать LCD Assistant.
- Открыть картинку: File → Load Image.
- Настройки: Byte orientation: Vertical, Size: 32×32 (или ваш размер), Output: Monochrome.
- File → Save Output — получите C-массив.
- В коде:
display.drawBitmap(x, y, имя_массива, ширина, высота, WHITE);
Код
Основной скетч: MAX_BPM_OLED_Buzzer.ino
/* MAX30102 + OLED 128x32 I2C + Buzzer + Arduino UNO
* Отображает средний BPM, анимацию сердца и звуковой сигнал при каждом ударе
* Основан на примере HeartRate из библиотеки SparkFun MAX3010x
* Подробности: www.surtrtech.com / YouTube SurtrTech
*/
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Wire.h>
#include "MAX30105.h"
#include "heartRate.h"
MAX30105 particleSensor;
const byte RATE_SIZE = 4;
byte rates[RATE_SIZE];
byte rateSpot = 0;
long lastBeat = 0;
float beatsPerMinute;
int beatAvg;
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Маленькое сердечко (24x21)
static const unsigned char PROGMEM logo2_bmp[] = {
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
};
// Большое сердечко (32x32)
static const unsigned char PROGMEM logo3_bmp[] = {
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() {
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.display();
delay(3000);
particleSensor.begin(Wire, I2C_SPEED_FAST);
particleSensor.setup();
particleSensor.setPulseAmplitudeRed(0x0A);
}
void loop() {
long irValue = particleSensor.getIR();
if (irValue > 7000) { // палец на датчике
display.clearDisplay();
display.drawBitmap(5, 5, logo2_bmp, 24, 21, WHITE);
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(50, 0);
display.println("BPM");
display.setCursor(50, 18);
display.println(beatAvg);
display.display();
if (checkForBeat(irValue)) { // удар обнаружен
display.clearDisplay();
display.drawBitmap(0, 0, logo3_bmp, 32, 32, WHITE);
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(50, 0);
display.println("BPM");
display.setCursor(50, 18);
display.println(beatAvg);
display.display();
tone(3, 1000);
delay(100);
noTone(3);
long delta = millis() - lastBeat;
lastBeat = millis();
beatsPerMinute = 60 / (delta / 1000.0);
if (beatsPerMinute < 255 && beatsPerMinute > 20) {
rates[rateSpot++] = (byte)beatsPerMinute;
rateSpot %= RATE_SIZE;
beatAvg = 0;
for (byte x = 0; x < RATE_SIZE; x++) beatAvg += rates[x];
beatAvg /= RATE_SIZE;
}
}
} else { // палец снят
beatAvg = 0;
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(30, 5);
display.println("Please Place");
display.setCursor(30, 15);
display.println("your finger");
display.display();
noTone(3);
}
}
Используемые библиотеки
Схема подключения
Оба модуля (MAX30102 и OLED) — I²C (SDA/SCL к A4/A5 на Uno). Пьезопищалка: «-» на GND, «+» через резистор на D3.
Производственный процесс
- Интегрированная система контроля доступа с QR, RFID и верификацией температуры
- Подключение нескольких DS18B20 1-Wire датчиков к Raspberry Pi для точного мониторинга температуры
- Создайте автоматизированную аэропоническую систему с Raspberry Pi и датчиком влажности
- Система удалённого мониторинга сердечного ритма с алертами AWS IoT
- Создание робота на Raspberry Pi и Python: полное руководство
- Интеграция термопары с Arduino Portenta H7 через MAX6675
- Создание игры в реальном времени на Arduino Nano с гироскопом MPU-6050 и OLED-дисплеем
- IoT-монитор пульса в реальном времени на Arduino и MAX30100
- Точный измерятель пульса на фоторезисторе и Arduino: сборка и настройка
- Максимизация пространства мастерской с Visual Components, Matterport и автоматизацией ProFeeder X