Цикл While не прерывается

Я пытаюсь построить схему, которая гудит до тех пор, пока не будет нажата кнопка, или она гудит 5 раз:

void alarm()
{
  int AlarmState = 0; //Just to get while loop going
  int count = 1;
  while(AlarmState==0)
  {
    int count = 1;
    AlarmState = digitalRead(alarmStop);                   
    digitalWrite(buzz,HIGH);
    AlarmState = digitalRead(alarmStop);
    delay(500);
    AlarmState = digitalRead(alarmStop);
    digitalWrite(buzz,LOW);
    AlarmState = digitalRead(alarmStop);
    delay(500);
    count++;
    if(count>=5){
       break;
    }
  }

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

Это часть более крупного проекта, но я надеюсь, что опубликовал только необходимый код. Функция запускается, но не прерывается после того, как число равно 5. Почему?

, 👍-1

Обсуждение

Удалите этот int count = 1; из цикла while., @ott--

Было бы разумнее использовать цикл for для подсчета до 5, а затем if (AlarmState != 0) break;., @Nick Gammon

@NickGammon for(unsigned char i = 0;i<5 && AlarmState != 0;i++){ ? Не уверен, что это соответствует проблеме, но это немного более читабельно (так как вы можете видеть, когда цикл закончится, внутри оператора/проверки)., @Paul

Ну, это должно быть && AlarmState == 0, чтобы соответствовать исходному сообщению, но да, это другой способ. На самом деле опубликованный код в вопросе читает alarmStop несколько раз, что немного тревожно (без каламбура). Я полагаю, это зависит от того, как быстро вы хотите отреагировать на изменение alarmStop., @Nick Gammon

Обратите внимание, что с помощью AlarmState = digitalRead(alarmStop); вы просто читаете последнее значение. Замените все эти строки на AlarmState |= digitalRead(alarmStop);; таким образом, как только одно чтение будет равно 1, оно завершится, @frarugi87


4 ответа


0

Попробуйте Это Сделать Просто:

void alarm()
{
  int count = 0;
  while ( digitalRead(alarmStop) && (count++ <5))
  {
    //A
    digitalWrite(buzz, HIGH);
    delay(500);
    digitalWrite(buzz, LOW);
    delay(500);
  }
}

Но в этом Коде есть логическая проблема. Допустим, ваш код находится в точке А (обозначен в комментарии) и в то же время нажата кнопка. Теперь этот код выше будет, все еще гудеть, а затем остановится.

Чтобы избежать Этого, попробуйте использовать прерывания. Для использования прерываний на Arduino я предпочитаю эту библиотеку. Скачать Можно Здесь. Извлеките это, и внутри вы найдете папку с именем PinChangeInt. Скопируйте всю эту папку в папку "Документы\Arduino\библиотеки". Теперь перезапустите Arduino IDE и скопируйте и вставьте этот код:

#include <PinChangeInt.h>

int buzz = 3;

bool alarmStatus = false;
#define PIN3 4
void pin3func() {
  digitalWrite(buzz, LOW);
  alarmStatus = true;
}

void setup() {
  pinMode(PIN3, INPUT); digitalWrite(PIN3, HIGH);
  PCintPort::attachInterrupt(PIN3, &pin3func, CHANGE);
}

int count = 0;
void loop() {
  if (count < 5)
  {
    if (!alarmStatus)
    {
      digitalWrite(buzz, HIGH);
    }
    delay(500);
    digitalWrite(buzz, LOW);
    delay(500);
  }
}

Из-за отсутствия аппаратного обеспечения я не тестировал этот код. Но я надеюсь, что это сработает.

,

(На вашем втором фрагменте кода) #define PIN3 4 ? Возможно, вы захотите использовать константу, а не определение. Если вы где-то напишете PIN31, он будет заменен на 41. Также немного странно определять PIN3 - 4. Кроме того, " int count = 0` помещается между функциями. Используйте статическую переменную (или глобальную переменную, размещенную в верхней части кода). Кроме того, я думаю, что вы нарушили некоторую логику, так как количество никогда не увеличивается. Переменная alarmStatus должна быть "volatile", так как она используется в прерывании (не уверен, что это тоже на Arduino)?, @Paul


0

Проблема с вашим кодом заключается в использовании функции delay(). Это функция , которой следует избегать большую часть времени по одной простой причине: когда Arduino выполняет инструкцию delay (), он ничего не делает, кроме как ждет. Это означает, среди прочего, что он не может реагировать на ввод данных пользователем. Как указано АРКОМ в его ответе, прерывания могут быть использованы для преодоления этой проблемы. Но на самом деле они вам не нужны: стандартный способ избежать задержек-вместо этого использовать функцию millis() для управления таймингами. Этот подход хорошо описан в учебнике по Arduino "Мигание без задержки ".

Вот как вы можете применить этот метод к своей функции alarm (): В двух словах, вы можете подумать, что функция delay() примерно эквивалентна этому:

void naiveDelay(uint32_t ms)
{
    uint32_t start = millis();
    while (millis() - start < ms) {
        // do nothing
    }
}

Проблема здесь заключается в части “ничего не делать". Вы не хотите, чтобы ваша программа ничего не делала, вы хотите, чтобы она следила за кнопкой “аварийная остановка”. Таким образом, простое решение вашей проблемы состоит в том, чтобы заменить функцию delay() приведенным выше кодом, а затем изменить ее так, чтобы она отслеживала кнопку, а не ничего не делала. Тогда вы получите что-то вроде этого:

void alarm()
{
    for (int count = 0; count < 5; count++) {

        // start the buzzer
        digitalWrite(buzz, HIGH);

        // first delay
        uint32_t start = millis();
        while (millis() - start < 500) {
            if (digitalRead(alarmStop) == HIGH) {
                digitalWrite(buzz, LOW);  // stop the buzzer
                return;
            }
        }

        // stop the buzzer
        digitalWrite(buzz, LOW);

        // second delay
        start = millis();
        while (millis() - start < 500) {
            if (digitalRead(alarmStop) == HIGH) {
                return;  // buzzer already off
            }
        }
    }
}
,

0

Я думаю, что основная проблема с тем, что код не нарушается в операторе while (), заключается в том, что @ott указал выше.

Чтобы подробнее рассказать о конкретной проблеме, обратите внимание, что вы определили в своем коде две разные переменные подсчета. У каждого из них своя сфера применения.

Как только вы вводите функцию будильника, вы определяете переменную int count и инициализируете ее. Затем, когда вы вводите оператор while (), вы определяете вторую переменную int count и инициализируете ее. Это НЕ одна и та же переменная. Эта вторая переменная используется и, к сожалению, каждый раз повторно инициализируется в цикле. Он всегда будет иметь значение 1, поэтому ваш тест на то, что он станет больше или равен 5, никогда не будет истинным. Таким образом, никакого перерыва.

Если вы закомментируете вторую строку int count, ваш цикл должен сработать и прерваться, как и ожидалось. это должно выглядеть так:

  while(AlarmState==0)
  {
  //  int count = 1;
    AlarmState = digitalRead(alarmStop);                   

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

,

0
void alarm()
{
  int AlarmState = 0; 
  int count = 1;
  while(AlarmState==0) //Ваше количество == 2, затем в то время как начинается снова, и вы переопределяете количество до 1, так что это становится бесконечным циклом
  {
    int count = 1; //Here you initialize "count" second time
    AlarmState = digitalRead(alarmStop);                   
    digitalWrite(buzz,HIGH);
    AlarmState = digitalRead(alarmStop);
    delay(500);
    AlarmState = digitalRead(alarmStop);
    digitalWrite(buzz,LOW);
    AlarmState = digitalRead(alarmStop);
    delay(500);
    count++; //Теперь вы увеличиваете значение счетчика, 1+1 = 2, возвращаетесь в "while" и читаете
    if(count>=5){
       break;
    }
  }
,