I am a new Arduino user and I am trying to learn something by my own.
Can you tell me how to get rid of delay() in the for loop of the following sketch?
My problem is that I would like to add a debounced button (debounced used millis()) to the sketch such that, when I push the button, a LED ligths up gradually (updating the brightness every 10 ms) from dark to very bright and then it goes back, with this process repeating. When I repush the button again, the LED should switch off. With the delay() inside the sketch, the program blocks.
Thanks a lot for your precious help!
const int LED=9; // Define LED for Pin 9
void setup()
{
pinMode (LED, OUTPUT); // Set the LED pin as an output
}
void loop()
{
for (int i=0; i<256; i++)
{
analogWrite(LED, i);
delay(10);
}
for (int i=255; i>=0; i--)
{
analogWrite(LED, i);
delay(10);
}
}
How you do this is to use some persistent variables (either local or global) to remember what you are doing rather than trapping the process in a for loop to remember what you are doing. Then you can use the outside loop() function to iterate through everything.
void loop()
{
// local persistent state variables:
static unsigned long lastChange = 0;
static int i = 0; // how bright
static int inc = +1; // waxing or waning
// Check if it's time to do something
if(millis() - lastChange < 10 )
return; // too early
// else do what needs doing
analogWrite(LED, i);
i += inc;
// Check for valid state
if (i > 255){
i = 255;
inc *= -1;
}
if(i < 0){
inc *= -1;
i = 0;
}
}
Once you've done that for one task, if you want to add more tasks, you can change the name of that function to something else, (for example, pulseLED) and then call it from a new outer loop:
The examples shown above are good for this particular case but a more general solution is a Finite State Machine. Here is your original sketch re-written as a Finite State Machine. Note that each 'delay' is now a place where the state has a millis() timer. The state is repeated every time through loop() (thousands of times per second) and when the counting is done, switches to a different state.
enum States {CountingUp, CountingDown} State = CountingUp;
int Brightness = 0;
unsigned long StateStartTime = 0;
const int LED = 9; // Define LED for Pin 9
void setup()
{
pinMode (LED, OUTPUT); // Set the LED pin as an output
}
void loop()
{
switch (State)
{
case CountingUp:
if (millis() - StateStartTime >= 10)
{
StateStartTime = millis();
analogWrite(LED, Brightness);
Brightness++;
if (Brightness > 255)
{
Brightness = 255;
State = CountingDown;
}
}
break;
case CountingDown:
if (millis() - StateStartTime >= 10)
{
StateStartTime = millis();
analogWrite(LED, Brightness);
Brightness--;
if (Brightness < 0)
{
Brightness = 0;
State = CountingUp;
}
}
break;
}
}
This is a finite state machine customized for this particular case, but it doesn't point towards more complicated programs. You may need to have several semi-independent FSMs, for example, one for the LEDs marching around a jukebox, one for the MP3 player, another handling serial communication, and maybe another handling coinage. They don't all need to be global state variables with the processing flattened into a single Markovized state space. The only state variables that should be global are ones that are necessary to communicate between FSMs.
I have tried to elaborate starting from your sketch. What I wanted to do is to add a button to your sketch such that: (i) when I push the button, the LED start fading according to your sketch and (ii) when I push the buttn again, the LED switches off.
Unfortunately, it does not work! I attach the code as follows. I would be extremely grateful if you could give me some indications of why it does not work. Thanks a lot!
enum States {CountingUp, CountingDown} State = CountingUp;
int Brightness = 0;
unsigned long StateStartTime = 0;
const int LED = 9; // Define LED for Pin 9
const int BUTTON = 2;
boolean BUTTONstatus = LOW;
boolean LEDstatus = LOW;
int waitDebounce = 50;
unsigned long lasttimeDebounce = 0;
boolean lastread = LOW;
void setup()
{
pinMode (LED, OUTPUT); // Set the LED pin as an output
pinMode (BUTTON, INPUT);
digitalWrite(LED, LEDstatus);
}
void loop()
{
boolean read = digitalRead(BUTTON);
if(read != lastread){
lasttimeDebounce = millis();
}
if((millis() - lasttimeDebounce) > waitDebounce){
if(read != BUTTONstatus && read == HIGH){
switch (State)
{
case CountingUp:
if (millis() - StateStartTime >= 10)
{
StateStartTime = millis();
analogWrite(LED, Brightness);
Brightness++;
if (Brightness > 255)
{
Brightness = 255;
State = CountingDown;
}
}
break;
case CountingDown:
if (millis() - StateStartTime >= 10)
{
StateStartTime = millis();
analogWrite(LED, Brightness);
Brightness--;
if (Brightness < 0)
{
Brightness = 0;
State = CountingUp;
}
}
break;
}
}
BUTTONstatus = read;
}
lastread = read;
}
The FSM has to repeat very often. What you have done is changed the sketch to run the FSM one step each time the button input goes from LOW to HIGH. That is NOT going to be quick.
Your original design was "fade up to full brightness, then fade down to off, and repeat". It is not clear exactly what you want you want the button to do. Did you want the button to switch between "OFF" and "fade up and down"? Did you want the OFF to happen immediately whatever the current brightness is? Did you want it to fade out from whatever the current brightness is? Did you want it to complete the current cycle until it reaches OFF and then not fade up again?
Describe what you want the light to do in more detail.
So you want to turn the effect on and off. Rather than have each step of the effect wait for a button press, use a flag to keep track of whether the effect is on or off. The button controls the flag. The flag controls the effect.
enum States {CountingUp, CountingDown} State = CountingUp;
int Brightness = 0;
unsigned long StateStartTime = 0;
const int LED = 9; // Define LED for Pin 9
const int BUTTON = 2;
boolean LEDState = false;
unsigned waitDebounce = 50;
unsigned long lasttimeDebounce = 0;
boolean lastread = LOW;
void setup()
{
pinMode (LED, OUTPUT); // Set the LED pin as an output
pinMode (BUTTON, INPUT);
analogWrite(LED, 0);
}
void loop()
{
boolean read = digitalRead(BUTTON);
if (read != lastread
&& millis() - lasttimeDebounce > waitDebounce)
{
// State just changed
lastread = read;
lasttimeDebounce = millis();
if (read == HIGH)
{
// State just changed to HIGH
LEDState = !LEDState;
}
}
if (LEDState)
FadeUpAndDown();
else
analogWrite(LED, 0);
}
void FadeUpAndDown()
{
switch (State)
{
case CountingUp:
if (millis() - StateStartTime >= 10)
{
StateStartTime = millis();
analogWrite(LED, Brightness);
Brightness++;
if (Brightness > 255)
{
Brightness = 255;
State = CountingDown;
}
}
break;
case CountingDown:
if (millis() - StateStartTime >= 10)
{
StateStartTime = millis();
analogWrite(LED, Brightness);
Brightness--;
if (Brightness < 0)
{
Brightness = 0;
State = CountingUp;
}
}
break;
}
}