3

I'm sorry for the basic question, but I have a switch case where any code placed after a certain function call simply never gets called, and I've spent half a day looking at it, so thank you so much for your help.

Running on an Arduino UNO.

Here is the loop, and every option in the switch case after the call to moist_sensor.read() simply never gets in:


void loop() {

  while (Serial.available() > 0) {
    char val = (char)Serial.read(); // read data byte by byte and store it
    Serial.println(val);
    switch(val) {
        
      case 'O':
            digitalWrite(13, LOW);
            
            break;
      
      case 'I':
            digitalWrite(13, HIGH);
            
            break;

      case 'W':
            water(2000);
            break;


      case 'E':

            int reading = moist_sensor.readd(); //THE PROBLEMATIC LINE
            //Serial.println(reading); // send the received data back to raspberry pi
            break;

//it never enters any of these cases below

      case 'M':

        //String reading2 = moist_sensor.packaged_reading();
        //Serial.println(reading2); // send the received data back to raspberry pi
        break;
        

      case 'W':
        
        water(5000);
        break;

      default:

        delay(5000);

    }
  }


I've tried changing the name of the function with fears of special keywords, swapping it with other cases (such as putting case 'W' above, where it works, and vice versa), and I always get the same behaviour. If i comment the line, everything works as expected.

I know the method isn't actually called all the time, but for sanity's sake, moist_sensor.readd() right now is just:

int readd() {
return 0; 
}

It also works fine if its the last case, but this buggs me, and I want to create other cases with function calls.

Thank you so much!

2 Answers 2

5

You seemed to have solved it. For the reason, take a look at the compiler errors:

sketch_nov22a:31: error: jump to case label [-fpermissive]
       case 'M':
            ^
sketch_nov22a:25: error: crosses initialization of 'int reading'
             int reading = moist_sensor.readd(); //THE PROBLEMATIC LINE
                 ^
sketch_nov22a:38: error: jump to case label [-fpermissive]
       case 'W':
            ^
sketch_nov22a:25: error: crosses initialization of 'int reading'
             int reading = moist_sensor.readd(); //THE PROBLEMATIC LINE
                 ^
sketch_nov22a:43: error: jump to case label [-fpermissive]
       default:
       ^
sketch_nov22a:25: error: crosses initialization of 'int reading'
             int reading = moist_sensor.readd(); //THE PROBLEMATIC LINE
                 ^
exit status 1

If you got it to compile your compiler must be configured a bit differently to mine. However you can see that by putting int reading = ... in the case block, the compiler tries to execute that first (to initialize reading) which causes it to jump case labels.

By moving int reading outside the case statement, the compiler no longer has to initialize the variable, and that line merely becomes a function call and assignment (not a variable initialization).


You can avoid that by putting the code into its own block, that is, instead of:

  case 'E':

        int reading = moist_sensor.readd(); //THE PROBLEMATIC LINE
        //Serial.println(reading); // send the received data back to raspberry pi
        break;

Use:

  case 'E':
        {
        int reading = moist_sensor.readd(); //THE PROBLEMATIC LINE
        //Serial.println(reading); // send the received data back to raspberry pi
        }
        break;
2
  • Yeah, I'm using the arduino-cli to compile/upload to the board from the RPI, and while I do get error messages, turns out I might be missing a ton of warnings. Interesting to actually look into the "error: jump to case label" and how it messes the compilers logic by still considering the variable declaration valid in the next cases of the switch, but not the initialization. Thank you for the block fix! I always thought repeated declarations in cases like this would be optimized by the compiler, does it apply to this case? I'd prefer to avoid a needlessly global variable.
    – jmart
    Nov 22, 2020 at 11:58
  • The scope and lifetime of a (non-static) variable inside a block is the block itself. The compiler may well put that variable into a register and not use memory at all. So I would say, yes the compiler will optimize as much as it can.
    – Nick Gammon
    Nov 22, 2020 at 23:21
4

As soon as I posted this, I looked at the variable declaration inside the case and thought I'd fix this ugly code, and turns out that is what breaks the entire thing, I had no idea...

case 'E':

            int reading = moist_sensor.readd(); //THE PROBLEMATIC LINE
            //Serial.println(reading); // send the received data back to raspberry pi
            break;

should just be

case 'E':

            reading = moist_sensor.readd(); //THE PROBLEMATIC LINE
            //Serial.println(reading); // send the received data back to raspberry pi
            break;

with the "int reading;" declaration somewhere else above.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.