Параметры Switch case прерываются после вызова функции

Прошу прощения за основной вопрос, но у меня есть случай переключения, когда любой код, размещенный после вызова определенной функции, просто никогда не вызывается, и я потратил полдня на его изучение, так что большое вам спасибо за вашу помощь.

Работает на Arduino UNO.

Вот цикл, и каждый параметр в случае переключения после вызова moist_sensor.read() просто никогда не попадает:


void loop() {

  while (Serial.available() > 0) {
    char val = (char)Serial.read(); // считывать данные байт за байтом и сохранять их
    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(); //ПРОБЛЕМНАЯ СТРОКА
            //Serial.println(чтение); // отправить полученные данные обратно в raspberry pi
            break;

// он никогда не входит ни в один из приведенных ниже случаев

      case 'M':

        //Чтение строки 2 = moist_sensor.packaged_reading();
        //Serial.println(reading2); // отправить полученные данные обратно в raspberry pi
        break;
        

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

      default:

        delay(5000);

    }
  }


Я пробовал изменять имя функции с помощью специальных ключевых слов, заменяя его другими случаями (например, помещая регистр 'W' выше, где это работает, и наоборот), и я всегда получаю одно и то же поведение. Если я прокомментирую строку, все будет работать так, как ожидалось.

Я знаю, что метод на самом деле вызывается не постоянно, но ради здравомыслия moist_sensor.readd() прямо сейчас просто:

int readd() {
return 0; 
}

Это также отлично работает, если это последний случай, но это меня раздражает, и я хочу создать другие случаи с помощью вызовов функций.

Большое вам спасибо!

, 👍3


2 ответа


4

Как только я опубликовал это, я посмотрел на объявление переменной внутри корпуса и подумал, что исправлю этот уродливый код, и оказалось, что именно это все и ломает, я понятия не имел ...

case 'E':

            int reading = moist_sensor.readd(); //ПРОБЛЕМНАЯ СТРОКА
            //Serial.println(чтение); // отправить полученные данные обратно в raspberry pi
            break;

должно быть просто

case 'E':

            reading = moist_sensor.readd(); //ПРОБЛЕМНАЯ СТРОКА
            //Serial.println(чтение); // отправить полученные данные обратно в raspberry pi
            break;

с объявлением "int reading;" где-то еще выше.

,

5

Казалось, вы решили эту проблему. По этой причине взгляните на ошибки компилятора:

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

Если вы получили его для компиляции, ваш компилятор должен быть настроен немного иначе, чем мой. Однако вы можете увидеть это , поставив int reading = ... в блоке case компилятор пытается выполнить это первым (для инициализации чтения), что приводит к переходу меток case.

Перемещая чтение int за пределы оператора case, компилятору больше не нужно инициализировать переменную, и эта строка просто становится вызовом и назначением функции (а не инициализацией переменной).


Вы можете избежать этого, поместив код в его собственный блок, то есть вместо:

  case 'E':

        int reading = moist_sensor.readd(); //ПРОБЛЕМНАЯ СТРОКА
        //Serial.println(чтение); // отправить полученные данные обратно в raspberry pi
        break;

Использование:

  case 'E':
        {
        int reading = moist_sensor.readd(); //ПРОБЛЕМНАЯ СТРОКА
        //Serial.println(чтение); // отправить полученные данные обратно в raspberry pi
        }
        break;
,

Да, я использую arduino-cli для компиляции / загрузки на плату из RPI, и хотя я получаю сообщения об ошибках, оказывается, я могу пропустить кучу предупреждений. Интересно на самом деле изучить "ошибку: переход к метке регистра" и то, как она портит логику компиляторов, по-прежнему считая объявление переменной действительным в следующих случаях переключения, но не при инициализации. Спасибо вам за исправление блока! Я всегда думал, что повторяющиеся объявления в подобных случаях будут оптимизированы компилятором, применимо ли это к данному случаю? Я бы предпочел избежать ненужной глобальной переменной., @jmart

Область действия и время жизни (нестатической) переменной внутри блока - это сам блок. Компилятор вполне может поместить эту переменную в регистр и вообще не использовать память. Поэтому я бы сказал, да, компилятор будет оптимизировать столько, сколько сможет., @Nick Gammon