0

so a brief introduction about the project which I am working on before I go onto my issue.

I am working on a love-o-meter project (Not similar to the arduino example), whereby 2 people place 1 of their hands on a pad and with their other hand holding each other. Making use of a pulse sensor, I measure the BPM for 10s and then indicate the score on a LED strip. Apart from indicating the compatibility score, I also plan to use the LED strip (cylon/fire effect) to indicate that the arduino is in the progress of calculating (when it is measuring the BPM for 10s) and also to indicate idling (rainbow cycle effect, when there is no one is using the love-o-meter).

However, here comes my issue: Performing the BPM measurement and displaying the cylon/fire effect function at the same time. I know that I cannot use the delay function and instead use millis(). However, the functions in the NeoPixel library already uses the delay effect and it seems like a tough job to edit the function to it using millis(). Is there another way to do so?

  • How do you take your BPM measurements? You could hack it work on a hardware timer interrupt and/or ADC 'conversion finished' interrupts and periodacally check for "BPM result ready" in the main loop. Hard to say without knowing your code. – Maximilian Gerhardt Mar 24 '18 at 17:19
  • @MaximilianGerhardt I am using the code from this link: github.com/WorldFamousElectronics/PulseSensor_Amped_Arduino/… though I have tweaked it to perform the measurement for 10s. If you would like my entire code, I can send you the paste bin link – Dominic Teo Mar 24 '18 at 17:32
  • That code already uses timer interrupts to run 'concurrently' to your normal code, so you should be able to display whatever you want with delay. It does not affect interrupts. – Maximilian Gerhardt Mar 24 '18 at 17:44
  • Measuring BPM with a hardware timer will be tricky unless your input is bounce-free. – Chris Stratton Mar 24 '18 at 18:07
  • @ChrisStratton So does that mean my BPM measured will be inaccurate the first few readings? If so, what do you recommend? Because my code is from taken from the pulse sensor example which I assume to be the best way to measure BPM. – Dominic Teo Mar 24 '18 at 18:31
2

If you can find another way of calculating the BMP during displaying an effect on the strip depends highly on your BMP sensor. If you can do the measurement with interrupts, it should work. In this case you should make sure, that the interrupt cannot be fired during the execution of the Adafruit_NeoPixel.show() function, since it is quite timing sensitive.

But since I recently worked on a project with a NeoPixel LED strip, I have already edited functions from the strandtest example for use with the millis() function. So you will not have to reinvent the wheel again :D I will try to strip away my custom code, so that you can easily use it.

float brightness = 1.0; 
uint32_t strip_state=0; 

uint32_t Wheel(Adafruit_NeoPixel *strip, byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip->Color((255 - WheelPos * 3)*brightness, 0, WheelPos * 3*brightness);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip->Color(0, WheelPos * 3 * brightness, (255 - WheelPos * 3)*brightness);
  }
  WheelPos -= 170;
  return strip->Color(WheelPos * 3 * brightness, (255 - WheelPos * 3)*brightness, 0);
}

void fill_color(uint32_t color){
  byte r= ((color & 0xFF0000) >> 16) * brightness;
  byte g= ((color & 0xFF00) >> 8) *brightness;
  byte b= (color & 0xFF) * brightness;
  color = strip.Color(r,g,b);
  for(unsigned int i=0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, color);
  }
  strip.show();
}

void fade_color(){
  for(unsigned int i=0;i<strip.numPixels();i++){
    strip.setPixelColor(i,Wheel(&strip,strip_state));
  }
  strip.show();
  strip_state++;
  if(strip_state>255) strip_state = 0;
}

void moving_rainbow(){
  for(unsigned int i=0; i<strip.numPixels(); i++) {
    strip.setPixelColor(i, Wheel(&strip,((i * 256 / strip.numPixels()) + strip_state) & 255));
  }
  strip.show();
  strip_state++;
}

void colorWipe(uint32_t color) {
  byte r= ((color & 0xFF0000) >> 16) * brightness;
  byte g= ((color & 0xFF00) >> 8) *brightness;
  byte b= (color & 0xFF) * brightness;
  color = strip.Color(r,g,b);

  strip.setPixelColor(strip_state, color);
  strip.show();
  strip_state++;
}

//Theatre-style crawling lights.
void theaterChase(uint32_t c) {
  byte r= ((c & 0xFF0000) >> 16) * brightness;
  byte g= ((c & 0xFF00) >> 8) *brightness;
  byte b= (c & 0xFF) * brightness;
  c = strip.Color(r,g,b);
  for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
    strip.setPixelColor(i + strip_state % 3, c);    //turn every third pixel on
    strip.setPixelColor(i + (strip_state +1) % 3, 0); // turn others off
    strip.setPixelColor(i + (strip_state +2) % 3, 0);
  }
  strip.show();
  strip_state++;
}

//Theatre-style crawling lights with rainbow effect
void theaterChaseRainbow() {
  for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
    strip.setPixelColor(i + strip_state % 3, Wheel(&strip, (i+strip_state) % 255));    //turn every third pixel on
    strip.setPixelColor(i + (strip_state +1) % 3, 0); // turn others off
    strip.setPixelColor(i + (strip_state +2) % 3, 0);
  }
  strip.show();
  strip_state++;
}

The functions use the float variable brigthness to modulate the overall brightness of all LEDs. You can set it to every value between 0.0 and 1.0.

The variable strip_state holds the current state of the effect on the strip. It is incremented everytime one of the functions is executed. Reset it to 0 if you want to restart an effect.

You yourself have to declare the variable strip as from the type Adafruit_NeoPixel.

So now you only have to call these function from the typical millis() code (like from the BlinkWithoutDelay example) in an interval, that you chose.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.