Как запустить 4 светодиода последовательно на основе кнопочного входа?
Я пытаюсь создать программу, которая последовательно запускает 4 светодиода, а также может делать другие вещи с разными входами и выходами. Из-за этого я использую функцию millis, а не задержку. У меня есть код, работающий, но не совсем так, как я хочу. Он проходит через светодиоды и выключает их, а затем снова проходит, как и предполагалось, но есть две проблемы:
- Он пройдет через первый оператор if, затем снова через первый, затем ко второму, затем через первый, второй, затем третий и т. Д. Я хочу, чтобы он каскадно проходил через операторы if, сохраняя светодиод от предыдущих шагов включенным без повторения. Это приводит к тому, что светодиоды мигают очень быстро.
- Код по-прежнему выполняется, даже если входные данные считываются так НИЗКО, как это зависит от миллиса. Мне как-то нужно, чтобы он начинался с самого начала каждый раз, когда кнопка нажата, и сбрасывался, когда кнопка не нажата.
под кодом находится изображение последовательного монитора, показывающее, что программа проходит через каждый оператор if, а не остается в одном и переходит к следующему. При необходимости я могу добавить видео, показывающее, что делают светодиоды.
ниже приведен код
//Code to build 4 sequentially run LEDs that reset everytime there is not input
int RTS_IN = A0; //input button
//Output LEDs, assigning them to pins
int LED_5 = 5;
int LED_6 = 6;
int LED_7 = 7;
int LED_8 = 8;
//1 second for each time interval
unsigned long Time1 = 1000;
unsigned long Time2 = 2000;
unsigned long Time3 = 3000;
unsigned long Time4 = 4000;
unsigned long Time5 = 5000;
//variables for holding millis values
unsigned long currentMillis;
unsigned long newMillis = 0;
void setup()
{
Serial.begin(9600);
pinMode(RTS_IN, INPUT);
pinMode(LED_5, OUTPUT);
pinMode(LED_6, OUTPUT);
pinMode(LED_7, OUTPUT);
pinMode(LED_8, OUTPUT);
}
void loop()
{
currentMillis = millis();
//using sequential method if the input button pressed and held
if(digitalRead(RTS_IN) == HIGH)
{
sequential();
}
//keeping LEDs OFF if button has been released
else
digitalWrite(LED_5, LOW);
digitalWrite(LED_6, LOW);
digitalWrite(LED_7, LOW);
digitalWrite(LED_8, LOW);
}
//method to run LEDs sequentially
void sequential()
{
//if statement checking to see if a second has passed to allow the first led to turn on
if(currentMillis - newMillis >= Time1)
{
Serial.println("5 is on");
digitalWrite(LED_5, HIGH);
delay(1);
//if statement checking to see if 2 seconds has passed to allow the second led to turn on
if(currentMillis - newMillis >= Time2)
{
Serial.println("6 is on");
digitalWrite(LED_6, HIGH);
delay(1);
//if statement checking to see if 3 seconds has passed to allow the third led to turn on
if(currentMillis - newMillis >= Time3)
{
Serial.println("7 is on");
digitalWrite(LED_7, HIGH);
delay(1);
//if statement checking to see if 4 seconds has passed to allow the fourth led to turn on
if(currentMillis - newMillis >= Time4)
{
Serial.println("8 is on");
digitalWrite(LED_8, HIGH);
delay(1);
//if statement to turn off LEDs and wait a second before turning the first back on
if(currentMillis - newMillis >= Time5)
{
Serial.println("All off");
digitalWrite(LED_5, LOW);
digitalWrite(LED_6, LOW);
digitalWrite(LED_7, LOW);
digitalWrite(LED_8, LOW);
//this is in order to add a period of this process to each of the
//interval times to keep up with millis without this, they would all stay on
Time1 = Time1 + 5000;
Time2 = Time2 + 5000;
Time3 = Time3 + 5000;
Time4 = Time4 + 5000;
Time5 = Time5 + 5000;
delay(1);
}
}
}
}
}
}
обновленный код ниже с операторами if else и другим программированием в сочетании
const int RTS_IN = A0;
const int LTS_IN = A1;
//break signal
const int BS_IN = A2;
const int BS_OUT = 11;
//reverse signal
const int RS_IN = A3;
const int RS_OUT = 10;
const int NR_OF_LEDS = 4;
const int RIGHTLEDS[NR_OF_LEDS] = { 6, 7, 8, 9 };
const int LEFTLEDS[NR_OF_LEDS] = { 5, 4, 3, 2 };
const int interval = 100;
int nrOfRightLedsOn = 0;
int nrOfLeftLedsOn = 0;
unsigned long t = 0;
void StateRight();
void StateRightProcess();
void StateLeft();
void StateLeftProcess();
boolean oldSwitchStateRS = LOW;
boolean newSwitchStateRS = LOW;
boolean oldSwitchStateBS = LOW;
boolean newSwitchStateBS = LOW;
void setup()
{
Serial.begin(9600);
pinMode(RTS_IN, INPUT);
pinMode(LTS_IN, INPUT);
for (int led = 0; led < NR_OF_LEDS; led++)
{
pinMode(RIGHTLEDS[led], OUTPUT);
}
for (int led = 0; led < NR_OF_LEDS; led++)
{
pinMode(LEFTLEDS[led], OUTPUT);
}
}
void loop()
{
StateRight();
StateLeft();
newSwitchStateBS = digitalRead(BS_IN);
if(newSwitchStateBS != oldSwitchStateBS)
{
if(newSwitchStateBS == HIGH)
{
digitalWrite(BS_OUT, HIGH);
}
else
digitalWrite(BS_OUT, LOW);
oldSwitchStateBS = newSwitchStateBS;
}
newSwitchStateRS = digitalRead(RS_IN);
if(newSwitchStateRS != oldSwitchStateRS)
{
if(newSwitchStateRS == HIGH)
{
digitalWrite(RS_OUT, HIGH);
}
else
digitalWrite(RS_OUT, LOW);
oldSwitchStateRS = newSwitchStateRS;
}
}
void StateRight()
{
if(digitalRead(RTS_IN) == LOW)
{
SwitchRightLedsOff();
nrOfRightLedsOn = 0;
t = millis() + interval;
}
else if (nrOfRightLedsOn < NR_OF_LEDS)
{
StateRightProcess();
}
else
{
if(millis() >= t + interval)
{
t = millis();
SwitchRightLedsOff();
nrOfRightLedsOn = 0;
}
}
}
void StateRightProcess()
{
if(millis() >= t + interval)
{
t = millis();
digitalWrite(RIGHTLEDS[nrOfRightLedsOn], HIGH);
nrOfRightLedsOn++;
}
}
void SwitchRightLedsOff()
{
for (int led = 0; led < NR_OF_LEDS; led++)
{
digitalWrite(RIGHTLEDS[led], LOW);
}
}
void StateLeft()
{
if(digitalRead(LTS_IN) == LOW)
{
SwitchLeftLedsOff();
nrOfLeftLedsOn = 0;
t = millis() + interval;
}
else if (nrOfLeftLedsOn < NR_OF_LEDS)
{
StateLeftProcess();
}
else
{
if (millis() >= t + interval)
{
t = millis();
SwitchLeftLedsOff;
nrOfLeftLedsOn = 0;
}
}
}
void StateLeftProcess()
{
if (millis() >= t + interval)
{
t = millis();
digitalWrite(LEFTLEDS[nrOfLeftLedsOn], HIGH);
nrOfLeftLedsOn++;
}
}
void SwitchLeftLedsOff()
{
for (int led = 0; led < NR_OF_LEDS; led++)
{
digitalWrite(LEFTLEDS[led], LOW);
}
}
@Myles, 👍3
Обсуждение1 ответ
Лучший ответ:
Честно говоря, я не совсем понимаю проблемы, но я стараюсь дать некоторые рекомендации и надеюсь, что вы сможете использовать эту идею для решения своих проблем.
То, что вам нужно, - это так называемый "конечный автомат".
Я думаю (в соответствии с вашей проблемой), что у вас есть 6 состояний:
0 Idle (no sequence)
1 One LED on
2 Two LEDs on
3 Three LEDs on
4 Four LEDs on
5 No LEDs on
Для этого лучше всего использовать тип перечисления и глобальную переменную с аналогичными значениями:
enum EState
{
Idle,
OneLedOn,
TwoLedsOn,
ThreeLedsOn,
FourLedsOn,
NoLedsOn
}
EState _state;
Вам нужна функция для проверки нового состояния в зависимости от текущего состояния. В словах что-то вроде:
current When Action New
state state
-------- ---------------------------- ---------------- -----
Idle digitalRead(RTS_IN) == HIGH Start counter OneLedOn
Switch on LED 0
OneLedOn digitalRead(RTS_IN) == LOW Switch LEDs off Idle
5 seconds have passed Switch on LED 1
Start counter TwoLedsOn
TwoLedsOn digitalRead(RTS_IN) == LOW Switch LEDs off Idle
5 seconds have passed Switch on LED 2
Start counter ThreeLedsOn
ThreeLedsOn digitalRead(RTS_IN) == LOW Switch LEDs off Idle
5 seconds have passed Switch on LED 3
Start counter ThreeLedsOn
FourLedsOn digitalRead(RTS_IN) == LOW Switch LEDs off Idle
5 seconds have passed Switch LEDs off
Start counter NoLedsOn
NoLedsOn digitalRead(RTS_IN) == LOW Switch LEDs off Idle
5 seconds have passed Switch on LED 0
Start counter OneLedn
(если вы нарисуете один круг для каждого состояния и стрелки между ними, так называемую диаграмму состояний UML, вы увидите гораздо более четкий способ изображения состояний и потоков).
У меня нет компилятора, поэтому я делаю это из головы.
void Process()
{
switch (_state)
{
case EState::Idle:
if ((digitalRead(RTS_IN) == HIGH)
{
_time = millis();
digitalWrite(LED_5, HIGH);
_state = EState::OneLedOn;
}
break;
case EState::OneLedOn:
if ((digitalRead(RTS_IN) == LOW)
{
SwitchLedsOff();
_state = Idle;
}
else if (millis() > time + 5000)
{
_time = millis();
digitalWrite(LED_6, HIGH);
_state = EState::TwoLedsOn;
}
break;
case EState::TwoLedsOn:
...
}
Функция SwitchLEDsoff
устанавливает все светодиоды на низкий уровень, и вам нужна только одна глобальная переменная long _time без знака, которую вы обновляете при запуске нового состояния и проверяете в большинстве состояний.
Обратите внимание, что, скорее всего, вы можете оптимизировать это (например, сделать каждое состояние своей собственной функцией и удалить почти дублированный код), но главная цель-дать вам понять, как использовать конечный автомат и использовать его в этом скетче и будущих скетчах.
Обновить
Следующий скетч такой же, как у вас, но:
- Оптимизирован для уменьшения дублирования кода (
processState
) - Введены константы
- Введенный массив светодиодов для итерации
- Удалил состояние, вместо него использовал
_nrOfLedsOn
- Удалено состояние ожидания, теперь обрабатывается отдельно
- Глобальные переменные с префиксом подчеркивания (личные предпочтения)
- Лучшие имена для переменных/функций
- Используемые прототипы для приведения функций в логический порядок (от высокого уровня к низкому)
Код:
const int RTS_IN = A0;
const int NR_OF_LEDS = 4;
const int LEDS[NR_OF_LEDS] = { 5, 6, 7, 8 };
const int DURATION = 300;
int _nrOfLedsOn = 0;
unsigned long _time = 0;
void ProcessState();
void ProcessLedsState();
void SwitchLedsOff();
void setup()
{
Serial.begin(9600);
pinMode(RTS_IN, INPUT);
for (int led = 0; led < NR_OF_LEDS; led++)
{
pinMode(LEDS[led], OUTPUT);
}
}
void loop()
{
ProcessState();
}
void ProcessState()
{
if (digitalRead(RTS_IN) == LOW)
{
SwitchLedsOff();
_nrOfLedsOn = 0;
_time = millis() + DURATION + 1;
}
else if (_nrOfLedsOn < NR_OF_LEDS)
{
ProcessLedsState();
}
else
{
if (millis() > _time + DURATION)
{
_time = millis();
SwitchLedsOff();
_nrOfLedsOn = 0;
}
}
}
void ProcessLedsState()
{
if (millis() > _time + DURATION)
{
_time = millis();
digitalWrite(LEDS[_nrOfLedsOn], HIGH);
_nrOfLedsOn++;
}
}
void SwitchLedsOff()
{
for (int led = 0; led < NR_OF_LEDS; led++)
{
digitalWrite(LEDS[led], LOW);
}
}
Я думаю, ты все сделал правильно! Я считаю, что это гораздо более ясный способ кодирования. Я постараюсь внедрить это в свой код и свяжусь с вами. Я ценю ваш быстрый ответ., @Myles
Не за что., @Michel Keijzers
Я реализовал новый код с вашей помощью, и он отлично работает, за исключением одного: он не входит в состояние 5 и не выключает светодиоды с высоким RTS_IN. Я обновил свой первоначальный пост, @Myles
Измените SwitchLedsOff;
на SwitchLedsOff();
в случае 5., @Michel Keijzers
Проверьте обновление, я оптимизировал скетч., @Michel Keijzers
Потрясающе, я проверю этот код и попытаюсь реализовать те части, которые смогу понять. Спасибо, что вы мне очень помогли., @Myles
какой смысл иметь эти операторы case, если код просто проваливается? Я также не понимаю, почему вы добавляете 1 к t в первом операторе if в void processState(). Не могли бы вы объяснить, пожалуйста?, @Myles
Вы правы насчет оператора switch
, я преобразовал его/объединил с предыдущим оператором if
. Я также исправил "ошибку", когда у меня было два метода с именем equal. И причина, по которой нужно добавить +1
: если вы видите функцию ProcessLedsState
, вы видите if (millis() > _time + DURATION)
... когда он равен, он не сработает сразу, поэтому я добавил 1. Возможно, вместо этого было бы лучше использовать>=
, так как вы, вероятно, хотите менять светодиоды каждые 300 мс, а не когда они (обязательно) превышают 300 мс., @Michel Keijzers
так нужны ли мне тогда только 2 case-оператора?, @Myles
Давайте [продолжим это обсуждение в чате](https://chat.stackexchange.com/rooms/133542/discussion-between-michel-keijzers-and-myles)., @Michel Keijzers
- Использовать timer0, не влияя на millis() и micros().
- Торговый автомат Arduino для мониторинга ввода монет в слот во время ожидания ввода пользователя
- Реализовать связь Visible Light с помощью Arduino
- 4-битный счетчик вверх и вниз
- Arduino Мигает двумя светодиодами без задержки (количество повторений)
- Скетч мигания ESP8266 не мигает светодиодом
- Та же кнопка одним кликом и двойным кликом
- Акцептант векселей ИКТ
Спасибо за замечательный вопрос. вот ссылка на проект Arduino, которую вы можете использовать для дальнейшего обсуждения. Я уверен, что вам будет очень легко поделиться своим проектом таким образом https://wokwi.com/arduino/projects/321913849735283283, @ArduinoFan