 # Finite State Machine question

Hi,

I have written code to turn on a random LED using a pushbutton and I am trying to work out how to use a FSM to turn each LED off after a specified time.

``````#include <FastLED.h>
#include <Bounce.h>

#define numLEDs 50
#define ledPin 2

struct CRGB leds[numLEDs];

const int buttonPin = 3;
Bounce pushbutton = Bounce(buttonPin, 10);  // 10 ms debounce
int ledNumber;
int isLedStatus[numLEDs];                   // 0=off, 1=on, 2=fading
unsigned long onTime = 5000;                // time LED is on

void setup() {
pinMode(buttonPin, INPUT_PULLUP);
Serial.begin(9600);
}

byte previousState = HIGH;

void turnOnCandle()
{
leds[ledNumber] = CRGB::Red;
isLedStatus[ledNumber] = 1;
FastLED.show();

Serial.print("LED number: ");
Serial.println(ledNumber);

}

void doRandomCandle()
{
do
{
ledNumber = random(0, numLEDs);
}
while (isLedStatus[ledNumber] != 0);

turnOnCandle();

}

void loop()
{
if (pushbutton.update()) {
if (pushbutton.fallingEdge()) {
doRandomCandle();
}
}
}
``````

I can make an array that records the time each LED was turned on using Millis() but I can’t work out how to check how the time of each one is doing against my onTime to turn it off again.

I have been reading lots of tutorials and examples of finite state machines, but I can’t find out anywhere that talks about tracking an array of objects.

Is this possible?

Thanks,

Rob

I can make an array that records the time each LED was turned on using Millis() but I can’t work out how to check how the time of each one is doing against my onTime to turn it off again.

``````unsigned long onTimes[numLEDs];

void loop()
{
// Some code to turn pins on and set onTimes[n] for the nth pin

unsigned long now = millis();
for(byte b=0; b<numLEDs; b++)
{
if(now - onTimes[b] > desiredOnTime)
{
// Quit wasting energy; turn the damned lights off!
}
}
}
``````

No state machines were harmed in the making of this code (snippet).

``````#include <Fsm.h>
#include <FastLED.h>
#include <Bounce.h>

#define numLEDs 50
#define ledPin 2

struct CRGB leds[numLEDs];

const int buttonPin = 3;
Bounce pushbutton = Bounce(buttonPin, 10);  // 10 ms debounce
int ledNumber;
int isLedStatus[numLEDs];                   // 0=off, 1=on, 2=fading
unsigned long isLedOnTimes[numLEDs];               // millis() at switching on LED
unsigned long onTime = 5000;                         // interval after which to fade (milliseconds)

void setup() {
pinMode(buttonPin, INPUT_PULLUP);
// Serial.begin(9600);
}

byte previousState = HIGH;

void turnOnCandle()
{
leds[ledNumber] = CRGB::Red;
isLedStatus[ledNumber] = 1;
isLedOnTimes[numLEDs] = millis();
FastLED.show();
}

{
leds[ledNumber] = CRGB::Black;
isLedStatus[ledNumber] = 0;
FastLED.show();
}

void doRandomCandle()
{
do
{
ledNumber = random(0, numLEDs);
}
while (isLedStatus[ledNumber] != 0);
turnOnCandle();
}

void loop()
{
if (pushbutton.update())
{
if (pushbutton.fallingEdge())
{
doRandomCandle();
}
}
unsigned long now = millis();
for (byte b = 0; b < numLEDs; b++)
{
if (now - isLedOnTimes[b] > onTime)
{
}
}
}
``````

I’m not sure if have implemented your suggestion correctly as it is doing some very weird things… The first time I hit the button, the LED goes off after 5 seconds as planned. Subsequent LEDs flash on for a split second only.

If I hit the button multiple times before the first 5 seconds have elapsed, none of them go off, but then after 5 seconds have elapsed subsequent ones flash on for a split second.

It’s important that an LED can be turned on at any time and will still go off after x seconds. Eventually I will add in further complexity, to fade the LED out over 5 seconds after it has been on for 60 seconds.

Sorry it was well past my bed time last night and I see a mistake I made this morning.

``````void turnOnCandle()
{
leds[ledNumber] = CRGB::Red;
isLedStatus[ledNumber] = 1;
isLedOnTimes[numLEDs] = millis();
FastLED.show();
}
``````

Should be:

``````void turnOnCandle()
{
leds[ledNumber] = CRGB::Red;
isLedStatus[ledNumber] = 1;
isLedOnTimes[ledNumber] = millis();
FastLED.show();
}
``````

I have also changed:

``````void fadeOutCandle()
{
leds[ledNumber] = CRGB::Black;
isLedStatus[ledNumber] = 0;  // added to reset the time of LED after it has been switched off
FastLED.show();
}
``````

Here is the new code in total, but it’s still not working as planned. LEDs now blink on for a split second each, without waiting for the onTime before switching off.

``````#include <Fsm.h>
#include <FastLED.h>
#include <Bounce.h>

#define numLEDs 50
#define ledPin 2

struct CRGB leds[numLEDs];

const int buttonPin = 3;
Bounce pushbutton = Bounce(buttonPin, 10);  // 10 ms debounce
int ledNumber;
int isLedStatus[numLEDs];                   // 0=off, 1=on, 2=fading
unsigned long isLedOnTimes[numLEDs];               // millis() at switching on LED
unsigned long onTime = 5000;                         // interval after which to fade (milliseconds)

void setup() {
pinMode(buttonPin, INPUT_PULLUP);
// Serial.begin(9600);
}

byte previousState = HIGH;

void turnOnCandle()
{
leds[ledNumber] = CRGB::Red;
isLedStatus[ledNumber] = 1;
isLedOnTimes[ledNumber] = millis();
FastLED.show();
}

{
leds[ledNumber] = CRGB::Black;
isLedStatus[ledNumber] = 0;
isLedOnTimes[ledNumber] = 0;
FastLED.show();
}

void doRandomCandle()
{
do
{
ledNumber = random(0, numLEDs);
}
while (isLedStatus[ledNumber] != 0);
turnOnCandle();
}

void loop()
{
if (pushbutton.update())
{
if (pushbutton.fallingEdge())
{
doRandomCandle();
}
}
unsigned long currentMillis = millis();
for (byte b = 0; b < numLEDs; b++)
{
if (currentMillis - isLedOnTimes[b] > onTime)
{
}
}
}
``````

I’m probably missing something simple, btu any advice would be great. Thanks!

I should have tried a bit more before replying.

This code works as planned. Woop Woop, now time to go to work :!

``````#include <Fsm.h>
#include <FastLED.h>
#include <Bounce.h>

#define numLEDs 50
#define ledPin 2

struct CRGB leds[numLEDs];

const int buttonPin = 3;
Bounce pushbutton = Bounce(buttonPin, 10);  // 10 ms debounce
int ledNumber;
int isLedStatus[numLEDs];                   // 0=off, 1=on, 2=fading
unsigned long isLedOnTimes[numLEDs];               // millis() at switching on LED
unsigned long onTime = 10000;                         // interval after which to fade (milliseconds)

void setup() {
pinMode(buttonPin, INPUT_PULLUP);
// Serial.begin(9600);
}

byte previousState = HIGH;

void turnOnCandle()
{
leds[ledNumber] = CRGB::Red;
isLedStatus[ledNumber] = 1;
isLedOnTimes[ledNumber] = millis();
FastLED.show();
}

{
leds[turnOffLED] = CRGB::Black;
isLedStatus[turnOffLED] = 0;
isLedOnTimes[turnOffLED] = 0;
FastLED.show();
}

void doRandomCandle()
{
do
{
ledNumber = random(0, numLEDs);
}
while (isLedStatus[ledNumber] != 0);

turnOnCandle();
}

void loop()
{
if (pushbutton.update())
{
if (pushbutton.fallingEdge())
{
doRandomCandle();
}
}
unsigned long currentMillis = millis();
for (byte b = 0; b < numLEDs; b++)
{
if (currentMillis - isLedOnTimes[b] > onTime)
{