Кнопка выхода из текущего цикла

button loop

У меня очень простая схема:

  • Кнопка, подключенная к контакту 2.
  • Светодиод, подключенный к контакту 9.

Желаемая функциональность:

При нажатии кнопки пользователь может переключаться между 4 шаблонами светодиодов.

Проблема:

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

Попытки решения:

Я пытался вставить функцию while в пару мест, например, while buttonstate =lastbuttonstate, но, похоже, это не сработало.

Вот код: (Я понимаю, что все циклы затухания сейчас одинаковы, в рабочей модели они будут разными)

//ПРОБЛЕМА: функция затухания должна завершить полный цикл, прежде чем разрешить переключение на следующий


const int  buttonPin = 2;    // контакт, к которому прикреплена кнопка
const int ledPin = 9;       // контакт, к которому прикреплен светодиод

// Переменные изменятся:
int buttonPushCounter = 0;   // счетчик количества нажатий кнопок
int buttonState = 0;         // текущее состояние кнопки
int lastButtonState = 0;     // предыдущее состояние кнопки

int brightness = 0;    // насколько яркий светодиод
int firstFadeAmount = 5;    // на сколько пунктов затухать светодиод
int secondFadeAmount = 5;    // на сколько пунктов затухать светодиод


void setup() {
  // инициализируем вывод кнопки как вход:
  pinMode(buttonPin, INPUT);
  // инициализируем светодиод как выход:
  pinMode(ledPin, OUTPUT);
  // инициализируем последовательную связь:
  Serial.begin(9600);
}


void loop() {
  // читаем входной контакт кнопки:
  buttonState = digitalRead(buttonPin);

  if (buttonState != lastButtonState) {
    if (buttonState == HIGH) {
      buttonPushCounter++;
    } 
    // Небольшая задержка, чтобы избежать подпрыгивания
    delay(50);
  }
  lastButtonState = buttonState;

  while (buttonPushCounter = lastButtonState) {
    if (buttonPushCounter == 1 && buttonState == HIGH) {
      fadeLoop1(); 
      delay(50);//JP Edit
    } 

    else if (buttonPushCounter == 2 && buttonState == HIGH) {
      fadeLoop2(); 
      delay(50); 
    } 

    else if (buttonPushCounter == 3 && buttonState == HIGH) {
      fadeLoop3(); 
      delay(50); 
    } 

    else if (buttonPushCounter == 4 && buttonState == HIGH) {
      fadeLoop4(); 
      delay(50); 
    } 

  }
  if (buttonPushCounter == 4) {  // Сбрасывается в ноль после 4 нажатий
     buttonPushCounter = 0;
  }

}


void fadeLoop1()  
{
  for (int i = 0; i < 100; i++) {  //Устанавливаем длину первого цикла затухания
    analogWrite(ledPin, brightness);
    brightness = brightness + firstFadeAmount;
    if (brightness <= 0 || brightness >= 255) {
      delay(1000);                  //Устанавливает удержание в верхней и нижней части цикла
      firstFadeAmount = -firstFadeAmount;
    }
    delay(100);
  }
  for (int i = 0; i < 100; i++) {  //Устанавливаем длину второго цикла затухания
    analogWrite(ledPin, brightness);
    brightness = brightness + secondFadeAmount;
    if (brightness <= 0 || brightness >= 255) {
      secondFadeAmount = -secondFadeAmount;
    }
    delay(30);
  }

  digitalWrite(ledPin, LOW);
}


void fadeLoop2()  
{
  for (int i = 0; i < 100; i++) {  //Устанавливаем длину первого цикла затухания
    analogWrite(ledPin, brightness);
    brightness = brightness + firstFadeAmount;
    if (brightness <= 0 || brightness >= 255) {
      delay(1000);                  //Устанавливает удержание в верхней и нижней части цикла
      firstFadeAmount = -firstFadeAmount;
    }
    delay(100);
  }
  for (int i = 0; i < 100; i++) {  //Устанавливаем длину второго цикла затухания
    analogWrite(ledPin, brightness);
    brightness = brightness + secondFadeAmount;
    if (brightness <= 0 || brightness >= 255) {
      secondFadeAmount = -secondFadeAmount;
    }
    delay(30);
  }

  digitalWrite(ledPin, LOW);
}


void fadeLoop3()  
{
  for (int i = 0; i < 100; i++) {  //Устанавливаем длину первого цикла затухания
    analogWrite(ledPin, brightness);
    brightness = brightness + firstFadeAmount;
    if (brightness <= 0 || brightness >= 255) {
      delay(1000);                  //Устанавливает удержание в верхней и нижней части цикла
      firstFadeAmount = -firstFadeAmount;
    }
    delay(100);
  }
  for (int i = 0; i < 100; i++) {  //Устанавливаем длину второго цикла затухания
    analogWrite(ledPin, brightness);
    brightness = brightness + secondFadeAmount;
    if (brightness <= 0 || brightness >= 255) {
      secondFadeAmount = -secondFadeAmount;
    }
    delay(30);
  }

  digitalWrite(ledPin, LOW);
}


void fadeLoop4()  
{
  for (int i = 0; i < 100; i++) {  //Устанавливаем длину первого цикла затухания
    analogWrite(ledPin, brightness);
    brightness = brightness + firstFadeAmount;
    if (brightness <= 0 || brightness >= 255) {
      delay(1000);                  //Устанавливает удержание в верхней и нижней части цикла
      firstFadeAmount = -firstFadeAmount;
    }
    delay(100);
  }
  for (int i = 0; i < 100; i++) {  //Устанавливаем длину второго цикла затухания
    analogWrite(ledPin, brightness);
    brightness = brightness + secondFadeAmount;
    if (brightness <= 0 || brightness >= 255) {
      secondFadeAmount = -secondFadeAmount;
    }
    delay(30);
  }

  digitalWrite(ledPin, LOW);
}

, 👍1

Обсуждение

Возможно, вы захотите расширить описание схемы. Кнопка подключена к контактам 2 и ???., @Mikael Patel

Спасибо. Кнопка подключена только к контакту 2 и используется только как счетчик., @user1702160

Кнопка тоже подключена к GND (или VCC) через резистор? Возможно, вы подключили разомкнутую цепь и, следовательно, имеете ошибочные входные значения., @Mikael Patel

Проблема в том, что функции FadeLoopN занимают процессор. Есть два подхода к решению этой проблемы: (1) переписать шаблоны затухания таким образом, чтобы они выполнялись с использованием прерываний по таймеру; или (2) создайте прерывание для кнопки и установите некоторый глобальный флаг в подпрограмме обслуживания прерывания, а затем проверяйте этот флаг в каждом цикле ваших функций затухания. Первый подход предпочтительнее, но второй менее инвазивный., @ex-punctis

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


2 ответа


0

Перепишите циклы затухания, чтобы они возвращались немедленно, и вместо этого используйте глобальное состояние для настройки светодиодов и millis()-timestamp для установки времени.

В качестве вдохновения вы можете использовать блинк без задержки.

,

Спасибо. Объясните, пожалуйста, что значит «немедленно вернуться» и как это включить в код? Я сейчас читаю о «миилисе», похоже, это правильный путь., @user1702160


1

Краткий ответ:

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

Развернутый ответ:

Подход «пока» — хороший способ протестировать отдельный шаблон, но для описываемого вами поведения необходимо ограничить использование циклов внутри функции «loop()».

По сути, если вы используете while для управления всем шаблоном, как вы уже видели, вам придется дождаться завершения while, прежде чем остальная часть кода сможет проверить нажатие кнопки.

Вот как я сделал то же самое. У меня нет под рукой кода, поэтому мне придется отредактировать ответ позже. Основная форма выглядит примерно так:

int pattern = 0;
int brightness = 0;
int maxBrightness = 100;

setup() 
{ 
// здесь ваш код установки
}


loop()
{
   if (pattern = 0)
   {
      // увеличиваем яркость
      //код вызова для установки текущей яркости светодиода
      if (brightness => maxBrightness)
      {
          brightness = 0;
      }
   }
   checkforbuttonpress();
}

Что вы заметили, я не использовал цикл for/ while для создания анимации, потому что уже существующая функция цикла() уже делает это за меня. Все, что мне нужно сделать, это отслеживать, что должно произойти прямо сейчас, с переменными, для которых задан шаблон и текущая яркость, чтобы код взаимодействовал с оборудованием. Не забудьте обрабатывать повторение вручную (в этом примере maxBrightness), и теперь при нажатии кнопки вы можете изменить шаблон где угодно, потому что нет вторичного цикла, которого нужно было бы ждать.

,