Switch case and millis

Hello everybody,

I got some problems with switch case and millis. Basically, what I'm trying to do is to blinking a led according to the position of a rotary encoder. When the encoder goes up (from 0 to x) the assigned switch case starts and the led assigned in it blinks for 2 seconds using millis and after that the led is off. I want to use millis and not delay because I need to have the program keep going in case the encoder moves and a new case has to start.

Furthermore, when the encoder moves from an higher value for instance 4 (and in this case we are in the switch case 4), so the led assigned to that case blinks for 2000 millis and after that move automatically to previous case (therefore switch case 3). It's a timer with leds.

If you look at line 166 in the else/switch/case1 I've already tried to get this, but didn't work!

#include <Adafruit_NeoPixel.h>
#include <avr/power.h>

const int  buttonPin = 4;    // the pin that the pushbutton is attached to
const int ledPin = 13;       // the pin that the LED is attached to

// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

int encoder0PinA = 12;
int encoder0PinB = 11;
int encoder0Pos = -1;
int encoder0PinALast = LOW;
int n = LOW;
int encoderSwitchPin = 4; //push button switch

unsigned long previousMillis = 0;        // will store last time LED was updated
const long interval = 2000;           // interval at which to blink (milliseconds)

//LED
#define PIN 6
// How many NeoPixels are attached to the Arduino?
#define NUMPIXELS      5
int sine[5] = {0, 1, 2, 3, 4}; //these are the pixels in order of animation


// When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals.
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);


void setup() {
  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  // initialize the LED as an output:
  pinMode(ledPin, OUTPUT);

  pinMode (encoder0PinA, INPUT);
  pinMode (encoder0PinB, INPUT);

  pixels.begin();
  pixels.setBrightness(40); //adjust brightness here
  pixels.show(); // Initialize all pixels to 'off'

  // initialize serial communication:
  Serial.begin(9600);
}

void loop() {
  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);
  n = digitalRead(encoder0PinA);
  unsigned long currentMillis = millis();

  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button
      // wend from off to on:
      buttonPushCounter++;
      Serial.println("on");
      Serial.print("number of button pushes:  ");
      Serial.println(buttonPushCounter);
    }
    else {
      // if the current state is LOW then the button
      // wend from on to off:
      Serial.println("off");
    }
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  // save the current state as the last state,
  //for next time through the loop
  lastButtonState = buttonState;

  // turns ON the LED every two button pushes by checking the modulo of the button push counter.
  if (buttonPushCounter % 2 == 0) {
    if (buttonState == HIGH) {
      for (int i = 0; i < NUMPIXELS; i++) {
        pixels.setPixelColor(i, pixels.Color(75, 250, 100)); //change RGB color value here
        pixels.show();

        for (int j = 0; j < 5; j++) {
          pixels.setPixelColor(j, pixels.Color(0, 0, 0));
        }

        pixels.show();
      }

      digitalWrite(ledPin, HIGH);

      encoder0Pos = 0;
    }
  }

  if ((encoder0PinALast == LOW) && (n == HIGH)) {
    if (digitalRead(encoder0PinB) == LOW) {

      encoder0Pos--;

      switch (encoder0Pos) {
        //n = encoder0Pos;

        case 0:    // your hand is on the sensor
          if ( encoder0Pos == 0) {
            for (int i = 0; i <= NUMPIXELS; i++) {
              // pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
              pixels.setPixelColor(i, pixels.Color(0, 0, 0)); // Moderately bright green color.
              pixels.show();
            }
          }

          Serial.println("OFF");
          break;

        case 1:    // your hand is on the sensor
          pixels.setPixelColor(sine[1], pixels.Color(0, 0, 0)); // Moderately bright green color.
          pixels.show();
          Serial.println("LED 1");
          break;
        case 2:    // your hand is close to the sensor
          pixels.setPixelColor(sine[2], pixels.Color(0, 0, 0)); // Moderately bright green color.
          pixels.show();
          Serial.println("LED 2");
          break;
        case 3:    // your hand is a few inches from the sensor
          pixels.setPixelColor(sine[3], pixels.Color(0, 0, 0)); // Moderately bright green color.
          pixels.show();
          Serial.println("LED 3");
          break;
        case 4:    // your hand is nowhere near the sensor
          pixels.setPixelColor(sine[4], pixels.Color(0, 0, 0)); // Moderately bright green color.
          pixels.show();
          Serial.println("LED 4");
          break;
      }

      if (encoder0Pos <= 0) {
        encoder0Pos = 0;
      }

    }


    else {
      encoder0Pos++;
       currentMillis = 0;
      switch (encoder0Pos) {
        // n = encoder0Pos;

        case 0:    // your hand is on the sensor
          if ( encoder0Pos == 0) {
            for (int i = 0; i <= NUMPIXELS; i++) {
              // pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
              pixels.setPixelColor(i, pixels.Color(0, 0, 0)); // Moderately bright green color.
              pixels.show();
            }
          }

          Serial.println("OFF");
          break;

        case 1:    // your hand is on the sensor
          if (currentMillis - previousMillis >= interval) {
             previousMillis = currentMillis;
          pixels.setPixelColor(sine[0], pixels.Color(60, 0, 0)); // Moderately bright green color.
          pixels.show();
          Serial.println("LED 1");
          }

          else {
            
            pixels.setPixelColor(sine[0], pixels.Color(0, 0, 0)); // Moderately bright green color.
            pixels.show();
            Serial.println("LED 1 OFF");
          }
          

          break;
        case 2:    // your hand is close to the sensor
          pixels.setPixelColor(sine[1], pixels.Color(60, 0, 0)); // Moderately bright green color.
          pixels.show();
          Serial.println("LED 2");
          break;
        case 3:    // your hand is a few inches from the sensor
          pixels.setPixelColor(sine[2], pixels.Color(60, 0, 0)); // Moderately bright green color.
          pixels.show();
          Serial.println("LED 3");
          break;
        case 4:    // your hand is nowhere near the sensor
          pixels.setPixelColor(sine[3], pixels.Color(60, 0, 0)); // Moderately bright green color.
          pixels.show();
          Serial.println("LED 4");
          break;
      }

      //Maximum value steps 24 that means 2 hrs
      if (encoder0Pos >= 24) {
        encoder0Pos = 24;
      }

    }
    Serial.print (encoder0Pos); //Display steps
    Serial.println (" ");
  }



  encoder0PinALast = n; //take count of encoder steps
}

I hope you can help me out, I cannot figure out how to deal it.

      switch (encoder0Pos) {
        //n = encoder0Pos;

        case 0:    // your hand is on the sensor
          if ( encoder0Pos == 0) {

The switch statement is doing a series of if/else if statements. When encoder0Pos is 0, case 0 is executed. There is no need to test again that encoder0Pos is 0.

  if (buttonPushCounter % 2 == 0) {
    if (buttonState == HIGH) {

You've already decided that the switch became pressed, so you incremented the counter. I don't see the purpose of testing that the switch IS high, here.

I see nothing in the code where you change the value of encoder0Pos in the switch statement.

Thanks for your reply PaulS. That's true, they were a repetition, I cleaned that part and it's still working.

Actually, when I move the encoder either up or down I change switch case and that works perfectly. The switch (encoder0Pos) is linked to the movement up/down of the encoder (encoder0Pos-- and encoder0Pos++) or at least thats what I thought and it works!!! When the encoder goes at 0 the case 0 is executed, when it goes a 1 the case one... And so on (back and forth)!

Should I link the encoder position and the switch in an another way? If so, why it is working?

My main problem is: how can I use millis in each single case (since they will have all different values) in order to get an led thats stay up for x time?

case 1:    // your hand is on the sensor
          if (currentMillis - previousMillis >= interval) {
             previousMillis = currentMillis;
          pixels.setPixelColor(sine[0], pixels.Color(60, 0, 0)); // Moderately bright green color.
          pixels.show();
          Serial.println("LED 1");
          }

          else {
            pixels.setPixelColor(sine[0], pixels.Color(0, 0, 0)); // Moderately bright green color.
            pixels.show();
            Serial.println("LED 1 OFF");
          }

          break;

My main problem is: how can I use millis in each single case (since they will have all different values) in order to get an led thats stay up for x time?

The switch statement will (or should) be executed thousands of times while the encoder is in any one position. The same case should be selected each time.

On any given pass through the case block, there may, or may not, be anything to do. Look at the blink without delay example to see how to execute loop() (and, by extension, the switch/case block of code) many, many times before there is actually something to do.

Look at the blink without delay example to see how to execute loop() (and, by extension, the switch/case block of code) many, many times before there is actually something to do.

I did and I got at the point where I'm stuck right now! I cannot figure out what I'm doing wrong to get this mills running properly. What I got so far is either execute the if and the led stays on or the else with an led always off. I tried hundreds of different solutions but none of them was the right one!!!

Prior to the switch statement, print() currentMillis, previousMillis, and interval. Make sure that they contain reasonable values.

To decode a quadrature encoder, keep a currentValue and remember what the two inputs were last time you looked at them. Assume that the two inputs never both change at the same time.

If input A has changed since the last time you looked at it, then INCREMENT the counter if A and B are now the same, otherwise DECREMENT it.
If input B has changed since the last time you looked at it, then DECREMENT the counter if A and B are now the same, otherwise INCREMENT it.

You may need to reverse the direction of this, but that's the pattern.

the blink pattern is:

  • if the led to be blink has changed, then turn the previous LED off, and rig the blink state so that the next bit will immediately turn the LED on.
  • If it's time to update the current LED, update it

To blink N and only N times, I hold a variable called 'num blinks remaining'. if it's ZERO, do nothing. If it's ODD, turn LED off and decrement. If it's EVEN (and not zero), turn LED on and decrement. So to blink twice, you set it to 4 and fix the blink timeout so that the next blink gets done immediately.

PaulS I changed the code according to what I understood, I moved the millis prior to the switch statement... But now it's working anymore! What am I doing wrong? :cry:

#include <Adafruit_NeoPixel.h>
#include <avr/power.h>

const int  buttonPin = 4;    // the pin that the pushbutton is attached to
const int ledPin = 13;       // the pin that the LED is attached to

// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

int state = 0;

int encoder0PinA = 12;
int encoder0PinB = 11;
int encoder0Pos = -1;
int encoder0PinALast = LOW;
//int n = LOW;
int currentValue=LOW;

unsigned long previousMillis = 0;        // will store last time LED was updated
const long interval = 2000;           // interval at which to blink (milliseconds)

//int i=interval;

//LED
#define PIN 6
// How many NeoPixels are attached to the Arduino?
#define NUMPIXELS      5
int sine[5] = {0, 1, 2, 3, 4}; //these are the pixels in order of animation


// When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals.
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);


void setup() {
  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  // initialize the LED as an output:
  pinMode(ledPin, OUTPUT);

  pinMode (encoder0PinA, INPUT);
  pinMode (encoder0PinB, INPUT);

  pixels.begin();
  pixels.setBrightness(40); //adjust brightness here
  pixels.show(); // Initialize all pixels to 'off'

  // initialize serial communication:
  Serial.begin(9600);
}

void loop() {
  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);
  currentValue = digitalRead(encoder0PinA);

  unsigned long currentMillis = millis();
  currentMillis = 0;
  
  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button
      // wend from off to on:
      buttonPushCounter++;
      Serial.println("on");
      Serial.print("number of button pushes:  ");
      Serial.println(buttonPushCounter);
    }
    else {
      // if the current state is LOW then the button
      // wend from on to off:
      Serial.println("off");
    }
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  // save the current state as the last state,
  //for next time through the loop
  lastButtonState = buttonState;

  // turns ON the LED every two button pushes by checking the modulo of the button push counter.
  //if (buttonPushCounter % 2 == 0) {
    if (buttonState == HIGH) {
      for (int i = 0; i < NUMPIXELS; i++) {
        pixels.setPixelColor(i, pixels.Color(75, 250, 100)); //change RGB color value here
        pixels.show();

        for (int j = 0; j < 5; j++) {
          pixels.setPixelColor(j, pixels.Color(0, 0, 0));
        }

        pixels.show();
      }

      digitalWrite(ledPin, HIGH);

      encoder0Pos = 0;

    //}
  }

  if ((encoder0PinALast == LOW) && (currentValue == HIGH)) {
    if (digitalRead(encoder0PinB) == LOW) {
      encoder0Pos--;

//encoder0Pos = currentValue;

if(currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;  
      switch (encoder0Pos) {

        case 0:    // your hand is on the sensor
          for (int i = 0; i <= NUMPIXELS; i++) {
            // pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
            pixels.setPixelColor(i, pixels.Color(0, 0, 0)); // Moderately bright green color.
            pixels.show();
          }
          Serial.println("OFF");
          break;

        case 1:    // your hand is on the sensor
          pixels.setPixelColor(sine[1], pixels.Color(0, 0, 0)); // Moderately bright green color.
          pixels.show();
          Serial.println("LED 1");
          break;

        case 2:    // your hand is close to the sensor
          pixels.setPixelColor(sine[2], pixels.Color(0, 0, 0)); // Moderately bright green color.
          pixels.show();
          Serial.println("LED 2");
          break;

        case 3:    // your hand is a few inches from the sensor
          pixels.setPixelColor(sine[3], pixels.Color(0, 0, 0)); // Moderately bright green color.
          pixels.show();
          Serial.println("LED 3");
          break;

        case 4:    // your hand is nowhere near the sensor
          pixels.setPixelColor(sine[4], pixels.Color(0, 0, 0)); // Moderately bright green color.
          pixels.show();
          Serial.println("LED 4");
          break;
      }

      if (encoder0Pos <= 0) {
        encoder0Pos = 0;
      }
    }


    else {
      encoder0Pos++;

      switch (encoder0Pos) {

        case 0:    // your hand is on the sensor
          for (int i = 0; i <= NUMPIXELS; i++) {
            // pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
            pixels.setPixelColor(i, pixels.Color(0, 0, 0)); // Moderately bright green color.
            pixels.show();
          }
          Serial.println("OFF");
          break;

        case 1:    // your hand is on the sensor
          pixels.setPixelColor(sine[0], pixels.Color(60, 0, 0)); // Moderately bright green color.
          pixels.show();
          Serial.println("LED 1");


          //          pixels.setPixelColor(sine[0], pixels.Color(0, 0, 0)); // Moderately bright green color.
          //          pixels.show();
          //          encoder0Pos--;
          //          Serial.println("LED 1 OFF");
          break;

        case 2:    // your hand is close to the sensor
          pixels.setPixelColor(sine[1], pixels.Color(60, 0, 0)); // Moderately bright green color.
          pixels.show();
          Serial.println("LED 2");
          break;

        case 3:    // your hand is a few inches from the sensor
          pixels.setPixelColor(sine[2], pixels.Color(60, 0, 0)); // Moderately bright green color.
          pixels.show();
          Serial.println("LED 3");
          break;

        case 4:    // your hand is nowhere near the sensor
          pixels.setPixelColor(sine[3], pixels.Color(60, 0, 0)); // Moderately bright green color.
          pixels.show();
          Serial.println("LED 4");
          break;
      }
      //Maximum value steps 24 that means 2 hrs
      if (encoder0Pos >= 24) {
        encoder0Pos = 24;
      }
    }
    Serial.print (encoder0Pos); //Display steps
    Serial.println (" ");

  }
  encoder0PinALast = currentValue; //take count of encoder steps
  }
}

PaulMurrayCbr I have the currentValue to keep track of the encoder value but I dunno how to implement the N times blinking in my code. I tried with for loops nested in the cases and the "delay" was working, but I cannot exit the case when I move the encoder to a new value until the loop is done!!!

I'm not really experienced with coding!

  unsigned long currentMillis = millis();
  currentMillis = 0;

Create a variable. Initialize it to now. Then, shit on it. What's the point?

PaulS true, it doesn't make any sense! In this way the counter is always at 0! However, I do have the same problem: the code is not executed anymore! When I turn the encoder nothing happen, none leds light up and nothing happen on the serial monitor as well!!! :slightly_frowning_face: :slightly_frowning_face: :slightly_frowning_face: