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);
  FastLED.addLeds<WS2811, ledPin, RGB>(leds, numLEDs);
  randomSeed(analogRead(0));
  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);
  FastLED.addLeds<WS2811, ledPin, RGB>(leds, numLEDs);
  randomSeed(analogRead(0));
  // Serial.begin(9600);
}

byte previousState = HIGH;

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

void fadeOutCandle()
{
  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)
    {
      fadeOutCandle();
    }
  }
}

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);
  FastLED.addLeds<WS2811, ledPin, RGB>(leds, numLEDs);
  randomSeed(analogRead(0));
  // Serial.begin(9600);
}

byte previousState = HIGH;

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

void fadeOutCandle()
{
  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)
    {
      fadeOutCandle();
    }
  }
}

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);
  FastLED.addLeds<WS2811, ledPin, RGB>(leds, numLEDs);
  randomSeed(analogRead(0));
  // Serial.begin(9600);
}

byte previousState = HIGH;

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

void fadeOutCandle(byte turnOffLED)
{
  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)
    {
      fadeOutCandle(b);
    }
  }
}