Go Down

Topic: Help looping code inside of a "case" (Read 181 times) previous topic - next topic

BlueSpider50

Jul 21, 2019, 11:16 pm Last Edit: Jul 21, 2019, 11:18 pm by BlueSpider50
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;   
  }
  }}







 


notsolowki

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

UKHeliBob

#2
Jul 21, 2019, 11:27 pm Last Edit: Jul 21, 2019, 11:29 pm by UKHeliBob
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
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

BlueSpider50

#3
Jul 21, 2019, 11:36 pm Last Edit: Jul 21, 2019, 11:42 pm by BlueSpider50
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?

UKHeliBob

Quote
will that code still loop?
It uses the loop() function to achieve the looping

Quote
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
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

dougp

do is set the cases in void setup?
SWAG method interpretation: Do I set the cases in void setup?
Everything we call real is made of things that cannot be regarded as real.  If quantum mechanics hasn't profoundly shocked you, you haven't understood it yet. - Niels Bohr

No private consultations undertaken!

cattledog

Code: [Select]
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 statement
Code: [Select]
if(key) does not execute.

You can see that with this simple example
Code: [Select]
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

Code: [Select]
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
Code: [Select]
switchKey = '\0'; before the break statement in the case.

BlueSpider50

#7
Jul 22, 2019, 04:02 am Last Edit: Jul 22, 2019, 04:05 am by BlueSpider50
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

cattledog

#8
Jul 22, 2019, 04:26 am Last Edit: Jul 22, 2019, 04:26 am by cattledog
Quote
if you want a case to not repeat add
switchKey = '\0';
before the break statement in the case.
Quote
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.

cattledog

Quote
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.

Code: [Select]

#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
  }
}



UKHeliBob

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.
Code: [Select]

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
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

BlueSpider50

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.

Code: [Select]

#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
  }
}




you are the man. works flawlessly.

thank you everyone for your very helpful insight!

Go Up