Остановить мигание светодиодов
Мой код:
// К контакту 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);}
Это то, что я пытался использовать, чтобы выключить светодиод из состояния непрерывного мигания. Итак, смысл этого проекта в том, чтобы заставить светодиоды мигать с помощью кнопки, а затем выключить их той же кнопкой. Это беспокоило меня в течение нескольких часов, и я сделал всю работу, но, похоже, не могу выполнить эту последнюю часть. Что здесь сделано неправильно?
ОТРЕДАКТИРОВАНО для уточнения:
Намерение состоит в том, чтобы при каждом нажатии кнопки светодиод переключался между мигающим и немигающим состоянием. Состояние светодиода определяется не уровнем (нажатие/ненажатие) самой кнопки, а самим действием нажатия.
@Utsav, 👍4
Обсуждение5 ответов
Лучший ответ:
Имеет смысл сделать проверку переключателя достаточно независимой от управления морганием. Это делается в следующем коде, который включает или выключает мигание при каждом нажатии кнопки. С этим кодом между нажатиями кнопки светодиод либо не горит, либо мигает с частотой около 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);
}
}
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
ОТРЕДАКТИРОВАНО
Функция 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
Как объяснил ОП в комментарии, он пытается добиться того, чтобы кнопка попеременно мигала и выключалась, а не нажималась кнопка, чтобы выключить светодиод.
Это можно сделать следующим образом:
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
попробуйте это:
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 всегда мигает, чтобы показать синхронность кода.
вот оно в действии.
код написан для картинки, но в основном работает на любом микроконтроллере.
- Интеграция 2 кнопок для включения и выключения светодиода.
- Код Arduino для управления 4 светодиодами с 4 кнопок
- Нужен ли подтягивающий/понижающий резистор для цепи светодиода кнопки?
- Светодиод с кнопочным управлением Arduino со сборкой AVR
- Как повторить другое действие внутри цикла?
- Изменение состояния светодиода с помощью кнопки приводит к нестабильному результату
- Кнопка переключения переключает между операторами обращения с разблокированием кнопки
- Проблемы с кнопками
Что вы хотите, чтобы произошло? Нажмите один раз, чтобы начать мигать, и еще раз, чтобы перестать мигать? Мигает при нажатии кнопки? Что-то другое?, @Mark Smith
Да, первое, что вы сказали. Нажмите один раз, чтобы начать мигать, и еще раз, чтобы перестать мигать., @Utsav
Могу ли я узнать, как сделать так, чтобы одна кнопка вызывала мигание светодиода, а другая кнопка останавливала мигание?, @XingSheng