Остановить мигание светодиодов

Мой код:

// К контакту 13 подключен светодиод на большинстве плат Arduino.
// дать ему имя:
int led = 13;
const int buttonPin = 2;

// процедура установки запускается один раз, когда вы нажимаете сброс:
void setup() {
  // инициализируем цифровой вывод как выход.
  pinMode(led, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
}

// процедура цикла выполняется снова и снова навсегда:
void loop() 
{
  bool buttonState = digitalRead(buttonPin);
  while (buttonState == LOW)
  {
   digitalWrite(led, HIGH);   // включаем светодиод (HIGH - уровень напряжения)
   delay(1000);               // ждем секунду
   digitalWrite(led, LOW);    // выключаем светодиод, понижая напряжение
   delay(1000);               // ждем секунду
   }
 if (buttonState == HIGH){
   digitalWrite(led, LOW);}
  }

Последняя строка кода:

if (buttonState == HIGH){
   digitalWrite(led, LOW);}

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

ОТРЕДАКТИРОВАНО для уточнения:

Намерение состоит в том, чтобы при каждом нажатии кнопки светодиод переключался между мигающим и немигающим состоянием. Состояние светодиода определяется не уровнем (нажатие/ненажатие) самой кнопки, а самим действием нажатия.

, 👍4

Обсуждение

Что вы хотите, чтобы произошло? Нажмите один раз, чтобы начать мигать, и еще раз, чтобы перестать мигать? Мигает при нажатии кнопки? Что-то другое?, @Mark Smith

Да, первое, что вы сказали. Нажмите один раз, чтобы начать мигать, и еще раз, чтобы перестать мигать., @Utsav

Могу ли я узнать, как сделать так, чтобы одна кнопка вызывала мигание светодиода, а другая кнопка останавливала мигание?, @XingSheng


5 ответов


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

3

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

enum { LED=13, ButtonPin=2, BounceMS=50, BlinkMS=256 };
unsigned long buttonAt;
bool blinky, bouncy, buttonState;

void setup() {
  pinMode(LED, OUTPUT);
  pinMode(ButtonPin, INPUT_PULLUP);
  blinky = bouncy = buttonState = false;
  buttonAt = millis();
}

void loop() {
  // Обнаружение изменений кнопки
  if (bouncy) {
    if (millis() - buttonAt > BounceMS)
      bouncy = false;       // Конец периода отката
  } else {
    if (digitalRead(ButtonPin) != buttonState) {
      buttonState = digitalRead(ButtonPin);
      buttonAt = millis();
      bouncy = true;        // Начать период устранения дребезга
      if (buttonState) {    // Была ли только что нажата кнопка?
        blinky = !blinky;   // Переключить мерцание
      }
    }
  }
  // Управление миганием
  if (blinky) {
    // Включаем светодиод для BlinkMS мс, затем выключаем для того же
    digitalWrite(LED, (millis() - buttonAt)%(2*BlinkMS) < BlinkMS);
  } else {
    digitalWrite(LED, LOW);
  }
}
,

2
while (buttonState == LOW)

погружает вас в бесконечный цикл, как только buttonState == LOW.
Вы должны опросить buttonState внутри этого цикла, если хотите выйти из него.
Однако этого недостаточно для ваших целей. Что вам действительно нужно, так это переменная (логическая) — назовем ее, например, blinking, — которая меняет свое значение каждый раз, когда вы видите спадающий фронт в buttonState.
Затем проверьте значение этой переменной в предложении if/else следующим образом:

if (blinking == true)
{
   digitalWrite(led, HIGH);   // включаем светодиод (HIGH - уровень напряжения)
   delay(1000);               // ждем секунду
   digitalWrite(led, LOW);    // выключаем светодиод, понижая напряжение
   delay(1000);               // ждем секунду
}
else
{
   digitalWrite(led, LOW);}
}

Но при этом вы вскоре столкнетесь со следующей проблемой: скорость опроса для вашей кнопки очень низкая из-за очень длительных задержек, которые удерживают вас около 2 секунд внутри предложения if.< бр> Попробуйте настроить цикл моргания с помощью ШИМ, как описано здесь
Затем используйте приведенное выше предложение if, чтобы установить коэффициент заполнения ШИМ равным 50%, и предложение else, чтобы установить его равным 0%.

,

Итак, вы хотите, чтобы я поместил **If (buttonState == HIGH)** внутри цикла while?, @Utsav

@Utsav Это не поможет. buttonState не отражает текущее состояние контакта. digitalRead делает это., @KIIV

@KIIV, поэтому я поместил еще один **bool buttonState = digitalRead(buttonPin);** внутри цикла while, а затем вырезал и вставил оператор **If** внутри цикла while. Они по-прежнему не дают результата: / Извините, я не смог реализовать то, что вы хотели..., @Utsav

@Utsav нет, вы хотите обновить buttonState, а не создавать новый и затенять другой из-за пределов области видимости., @KIIV

Когда я создаю эту новую переменную bool под названием «мигание», задаю ли я переменную число? например: **bool моргание = 0;** или сделать что-то еще? я совсем запуталась.., @Utsav

Этот ответ несколько вводит в заблуждение. Опрос buttonState внутри цикла while(buttonState==LOW) ничего не дает., @Mark Smith


3

ОТРЕДАКТИРОВАНО

Функция Arduino loop() делает использование цикла while избыточным в этом случае. Хуже того: то, как вы реализовали этот цикл while, предотвращает обновление buttonState, что приводит к застреванию в цикле.

Что вам действительно нужно, так это использовать таймеры для мигания светодиода и машину с двумя состояниями, управляемую переходами кнопок с ВЫСОКОГО на НИЗКИЙ.

Вместо этого попробуйте следующее:

#include "Timer.h"

// К контакту 13 подключен светодиод на большинстве плат Arduino.
// дать ему имя:
const int led = 13;
const int buttonPin = 2;

// объявляем переменные состояния глобальными
bool buttonState = LOW;
bool buttonState_prev = LOW;
bool toggleBlinking;
bool blinkState;

// объявляем объект Timer, чтобы мигание можно было выполнять без потери нажатия кнопок
Timer timer_b;
int blink_id;

// процедура установки запускается один раз, когда вы нажимаете сброс:
void setup() {
  // инициализируем цифровой вывод как выход.
  pinMode(led, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);

  // исходное состояние: переключать светодиод каждые 1000 мс
  blink_id = timer_b.oscillate(led, 1000, HIGH);
  blinkState = true;
  toggleBlinking = false;
}

// процедура цикла выполняется снова и снова навсегда:
void loop() {
  // Обновить таймер (обязательно)
  timer_b.update();

  // проверяем, была ли нажата кнопка (с ВЫСОКОГО на НИЗКИЙ),
  // затем отменить дребезг и поднять флаг переключения
  buttonState = digitalRead(buttonPin);
  if ((buttonState != buttonState_prev) && (buttonState_prev == HIGH)) {
    // простое устранение дребезга кнопок (подтверждение нажатия через несколько мс)
    delay (50);
    buttonState = digitalRead(buttonPin);
    if (buttonState != buttonState_prev) toggleBlinking = true;
  }

  // сохранить текущее состояние светодиода, если кнопка не была нажата
  switch (blinkState) {
    case true:
      // если кнопка была нажата, прекращаем мигать и меняем состояние светодиода
      if (toggleBlinking == true) {
        timer_b.stop (blink_id);
        blinkState = false;
      }
      break;
    case false:
      digitalWrite(led, LOW);
      // если кнопка была нажата, начинаем мигать и менять состояние светодиода
      if (toggleBlinking == true) {
        blink_id = timer_b.oscillate(led, 1000, HIGH);
        blinkState = true;
      }
      break;
  }

  buttonState_prev = buttonState;
  toggleBlinking = false;
}

ПРИМЕЧАНИЕ. Вам потребуется установить библиотеку Timer.h. Я ПРОВЕРИЛ СВОЙ КОД, И ОНО РАБОТАЕТ.

,

Это не [тупик](https://en.wikipedia.org/wiki/Deadlock), но в остальном хорошо :-), @Mark Smith

Вы правы, спасибо. Я отредактирую ответ., @Enric Blanco

Ваш код просто заставляет светодиод мигать один раз... Я понимаю, что вы пытаетесь здесь сделать, но я хотел, чтобы светодиод мигал непрерывно после нажатия кнопки. Но при повторном нажатии кнопки они перестают мигать. Как я уже сказал, светодиод мигает только один раз, а затем перестает мигать без нажатия кнопки..., @Utsav

Хорошо, я посмотрю, как ты подтягиваешься. Я проверю его., @Enric Blanco

Да, извините, надо было рассказать подробнее :/, @Utsav

@EnricBlanco, есть новости? извините, я просто молчал об этом некоторое время и мне нужно объяснение проблем.., @Utsav

Я отредактировал ответ, посмотрите., @Enric Blanco


3

Как объяснил ОП в комментарии, он пытается добиться того, чтобы кнопка попеременно мигала и выключалась, а не нажималась кнопка, чтобы выключить светодиод.

Это можно сделать следующим образом:

bool prevButtonState;
bool ledBlinking;

void loop() 
{
    bool buttonState = digitalRead(buttonPin);

    if (prevButtonState && !buttonState)
    { // Нажатие края: есть переход между высоким и низким
        ledBlinking = !ledBlinking;
    }
    prevButtonState = buttonState;

    if (ledBlinking)
    {
        digitalWrite(led, HIGH);   // включаем светодиод (HIGH - уровень напряжения)
        delay(1000);               // ждем секунду
        digitalWrite(led, LOW);    // выключаем светодиод, понижая напряжение
        delay(1000);               // ждем секунду
    }
    else
    {
        digitalWrite(led, LOW);
    }
}

Однако это приводит к очень длительному времени между последовательными проверками кнопки (поскольку между циклами существует 2-секундная задержка). Вы можете решить эту проблему с помощью функции millis:

bool prevButtonState;
bool ledBlinking;
unsigned long prevMillis;

void loop() 
{
    bool buttonState = digitalRead(buttonPin);

    if (prevButtonState && !buttonState)
    { // Нажатие края: есть переход между высоким и низким
        ledBlinking = !ledBlinking;

        prevMillis = millis() - 1000; // Принудительная проверка
    }
    prevButtonState = buttonState;

    if (ledBlinking)
    {
        if ((millis() - prevMillis) >= 1000)
        {
            prevMillis += 1000;
            digitalWrite(led, !digitalRead(led));
        }
    }
    else
    {
        digitalWrite(led, LOW);
    }
}

Далее возникает проблема устранения дребезга, но она становится ОТ. Предложение: используйте библиотеку Bounce2 для управления кнопкой, если вы испытываете отказы

,

Нет, я хочу использовать кнопку, чтобы выключить светодиод... Как выключатель и лампочку... с той лишь разницей, что лампочка мигает., @Utsav

В этом комментарии вы говорите, что хотите одно нажатие -> мигание светодиода, другое нажатие -> погас. Это то, что делает мой код. Ваш код удерживается -> светодиод мигает, оставьте ненажатым -> светодиод погаснет, @frarugi87


1

попробуйте это:

if (key_pressed()) digitalWrite(LED_PIN, (digitalRead(LED_PIN)==ON)?OFF:ON);
else digitalWrite(LED_PIN, OFF);

определить ВКЛ/ВЫКЛ в зависимости от подключения светодиода.

Изменить.

Если вы хотите, чтобы кнопка также меняла режим мигания светодиода, попробуйте это.

    if (btn_pressed())                  //если обнаружен задний фронт btn
        btn_status ^= 1;                // перевернуть последний бит. btn_status += 1; работает также
    if (btn_status & 0x01) led1_flp();  //перевернуть светодиод1
    else led1_off();                    //иначе выключаем led1

    //перевернуть светодиод2
    IO_FLP(LED_PORT, LED2);

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

в основном, нажмите кнопку, светодиод начнет мигать; нажмите кнопку второй раз, светодиод перестанет мигать;

индикатор 2 всегда мигает, чтобы показать синхронность кода.

вот оно в действии.

код написан для картинки, но в основном работает на любом микроконтроллере.

,