Перезапустите последовательность NeoPixel с помощью кнопки в любое время.

Я очень доволен своей новой штуковиной Arduino и экспериментирую со всеми этими пикселями :).

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

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

Я знаю, что delay(); полностью остановит код и подождет, пока истечет время, но я написал некоторый код без использования delay(); и вместо этого использовал millis();.

Пока что мои светодиоды увеличиваются через мою полосу, но я не могу перезапустить ее, пока она не пройдет полностью. Я читал, что часть while(); в моем коде работает как delay();, и это предотвратит его перезапуск до полного цикла. Я использовал код millis(); из другого примера, поэтому он не похож на код из Blink Without Delay.

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

#include <FastLED.h>

#define NUM_LEDS_PER_STRIP 16
CRGB ledStrip[NUM_LEDS_PER_STRIP];

const int signalButtonPin = 4;
const int ledStripPin = 8;

int buttonState = 0;
int lastButtonState = 0;

int delaySignalAnimation = 100;

unsigned long currentMillis = 0;
unsigned long previousMillis = 0;

void setup() {
  pinMode(signalButtonPin, INPUT_PULLUP);
  pinMode(ledStripPin, OUTPUT);
  FastLED.addLeds<NEOPIXEL, 8>(ledStrip, NUM_LEDS_PER_STRIP);
}

void loop() {
  buttonState = digitalRead(signalButtonPin);
  if (buttonState != lastButtonState) {
    if (buttonState == LOW) {
      fill_solid(ledStrip, NUM_LEDS_PER_STRIP, CRGB::Black);
      for (int i = 0; i < 16; i++) {
        ledStrip[i] = CRGB::Blue;
        FastLED.setBrightness(100);
        FastLED.show();
        currentMillis = previousMillis = millis();
        while (previousMillis + delaySignalAnimation >= currentMillis) {
          currentMillis = millis();
        }
      }
    } else {
      lastButtonState = buttonState;
    }
    fill_solid(ledStrip, NUM_LEDS_PER_STRIP, CRGB::Black);
    FastLED.setBrightness(0);
  }
  FastLED.show();
}

Заранее спасибо за помощь.

, 👍0


2 ответа


1

Во-первых, хорошо, что вы пытаетесь избежать delay().

Однако ваш цикл while в значительной степени делает то же самое, что и delay().

Вместо этого вам нужно изменить свой образ мышления. Вместо «Я хочу последовательно зажечь светодиоды от 0 до 15» вам нужно подумать «У меня горит 6 светодиодов. Теперь мне нужно зажечь 7-й».

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

Когда вы знаете, как перезапустить последовательность в конце, вы также должны знать, как перезапустить последовательность при нажатии кнопки.

Например, loop() может выглядеть примерно так (не проверено):

void loop() {
    static uint8_t lednum = 0;
    static uint32_t animTicker = millis();

    if (millis() - animTicker >= 1000) { // Один раз в секунду
        animTicker = millis();

        lednum++;
        if (lednum > NUM_LEDS_PER_STRIP) lednum = 0; // Это сбрасывает последовательность

        // Включаем светодиоды до lednum и выключаем остальные
        for (uint8_t i = 0; i < NUM_LEDS_PER_STRIP; i++) {
            if (i < lednum) {
                ledStrip[i] = CRGB::Blue;
            } else {
                ledStrip[i] = CRGB::Black;
            }
        }

        FastLED.show();
    }

    buttonState = digitalRead(signalButtonPin);

    if (buttonState != lastButtonState) {
        lastButtonState = buttonState;
        if (buttonState == LOW) {
            lednum = 0;
        }
    }
}

Ключ здесь в том, что переменная lednum содержит количество светодиодов, которые вы хотите отобразить. Раз в секунду под управлением millis() светодиоды обновляются, чтобы отображать заданное количество светодиодов.

,

Спасибо за ответ на мой вопрос. Я посмотрю ваш скетч и отвечу, как дела. Да, я читал, что это будет равносильно задержке. Я видел какой-то код, использующий unit8_t или unit32_t, но меня это напугало, потому что это выглядит пугающе :D., @Marvin

Это просто переменные определенного размера. «u» — «без знака». «int» — это «целое число», а «x_t» — это количество битов. uint8_t — это то же самое, что и byte, но переносимое («byte» специфично для Arduino). uint32_t — это то же самое, что и unsigned long, но, опять же, его можно использовать в разных архитектурах., @Majenko

Хорошо, это звучит уже не так страшно, это похоже на сокращенную версию этих слов. Спасибо., @Marvin

Я загрузил ваш скетч и теперь могу сбросить во время подсчета. Теперь мне нужно посмотреть, как я могу запустить последовательность одной и той же кнопкой, и что она остановится после 1 цикла, потому что она работает снова и снова, но для этого и нужен цикл :), @Marvin


0

Это не ответ, а расширение кода Маженко.

Он добавляет еще один слой между функциями нажатия кнопки и светодиодного дисплея, чтобы сделать программу более гибкой

void loop() {

    static bool     tick          = false;                 // периодический триггерный сигнал
    static bool     zap           = false;                 // включить сигнал для запуска последовательности
    static bool     buttonClicked = false;                 // кнопка переведена с "отпущена" на "нажата"

    static uint8_t  mode          = 0;                     // выбирает световую последовательность для запуска
    static uint8_t  lednum        = 0;

    static uint32_t animTicker    = millis();


    if (millis() - animTicker >= 1000) {                   // Один раз в секунду
        animTicker = millis();
        tick = true;                                       // устанавливаем тиковый флаг
    }


    if (buttonClicked) {                                   // вы можете проверить двойной щелчок здесь
        buttonClicked = false;
        zap = !zap;                                        // запуск/остановка с помощью кнопки ... zap используется для разделения функции нажатия кнопки и функции отображения
        if (zap) {
            lednum = 0;                                    // запускаем анимацию с самого начала
            mode += 1; if (mode > 2) mode = 0;             // выбор следующего режима .... это можно сделать двойным щелчком мыши
        }
    }


    if (tick && zap) {
        tick = false;                                                   // сбрасываем галочку .... zap остается установленным в течение всей последовательности анимации
        lednum++;

        if (lednum > NUM_LEDS_PER_STRIP) {
            zap = false;                                                // Это останавливает последовательность (выполняется только один раз) ... используйте счетчик, если нужны множители
        }

        else {
            switch (mode) {                                             // выбираем одну из последовательностей .... в этом примере меняются только цвета

                case 0:
                    for (uint8_t i = 0; i < NUM_LEDS_PER_STRIP; i++) {  // Включаем светодиоды до lednum и выключаем остальные
                        if (i < lednum) {
                            ledStrip[i] = CRGB::Blue;
                        } else {
                            ledStrip[i] = CRGB::Black;
                        }
                    }
                    break;

                case 1:
                    for (uint8_t i = 0; i < NUM_LEDS_PER_STRIP; i++) {
                        if (i < lednum) {
                            ledStrip[i] = CRGB::Red;
                        } else {
                            ledStrip[i] = CRGB::Black;
                        }
                    }
                    break;

                case 2:
                    for (uint8_t i = 0; i < NUM_LEDS_PER_STRIP; i++) {
                        if (i < lednum) {
                            ledStrip[i] = CRGB::Green;
                        } else {
                            ledStrip[i] = CRGB::Yellow;
                        }
                    }
                    break;
            }

            FastLED.show();
        }
    }


    buttonState = digitalRead(signalButtonPin);

    if (buttonState != lastButtonState) {        // переход состояния кнопки
        lastButtonState = buttonState;           // новое "последнее состояние"
        if (buttonState == LOW) {                // переход от "отпущено" к "нажато"
            buttonClicked = true;
        }
    }
}
,

Привет jsotola, я вижу, вы разместили состояние машины. Я тоже продвигаюсь к конечной машине, но еще не знаком с ней. Я постараюсь реализовать ваш код и поделюсь своим прогрессом. Принимает ли двойной щелчок действие, если я дважды нажимаю кнопку сразу после него, или он засчитывается навсегда до второго нажатия? Спасибо за ваш код и ваше время, чтобы сделать его. :), @Marvin

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

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