Перезапустите последовательность 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();
}
Заранее спасибо за помощь.
@Marvin, 👍0
2 ответа
Во-первых, хорошо, что вы пытаетесь избежать 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()
светодиоды обновляются, чтобы отображать заданное количество светодиодов.
Это не ответ, а расширение кода Маженко.
Он добавляет еще один слой между функциями нажатия кнопки и светодиодного дисплея, чтобы сделать программу более гибкой
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
- Кнопка с таймером переключения и функцией сброса времени + светодиод обратной связи
- Та же кнопка одним кликом и двойным кликом
- Как запрограммировать кнопку на цвет для полоски неопикселей?
- Реструктурировать код для многозадачности Neopixel + ИК-пульт + ардуино
- Кнопка переключения переключает между операторами обращения с разблокированием кнопки
- Непрерывно запускайте функцию световой последовательности в операторе if
- Код кнопки синхронизации
- Strip.clear() не очищает/отключает полосу NeoPixel после сброса ESP8266.
Спасибо за ответ на мой вопрос. Я посмотрю ваш скетч и отвечу, как дела. Да, я читал, что это будет равносильно задержке. Я видел какой-то код, использующий unit8_t или unit32_t, но меня это напугало, потому что это выглядит пугающе :D., @Marvin
Это просто переменные определенного размера. «u» — «без знака». «int» — это «целое число», а «x_t» — это количество битов. uint8_t — это то же самое, что и byte, но переносимое («byte» специфично для Arduino). uint32_t — это то же самое, что и unsigned long, но, опять же, его можно использовать в разных архитектурах., @Majenko
Хорошо, это звучит уже не так страшно, это похоже на сокращенную версию этих слов. Спасибо., @Marvin
Я загрузил ваш скетч и теперь могу сбросить во время подсчета. Теперь мне нужно посмотреть, как я могу запустить последовательность одной и той же кнопкой, и что она остановится после 1 цикла, потому что она работает снова и снова, но для этого и нужен цикл :), @Marvin