Switch Case Example clarification

Hi folks. New guy here and in need of some explanation on switch case. In the example code provided for learners, the code seems to run the case and then skips out to do the default. Is this how it is supposed to work? How would I get the pin turned on by case 'a' ,for example, to stay on until 'b' is input. Right now case 'a' , (or b or c for that matter) only flashes on and then it's immediately shut off.

Many Thanks!

/*
  Switch statement  with serial input
 
 Demonstrates the use of a switch statement.  The switch
 statement allows you to choose from among a set of discrete values
 of a variable.  It's like a series of if statements.
 
 To see this sketch in action, open the Serial monitor and send any character.
 The characters a, b, c, d, and e, will turn on LEDs.  Any other character will turn
 the LEDs off.
 
 The circuit:
 * 5 LEDs attached to digital pins 2 through 6 through 220-ohm resistors
 
 created 1 Jul 2009
 by Tom Igoe 
 
This example code is in the public domain.
   
 http://www.arduino.cc/en/Tutorial/SwitchCase2
 */

void setup() {
  // initialize serial communication:
  Serial.begin(9600); 
   // initialize the LED pins:
      for (int thisPin = 9; thisPin < 12; thisPin++) {
        pinMode(thisPin, OUTPUT);
      } 
}

void loop() {
  // read the sensor:
  if (Serial.available() > 0) {
    int inByte = Serial.read();
    // do something different depending on the character received.  
    // The switch statement expects single number values for each case;
    // in this exmaple, though, you're using single quotes to tell
    // the controller to get the ASCII value for the character.  For 
    // example 'a' = 97, 'b' = 98, and so forth:

    switch (inByte) {
    case 'a':    
      digitalWrite(9, LOW);
      break;
    case 'b':    
      digitalWrite(10, LOW);
      break;
    case 'c':    
      digitalWrite(11, LOW);
      break;
    default:
      // turn all the LEDs off:
      for (int thisPin =9; thisPin < 12; thisPin++) {
        digitalWrite(thisPin, HIGH);
      }
    } 
  }
}

Change Serial Monitor to not send line terminating characters.

NO.
Default only runs if none of the other cases apply.

Question as to practices:

Is there any reason to use Switch/Case vs a chain of if/else if's? Which is preferred for what scenarios?

The only difference is readability. At the end of the compilation they both produce the same code. It is easier for most folks to read a chain of case statements than it is to weed through all the if esle-if statements. But there is zero performance difference.

For a series of simple comparisons, like the example, I find a switch / case to be more readable.

Some compilers (not the avr-gcc compiler) will use a computed jump dramatically improving speed and reducing size.

Use whichever will make sense to your future self; in one year, which one will you understand without having to think.

Delta_G:
The only difference is readability. At the end of the compilation they both produce the same code. It is easier for most folks to read a chain of case statements than it is to weed through all the if esle-if statements. But there is zero performance difference.

No the code implementation is different ( significantly switch uses ..jump tables if then else ... indirect pointer transfer ).. if the switch case resolves logically to a simple two stage process then generally the compiler will revert the code to reflect this, and generate if then else ... in this case obviously the switch case should not have neen used in the first place

A switch case compiled to a jump table is a far more efficient solution for a multiple values selection than the comparable if then else chain.

Just a bit of history for you ... Switch case was originaly proposed by Worth the designer of 'Pascal' but he mainrtained that all cases should be defined, so for a 16 bit unsigned integer you would have had a table with entries 0 to 65535 not very practical, solution other language development defined the 'default' sometimes refered to as the 'Otherwise clause' thus limiting the size of the jump table.

The switch case in C / C++ does have limtations on combinatorial based selection which ...if then else does not.

However equally the asbility to define

case n:
case n+1:

{...... break;}

i.e multiple selection using same code without the need for combinatorial equations which would the case in if then else chains..

Coding Badly had the correct answer to your problem. If you put in a Serial.println() in each of the case statements, you can see it strobe the default case unless you have "No line ending" set in the Serial monitor. One minor change:

   int inByte = tolower(Serial.read());

and you don't have to worry about the person who runs their keyboard with the Caps Lock on.

Thanks! Setting the serial monitor to "No line ending" fixed the issue. Now it works like the examples on the YouTubes. No trouble in the code at all! Now to try the extra suggestions concerning capital letter input.

Again, Thanks to all!

Hello All,

I am also interested in using the Switch Case, but in relation to time. Therefore, how can I use two different intervals, such as fast and slow when I am pressing the button?

For example, when I press the button quickly (0.5sec) the Red led will turn on, but if I press the button slowly (2 sec.) then the Green led will be on, etc.

Any ideas, if this can be implemented with the Switch case? It seems obvious, but :slight_smile:

Best.

Any ideas, if this can be implemented with the Switch case?

Possibly, but why? There are only three states. The switch was pressed for less than 1/2 a second, the switch was pressed for 1/2 second or more but less than 2 seconds, or the switch was pressed for more than 2 seconds.

The switch statement is not designed to be used with ranges. The if statement is. Use the appropriate tool for the job.

Button closing to GND, GitHub - thomasfredericks/Bounce2: Debouncing library for Arduino and Wiring for button handling.

A press of

  • 0.5 seconds to 2 seconds (excluding) lites green led
  • 2 seconds to 3 seconds (excluding) lites red led
#include <Bounce2.h>

const byte redLedPin = 2;
const byte greenLedPin = 3;
const byte buttonPin = 4;

Bounce Taste;

void setup() {
  pinMode(redLedPin, OUTPUT);
  pinMode(greenLedPin, OUTPUT);
  Taste.attach(buttonPin, INPUT_PULLUP);
}

void loop() {
  static unsigned long downAt;
  if (Taste.update()) {
    if (Taste.fell()) {
      downAt = millis();
      digitalWrite(redLedPin, LOW);
      digitalWrite(greenLedPin, LOW);
    } else {
      switch (millis() - downAt) {
        case 500 ... 1999:
          digitalWrite(redLedPin, HIGH);
          break;
        case 2000 ... 2999:
          digitalWrite(greenLedPin, HIGH);
          break;
      }
    }
  }
}

KenF:
NO.
Default only runs if none of the other cases apply.

Nope, it will happily run if there is no break (or return() or other statement that changes the control flow) between the cases.

For real abuse of a case, check out duff's device
Duff himself said that "This code forms some sort of argument in that debate ["fall through" in a case], but I'm not sure whether it's for or against."

KeithRB:
Nope, it will happily run if there is no break (or return() or other statement that changes the control flow) between the cases.

You're replying to a 2 year old part of the thread :wink:

But it was wrong! And I like bringing up Duff's Device anytime I can, just because. 8^)

Whandall:
Button closing to GND, GitHub - thomasfredericks/Bounce2: Debouncing library for Arduino and Wiring for button handling.

A press of

  • 0.5 seconds to 2 seconds (excluding) lites green led
  • 2 seconds to 3 seconds (excluding) lites red led
#include <Bounce2.h>

const byte redLedPin = 2;
const byte greenLedPin = 3;
const byte buttonPin = 4;

Bounce Taste;

void setup() {
 pinMode(redLedPin, OUTPUT);
 pinMode(greenLedPin, OUTPUT);
 Taste.attach(buttonPin, INPUT_PULLUP);
}

void loop() {
 static unsigned long downAt;
 if (Taste.update()) {
   if (Taste.fell()) {
     downAt = millis();
     digitalWrite(redLedPin, LOW);
     digitalWrite(greenLedPin, LOW);
   } else {
     switch (millis() - downAt) {
       case 500 ... 1999:
         digitalWrite(redLedPin, HIGH);
         break;
       case 2000 ... 2999:
         digitalWrite(greenLedPin, HIGH);
         break;
     }
   }
 }
}

Wandhal thank you for your input! It looks useful, however, I am wondering how to set the level of the fell() and rose()? For example, I am using a sensor, not a button anymore :slight_smile: Values are in a respective window (eg. between 22k 30k) and I would like to follow the timing of the difference (e.g. if the input rises for 10% start counting time and do something after 0.5sec, of course if the value is above... etc). Hence I am thinking to have a custom settings for the low and high value of the fell, rose... and then start counting time!

Best.

I have done some changes...

static unsigned long highAt;

if(Sensor.getProximity() > Redline){
  Taste.update();
  if(Taste.rose()){
    highAt = millis();
    //Serial.println(highAt);
  }
  else{
    switch (millis() - highAt) {
      case 500 ... 1999:
        //Serial.println("between 500 and 1990");
        break;
      case 2000 ... 2999:
        //Serial.println("above 2999");
        break;    
    }
  }
}

I would like to measure the time accordingly. I have as well put my measurements into the pic :slight_smile: looks nice, must admit...

Why are you abusing the switch statement that way? if/else if would look a lot more intelligent.

Agree, but I am not sure how to implement the timing in that case...

mu234:
Agree, but I am not sure how to implement the timing in that case...

    unsigned long duration = millis() - highAt;
    if(duration >= 500 && duration < 2000)
    {
        //Serial.println("between 500 and 1990");
    }
    else if(duration >= 2000 && duration < 3000)
    {
        //Serial.println("above 2999");
    }

Of course, that last commented out Serial.print() statement is nonsense...