Skip to content

Instantly share code, notes, and snippets.

@gallaugher
Created May 9, 2021 01:20
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 gallaugher/a5aab6a22a1f6bdc6dc2de3be3c295bd to your computer and use it in GitHub Desktop.
Save gallaugher/a5aab6a22a1f6bdc6dc2de3be3c295bd to your computer and use it in GitHub Desktop.
This Code Won't Work on an nrf52840 (non-Express)
#include <NeoPixelBus.h>
#include <NeoPixelAnimator.h>
#include <Wire.h>
#include "MAX30105.h" //MAX3010x library
#include "heartRate.h" //Heart rate calculating algorithm
RgbColor BLACK(0, 0, 0);
RgbColor RED(128, 0, 0);
MAX30105 particleSensor;
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(9, 12);
NeoPixelAnimator animations(2); // NeoPixel animation management object
const byte RATE_SIZE = 4; // Increase this for more averaging. 4 is good.
byte rates[RATE_SIZE]; // Array of heart rates
byte rateSpot = 0;
long lastBeat = 0; // Time at which the last beat occurred
float beatsPerMinute;
int beatAvg;
void setup() {
Serial.begin(115200);
initRandom();
// initialize LEDs
strip.Begin();
strip.ClearTo(RED);
strip.Show();
//animations.StartAnimation(0, 2000, beatAnimation);
delay(1000);
Serial.println("LEDs initialized");
// Initialize sensor
particleSensor.begin(Wire, I2C_SPEED_FAST); //Use default I2C port, 400kHz speed
particleSensor.setup(); //Configure sensor with default settings
particleSensor.setPulseAmplitudeRed(0x0A); //Turn Red LED to low to indicate sensor is running
delay(1000);
Serial.println("Sensor initialized");
}
void loop() {
long irValue = particleSensor.getIR(); // Reading the IR value it will permit us to know if there's a finger on the sensor or not
if (irValue > 7000) {
// finger detected
if (lastBeat == 0 && !animations.IsAnimating()) {
animations.StartAnimation(1, 2000, readingAnimation);
}
if (checkForBeat(irValue) == true) {
// we sensed a beat!
long delta = millis() - lastBeat; // Measure duration between two beats
lastBeat = millis();
beatsPerMinute = 60 / (delta / 1000.0); // Calculating the BPM
if (beatsPerMinute < 255 && beatsPerMinute > 20) { // To calculate the average we strore some values (4) then do some math to calculate the average
rates[rateSpot++] = (byte) beatsPerMinute; // Store this reading in the array
rateSpot %= RATE_SIZE;
// Take average of readings
beatAvg = 0;
for (byte x = 0 ; x < RATE_SIZE ; x++) {
beatAvg += rates[x];
}
beatAvg /= RATE_SIZE;
Serial.print("Heart rate ");
Serial.println(beatAvg);
}
if (beatsPerMinute < 255 && beatsPerMinute > 55) {
// stable beat detected
animations.StopAnimation(1);
animations.StartAnimation(0, 500, beatAnimation);
}
}
}
else { // If no finger is detected it inform the user and put the average BPM to 0 or it will be stored for the next measure
beatAvg = 0;
lastBeat = 0;
animations.StopAnimation(1);
strip.ClearTo(BLACK);
}
animations.UpdateAnimations();
strip.Show();
delay(15);
}
void beatAnimation(const AnimationParam& param) {
strip.ClearTo(RgbColor::LinearBlend(RED, BLACK, param.progress));
}
void fadeAnimation(const AnimationParam& param) {
float index = param.progress * 2;
// fade in
if (index < 1) {
strip.ClearTo(RgbColor::LinearBlend(BLACK, RED, index));
}
// fade out
else {
strip.ClearTo(RgbColor::LinearBlend(RED, BLACK, index - 1));
}
if (param.state == AnimationState_Completed) {
animations.RestartAnimation(0);
}
}
void readingAnimation(const AnimationParam& param) {
float progress = param.progress * 6;
byte index = progress;
progress = progress - index; // range from 0 to 1
strip.ClearTo(BLACK);
switch (index) {
case 0:
strip.SetPixelColor(4, RgbColor::LinearBlend(BLACK, RED, progress));
break;
case 1:
strip.SetPixelColor(4, RgbColor::LinearBlend(RED, BLACK, progress));
strip.SetPixelColor(3, RgbColor::LinearBlend(BLACK, RED, progress));
strip.SetPixelColor(5, RgbColor::LinearBlend(BLACK, RED, progress));
break;
case 2:
strip.SetPixelColor(3, RgbColor::LinearBlend(RED, BLACK, progress));
strip.SetPixelColor(5, RgbColor::LinearBlend(RED, BLACK, progress));
strip.SetPixelColor(2, RgbColor::LinearBlend(BLACK, RED, progress));
strip.SetPixelColor(6, RgbColor::LinearBlend(BLACK, RED, progress));
break;
case 3:
strip.SetPixelColor(2, RgbColor::LinearBlend(RED, BLACK, progress));
strip.SetPixelColor(6, RgbColor::LinearBlend(RED, BLACK, progress));
strip.SetPixelColor(1, RgbColor::LinearBlend(BLACK, RED, progress));
strip.SetPixelColor(7, RgbColor::LinearBlend(BLACK, RED, progress));
break;
case 4:
strip.SetPixelColor(1, RgbColor::LinearBlend(RED, BLACK, progress));
strip.SetPixelColor(7, RgbColor::LinearBlend(RED, BLACK, progress));
strip.SetPixelColor(0, RgbColor::LinearBlend(BLACK, RED, progress));
strip.SetPixelColor(8, RgbColor::LinearBlend(BLACK, RED, progress));
break;
case 5:
strip.SetPixelColor(0, RgbColor::LinearBlend(RED, BLACK, progress));
strip.SetPixelColor(8, RgbColor::LinearBlend(RED, BLACK, progress));
break;
}
if (param.state == AnimationState_Completed) {
animations.RestartAnimation(0);
}
}
void initRandom() {
// random works best with a seed that can use 31 bits
// analogRead on a unconnected pin tends toward less than four bits
uint32_t seed = analogRead(0);
delay(1);
for (int shifts = 3; shifts < 31; shifts += 3) {
seed ^= analogRead(0) << shifts;
delay(1);
}
// Serial.println(seed);
randomSeed(seed);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment