0

I wrote a FSM with the help of some tutorials through out the world wide web and so far it does what I want to do with it.

But one thing that is not the way I want to be, is to exit the state noLightPause during the non blocking delay with the button to enter the yellowLight state again. I cannot figure out where to put the buttonState inside my code, if it should be that simple to exit that state, because it was hard enought for me to get my machine going to that point :D.

Do not get confused, I soldered the button from ground to the pin, so LOW gets the input :).

Hope you guys can help me with that problem to get me further with my machine.

Thanks in advance for all your help, here is my code:

#include <FastLED.h>

#define NUM_LEDS 16

CRGB ledStrip [NUM_LEDS];

const int buttonPin = 4;
const int ledStripPin = 8;
const int ledOnBoard = 13;
const int interval = 100;

int buttonState = 0;
int lastButtonState = 0;

int ledOnBoardState = LOW;

unsigned long previousMillis = 0;
static unsigned long noDelayPause;

enum statusType {whiteLight, yellowLight, noLightPause, noLight};

statusType currentStatus = whiteLight;

void setup() {

  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(ledStrip, OUTPUT);
  pinMode(ledOnBoard, OUTPUT);

  FastLED.addLeds<NEOPIXEL, 8>(ledStrip, NUM_LEDS).setCorrection(DirectSunlight);
  FastLED.show();
}

void loop() {

  //----------------------------------------
  // just to see if the machine is blocking something

  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    if (ledOnBoardState == LOW) {
      ledOnBoardState = HIGH;
    } else {
      ledOnBoardState = LOW;
    }
    digitalWrite(ledOnBoard, ledOnBoardState);
  }

  //----------------------------------------

  switch (currentStatus) {

    case whiteLight:
      currentStatus = whiteLightFunction();
      break;

    case yellowLight:
      currentStatus = yellowLightFunction();
      break;

    case noLightPause:
      noDelayPause = millis();
      currentStatus = noLightPauseFunction();
      break;

    case noLight:
      if (millis() - noDelayPause > 1000) {
        currentStatus = noLightFunction();
        break;
      }
  }
}

statusType whiteLightFunction() {

  if (digitalRead(buttonPin) == LOW) {

    return (yellowLight);

  } else {

    fill_solid(ledStrip, NUM_LEDS, CRGB::White);
    FastLED.setBrightness(100);
    FastLED.show();

    return (whiteLight);
  }
}

statusType yellowLightFunction() {

  if (digitalRead(buttonPin) == LOW) {

    fill_solid(ledStrip, NUM_LEDS, CRGB::Yellow);
    FastLED.setBrightness(100);
    FastLED.show();

    return (yellowLight);

  } else {

    return (noLightPause);
  }
}

statusType noLightPauseFunction() {

  fill_solid(ledStrip, NUM_LEDS, CRGB::Black);
  FastLED.show();

  if (digitalRead(buttonPin) == LOW) {

    return (yellowLight);

  } else {

    if (digitalRead(buttonPin) == HIGH) {

      return (noLight);
    }
  }
}

statusType noLightFunction() {

  if (digitalRead(buttonPin) == LOW) {

    return (yellowLight);

  } else {

    return (whiteLight);
  }
}
1
  • 2
    I'm not sure I follow the question, "Where do I put the buttonState". You are reading the button inside the function and letting that decide which status to take next. That sounds perfectly reasonable. What is happening or not happening right now that doesn't meet your expectations? Compare and contrast the symptom and expected behavior a little.
    – Delta_G
    Apr 19 '20 at 16:07
0

You should also introduce a button state to have the FSM working as a FSM

 bool buttonState = false;

in the loop you check for the press/release and change the state:

if (digitalRead(buttonPin) == LOW && buttonState == true) buttonState == false;
if (digitalRead(buttonPin) == HIGH && buttonState == false) buttonState == true;

inside your function you only go for buttonState eg

statusType noLightFunction() {
if (buttonState == false) {  // Button is NOT pressed

    return (yellowLight);

  } else {       // Button is pressed

    return (whiteLight);
  }
}

The button acts as a toogle switch as long as you keep it pressed (or released) nothing will change only the state changes caise an action to happen. I personally use "speaking" vars I still know years later so instead of buttonState I use buttonIsPressed but thats flavour

3
  • Thanks for your advice Codebreaker. I will do that to complete my FSM and I found a solution that kinda does what you describe here. The yellowLight state returns with a simple: if (millis() - noDelayPause > 1000 || digitalRead(buttonPin) == LOW). Or after the time has passed it goes into the whiteLight state.
    – Marvin
    Apr 19 '20 at 18:06
  • Be aware that the solution with going directly to read the pin in the function wont work in more complex scenarios due to processing time and other issues. Please close the question as solved/accepted Apr 19 '20 at 18:11
  • when comparing boolean values, do not use if (buttonState == true) ... use if ( buttonState ) or if ( !buttonState )
    – jsotola
    Apr 19 '20 at 18:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.