Guide no. 90
Three electrodes, an AD8232 module and Arduino UNO: the heart's trace on the Serial Plotter and an estimate of the heart rate. For learning, not for health checks.
By Ada Intelisano · informaticait.it technical team
- The AD8232 amplifies and filters the heart's very weak electrical signal; Arduino reads it on A0.
- It is not a medical device: no diagnosis, no health checks. If you have any concerns, see a doctor.
- Electrodes on the body only with Arduino running on batteries or connected to a laptop with the charger unplugged.
- The Serial Plotter draws the trace; the beats per minute it calculates are only an indication.
With every beat the heart produces an electrical impulse that reaches the skin, very faint. The AD8232 amplifies it and cleans it up, and Arduino draws it on the Serial Plotter. It helps you understand how an electrocardiogram works, and nothing more.
- This is not a medical device. SparkFun and DFRobot say so on their module pages: it is not for diagnosis or treatment. So no checks on your health or anyone else's, and no reading the trace for signs about the heart: if in doubt, see a doctor. Analog Devices notes that real medical equipment follows specific safety standards.
- Electrodes on the body only when everything runs on batteries: Arduino connected to a laptop with the charger unplugged, or to a 9 V battery. Never a desktop PC, never a laptop while it is charging, and no other cable to anything that is plugged into the mains (a monitor, a USB hub with its own power supply).
- Why: with the gel, the electrodes make very good contact with the skin. With the circuit connected to the 230 V mains, usually nothing happens, but in rare cases a current loop forms through the mains, and the person wearing the electrodes is part of it. That is why SparkFun recommends a battery, and M5Stack prints on its ECG module that you should use an isolated power supply.
1The parts
- the SparkFun SEN-12650 module, which comes without pins: solder a row of six pins into the holes from GND to SDN (guide no. 70). With it, the SparkFun CAB-12970 cable and three disposable electrodes;
- or the AD8232 kit: same board and same pins, with the cable and electrodes in the box;
- Arduino UNO with its USB cable, five female-to-male jumper wires, and a laptop that can run on its battery.
2How it works and how to wire it
This is a single-lead ECG: it measures the voltage between the right arm (RA) and the left arm (LA); the third electrode (RL, right leg) helps the AD8232 keep the noise down. The SparkFun board follows the Analog Devices “cardiac monitor” circuit: the signal is made 1100 times larger, and only frequencies between 0.5 and 40 Hz get through. OUTPUT swings around 1.65 V, which Arduino reads as about 340 (our calculation).
- 3.3v → 3.3V, never to 5V: the AD8232 works from 2 to 3.5 V and can take 3.6 V at most.
- LO+ → A1, LO− → A2: they go up to 3.3 V when LA (LO+) or RA (LO−) comes off. A digital pin on the UNO is only
sure to see a “high” from 3 V up (ATmega328P datasheet), so we read them with
analogRead: about 675 (our calculation) with the electrode off, almost 0 with the electrode on. - SDN stays free (a resistor on the board keeps the chip on). Never connect it to a pin on the UNO: the UNO's 5 V is more than the chip can take.
3The sketch
// The heart's signal with the AD8232 and Arduino UNO. For learning only: this is NOT // a medical device. Electrodes on the body only when everything runs on batteries. #include <Arduino.h> const bool HAS_LO = true; // false for the DFRobot SEN0213 (LO+ and LO- not available) const byte EVERY = 10; // one line to the Plotter every 10 readings (IDE 1.8: use 1) const int MARGIN = 100; // how far the R peak must rise above the average (adjust it) long sum; // moving average of the readings, multiplied by 64 unsigned long lastRead, lastBeat; bool above = false; // is the signal already above the threshold? int bpm = 0, highest = 0; byte counted = 0; void setup() { Serial.begin(115200); pinMode(LED_BUILTIN, OUTPUT); // the L LED blinks at every beat sum = analogRead(A0) * 64L; lastRead = micros(); } void loop() { if (micros() - lastRead < 4000) return; // one reading every 4 ms lastRead += 4000; int value = analogRead(A0); // OUTPUT of the module sum += value - sum / 64; // the average follows the baseline int threshold = sum / 64 + MARGIN; unsigned long now = millis(); // LO+ (A1) and LO- (A2): about 675 if an electrode is off, almost 0 if it is on if (HAS_LO && (analogRead(A1) > 400 || analogRead(A2) > 400)) { value = threshold = bpm = 0; // on the Plotter: flat line at zero } else if (!above && value > threshold) { // R peak: one beat above = true; unsigned long interval = now - lastBeat; if (interval > 300) { // under 0.3 s it is not a new beat if (interval < 2000) bpm = 60000UL / interval; lastBeat = now; } } else if (value < threshold) { above = false; } digitalWrite(LED_BUILTIN, now - lastBeat < 100); // on for 0.1 s // the highest reading of each group goes to the Plotter, so the R peak is not lost if (counted == 0 || value > highest) highest = value; if (++counted < EVERY) return; counted = 0; Serial.print(F("ECG:")); Serial.print(highest); Serial.print(F(",Threshold:")); Serial.print(threshold); Serial.print(F(",BPM:")); Serial.println(bpm); }
Arduino reads OUTPUT 250 times a second: above the threshold (the average plus MARGIN) there is an R peak
and the L LED lights up. The Plotter gets one line every ten readings because the one in IDE 2, as its source code shows, displays only the
last 50 lines: two seconds. With the old IDE 1.8 (500 lines), set EVERY = 1.
4Where the electrodes go
SparkFun gives two placements: forearms and right thigh (A) or chest near the shoulders and right side above the hip (B); the closer they are to the heart, the better. On the SparkFun cable RA is black, LA blue, RL red: other cables differ, so check the labels.
- Snap the leads onto the electrodes before you stick them on.
- Clean, dry skin: hair does not conduct.
- New electrodes for every session: once used, they no longer make good contact.
- Check that RA and LA are on the correct side of the heart.
- Keep still and relaxed, and breathe normally.
5Watch the trace
Charger unplugged, sketch uploaded, electrodes on: open the Serial Plotter (Tools menu or the button at the top right) at 115200 baud.
The P wave is the impulse that starts in the atria. In the QRS complex, with the R peak, the ventricles pump the blood: it is the “beep” of hospital monitors, as SparkFun puts it. The T wave comes when they relax.
- Flat line at zero: an electrode has come off.
- Messy trace: you are moving, tensing your muscles or breathing hard; try moving the electrodes a little.
- Lots of dense noise: DFRobot suggests touching something metal (static electricity).
6Beats per minute: an exercise
One beat passes between two R peaks: 800 milliseconds
make 60,000 ÷ 800 = 75 per minute. That is the calculation behind the BPM column (it ignores peaks closer than 0.3 s and
gaps longer than 2 s). The threshold should sit halfway up the R peaks, above the T waves: lower or raise MARGIN until it does.
- The number is only an indication: movement, tall T waves or an electrode coming loose throw it off. It is there to show how a heart rate is counted: do not compare it with a medical device and do not draw conclusions from it.
7The other modules
- AD8232 kit: same board, same pins, same sketch. Unlabeled snaps? Use a multimeter: in the SparkFun schematic the plug tip is RL, the ring LA, the sleeve RA.
- DFRobot SEN0213 (with cable and electrodes): 3.3 to 6 V, 5 V recommended. VCC to 5V, GND to GND, A to
A0; LO+ and LO− are not on the connector, so
HAS_LO = false.
- Compare placements A and B, then clench your fist.
- With the 9 V battery, watch the L LED.
- the AD8232 amplifies and filters the signal;
- two R peaks give an estimate of the heart rate;
- electrodes on the body only on batteries.
Useful products
Other guides
- Resistor colour code and tolerances
- N-channel and P-channel MOSFETs
- Bipolar transistor (BJT) or MOSFET?
- Relays: how to drive them and how much current they draw
- THT and SMD/SMT components
- XIAO board pinouts
- LEDs: forward voltage and series resistor
- The multimeter: measuring voltage and current
- Wemos D1 mini: first steps
- MOSFET module with Arduino and ESP32
- Relay module with Arduino and ESP32
- 3D printing filaments: PLA, PETG and fibre-filled versions
- Analog and digital: the differences
- ADS1115: 16-bit converter with Arduino and ESP32
- From bits to real values: converting sensor readings
- DS3231 RTC clock with Arduino and ESP32
- Linear or switching regulator: which one to choose
- Step-down, step-up and buck-boost: choosing the right module
- Voltage divider: reading voltages higher than 5 V or 3.3 V
- Pull-up, pull-down and bounce: wiring a button properly
- 3.3 V and 5 V logic levels: getting an ESP32 and an Arduino to talk
- The I²C bus: addresses, pull-ups and the scanner
- Lithium batteries: voltages, charging and protection
- ESP32 power consumption and deep sleep: how long the battery lasts
- Temperature sensors compared
- ESP32: which pins to use and which to avoid
- Getting started with the ESP32 in Arduino IDE 2 and PlatformIO
- SSD1306 OLED display and 16×2 I²C LCD with Arduino and ESP32
- PIR motion sensor and HC-SR04 ultrasonic sensor
- Date and time from the Internet with the ESP32: NTP, Italian time zone and daylight saving time
- MicroSD data logger: saving measurements to CSV
- Solar-powered ESP32: panel, charger and the numbers for Italy
- Web server on the ESP32: control a relay from your phone
- Your first LED: wire it up and make it blink
- The button: let Arduino decide
- The potentiometer: turn a knob and read its value
- Soft light: adjusting the brightness of an LED
- The buzzer: playing notes and melodies
- The traffic light: three LEDs in sequence
- The thermometer: reading the temperature with the TMP36
- The servo motor: moving an arm with Arduino
- The night light: the photoresistor and your first decision
- The relay: switching on a light bulb with Arduino
- The LCD display: making Arduino write
- The electronic dice: your first complete project
- The RGB LED: every color from three lights
- The joystick: two-axis control with a shield
- The LED ring: twelve colors from a single pin
- The DC motor: driving it with a MOSFET
- Soil moisture: the plant that asks for water
- The stepper motor: turn exactly as far as you want
- The parking sensor: faster and faster beeps
- The 7-segment display: big, bright numbers
- Automatic watering: the plant that waters itself
- The keypad: a lock with a secret code
- Networked weather station: values and chart on your phone
- A Telegram bot on the ESP32: your home from your phone
- MQTT with the ESP32: the language of connected devices
- Updating the ESP32 over Wi-Fi (OTA)
- ESP-NOW: two ESP32 boards talking without a router
- WebSocket with the ESP32: the LED that follows the slider
- Readings on a Google sheet, with deep sleep
- WiFiManager: choose the Wi-Fi from your phone
- Bluetooth LE with the ESP32: the phone without a network
- The camera in your browser with the ESP32-S3
- A portable Bluetooth speaker you build yourself
- Bluetooth desktop speakers, 2 × 20 W
- Stereo MP3 player with two buttons
- The shelf that plays music: a Visaton exciter
- How to solder well
- How much does it draw? Current and power with the INA219
- Load-cell scale with the HX711
- CO2 traffic light: when to open the windows
- RFID card door opener
- GPS: track logger on microSD
- LoRa: how far does it go? A range test with two boards
- Battery weather sign with an e-paper display
- Web radio with an ESP32 and an I2S amplifier
- Getting started with the Raspberry Pi Pico 2 in MicroPython
- Your first amplifier: the LM386 and a speaker
- Talking Arduino: the DFR0760 speech synthesis module
- The spectrum of your music on an LED matrix
- Drawing with 64 LEDs: the 8×8 matrix with the MAX7219
- A real voltage: the 12-bit MCP4725 DAC