CircuitPython is being used below. Are you new to using CircuitPython? No worries, there is a full getting started guide here.

Adafruit suggests using the Mu editor to edit your code, print & plot your output, and have an interactive REPL in CircuitPython. You can learn about Mu and its installation in this tutorial.

A Basic Plot Program

The code below takes light readings and plots them out in the plotter function in Mu.

Now open the Plotter window and the Serial window in Mu.

Upload the code below as to the CIRCUITPY flash drive that appears when you plug your Circuit Playground Express into a USB port. 

Download: file
import time

import analogio
import board
import neopixel

def sign(value):
    if value > 0:
        return 1
    if value < 0:
        return -1
    return 0

pixels = neopixel.NeoPixel(board.NEOPIXEL, 10, brightness=1.0)
light = analogio.AnalogIn(board.LIGHT)

# Turn only pixel #1 green
pixels[1] = (0, 255, 0)

# How many light readings per sample
# How many samples we take to calculate 'average'
samples = [0] * NUM_SAMPLES
lasttime = time.monotonic()

while True:
    for i in range(NUM_SAMPLES):
        # Take NUM_OVERSAMPLE number of readings really fast
        oversample = 0
        for s in range(NUM_OVERSAMPLE):
            oversample += float(light.value)
        # and save the average from the oversamples
        samples[i] = oversample / NUM_OVERSAMPLE  # Find the average

        mean = sum(samples) / float(len(samples))  # take the average
        print((samples[i] - mean,))  # 'center' the reading

        if i > 0:
            # If the sign of the data has changed munus to plus
            # we have one full waveform (2 zero crossings), pulse LED
            if sign(samples[i]-mean) <= 0 and sign(samples[i-1]-mean) > 0:
                pixels[9] = (200, 0, 0)  # Pulse LED
                pixels[9] = (0, 0, 0)    # Turn LED off

        time.sleep(0.025)  # change to go faster/slower

Place your finger lightly but firmly on the green LED, parallel to the USB cable to you cover the green NeoPixel and the light sensor (next to the eye symbol on the Circuit Playground Express).

The code will start to average the readings over time to come up with good data.

The best readings show a waveform in the Mu Plotter where the readings are varying between approximately 1000 and -1000.

And you should have a screen similar to the one below.

It takes a bit of time to get the reading the right amplitude and for the CircuitPython program to scale the reading centered around zero (this is called "removing the DC offset" in engineering terms).

It doesn't look like your traditional 'heart rate' blip, that's normal! It can look sinusoidal or even square-ish

If the numbers range are too small you are probably pressing to hard. If the numbers are too large or you don't have a varying plot, you may be pressing too lightly. Try different pressures to get numbers and a plot similar to above. The trick is to keep your finger steady, covering both the green NeoPixel and the light sensor, for a few seconds.

With the waveform "dialed in" to be around +1000 to -1000 on the Mu plotter, the blinking of the red NeoPixel LED #9 should be indicative of your pulse. The code checks every time the signal transitions from negative to positive, indicating one full cycle of the heartbeat and blinks the LED at that point.

To get your heart rate in beats per minute you can:

  • Time 15 seconds, count the number of red LED flashes and multiply by 4
  • Time 60 seconds (1 minute) and count the red LED flashes.

The number you get is your heart rate (more or less). Commercial units and doctors & nurses can determine this more accurately but your number should be close, within less than 10%.

What is Happening?

The amount of light hitting the photo sensor on the Circuit Playground Express is changing based on the amount of blood in your finger. As your heart pumps, the blood flow changes and you can see those changes in the plot as changes in light intensity.

This guide was first published on Feb 20, 2019. It was last updated on Feb 20, 2019. This page (CircuitPython) was last updated on Jun 17, 2019.