Help looping code inside of a "case"

hello, I am trying to figure out how to loop code inside of a case statement. In the attached code i am trying to loop "case'4'":

code:

#include <Keypad.h>

#define REDPIN 10
#define GREENPIN 11
#define BLUEPIN 9

#define FADESPEED 10

const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
char keys[ROWS][COLS] = {
{'1','2','3','4'},
{'5','6','7','8'},
{'9','0','A','B'},
{'C','D','E','F'}
};

byte rowPins[ROWS] = {6,7,8,12};
byte colPins[COLS] = {2,3,4,5};

Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

void setup(){
Serial.begin(9600);
// keypad.addEventListener(keypadEvent);
pinMode(REDPIN, OUTPUT);
pinMode(GREENPIN, OUTPUT);
pinMode(BLUEPIN, OUTPUT);
analogWrite(REDPIN, 0);
analogWrite(GREENPIN, 0);
analogWrite(BLUEPIN, 0);
}

void loop(){
char key = keypad.getKey();
if(key)
{
switch(key)
{
case '1':
analogWrite(REDPIN, 255);
analogWrite(GREENPIN, 0);
analogWrite(BLUEPIN, 0);
break;
case'2':
analogWrite(GREENPIN, 255);
analogWrite(REDPIN, 0);
analogWrite(BLUEPIN, 0);
break;
case'3':
analogWrite(BLUEPIN, 255);
analogWrite(GREENPIN, 0);
analogWrite(REDPIN, 0);
break;

case'4' :
int r, g, b;

// fade from blue to violet

for (r = 0; r < 256; r++) {
analogWrite(REDPIN, r);
delay(FADESPEED);
}
// fade from violet to red
for (b = 255; b > 0; b--) {
analogWrite(BLUEPIN, b);
delay(FADESPEED);
}
// fade from red to yellow
for (g = 0; g < 256; g++) {
analogWrite(GREENPIN, g);
delay(FADESPEED);
}
// fade from yellow to green
for (r = 255; r > 0; r--) {
analogWrite(REDPIN, r);
delay(FADESPEED);
}
// fade from green to teal
for (b = 0; b < 256; b++) {
analogWrite(BLUEPIN, b);
delay(FADESPEED);
}
// fade from teal to blue
for (g = 255; g > 0; g--) {
analogWrite(GREENPIN, g);
delay(FADESPEED);

}
break;
}
}}

Keypad_controlled_LEDstrip_NEWLOOP.ino (1.96 KB)

A While loop or a for loop come to mind. Then you can create an event to break the loop when done.

Declaring variables with a case requires that the case code is enclosed in { and } but a for loop inside a case is not necessary. All you need to do is update a counter variable each time the code for the case is executed, execute the code associated with the counter and move to a different case when the counter reaches the required value

Doing it this way means that the program does not block teh free running of loop() so it can contain code to do other things such as reading inputs

So I should use my case statements to set a counter variable and then depending on what that variable is, write code for it?

will that code still loop?

do is set the cases in void setup?

will that code still loop?

It uses the loop() function to achieve the looping

do is set the cases in void setup?

Personally I prefer to use an enum to give the cases meaningful names and you don't do that in any function. I do not know what you mean by your question

BlueSpider50:
do is set the cases in void setup?

SWAG method interpretation: Do I set the cases in void setup?

char key = keypad.getKey();
  if(key)
  {
    switch(key)
    {

If you don't press a key, the keypad library makes the return value from .getKey() == '\0' and the conditional statementif(key) does not execute.

You can see that with this simple example

void setup() {
  Serial.begin(115200);
  char key = '\0';
  if (key)
    Serial.println("key");
  else
    Serial.println("NoKey");
}

To make the cases repeat with loop() until a new key is pressed try heading your code with this

static char switchKey = '\0';
char key = keypad.getKey();
  if(key != '\0')
    switchKey = key;

  switch(switchKey)
    {
   case '1':

if you want a case to not repeat add switchKey = '\0'; before the break statement in the case.

THANK YOU! that did the trick, thank you so much.

that works very well, buuuut now once that code in the case is looping, i cant stop it with any of the other cases

if you want a case to not repeat add
switchKey = '\0';
before the break statement in the case.

buuuut now once that code in the case is looping, i cant stop it with any of the other cases

Did you add the switchKey assignment in the case you don't want to loop?

If that does not do what you want, please post your latest code and explain the issues.

buuuut now once that code in the case is looping, i cant stop it with any of the other cases

The code in case 4 is what is called "blocking". The lengthy for loops block reading the keypad. You need to check for a new key within each for loop and use that input to break out of the case.

There are several possible ways to create the break when a key press is read within the for loops, and I have chosen to use the watchdog timer as a way to exit from the blocking loops when a new key is read. You can google "Arduino watchdog timer" for more information about the watchdog.

I trigger the watchdog in a function I have called checkForExit(). I have made key a global variable as it is used in both loop() and the checkForExit() function.

My keypad is different from yours, and I have used my configuration for test, but you can easily change back to yours.

See if this does what you want for both repeats and exit from case 4.

#include <Keypad.h>
#define REDPIN 10
#define GREENPIN 11
#define BLUEPIN 9
#define FADESPEED 10
const byte ROWS = 4;   //four rows
const byte COLS = 4;  //four columns
/*
  char keys[ROWS][COLS] = {
  {'1', '2', '3', '4'},
  {'5', '6', '7', '8'},
  {'9', '0', 'A', 'B'},
  {'C', 'D', 'E', 'F'}
  };
*/
char keys[ROWS][COLS] =
{
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};
//Code that shows the the keypad connections to the arduino terminals
byte rowPins[ROWS] = {12, 8, 7, 6}; //Rows 0 to 3
byte colPins[COLS] = {5, 4, 3, 2}; //Columns 0 to 3

Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

#include <avr/wdt.h> // break from for loops with watchdog timer

char key;

void setup() {
  Serial.begin(9600);
  MCUSR = 0; //clear any existing watchdog resets

  pinMode(REDPIN, OUTPUT);
  pinMode(GREENPIN, OUTPUT);
  pinMode(BLUEPIN, OUTPUT);
  analogWrite(REDPIN, 0);
  analogWrite(GREENPIN, 0);
  analogWrite(BLUEPIN, 0);
}

void loop() {
  static char switchKey = '\0';
  key = keypad.getKey();
  if (key != '\0')
  {
    Serial.println(key);
    switchKey = key;
  }
  switch (switchKey)
  {
    case '1':
      Serial.println("case 1");
      checkForExit();
      analogWrite(REDPIN, 255);
      analogWrite(GREENPIN, 0);
      analogWrite(BLUEPIN, 0);
      //switchKey = '\0';//non repeating
      break;
    case'2':
      Serial.println("case 2");
      //checkForExit();
      analogWrite(GREENPIN, 255);
      analogWrite(REDPIN, 0);
      analogWrite(BLUEPIN, 0);
      switchKey = '\0';//non repeating
      break;
    case'3':
      Serial.println("case 3");
      //checkForExit();
      analogWrite(BLUEPIN, 255);
      analogWrite(GREENPIN, 0);
      analogWrite(REDPIN, 0);
      switchKey = '\0';//non repeating
      break;
    case'4' :
      { //add bracket for local variable scope
        int r, g, b;
        Serial.println("case 4");
        // fade from blue to violet

        for (r = 0; r < 256; r++) {
          checkForExit();
          analogWrite(REDPIN, r);
          delay(FADESPEED);
        }
        // fade from violet to red
        for (b = 255; b > 0; b--) {
          checkForExit();
          analogWrite(BLUEPIN, b);
          delay(FADESPEED);
        }
        // fade from red to yellow
        for (g = 0; g < 256; g++) {
          checkForExit();
          analogWrite(GREENPIN, g);
          delay(FADESPEED);
        }
        // fade from yellow to green
        for (r = 255; r > 0; r--) {
          checkForExit();
          analogWrite(REDPIN, r);
          delay(FADESPEED);
        }
        // fade from green to teal
        for (b = 0; b < 256; b++) {
          checkForExit();
          analogWrite(BLUEPIN, b);
          delay(FADESPEED);
        }
        // fade from teal to blue
        for (g = 255; g > 0; g--) {
          checkForExit();
          analogWrite(GREENPIN, g);
          delay(FADESPEED);

        }
        break;
      }//add bracket for local variable scope
  }
}

void checkForExit()
{
  key = keypad.getKey();
  if (key != '\0')
  {
    wdt_enable(WDTO_15MS); // turn on the WatchDog 15ms to reset
    for (;;) {}//triggers reset after 15ms
  }
}

Here is my take on avoiding for loops, and hence delays in reading inputs to change the flow of the program. I don't have a keypad to hand so in this code the program flow is determined by a pushbutton but as long as the code in loop() does not block its free running then the input will be read thousands of times a second which makes it extremely responsive.

unsigned long currentTime;
//unsigned long stateStartTime;
unsigned long countStartTime;
unsigned long countPeriod;
byte count;
byte currentState;
byte countLimit;

const byte buttonPin = A1;
byte currentButtonState;
byte previousButtonState;

void setup()
{
  Serial.begin(115200);
  pinMode(buttonPin, INPUT_PULLUP);
  currentButtonState = HIGH;
  previousButtonState = HIGH;
  countStartTime = millis();
  countPeriod = 100;
  count = 0;
  countLimit = 20;
  currentState = 0;
  Serial.println("starting in state 0");
}

void loop()
{
  currentTime = millis();
  switch (currentState)
  {
    case 0:
      if (currentTime - countStartTime > countPeriod)
      {
        Serial.print("count : ");
        Serial.println(count);
        countStartTime = currentTime;
        count++;
        if (count == countLimit)
        {
          count = 0;
          countLimit = 10;
          countPeriod = 200;
          currentState = 1;
          Serial.println("moving to state 1");
        }
      }
    case 1:
      if (currentTime - countStartTime > countPeriod)
      {
        Serial.print("count : ");
        Serial.println(count);
        countStartTime = currentTime;
        count++;
        if (count == countLimit)
        {
          count = 0;
          countLimit = 20;
          countPeriod = 100;
          currentState = 0;
          Serial.println("moving to state 0");
        }
      }
  }
  
  //code here to be executed each time through loop()
  previousButtonState = currentButtonState;
  currentButtonState = digitalRead(buttonPin);
  if (currentButtonState != previousButtonState && currentButtonState == LOW)
  {
    currentState = !currentState;
    Serial.print("\tearly move to state ");
    Serial.println(currentState);
    countStartTime = currentTime;
    count = 0;
    if (currentState == 0)
    {
      countLimit = 20;
      countPeriod = 100;
    }
    else
    {
      countLimit = 10;
      countPeriod = 200;
    }
  }
}

Note that the program could be improved by using arrays or a struct to hold parameters for the states

cattledog:
The code in case 4 is what is called "blocking". The lengthy for loops block reading the keypad. You need to check for a new key within each for loop and use that input to break out of the case.

There are several possible ways to create the break when a key press is read within the for loops, and I have chosen to use the watchdog timer as a way to exit from the blocking loops when a new key is read. You can google "Arduino watchdog timer" for more information about the watchdog.

I trigger the watchdog in a function I have called checkForExit(). I have made key a global variable as it is used in both loop() and the checkForExit() function.

My keypad is different from yours, and I have used my configuration for test, but you can easily change back to yours.

See if this does what you want for both repeats and exit from case 4.

#include <Keypad.h>

#define REDPIN 10
#define GREENPIN 11
#define BLUEPIN 9
#define FADESPEED 10
const byte ROWS = 4;  //four rows
const byte COLS = 4;  //four columns
/*
  char keys[ROWS][COLS] = {
  {'1', '2', '3', '4'},
  {'5', '6', '7', '8'},
  {'9', '0', 'A', 'B'},
  {'C', 'D', 'E', 'F'}
  };
/
char keys[ROWS][COLS] =
{
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'
', '0', '#', 'D'}
};
//Code that shows the the keypad connections to the arduino terminals
byte rowPins[ROWS] = {12, 8, 7, 6}; //Rows 0 to 3
byte colPins[COLS] = {5, 4, 3, 2}; //Columns 0 to 3

Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

#include <avr/wdt.h> // break from for loops with watchdog timer

char key;

void setup() {
  Serial.begin(9600);
  MCUSR = 0; //clear any existing watchdog resets

pinMode(REDPIN, OUTPUT);
  pinMode(GREENPIN, OUTPUT);
  pinMode(BLUEPIN, OUTPUT);
  analogWrite(REDPIN, 0);
  analogWrite(GREENPIN, 0);
  analogWrite(BLUEPIN, 0);
}

void loop() {
  static char switchKey = '\0';
  key = keypad.getKey();
  if (key != '\0')
  {
    Serial.println(key);
    switchKey = key;
  }
  switch (switchKey)
  {
    case '1':
      Serial.println("case 1");
      checkForExit();
      analogWrite(REDPIN, 255);
      analogWrite(GREENPIN, 0);
      analogWrite(BLUEPIN, 0);
      //switchKey = '\0';//non repeating
      break;
    case'2':
      Serial.println("case 2");
      //checkForExit();
      analogWrite(GREENPIN, 255);
      analogWrite(REDPIN, 0);
      analogWrite(BLUEPIN, 0);
      switchKey = '\0';//non repeating
      break;
    case'3':
      Serial.println("case 3");
      //checkForExit();
      analogWrite(BLUEPIN, 255);
      analogWrite(GREENPIN, 0);
      analogWrite(REDPIN, 0);
      switchKey = '\0';//non repeating
      break;
    case'4' :
      { //add bracket for local variable scope
        int r, g, b;
        Serial.println("case 4");
        // fade from blue to violet

for (r = 0; r < 256; r++) {
          checkForExit();
          analogWrite(REDPIN, r);
          delay(FADESPEED);
        }
        // fade from violet to red
        for (b = 255; b > 0; b--) {
          checkForExit();
          analogWrite(BLUEPIN, b);
          delay(FADESPEED);
        }
        // fade from red to yellow
        for (g = 0; g < 256; g++) {
          checkForExit();
          analogWrite(GREENPIN, g);
          delay(FADESPEED);
        }
        // fade from yellow to green
        for (r = 255; r > 0; r--) {
          checkForExit();
          analogWrite(REDPIN, r);
          delay(FADESPEED);
        }
        // fade from green to teal
        for (b = 0; b < 256; b++) {
          checkForExit();
          analogWrite(BLUEPIN, b);
          delay(FADESPEED);
        }
        // fade from teal to blue
        for (g = 255; g > 0; g--) {
          checkForExit();
          analogWrite(GREENPIN, g);
          delay(FADESPEED);

}
        break;
      }//add bracket for local variable scope
  }
}

void checkForExit()
{
  key = keypad.getKey();
  if (key != '\0')
  {
    wdt_enable(WDTO_15MS); // turn on the WatchDog 15ms to reset
    for (;:wink: {}//triggers reset after 15ms
  }
}

you are the man. works flawlessly.

thank you everyone for your very helpful insight!