Как повторить другое действие внутри цикла?

Итак, я только начал программировать Arduino (и вообще), поэтому я делаю простые вещи, такие как включение и выключение светодиодов.

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

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

Кто-нибудь может мне помочь? вот код

int LED1 = 2;
int LED2 = 3;
int LED3 = 4;
int LED4 = 5;
int LED5 = 6;
int buttonON = 7;
int buttonOFF = 8;

void setup()
{
  pinMode(LED1, OUTPUT); 
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(LED4, OUTPUT);
  pinMode(LED5, OUTPUT);
  pinMode(buttonON, INPUT_PULLUP);
  pinMode(buttonOFF, INPUT_PULLUP);
}

void loop ()
{
  if (digitalRead(buttonON)== LOW)
  {
    delay(300), digitalWrite(LED1, HIGH);
    delay(50), digitalWrite(LED2, HIGH);
    delay(50), digitalWrite(LED3, HIGH);
    delay(50), digitalWrite(LED4, HIGH);
    delay(50), digitalWrite(LED5, HIGH);
    delay(300), digitalWrite(LED1, LOW);
    delay(100), digitalWrite(LED2, LOW);
    delay(100), digitalWrite(LED3, LOW);
    delay(100), digitalWrite(LED4, LOW);
    delay(100), digitalWrite(LED5, LOW);
  }
 if (digitalRead(buttonOFF)== LOW)
 {
  digitalWrite(LED1, LOW);
  digitalWrite(LED2, LOW);
  digitalWrite(LED3, LOW);
  digitalWrite(LED4, LOW);
  digitalWrite(LED5, LOW);
 }
}

P.S. если у кого-нибудь есть другие общие советы, я бы очень их оценил

, 👍5

Обсуждение

вставьте разделительный слой между нажатием кнопки и светодиодным освещением ... используйте переменную флага .... "если (digitalRead(кнопка)== НИЗКИЙ) ledsON = true;` .... затем далее в коде" если (ledsON) { / код светодиодного освещения}"... вы можете установить/снять флажок "ledsON" любое количество раз, чтобы вы могли проверять кнопку после того, как загорится каждый светодиод ... таким образом, вам не придется удерживать кнопку до тех пор, пока последовательность не будет завершена, @jsotola

хороший способ задать вопрос ;) Красиво написано, отформатировано +1, @ArduinoFan

Я так понимаю, вы новичок в программировании?, @user253751

да, как я уже сказал, я только начал и решил начать программировать с помощью Arduino, @AndreFro


3 ответа


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

3

Вы прекрасно написали свой вопрос. В вашем случае, согласно вашей логике, кнопку нужно держать нажатой, чтобы светодиоды горели в нужном вам порядке. Функция single loop() является частью скетча Arduino, но она никогда не является ограничением.

Один из способов решить вашу проблему-сделать логику светодиодного привода независимой от состояния нажатия кнопки.

  • Как только вы обнаружите нажатие кнопки, сохраните событие в одной переменной.
  • Давайте назовем это ButtonStatus.
  • Поэтому вскоре после обнаружения нажатия клавиши обновите переменную ButtonStatus до значения TRUE.
  • Ваша логика светодиодного привода может проверить это значение переменной, чтобы решить, следует ли управлять светодиодами или нет
  • Вскоре после того, как вы обнаружите еще одно нажатие второй кнопки, вы можете обновить значение переменной до FALSE.
    Вот результат моделирования Arduino для вашего кода и код, предложенный @cat

ниже приведено после адаптации решения от cat

Ссылки на моделирование находятся здесь: Оригинальная проблема решение 1

int LED1 = 2;
int LED2 = 3;
int LED3 = 4;
int LED4 = 5;
int LED5 = 6;
int buttonON = 7;
int buttonOFF = 8;
int ledEffectON;
void setup()
{
  pinMode(LED1, OUTPUT); 
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(LED4, OUTPUT);
  pinMode(LED5, OUTPUT);
  pinMode(buttonON, INPUT_PULLUP);
  pinMode(buttonOFF, INPUT_PULLUP);
}

void loop ()
{
  if (digitalRead(buttonON)== LOW)
      ledEffectON = true;

  if (digitalRead(buttonOFF)== LOW)
      ledEffectON = false;

  if(ledEffectON)
  {
    delay(300), digitalWrite(LED1, HIGH);
    delay(50), digitalWrite(LED2, HIGH);
    delay(50), digitalWrite(LED3, HIGH);
    delay(50), digitalWrite(LED4, HIGH);
    delay(50), digitalWrite(LED5, HIGH);
    delay(300), digitalWrite(LED1, LOW);
    delay(100), digitalWrite(LED2, LOW);
    delay(100), digitalWrite(LED3, LOW);
    delay(100), digitalWrite(LED4, LOW);
    delay(100), digitalWrite(LED5, LOW);
  }
}

Ссылка на документы на кнопках. Симулятор Arduino Wokwi имитирует debounce по умолчанию - точно так же, как в реальном мире. Отмена-это очень важный метод, который вы должны рассмотреть возможность добавления в код. Чтобы отключить опцию "отскок", используйте следующий трюк!

{ "bounce": "0" }
,

Спасибо, я действительно ценю время, которое вы потратили на это объяснение, @AndreFro

Очень красивые диаграммы!, @JosephDoggie

@Juraj принес резисторы. Я также обновил ссылки, на которые ссылаются. Теперь вы также должны увидеть токоограничивающие резисторы!, @ArduinoFan


2

Вам просто нужно сохранить состояние светодиодов в новой переменной ...

void loop ()
{
  if (digitalRead(buttonON)== LOW)
      ledEffectON = true;

  if (digitalRead(buttonOFF)== LOW)
      ledEffectON = false;

  if(ledEffectON)
  {
    delay(300), digitalWrite(LED1, HIGH);
    delay(50), digitalWrite(LED2, HIGH);
    delay(50), digitalWrite(LED3, HIGH);
    delay(50), digitalWrite(LED4, HIGH);
    delay(50), digitalWrite(LED5, HIGH);
    delay(300), digitalWrite(LED1, LOW);
    delay(100), digitalWrite(LED2, LOW);
    delay(100), digitalWrite(LED3, LOW);
    delay(100), digitalWrite(LED4, LOW);
    delay(100), digitalWrite(LED5, LOW);
  }
}
,

https://wokwi.com/arduino/projects/304626706673566272 Замечательное решение!, @ArduinoFan

Спасибо за короткий и простой ответ, @AndreFro

Очень редко проверяется наличие кнопки. Его нужно нажать, когда светодиод 5 погаснет, @DataFiddler

разве это не тот же код, что и в ответе Ардуинофана?, @Juraj


6

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

Кроме того, контакты кнопок, как правило, несколько раз отскакивают в течение нескольких миллисекунд, когда они меняют состояние, посылая последовательность импульсов включения/выключения в микроконтроллер, поэтому их необходимо отключить. Вы можете найти много алгоритмов дебоунсинга в Интернете, но вот простой дебоунсер, который я разместил на GitHub.

void loop ()
{
  static bool doLightshow = false;

  static Debouncer buttonOn(buttonON);
  static Debouncer buttonOff(buttonOFF);

  buttonOn.Update();
  buttonOff.Update();

  if (buttonOn.Fall())
  {
    Serial.println("buttonOn falling edge.");
    doLightshow = true;
  }
  else if (buttonOff.Fall())
  {
    Serial.println("buttonOff falling edge.");
    doLightshow = false;
  }

  if (doLightshow)
  {
    // Do lightshow.
    . . .
  }
  else
  {
    digitalWrite(LED1, LOW);
    digitalWrite(LED2, LOW);
    digitalWrite(LED3, LOW);
    digitalWrite(LED4, LOW);
    digitalWrite(LED5, LOW);
  }
}

Благодаря тому, как вы аккуратно написали свой код, вы, вероятно, сможете выделить шаблон в световом шоу.

Состояние Время задержки Светодиодный контакт Состояние светодиода
0 300 СВЕТОДИОД1 ВЫСОКИЙ
1 50 СВЕТОДИОД2 ВЫСОКИЙ
2 50 СВЕТОДИОД3 ВЫСОКИЙ
3 50 СВЕТОДИОД4 ВЫСОКИЙ
4 50 СВЕТОДИОД5 ВЫСОКИЙ
5 300 СВЕТОДИОД1 НИЗКИЙ
6 100 СВЕТОДИОД2 НИЗКИЙ
7 100 СВЕТОДИОД3 НИЗКИЙ
8 100 СВЕТОДИОД4 НИЗКИЙ
9 100 СВЕТОДИОД5 НИЗКИЙ

Это хорошо подходит для создания конечного автомата, который может храниться в массиве структур:

typedef struct LightshowData
{
  unsigned int delayTime;
  byte ledPin;
  bool ledState;
};

const byte numStates = 10;

const LightshowData lightshowData[numStates] =
{
  { 300, LED1, HIGH },
  {  50, LED2, HIGH },
  {  50, LED3, HIGH },
  {  50, LED4, HIGH },
  {  50, LED5, HIGH },
  { 300, LED1, LOW },
  { 100, LED2, LOW },
  { 100, LED3, LOW },
  { 100, LED4, LOW },
  { 100, LED5, LOW }
};

Теперь конечный автомат может циклически перемещаться по массиву неблокирующим образом:

    // Do lightshow.
    static byte state = 0;
    unsigned long currentTimestamp = millis();
    static unsigned long previousTimestamp = currentTimestamp;

    if (currentTimestamp - previousTimestamp >= lightshowData[state].delayTime)
    {
      previousTimestamp += lightshowData[state].delayTime;
      digitalWrite(lightshowData[state].ledPin, lightshowData[state].ledState);
      state = ++state % numStates;
      Serial.print("state = ");
      Serial.println(state);
    }

Возможно, вам захочется сбросить состояние до 0 после отрицательного края при нажатиикнопки, в противном случае световое шоу продолжится с того места, на котором оно остановилось после остановки и перезапуска.

Вот моделирование светового шоу Wokwi с защитными резисторами 250 Ом для светодиодов.

Wokwi по умолчанию имитирует отскок кнопки, чтобы более точно моделировать реальный мир, поэтому желательно иметь некоторую форму отскока кнопки.

,

спасибо, чувак, выглядит немного сложно, но я обязательно проверю это, @AndreFro

Когда функция loop() не требует никакого времени ( избегайте задержек и вложенных циклов, отнимающих много времени), логика вашей программы полностью отличается от предыдущей, но более гибкая и простая, как только вы привыкнете к ней., @DataFiddler