Skip to content

Instantly share code, notes, and snippets.

@rosterloh
Created May 3, 2018 08:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rosterloh/237d1b9b28785eb4461664613e652d3b to your computer and use it in GitHub Desktop.
Save rosterloh/237d1b9b28785eb4461664613e652d3b to your computer and use it in GitHub Desktop.
MicroPython Optical Heart Rate
from machine import Pin, Signal, I2C, ADC, Timer
import ssd1306
import time
adc = ADC(0)
i2c = I2C(-1, Pin(5), Pin(4))
display = ssd1306.SSD1306_I2C(128, 32, i2c)
MAX_HISTORY = 250
TOTAL_BEATS = 30
HEART = [
[ 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 1, 1, 0, 0, 0, 1, 1, 0],
[ 1, 1, 1, 1, 0, 1, 1, 1, 1],
[ 1, 1, 1, 1, 1, 1, 1, 1, 1],
[ 1, 1, 1, 1, 1, 1, 1, 1, 1],
[ 0, 1, 1, 1, 1, 1, 1, 1, 0],
[ 0, 0, 1, 1, 1, 1, 1, 0, 0],
[ 0, 0, 0, 1, 1, 1, 0, 0, 0],
[ 0, 0, 0, 0, 1, 0, 0, 0, 0],
]
last_y = 0
def refresh(bpm, beat, v, minima, maxima):
global last_y
display.vline(0, 0, 32, 0)
display.scroll(-1,0) # Scroll left 1 pixel
if maxima-minima > 0:
# Draw beat line.
y = 32 - int(16 * (v-minima) / (maxima-minima))
display.line(125, last_y, 126, y, 1)
last_y = y
# Clear top text area.
display.fill_rect(0,0,128,16,0) # Clear the top text area
if bpm:
display.text("%d bpm" % bpm, 12, 0)
# Draw heart if beating.
if beat:
for y, row in enumerate(HEART):
for x, c in enumerate(row):
display.pixel(x, y, c)
display.show()
def calculate_bpm(beats):
if beats:
beat_time = beats[-1] - beats[0]
if beat_time:
return (len(beats) / (beat_time)) * 60
def detect():
# Maintain a log of previous values to
# determine min, max and threshold.
history = []
beats = []
beat = False
bpm = None
# Clear screen to start.
display.fill(0)
while True:
v = adc.read()
history.append(v)
# Get the tail, up to MAX_HISTORY length
history = history[-MAX_HISTORY:]
minima, maxima = min(history), max(history)
threshold_on = (minima + maxima * 3) // 4 # 3/4
threshold_off = (minima + maxima) // 2 # 1/2
if v > threshold_on and beat == False:
beat = True
beats.append(time.time())
# Truncate beats queue to max
beats = beats[-TOTAL_BEATS:]
calculate_bpm(beats)
if v < threshold_off and beat == True:
beat = False
refresh(bpm, beat, v, minima, maxima)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment