Почему циклы 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
@Keltari, 👍1
Обсуждение3 ответа
Лучший ответ:
замените >=
и <=
на >
и <
соответственно.
Вы хотите, чтобы он остановился на 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
У вас есть две проблемы, связанные с проверкой границ. Для краткости, поскольку все светодиодные ветви оператора 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;
Я согласен с @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;
Это легко проверить, и вы сразу увидите, что проблема исчезла.
- Как повторить другое действие внутри цикла?
- в то время как (1) внутри, если условно
- Хочу оптимизировать этот код и добавить цикл
- Для loop, похоже, изменяется выполнение pow()
- Проблема с датчиком температуры и влажности DHT11
- Получение ошибки ets 8 января 2013,rst cause:4,boot mode(1,6) wdt reset
- Выводы прерываний Arduino Mega 2560 и отображение портов с помощью поворотного энкодера
- Данные DHT11 из Arduino UNO в Firebase через ESP8266
вы можете удалить 2/3 кода, если используете массивы, @jsotola
@jsotola это, вероятно, правда, но не меняет мою ошибку,, @Keltari
первый цикл
do
считает до -1 ... второй циклdo
печатает -1 и считает до 256 ... второй циклdo
продолжает считать с 256, потому чтоdo-while
всегда выполняется хотя бы один раз. .. используйтеif (legThreeBrightness > 255){
, @jsotolaКажется, заголовок вопроса должен немного измениться, например: «Почему циклы do while останавливаются позже, чем я ожидаю?», @Acccumulation