0

Hi all I use 2 sensors and 2 led strips. I want to let both led strips light up without interrupting each other while reading the different values from the inputs. But Arduino still pauses when one lights up, the other one needs to wait for the time to pass, either one misses reading the value when one is processing the output.

I know delay(wait); makes it block out the coming data, but it lets the strips light up for 6 seconds. If I remove it, the strips will light one 1 second only. What should I do? Thanks so much!

#include <Adafruit_NeoPixel.h>
#define PIN 6
int ledFadeTime = 7;
Adafruit_NeoPixel strip3 = Adafruit_NeoPixel(60, 9, NEO_GRB +NEO_KHZ800);//led pin
Adafruit_NeoPixel strip4 = Adafruit_NeoPixel(60, 7, NEO_GRB + NEO_KHZ800);//led pin
const int sensorPin3 = A2;//motion sensor
const int sensorPin4 = A3; //flash sensor

unsigned long strip3OnTime;
unsigned long strip4OnTime;
bool strip3On;
bool strip4On;
unsigned long previousMillis = 0;
const long interval = 1000;

void setup() {

  Serial.begin(9600);
  strip3.begin();
  strip3.show();
  strip4.begin();
  strip4.show();

  strip3On = false;
  strip4On = false; 
}

void loop(){
 int Val3 = analogRead (sensorPin3); // sensor val
 int Val4 = analogRead (sensorPin4); 

 Serial.print(Val3);
 Serial.print(" ");
 Serial.println(Val4);


   if (Val3>70) {  
     rgbFadeInAndOut3(0, 0, 255, ledFadeTime);   
     //analogWrite(strip3, HIGH);
     strip3On = true;
     strip3OnTime = millis();
   }
   if (Val4>70) {    
     rgbFadeInAndOut4(0, 0, 255, ledFadeTime); 
     //analogWrite(strip4, HIGH);
     strip4On = true;
     strip4OnTime = millis();
   }

   if(strip3On) 
     if(millis() - strip3OnTime > 7000) {
       rgbFadeInAndOut3(0, 0, 1, 5000); 
       strip3On = false;
     }   
   if(strip4On) 
     if(millis() - strip4OnTime > 7000) {
       rgbFadeInAndOut4(0, 0, 1, 5000); 
       strip4On = false;
     }
 }

 void rgbFadeInAndOut3(uint8_t red, uint8_t green, uint8_t blue, uint8_t wait) {
   unsigned long currentMillis = millis();
   if (currentMillis - previousMillis >= interval){
     previousMillis = currentMillis;

   for(uint8_t b = 0; b <255; b++) {
      for(uint8_t i=0; i < strip3.numPixels(); i++) {
         strip3.setPixelColor(i, red * b/255, green * b/255, blue * b/255);      
       }   
      strip3.show();
     delay(wait);
   };

   for(uint8_t b=255; b > 0; b--) {
      for(uint8_t i = 0; i < strip4.numPixels(); i++) {
         strip3.setPixelColor(i, red * b/255, green * b/255, blue * b/255);
      }    
      strip3.show();
      delay(wait);
   };
 };
 }
 void rgbFadeInAndOut4(uint8_t red, uint8_t green, uint8_t blue, uint8_t wait) {
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval){
     previousMillis = currentMillis;

   for(uint8_t b = 0; b <255; b++) {
      for(uint8_t i=0; i < strip4.numPixels(); i++) {
         strip4.setPixelColor(i, red * b/255, green * b/255, blue * b/255);   
      }
      strip4.show();
      delay(wait);
   };

   for(uint8_t b=255; b > 0; b--) {
      for(uint8_t i = 0; i < strip4.numPixels(); i++) {
         strip4.setPixelColor(i, red * b/255, green * b/255, blue * b/255);    
      }
      strip4.show();
      delay(wait);    
   };
 };
 }  
2

Very simple. It takes only 3 steps.

  1. Blink an led stripe with no delay.
  2. Blink two led stripes, using the code developed in step 1.
  3. Enjoy your blinking let stripes.

edit: since you seem to be struggling, here is one (of countless) way(s) to do #1 above.

//blinky_ledx2.ino

//blink two led strips independently

//blinky rate
#define LED_DLY         100     //duration for led1, in ms
#define LED             12      //led to be blinked

int led = 13;

//run user routine, non-blocking
void NB_run(void (*func_ptr)(void)) {
    static uint32_t millis_next=0;                          //next match point

    if (millis() >= millis_next) {                          //time is up
        millis_next += LED_DLY;                             //advance match-up time
        func_ptr();                                         //execute user function
    }
}

//blinky example
void blinky1(void) {
    //blink LED
    digitalWrite(LED, !digitalRead(LED));
}

void setup() {
    // put your setup code here, to run once:
    pinMode(led, OUTPUT);
    pinMode(LED, OUTPUT);                                   //LED as output
}

void loop() {
    NB_run(blinky1);                                        //run blinky1 at set intervals for LED
    digitalWrite(led, !digitalRead(led));                   //blink led
}

the heart of this is NB_run() -> it executes func_ptr() once the set time has been reached. otherwise, it returns without doing anything, as shown in the example below.

D13 is blinked constantly in the main loop, while D12 is blinked based on LED_DLY, in a non-blocking fashion.

enter image description here

I purposely wrote NB_run() so that it needs additional "parameterization" to run multiple tasks - what you have here is the basis of a generic framework for a rudimentary pseudo multi-tasker. it is not difficult at all for you to extend the code to run 2 stripes.

good luck.

edit2: it was pointed out to me, quite correctly, that something like this can be done via rtos. true, but a typical rtos has lots of overhead and requires a more substantial hardware to support.

one exception is macro-based rtos, like protothread. in that particular implementation, you will see that there is little gain in terms of code complexity, but some stylistically.

here is an implementation of running two tasks concurrently via protothread, only code for one task is shown, however.

//thread 1
PT_THREAD(protothread1(struct pt *pt, uint32_t pr)) {
    static uint32_t time_next=0;        //time for the next blinking

    PT_BEGIN(pt);
    while (1) {
        PT_WAIT_UNTIL(pt, millis() > time_next);
        time_next += pr;                //advance time to the next match up point
        toggleLED(LED1);                //run user task - blink led1
    }
    PT_END(pt);
}


void loop() {
    protothread1(&pt1, LED1_DLY);       //running thread1
    protothread2(&pt2, LED2_DLY);       //running thread2

}

you can see that it retains largely the code structure presented earlier.

here is the outcome of that code, blinking D12/D13 at different rates.

enter image description here

  • I added a function for light animation, void rgbFadeInAndOut3 & void rgbFadeInAndOut4 are set to be 6 seconds, if I remove delay, the animation is going to reduce to 1 second, and it's still blocking the coming data. – YT Chou Apr 13 '17 at 6:00
  • > it's still blocking the coming data.... because you continue to use delay. as long as you do that, you will never get the kind of behaviors you want. – dannyf Apr 14 '17 at 0:20

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.