Почему циклы Do While не останавливаются?

Я давно смотрю на это, и у меня косоглазие. Я пишу простую программу для изменения цвета трехцветного светодиода. Он работает, но потом я заметил, что светодиод иногда мигает. Я провел множество тестов и, в конце концов, используя последовательный монитор, обнаружил проблему. Яркость должна отсчитываться до уровня яркости 0 и до уровня 255. Однако иногда он отсчитывается от 0 до -1 и иногда продолжается до бесконечности после 255. Я не могу понять, почему. Ниже приведен код и выходные данные последовательного монитора. Единственный способ остановить это вручную установить значение вне цикла. Вы можете видеть, что эти строки закомментированы, чтобы учесть ошибку.

int randLeg;  // var для выбора случайной ноги

// установить все 3 ноги на максимальную яркость в начале
int legThreeBrightness = 255;
int legFiveBrightness = 255;
int legSixBrightness = 255;
int delayTime = 15;
int increment = 1;

void setup() {

    Serial.begin(9600);     

    // установить выводы в качестве вывода
    pinMode(3, OUTPUT);
    pinMode(5, OUTPUT);
    pinMode(6, OUTPUT);
    
    // включить все светодиоды
    analogWrite(3, legThreeBrightness);
    analogWrite(5, legFiveBrightness);
    analogWrite(6, legSixBrightness);

    randomSeed(analogRead(0));  // генератор начальных случайных чисел

}  

void loop() {  
  
    randLeg = random(4, 7);  // выбираем случайную ногу
    
    switch (randLeg) {
    case 4:  //-1 для контакта 3
        if (legThreeBrightness == 255){
          do {
                Serial.println(legThreeBrightness);
                analogWrite(3, legThreeBrightness);
                delay(delayTime);
                legThreeBrightness = legThreeBrightness - increment;
             } while (legThreeBrightness >= 0);   
             //legThreeBrightness = 0;
        }
        else {
         do {
                Serial.println(legThreeBrightness);
                analogWrite(3, legThreeBrightness);
                delay(delayTime);
                legThreeBrightness = legThreeBrightness + increment;
             } while (legThreeBrightness <= 255);
             //legThreeBrightness = 255;
        }
      break;
      
    case 5:
        if (legFiveBrightness == 255){
          do {
                ////Serial.println(le gFiveBrightness);
                analogWrite(5, legFiveBrightness);
                delay(delayTime);
                legFiveBrightness = legFiveBrightness - increment;
             } while (legFiveBrightness >= 0);  
             //legFiveBrightness = 0;
        }
        else {
         do {
                ////Serial.println(legFiveBrightness);
                analogWrite(5, legFiveBrightness);
                delay(delayTime);
                legFiveBrightness = legFiveBrightness + increment;
             } while (legFiveBrightness <= 255);
             //legFiveBrightness = 255;
        }
      break;
    case 6:
        if (legSixBrightness == 255){
          do {
                ////Serial.println(legSixBrightness);
                analogWrite(6, legSixBrightness);
                delay(delayTime);
                legSixBrightness = legSixBrightness - increment;
             } while (legSixBrightness >= 0);   
             //legSixBrightness = 0;
        }
        else {
         do {
                ////Serial.println(legSixBrightness);
                analogWrite(6, legSixBrightness);
                delay(delayTime);
                legSixBrightness = legSixBrightness + increment;
             } while (legSixBrightness <= 255);
             //legSixBrightness = 255;
        }
      break;
   }
    
      
}

10 9 8 7 6 5 4 3 2 1 0 -1

и

250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265

, 👍1

Обсуждение

вы можете удалить 2/3 кода, если используете массивы, @jsotola

@jsotola это, вероятно, правда, но не меняет мою ошибку,, @Keltari

первый цикл do считает до -1 ... второй цикл do печатает -1 и считает до 256 ... второй цикл do продолжает считать с 256, потому что do-while всегда выполняется хотя бы один раз. .. используйте if (legThreeBrightness > 255){, @jsotola

Кажется, заголовок вопроса должен немного измениться, например: «Почему циклы do while останавливаются позже, чем я ожидаю?», @Acccumulation


3 ответа


Лучший ответ:

6

замените >= и <= на > и < соответственно.

Вы хотите, чтобы он остановился на 0, но ваш do-while сделает еще один раунд, так как 0>=0 истинно. Таким образом, ваш код останавливается только на -1 и 256.

Когда legThreeBrightness равно 256, он должен вести обратный отсчет, но ваш if (legThreeBrightness == 255){ этого не определяет, поэтому код продолжит обратный отсчет . Я бы, вероятно, изменил эту строку на if (legThreeBrightness >= 255){, чтобы этого никогда не произошло (чего не должно быть, но все же).

,

Честно говоря, я думаю, что действительно пробовал это прошлой ночью, но я попробую еще раз. Это также не объясняет, почему это происходит только иногда. Я отчитаюсь., @Keltari

Это определенно так - вы можете видеть в выводе, что он выходит за пределы и просто продолжает работать. например из одной части пробега: 252 253 254 255 256 256 257 256 258 257 257 259 258 259 258 260 259 260 260 261 262 263 261 262 263 264 265 261 264 265 266 267 262 263 Еще один способ предотвратить выход значения за границы — не использовать цикл do while, который запускает цикл ДО проверки значения. Но вам все равно нужно будет использовать < или > для сравнения, так как вы не хотите, чтобы значение уменьшалось/увеличивалось в прошлом, когда вы достигли границы своего диапазона., @Peter Feerick

это решило проблему, @Keltari


1

У вас есть две проблемы, связанные с проверкой границ. Для краткости, поскольку все светодиодные ветви оператора switch одинаковы, я буду ссылаться на legNumBrightness вместо отдельных legThreeBrightness, legFiveBrightness, переменные legSixBrightness, так как это относится ко всем трем (по отдельности).

Поскольку циклы do while всегда запускаются один раз перед проверкой условия, возникает проблема со значением legNumBrightness, выходящим за пределы допустимого диапазона. т. е. когда оно равно 255, оно уменьшается на единицу, пока не станет равным нулю, а затем, поскольку 0>=0 все еще верно (0 равно 0, после all), он снова уменьшается, поэтому legNumBrightness теперь равен -1. Таким образом, при следующем посещении этого legNumBrightness = 255 выполняется приращение вверх на одну ветвь, пока не будет достигнуто 255 <= 255, что снова верно, и, следовательно, перейдет к 256. Поскольку используемый тест границ if используется только для legNumBrightness == 255, он будет уменьшаться только в том случае, если значение равно точно 255. Таким образом, если оно не равно 255, оно будет увеличиваться до тех пор, пока достигнуто максимальное значение int (32767), переполнение до -32768 и, возможно, дальнейшее переключение между -32768 и 32767.

Поэтому, чтобы исправить это, вам нужно изменить проверку привязки if (legNumBrightness == 255) на если (legNumBrightness >= 255). Теперь, из-за цикла do while, legNumBrightness по-прежнему будет иногда переходить к -1 и 256, но может больше не выходит за рамки 256. Чтобы исправить превышение -1 и 256, удалите = из тестов do while, чтобы они стали while (legNumBrightness > 0) и while (legNumBrightness < 255) и, таким образом, не будет пытаться увеличивать или уменьшать приращение при достижении границы.

Я бы также рекомендовал использовать цикл while() вместо цикла do while(), чтобы условие проверялось перед запуск содержимого цикла, но после краткого тестирования этой логики в этом нет необходимости.

например, для legThreeBrightness

 case 4:  //-1 для контакта 3
        if (legThreeBrightness >= 255){
          do {
                //Serial.println(legThreeBrightness);
                analogWrite(3, legThreeBrightness);
                delay(delayTime);
                legThreeBrightness = legThreeBrightness - increment;
             } while (legThreeBrightness > 0);   
             //legThreeBrightness = 0;
        }
        else {
         do {
                //Serial.println(legThreeBrightness);
                analogWrite(3, legThreeBrightness);
                delay(delayTime);
                legThreeBrightness = legThreeBrightness + increment;
             } while (legThreeBrightness < 255);
             //legThreeBrightness = 255;
        }
      break;
,

0

Я согласен с @Gerben в том, что вам нужно изменить >= и <= на > и < соответственно для проверки цикла do-while.

Во-вторых, ваш оператор if ожидает, что legThreeBrightness (и др.) будет равен 255, чтобы уменьшить яркость. Поскольку ваш оператор while превышает 255 из-за <= 255, оператор if всегда будет выполнять else и, поскольку это do-while, он выполнит цикл один раз, увеличивая legThreeBrightness.

Чтобы исправить это, измените оператор if, чтобы он проверял значение выше 250:

case 4:  //-1 для контакта 3
    if (legThreeBrightness > 250){  // <---- Обратите внимание на > 250
      do {
            //Serial.println(legThreeBrightness);
            analogWrite(3, legThreeBrightness);
            delay(delayTime);
            legThreeBrightness = legThreeBrightness - increment;
         } while (legThreeBrightness > 0);   
         //legThreeBrightness = 0;
    }
    else {
     do {
            //Serial.println(legThreeBrightness);
            analogWrite(3, legThreeBrightness);
            delay(delayTime);
            legThreeBrightness = legThreeBrightness + increment;
         } while (legThreeBrightness < 255);
         //legThreeBrightness = 255;
    }
  break;

Это легко проверить, и вы сразу увидите, что проблема исчезла.

,