Created
May 9, 2021 01:20
-
-
Save gallaugher/a5aab6a22a1f6bdc6dc2de3be3c295bd to your computer and use it in GitHub Desktop.
This Code Won't Work on an nrf52840 (non-Express)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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