Cirkit Designer LogoCirkit DesignerYour all-in-one circuit design IDE Launch Cirkit Designer App

Arduino Nano-Based ECG Data Logger with OLED Display and SD Card Storage

View and Edit Project In Cirkit DesignerImage of Arduino Nano-Based ECG Data Logger with OLED Display and SD Card Storage

Circuit Documentation

Summary

The circuit is designed to collect and display electrocardiogram (ECG) data using an AD8232 Heart Rate Monitor. The data is sampled at a rate of 500 Hz and written to a microSD card. An OLED display shows the z-scored ECG curve, which can be turned off with a rocker switch. The Arduino Nano serves as the central processing unit, interfacing with the heart rate monitor, SD card module, and OLED display. A TP4056 module with an 18650 battery in a holder provides power management, and an MT3608 boost converter steps up the voltage to power the Arduino Nano. The circuit also includes a battery level indicator to monitor the battery status.

Component List

Arduino Nano

TP4056

AD8232 Heart Rate Monitor

Rocker Switch (x2)

18650 Battery in Holder

Adafruit OLED Monochrome 128x32 I2C

Battery Level Indicator

Micro SD Card Module

MT3608

Wiring Details

Arduino Nano

TP4056

AD8232 Heart Rate Monitor

Rocker Switch (x2)

18650 Battery in Holder

Adafruit OLED Monochrome 128x32 I2C

Battery Level Indicator

Micro SD Card Module

MT3608

Documented Code

/*
 * Arduino Sketch for ECG Data Collection and Display
 *
 * This code collects ECG data from the AD8232 Heart Rate Monitor at a sampling
 * rate of at least 500 Hz. The amplitude and time are written to a microSD card
 * and the z-scored ECG curve is displayed on an OLED display. The display can
 * be turned off using a rocker switch.
 */

#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

#define ECG_PIN A0
#define LO_PLUS_PIN 3
#define LO_MINUS_PIN 2
#define SDN_PIN 4
#define SD_CS_PIN 10
#define ROCKER_SWITCH_PIN 5

File dataFile;

const int sampleRate = 500; // 500 Hz
const int sampleInterval = 1000 / sampleRate; // in milliseconds
const int bufferSize = 500; // Buffer size for z-score calculation
int ecgBuffer[bufferSize];
int bufferIndex = 0;

void setup() {
  pinMode(LO_PLUS_PIN, INPUT);
  pinMode(LO_MINUS_PIN, INPUT);
  pinMode(SDN_PIN, OUTPUT);
  pinMode(ROCKER_SWITCH_PIN, INPUT);
  digitalWrite(SDN_PIN, LOW); // Enable AD8232

  Serial.begin(9600);
  if (!SD.begin(SD_CS_PIN)) {
    Serial.println("SD card initialization failed!");
    return;
  }
  dataFile = SD.open("ecgdata.txt", FILE_WRITE);
  if (!dataFile) {
    Serial.println("Error opening ecgdata.txt");
    return;
  }

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.display();
  delay(2000);
  display.clearDisplay();
}

void loop() {
  static unsigned long lastSampleTime = 0;
  unsigned long currentTime = millis();
  if (currentTime - lastSampleTime >= sampleInterval) {
    lastSampleTime = currentTime;
    int ecgValue = analogRead(ECG_PIN);
    dataFile.print(currentTime);
    dataFile.print(",");
    dataFile.println(ecgValue);
    dataFile.flush();

    ecgBuffer[bufferIndex] = ecgValue;
    bufferIndex = (bufferIndex + 1) % bufferSize;

    if (digitalRead(ROCKER_SWITCH_PIN) == HIGH) {
      display.clearDisplay();
      display.setCursor(0, 0);
      display.print("ECG: ");
      display.println(zScore(ecgValue));
      drawECGCurve();
      display.display();
    } else {
      display.clearDisplay();
      display.display();
    }
  }
}

float zScore(int value) {
  float mean = 0;
  float stdDev = 0;
  for (int i = 0; i < bufferSize; i++) {
    mean += ecgBuffer[i];
  }
  mean /= bufferSize;
  for (int i = 0; i < bufferSize; i++) {
    stdDev += pow(ecgBuffer[i] - mean, 2);
  }
  stdDev = sqrt(stdDev / bufferSize);
  return (value - mean) / stdDev;
}

void drawECGCurve() {
  int x = 0;
  for (int i = 0; i < bufferSize - 1; i++) {
    int y1 = map(zScore(ecgBuffer[i]), -3, 3, 0, display.height());
    int y2 = map(zScore(ecgBuffer[i + 1]), -3, 3, 0, display.height());
    display.drawLine(x, y1, x + 1, y2, WHITE);
    x++;
    if (x >= display.width()) {
      x = 0;
    }
  }
}

This code is responsible for