To be honest, I don't understand exactly the problems, but I try to give some guideline and hope you can use the idea to fix your problems.
What you need is a so called 'state machine'.
I think (according to your problem) that you have 6 states:
0 Idle (no sequence)
1 One LED on
2 Two LEDs on
3 Three LEDs on
4 Four LEDs on
5 No LEDs on
For this you can best use an enum type and global variable with similar values:
enum EState
{
Idle,
OneLedOn,
TwoLedsOn,
ThreeLedsOn,
FourLedsOn,
NoLedsOn
}
EState _state;
You need a function to check the new state, depending on the current state. In words something like:
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
(if you would draw one circle for each state and arrows between them, a so called UML State Diagram, you will see a much clearer way to depict the states and flows).
I don't have a compiler so I do it out of my head.
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:
...
}
The function SwitchLEDsoff sets all LEDs to low, and you only need one unsigned long _time global variable which you update when a new state starts and check in most states.
Note that high likely you can optimize this (like making each state its own function and removing almost duplicated code), but the main goal is to let you understand how to use a state machine and to use it in this sketch and future sketches.
Update
The following sketch is the same as yours but:
- Optimized for reducing code duplication (
ProcessState) - Introduced constants
- Introduced array for LEDs to iterate over
- Removed the state, instead used
_nrOfLedsOn - Removed idle state, handled separately now
- Prefixed global variables with an underscore (personal preference)
- Better names for variables/functions
- Used prototypes to put functions in logical order (high level to low level)
Code:
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 SwitchLedsOff();
void ProcessState();
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);
}
}