산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

MAX30102 펄스 옥시미터로 정밀 심박수 & SpO₂ 모니터링 - 아두이노 우노

부품 및 소모품

부품 수량 비고
아두이노 우노 1
아다프루트 OLED 128x32 1 I2C 인터페이스
부저 1 심박 동기 비프음용
맥심 MAX30102 고감도 펄스 옥시미터/심박 센서 1 웨어러블 헬스용, WAVGAT 모듈 등 변형 상관없음 (IC가 MAX30102면 됨)

프로젝트 소개

소개

안녕하세요. 이 튜토리얼에서는 MAX30102 펄스 옥시미터/심박수 모니터 모듈을 아두이노 우노와 인터페이스하고, OLED 디스플레이와 부저를 활용해 BPM(분당 심박수) 측정 프로젝트를 만듭니다.

구성품

MAX30102 펄스 옥시미터로 정밀 심박수 & SpO₂ 모니터링 - 아두이노 우노
사용 부품들

테스트

사용한 코드는 스파크펀(SparkFun) MAX3010x 라이브러리 예제들로 명확합니다. OLED와 부저용으로 만든 코드는 라이브러리의 "HeartRate" 예제를 수정해 손가락을 센서에 대라는 안내를 추가했습니다.

MAX30102 펄스 옥시미터로 정밀 심박수 & SpO₂ 모니터링 - 아두이노 우노
"손가락을 대세요" 안내 화면

손가락을 대고 가만히 있으면 부저 '삐-' 소리가 심박과 동기화되거나 OLED 애니메이션이 심박과 맞춰지며, 그때 정확한 BPM을 읽을 수 있습니다.

참고: 코드에서 평균 BPM을 출력합니다. 4회 BPM 평균이라 더 정확합니다. 약간 시간 주세요.

MAX30102 펄스 옥시미터로 정밀 심박수 & SpO₂ 모니터링 - 아두이노 우노
평균 BPM 표시 화면

OLED용 비트맵 만들기

심박 감지 시 작은 하트 → 큰 하트 비트맵 전환으로 박동 애니메이션 구현. 부저 소리와 동기화.

MAX30102 펄스 옥시미터로 정밀 심박수 & SpO₂ 모니터링 - 아두이노 우노
코드에 포함된 두 하트 비트맵 (32x32, 24x21 픽셀)

비트맵 생성 과정:

  1. 검은 그림/흰 배경 이미지 준비 (OLED 해상도 128x32, 비트맵은 이보다 작게)
  2. LCD Assistant 다운로드 및 실행
  3. 이미지 불러오기 → 설정 조정 (수평/수직 스캔 등) → C 배열로 내보내기
  4. 생성된 배열을 코드에 복사
MAX30102 펄스 옥시미터로 정밀 심박수 & SpO₂ 모니터링 - 아두이노 우노
LCD Assistant 설정 예시
MAX30102 펄스 옥시미터로 정밀 심박수 & SpO₂ 모니터링 - 아두이노 우노
생성된 16진수 배열

코드에서 호출 예시:

display.drawBitmap(5, 5, logo2_bmp, 24, 21, WHITE);
// display.drawBitmap(시작 x, 시작 y, 비트맵 이름, 너비, 높이, 색상);

손가락 감지 시 logo2(작은 하트), 심박 감지 시 logo3(큰 하트) 호출.

소스 코드

/* This code works with MAX30102 + 128x32 OLED i2c + Buzzer and Arduino UNO
 * It displays the Average BPM on the screen, with an animation and a buzzer sound
 * everytime a heart pulse is detected
 * It's a modified version of the HeartRate library example
 * Refer to www.surtrtech.com for more details or SurtrTech YouTube channel */
#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); // 빨간 LED 낮게 설정 (센서 동작 표시)
}

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) == true) { // 심박 감지
      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); // 부저 100ms 비프 (짧게 줄여도 됨)
      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;
      }
    }
  }

  if (irValue < 7000) { // 손가락 미감지
    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);
  }
}

필수 라이브러리

회로도

두 모듈 모두 I2C 인터페이스. 2핀 부저(-)는 GND, (+)는 저항 거쳐 D3 핀에 연결.

MAX30102 펄스 옥시미터로 정밀 심박수 & SpO₂ 모니터링 - 아두이노 우노

제조공정

  1. 통합 QR, RFID, 온도 검증 출입 통제 시스템
  2. 라즈베리 파이 다중 DS18B20 1-와이어 센서 연결으로 정확한 온도 모니터링
  3. 라즈베리 파이와 습도 센서로 자동 에어로포닉스 시스템 만들기
  4. AWS IoT 알림으로 원격 심박수 모니터링 시스템 구축
  5. 라즈베리 파이와 파이썬으로 로봇 만들기: 완전 가이드
  6. MAX6675 IC로 아두이노 포텐타 H7에 열전대 센서 연동하기
  7. 아두이노 나노와 MPU-6050으로 실시간 자이로스코프 게임 만들기
  8. 아두이노와 MAX30100으로 만드는 실시간 IoT 심박수 모니터
  9. 포토레지스터와 아두이노로 정확한 심박수 모니터 만들기
  10. Visual Components, Matterport & ProFeeder X 자동화로 작업장 공간 최대화