-
One thing you should learn from this exercise; when you do not define everything fully the software sketch can be cumbersome.
-
If we were to start over, this sketch should have been written using State Machine techniques. We will leave that topic for next time.
Try this version of the sketch.
- You should see 5 different LED display modes.
enum LEDmodes {START, SEQUENCE, SINGLEled, RANDOM, ALL, REVERSEsequence, END }; // <--------<<<<< M O D E S
- Work your way through the sketch to see how things are being done.
- If you want to learn, ask questions.
After you test the sketch, add a 4th LED/resistor to pin #8 and make this change:
- Change:
const byte LEDarray[] = {2, 3, 4}; //PIN---[220R]---A[LED]K---GND W i t h 3 L E D s
- To:
const byte LEDarray[] = {2, 3, 4, 8}; //PIN---[220R]---A[LED]K---GND W i t h 4 L E D s
What happens when you make the above changes ?
//********************************************^************************************************
// https://forum.arduino.cc/t/3-led-blinking-randomly-using-millis-got-reversed-for-some-reason/1164916/4
//
// LarryD
//
// Version YY/MM/DD Comments
// ======= ======== ====================================================================
// 1.00 20/09/03 Running code
// 1.10 20/09/04 Added the increment and decrement switches
// 1.20 20/09/05 Cleaned up the sketch a bit
// 1.30 20/09/10 Added a random/sequence Mode switch
// 1.40 20/09/10 Changed MODE from 2 to more than 3 . . . display modes
//
//************************************************
#define LEDon HIGH //PIN---[220R]---A[LED]K---GND
#define LEDoff LOW
#define PUSHED LOW //+5V---[Internal 50k]---PIN---[switch]---GND
#define RELEASED HIGH
#define CLOSED LOW //+5V---[Internal 50k]---PIN---[switch]---GND
#define OPEN HIGH
#define EXPIRED true
#define STILLtiming false
#define ENABLED true
#define DISABLED false
#define YES true
#define NO false
#define minimumLEDoffTime 200ul
// m i l l i s ( ) B a s e d T I M E R S
//********************************************^************************************************
//
struct makeTIMER
{
//#define ENABLED true
//#define DISABLED false
//
//#define YES true
//#define NO false
//
//#define EXPIRED true
//#define STILLtiming false
unsigned long Time; //when the TIMER started
unsigned long Interval; //delay time in ms which we are looking for
bool TimerFlag; //is the TIMER enabled ? ENABLED/DISABLED
bool Restart; //restart this TIMER ? YES/NO
//****************************************
//function to check if the TIMER is enabled and check if the TIMER has expired
bool checkTIMER()
{
//*********************
//is this TIMER enabled and has this TIMER expired ?
if (TimerFlag == ENABLED && millis() - Time >= Interval)
{
//*********************
//should this TIMER restart ?
if (Restart == YES)
{
//restart this TIMER
Time = millis();
}
//this TIMER is enabled and has expired
return EXPIRED;
}
//this TIMER is disabled and/or has not expired
return STILLtiming;
} //END of checkTIMER()
//****************************************
//function to enable the TIMER
void enableTIMER()
{
TimerFlag = ENABLED;
//restart this TIMER
Time = millis();
} //END of enableTIMER()
//****************************************
//function to disable this TIMER
void disableTIMER()
{
TimerFlag = DISABLED;
} //END of disableTIMER()
//****************************************
//function to restart this TIMER
void restartTIMER()
{
Time = millis();
} //END of restartTIMER()
}; //END of struct makeTIMER
//********************************************^************************************************
/*example
// *******************
makeTIMER toggleLED =
{
0, 500ul, ENABLED/DISABLED, YES/NO //.Time, .Interval, .TimerFlag, .Restart
};
*/
//*******************
makeTIMER heartbeatTimer =
{
0, 500ul, ENABLED, YES //.Time, .Interval, .TimerFlag, .Restart
};
//*******************
makeTIMER checkSwitchesTimer =
{
0, 50ul, ENABLED, YES //.Time, .Interval, .TimerFlag, .Restart
};
//*******************
makeTIMER LEDonTimer =
{
0, 1000ul, DISABLED, NO //.Time, .Interval, .TimerFlag, .Restart
};
//*******************
makeTIMER LEDoffTimer =
{
0, minimumLEDoffTime, DISABLED, NO //.Time, .Interval, .TimerFlag, .Restart
};
//********************************************^************************************************
//LED display modes
enum LEDmodes {START, SEQUENCE, SINGLEled, RANDOM, ALL, REVERSEsequence, END }; // <------<<<< M O D E S
//the LED GPIOs used in the display
const byte LEDarray[] = {2, 3, 4}; //PIN---[220R]---A[LED]K---GND W i t h 3 L E D s
//const byte LEDarray[] = {2, 3, 4, 8}; //PIN---[220R]---A[LED]K---GND W i t h 4 L E D s
const byte incSwitch = 5; //+5V---[Internal 50k]---PIN---[switch]---GND
const byte decSwitch = 6;
const byte modeSwitch = 7;
const byte heartbeatLED = 13;
byte randNumber;
byte LEDselected;
byte lastIncSwitch = RELEASED; //the last state of this switch
byte lastDecSwitch = RELEASED;
byte lastModeSwitch = RELEASED;
int singleLEDcounter = -1;
int sequenceCounter = 0; //start out with the first LED
int modeCounterFlag = START + 1; //start out in sequence mode
// s e t u p ( )
//********************************************^************************************************
void setup()
{
Serial.begin(115200);
pinMode(heartbeatLED, OUTPUT);
//all LED GPIOs made OUTPUTS
for (byte x = 0; x < sizeof(LEDarray) / sizeof(LEDarray[0]); x++)
{
pinMode(LEDarray[x], OUTPUT);
}
pinMode(incSwitch, INPUT_PULLUP);
pinMode(decSwitch, INPUT_PULLUP);
pinMode(modeSwitch, INPUT_PULLUP);
randomSeed(analogRead(A0));
} //END of setup()
// l o o p ( )
//********************************************^************************************************
void loop()
{
//************************************************ T I M E R heartbeat
//is this TIMER enabled, is it time to toggle the heartbeat LED ?
if (heartbeatTimer.checkTIMER() == EXPIRED)
{
//time toggle the LED
digitalWrite(heartbeatLED, !digitalRead(heartbeatLED));
}
//************************************************ T I M E R checkSwitches
//is this TIMER enabled, is it time to scan our switches ?
if (checkSwitchesTimer.checkTIMER() == EXPIRED)
{
//time to check the switches
checkSwitches();
}
//************************************************ T I M E R LEDon
//is this TIMER enabled, is it time to turn OFF this LED ?
if (LEDonTimer.checkTIMER() == EXPIRED)
{
//all LED GPIOs go OFF
for (byte x = 0; x < sizeof(LEDarray) / sizeof(LEDarray[0]); x++)
{
digitalWrite(LEDarray[x], LEDoff);
}
//we are finished using this TIMER
LEDonTimer.disableTIMER();
//enable the LEDoff TIMER
LEDoffTimer.enableTIMER();
}
//************************************************ T I M E R LEDoff
//is this TIMER enabled, is it time to turn ON LED(s) ?
if (LEDoffTimer.checkTIMER() == EXPIRED)
{
//we are finished using this TIMER
LEDoffTimer.disableTIMER();
}
//************************************************ Next LED
//has LED timing stopped ?
if (LEDonTimer.TimerFlag == DISABLED && LEDoffTimer.TimerFlag == DISABLED)
{
//what LED display mode are we in ?
switch (modeCounterFlag)
{
//**********************
case SEQUENCE:
{
//pick the next LED in the sequence
sequence();
}
break;
//**********************
case SINGLEled:
{
//operate just one LED
single();
}
break;
//**********************
case RANDOM:
{
//pick another random LED to operate
randomly();
}
break;
//**********************
case ALL:
{
//operate LEDs
ALLleds();
}
break;
//**********************
case REVERSEsequence:
{
//operate LEDs
reverse();
}
break;
} //END of switch/case
}
//************************************************
//other non blocking code goes here
//************************************************
} //END of loop()
// c h e c k S w i t c h e s ( )
//********************************************^************************************************
void checkSwitches()
{
byte state;
//************************************************ incSwitch
state = digitalRead(incSwitch);
//has there been a change in switch's state ?
if (lastIncSwitch != state)
{
//update to this new state
lastIncSwitch = state;
//*************************************
//if the decSwitch is released, is the increment switch PUSHED ?
if (lastDecSwitch == RELEASED && state == PUSHED)
{
//increase the LED OFF time
LEDoffTimer.Interval += 100ul;
}
} //END of this switch
//************************************************ decSwitch
state = digitalRead(decSwitch);
//has there been a change in switch's state ?
if (lastDecSwitch != state)
{
//update to this new state
lastDecSwitch = state;
//*************************************
//if the incSwitch is released, is the decrement switch PUSHED ?
if (lastIncSwitch == RELEASED && state == PUSHED)
{
//decrease the LED OFF time
LEDoffTimer.Interval -= 100ul;
//do not go under minimumLEDoffTime
if (LEDoffTimer.Interval < minimumLEDoffTime)
{
LEDoffTimer.Interval = minimumLEDoffTime;
}
}
} //END of this switch
//************************************************ modeSwitch
state = digitalRead(modeSwitch);
//has there been a change in switch's state ?
if (lastModeSwitch != state)
{
//update to this new state
lastModeSwitch = state;
//*************************************
//is the mode switch PUSHED ?
if (state == PUSHED)
{
//only increment modeCounter if not in SINGLEled
if (modeCounterFlag != SINGLEled)
{
//next LED display mode
modeCounterFlag++;
}
//are we at the end of the LED display modes
if (modeCounterFlag == END)
{
//back to the beginning of the display modes
modeCounterFlag = START + 1;
}
//set up initial conditions
switch (modeCounterFlag)
{
//**********************
case SINGLEled:
{
//first element in the LEDarray
singleLEDcounter++;
//have we done each LED ?
if (singleLEDcounter > (sizeof(LEDarray) / sizeof(LEDarray[0]) - 1))
{
//okay, next display mode
modeCounterFlag++;
//re-initialize for next time
singleLEDcounter = -1;
}
}
break;
//**********************
case SEQUENCE:
{
//first element in the LEDarray
sequenceCounter = 0;
}
break;
//**********************
case REVERSEsequence:
{
//last element in the LEDarray
sequenceCounter = (sizeof(LEDarray) / sizeof(LEDarray[0]) - 1);
}
break;
} //END of switch/case
}
} //END of this switch
} //END of checkSwitches()
// r e v e r s e ( )
//********************************************^************************************************
void reverse()
{
//the selected LED goes ON LEDarray[0], LEDarray[1] or LEDarray[2]
digitalWrite(LEDarray[sequenceCounter], LEDon);
//enable the LEDon TIMER
LEDonTimer.enableTIMER();
//next LED to operate
sequenceCounter--;
//don't go less than first LED in LEDarray[]
if (sequenceCounter < 0)
{
//start at the last LEDarray element
sequenceCounter = (sizeof(LEDarray) / sizeof(LEDarray[0]) - 1);
}
//enable the LEDon TIMER
LEDonTimer.enableTIMER();
} //END of reverse()
// A L L l e d s ( )
//********************************************^************************************************
void ALLleds()
{
//all LED GPIOs go ON
for (byte x = 0; x < sizeof(LEDarray) / sizeof(LEDarray[0]); x++)
{
digitalWrite(LEDarray[x], LEDon);
}
//enable the LEDon TIMER
LEDonTimer.enableTIMER();
} //END of ALLleds()
// s i n g l e ( )
//********************************************^************************************************
void single()
{
digitalWrite(LEDarray[singleLEDcounter], LEDon);
//enable the LEDon TIMER
LEDonTimer.enableTIMER();
} //END of single()
// s e q u e n c e ( )
//********************************************^************************************************
void sequence()
{
//the selected LED goes ON LEDarray[0], LEDarray[1] or LEDarray[2]
digitalWrite(LEDarray[sequenceCounter], LEDon);
//enable the LEDon TIMER
LEDonTimer.enableTIMER();
//next LED to operate
sequenceCounter++;
//don't go past the last LED in LEDarray[]
if (sequenceCounter > (sizeof(LEDarray) / sizeof(LEDarray[0])) - 1)
{
//start at the first LED
sequenceCounter = 0;
}
} //END of sequence()
// r a n d o m l y ( )
//********************************************^************************************************
void randomly()
{
//select a LEDarray[] element i.e. 0, 1, 2
LEDselected = random(0, (sizeof(LEDarray) / sizeof(LEDarray[0])));
//the selected LED goes ON
digitalWrite(LEDarray[LEDselected], LEDon);
//enable the LEDon TIMER
LEDonTimer.enableTIMER();
} //END of randomly()
//********************************************^************************************************