Включение и выключение мигающего светодиода

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

   const int redLed = 10;
const int buttonPin = 2;
unsigned long newTime;
unsigned long oldTime = 0;
byte newButtonState;
byte oldButtonState = 0;
boolean ledState = false;
boolean blinkState = false;
boolean state = LOW;


void setup() {
  pinMode(redLed, OUTPUT);
  Serial.begin(9600);
  pinMode(buttonPin, INPUT);
}

void loop() {

  newButtonState = digitalRead(buttonPin);
  delay(100);


  // check if button state has changed
  if (newButtonState != oldButtonState) {
    // if button was pushed
    if (newButtonState == HIGH) {
      // check led state
      if (ledState == false) {
        ledState = true;
        blinkState = true;
      } else {
        ledState = false;
        blinkState = false;
      }
      if (ledState == true && blinkState == true) {
        newTime = millis();
        if (newTime - oldTime >= 250) {
          state = !state;
          oldTime = newTime;
        }
        digitalWrite(redLed, state);
      }
    }
  }
  oldButtonState = newButtonState;
}

, 👍1

Обсуждение

Также не нужно добавлять "= = true" для сравнения логических значений, вы можете удалить "= = true "и вместо" = = false " поставить ! перед выражением лица., @Michel Keijzers

Спасибо, я этого не знал. Я видел несколько скетчей, где они использовали логические значения без использования"==", и я подумал, что это другое обозначение операторов if. Но что , если вы оцениваете два логических значения одновременно, например "если (ledState == true && blinkState == true)", можете ли вы также написать их без знаков==?, @Zaffresky

Да, чем вы можете написать " если (ledState && blinkState)", если вы хотите написать " если (ledState == true && blinkState == false)", вы можете написать " если (ledState && !blinkState)`, @Michel Keijzers

Круто. Узнал что-то новое. Спасибо, @Zaffresky

Я добавил ответ, чтобы показать еще одно улучшение., @Michel Keijzers


4 ответа


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

0

Я не понимаю, зачем вам устанавливать blinkState вместе с ledState. Я предполагаю, что вы хотите, чтобы кнопка переключала мигание. 1 нажмите --> СВЕТОДИОД мигает, еще одно нажатие -->> СВЕТОДИОД перестает мигать, ...>>

Я предлагаю реструктурировать ваш код. Первый отдельный вход и выход, означающий код проверки кнопки и код мигания светодиода. Для мигания у вас уже есть переменная состояния с именем blinkState. Поэтому в вашей функции loop() вы сначала пишете

newTime = millis();
if(blinkState && newTime - oldTime >= 250){
    ledState = !ledState;
    oldTime = newTime;
}

Это будет переключать состояниесветодиода всякий раз, когда задано состояние мигания, с интервалами. Теперь мы просто перепишем() это значение непосредственно после этого:

digitalWrite(redLed, ledState);

Теперь нам нужно справиться с кнопкой. Ваша кнопка, если утверждения кажутся хорошими, поэтому нам нужно только изменить то, что находится внутри утверждений. Там мы просто отрицаем переменную blinkState:

if (newButtonState != oldButtonState) {
    // если кнопка была нажата
    if (newButtonState == HIGH) {
        blinkState = !blinkState;
    }
}
oldButtonState = newButtonState;
delay(100);

С помощью этого кода светодиод перестанет меняться и сохранит то состояние, в котором он находился, когда вы нажали кнопку. Если вы хотите, чтобы светодиод выключился в этот момент, вам следует добавить ledState = false; после отрицания состояния мигания.

Обратите внимание, что этот код не нуждается в вашей переменной состояния. Для этого достаточно 2 переменных. 1 для текущего состояния светодиода, 1 для состояния мигания.

Также обратите внимание, что использование функции delay () - не лучший способ отменить действие кнопки. Это простой способ, но он может вести себя не совсем так, как вы хотите. Если вы хотите улучшить разборку, вы можете использовать библиотеку Bounce2 с github. Если вы не хотите использовать для этого библиотеку, вы все равно можете узнать об их способах отмены в файле Readme.

,

Спасибо за ваше очень ясное объяснение. Кроме того, предложение взломать код облегчает его выполнение., @Zaffresky

Я постараюсь следовать этому подходу, но все эти взаимозависимые переменные состояния являются для меня новыми и временами сбивают с толку. Я также читал о концепции state machine, и мне интересно, было бы проще кодировать в таких контекстах, @Zaffresky

Переменные состояния не являются взаимозависимыми. Вы могли бы видеть, что обе переменные относятся к другому виду. В то время как "ledState" напрямую описывает текущее выходное значение светодиодного вывода, "blinkState" описывает действие, которое немного более абстрактно. Подумайте о том, чтобы поставить одну ногу перед другой, что вы могли бы назвать одним шагом. Изменив вымышленную переменную состояния, такую как "состояние ноги", мы могли бы изменить, какая нога является передней, и, таким образом, выполнять шаги. Тогда действие "ходьба" более абстрактно, так как оно представляет собой последовательность шагов. ходьба описывает действие последовательной смены передней ноги., @chrisl

В этом случае переменная состояния не будет особенно простой в реализации. Чтобы быть точным: С помощью этого кода у вас уже есть машина состояний (поскольку вы обрабатываете переменные состояния и действуете в соответствии с ними). Просто не один, который можно легко продлить. Вы можете изменить это на более расширяемую версию (в Интернете и на этой стороне есть много руководств по FSMs), хотя это было бы больше для облегчения расширения функциональных возможностей. С текущей областью действия кода вас устраивает эта структура., @chrisl


0

Вы никогда не устанавливаете pinMode кнопки.

Обычно по умолчанию используется ввод, если вы ничего не указываете вручную, и я предполагаю из ваших результатов, что у вас нет внешнего съемного или съемного резистора. Поэтому вам необходимо указать PIN-режим(buttonPin, INPUT_PULLUP); и убедитесь, что ваш переключатель или кнопка подключает входной вывод к земле при активации (это означает, что "активный" будет НИЗКИМ).

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

,

В цепи есть понижающий резистор. Я добавил контакт, но он все еще не работает. Я подозреваю, что это связано с условными утверждениями. Я попытался изменить "если ledState == true && blinkState == true" на некоторое время, и он действительно начинает мигать, но затем не выключается. Я действительно хочу понять, что здесь не так с моей логикой., @Zaffresky


2

Обратите внимание, что это не ответ, но я хочу показать некоторые примеры кода, основанные на комментарии:

Вы можете использовать, как сказано в комментарии:

  • Удалите "== true" в логическом условии
  • Замените "== false" на"! " в логическом условии

Вы получите это:

  // проверьте, изменилось ли состояние кнопки
  if (newButtonState != oldButtonState) {
    // если кнопка была нажата
    if (newButtonState == HIGH) {
      // проверьте состояние светодиода
      if (!ledState) {
        ledState = true;
        blinkState = true;
      } else {
        ledState = false;
        blinkState = false;
      }
      if (ledState && blinkState) {
        newTime = millis();
        if (newTime - oldTime >= 250) {
          state = !state;
          oldTime = newTime;
        }
        digitalWrite(redLed, state);
      }
    }
  }
  oldButtonState = newButtonState;
}

О следующем фрагменте:

  if (!ledState) {
    ledState = true;
    blinkState = true;
  } else {
    ledState = false;
    blinkState = false;
  }

Так как вы пишете ledState и blinkState в обоих предложениях, и условие простое (поэтому вам не нужно помещать его во временную переменную, вы можете заменить этот фрагмент следующим:

blinkState = !ledState;
ledState = !ledState;

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

,

0

Ваш мигающий код активен только

if (newButtonState != oldButtonState) 

так что он не будет мигать (сам по себе)

Чтобы переключить мигание, просто измените его, например, так

void loop() {
  bool newButtonState = digitalRead(buttonPin);
  if (newButtonState != oldButtonState) { 
    // состояние кнопки изменилось
    delay(5);  // debounce
    oldButtonState = newButtonState; // запуск только один раз за нажатие кнопки
    if (newButtonState == HIGH) {
      // переключить состояние мигания
      blinkState = ! blinkState;
    } 
  }

  if (blinkState) {
     // Мигать без задержки
     unsigned long newTime = millis();
     if (newTime - oldTime >= 250) {
        state = !state;
        oldTime = newTime;
        digitalWrite(redLed, state);
     }
  } else {
     // не мигает : просто оставьте красный как есть
  }
}

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

,