Help with alternating ON, BLINK, OFF, LED code

Hello, I am working on some code that cycles the state of two LEDS, controlled by one button. This is what I want it to do:

  1. Press the button to turn LED1 on,
  2. Press button again to begin blinking LED1,
  3. Press button again to turn LED1 off, AND Turn LED2 on,
  4. Press button again to begin blinking LED2,
  5. Press button again to turn LED2 off, AND turn LED1 on,

After Step 5. we find ourselves at the beginning of the cycle and it can repeat. This code that I have modified achieves everything except step #4, the blinking of LED2 state. Can anyone show me what I'm missing?

Below is the code I have modified, I don't need any of the serial print stuff, but ran into some issues when I took those steps out. Thank you to the original author of the finite state machine sketch that I used as a baseline:




// millis_and_finite_state_machine.ino
// ---------------------------------------------
// License: The Unlicense, Public Domain.
// Author: Koepel
// 2019 january 23
// ---------------------------------------------
// 
// millis and a finite state machine
//
// This sketch uses a button and is going through a few different states.
// The serial monitor tells what to do.
//
// The "State Change Detection" example is used.
// The "Blink without Delay" example is used.
// Variables of the "bool" type are used to pass on information.
// Two "previousMillis" variables are used, but a single "previousMillis" 
// could be used, because they do not overlap.
//
// The finite state machine has a few ..._INIT states.
// They are used to make a setup for the new state.
//
// A push button is connected between pin 4 and GND.
//
// I want to change this sketch:
//   When the led is off and the button is pressed for a long time,
//   then I want to turn the led on and after some time turn it off.
// 


// An 'enum' is the best way to for a list of the states.
enum
{
  STATE_IDLE_INIT,
  STATE_IDLE,
  STATE_ON_INIT,
  STATE_ON_BEFORE_BUTTON,
  STATE_ON_BUTTON_2_SECONDS,
  STATE_OFF_INIT,
  STATE_OFF,
  STATE_BLINK_INIT,
  STATE_BLINK,
  STATE_BLINK_INIT2,
} state;

const int buttonPin = 4;
int last_button_value = HIGH;   // pin 2 is HIGH when button is not pressed
unsigned long previousMillisButton;

const int ledPin = 10;
const int ledPin2 = 11;

int led_value;

unsigned long previousMillisBlinking;
bool blinking;   // boolean variable, should the led blink or not.


void setup()
{
  Serial.begin( 9600);
  Serial.println( "The sketch has started.");
  pinMode( buttonPin, INPUT_PULLUP);
  pinMode( ledPin, OUTPUT);
  pinMode( ledPin2, OUTPUT);
}


void loop()
{
  unsigned long currentMillis = millis();
  
  
  // ---------------------------------------------------
  // BUTTON
  // ---------------------------------------------------
  // Detect if the button changes, and pass
  // that information on, to the finite state machine.
  // Only the event of the change is passed on, because
  // this sketch did not need to know the state
  // of the button, only a change.
  // ---------------------------------------------------
  bool buttonPressed = false;
  bool buttonReleased = false;

  int button_value = digitalRead( buttonPin);

  if( button_value != last_button_value)
  {
    if( button_value == LOW)  // low is button pressed
    {
      buttonPressed = true;
    }
    else
    {
      buttonReleased = true;
    }
    last_button_value = button_value;
  }
  

  // ---------------------------------------------------
  // FINITE STATE MACHINE
  // ---------------------------------------------------
  // The final state machine uses information to
  // make decisions.
  // ---------------------------------------------------
  
  switch( state)
  {
    case STATE_IDLE_INIT:
      // Before going to the actual "idle" state, a message is printed.
      Serial.println( "Press the button to turn the led on.");
      state = STATE_IDLE;
      break;
    case STATE_IDLE:
      // This "idle" state is when there is nothing to do.
      // This state is executed until a button is pressed.
      // It "waits" until a button is pressed, but it does
      // not really wait, since it is run over and over again.
      if( buttonPressed)
      {
        state = STATE_ON_INIT;
      }
      break;
    case STATE_ON_INIT:
      // The state when the led is "on" is split into three states.
      // This is the initial part to turn the led on and print a message.
      digitalWrite( ledPin, HIGH);
      digitalWrite( ledPin2, LOW);
      

      Serial.println( "Press button to begin blinking.");
      state = STATE_ON_BEFORE_BUTTON;
      break;
    case STATE_ON_BEFORE_BUTTON:
      // This state "waits" until a button is pressed.
      // As soon as a button is pressed, the value of millis()
      // is stored, to be able to calculate how long the button is pressed.
      if( buttonPressed)
      {
        previousMillisButton = currentMillis;
        state = STATE_BLINK_INIT;
      }
      break;
    case STATE_ON_BUTTON_2_SECONDS:
      // When the button is released before 2 seconds are passed,
      // then return to the state to "wait" for the button.
      if( buttonReleased)
      {
        state = STATE_ON_BEFORE_BUTTON;
      }
      else
      {
        if( currentMillis - previousMillisButton >= 100)
        {
          state = STATE_BLINK_INIT;
        }
      }
      break;
    case STATE_OFF_INIT:
      digitalWrite( ledPin, LOW);
       digitalWrite( ledPin2, HIGH);

      Serial.println( "Press button to turn off LED.");
      state = STATE_OFF;
      break;
    case STATE_OFF:
      if( buttonPressed)
      {
        state = STATE_BLINK_INIT;
      }
      break;
    case STATE_BLINK_INIT:
      // Set up the blinking.
      // Updating the previousMillisBlinking is not really required.
      previousMillisBlinking = currentMillis;
      blinking = true;
      Serial.println( "Press button to stop blinking.");
      state = STATE_BLINK;
      break;
    case STATE_BLINK:
      // This state "waits" until a button is pressed.
      // At the moment the button is pressed, the led could be on or off.
      // Therefor the led is turned off, to be sure that it will be off.
      if( buttonPressed)
      {
        blinking = false;
        digitalWrite( ledPin, LOW);  // be sure to turn led off
        digitalWrite( ledPin2, HIGH);
        state = STATE_IDLE_INIT;
      }


  }

  
  
  // ---------------------------------------------------
  // BLINK WITHOUT DELAY
  // ---------------------------------------------------
  // Blinking the led is outside the final state machine.
  // The final state machine can turn the blinking on and off.
  // ---------------------------------------------------

  if( blinking)
  {
    if( currentMillis - previousMillisBlinking >= 300)
    {
      previousMillisBlinking = currentMillis;
      
      if( led_value == LOW)
      {
        led_value = HIGH;
      }
      else
      {
        led_value = LOW;
      }
      digitalWrite( ledPin, led_value);
    }
  }
  
  delay( 10);  // a delay as a simple way to debounce the button
}

then, put them back. It might be you have deleted to much.
call @Koepel for help with his skeleton sketch you might have destroyed.

I put them back. I'm more apologizing for the unnecessary/unneeded text in the code.

Hello faurien

What is the real-life purpose of this sketch?

It is for a DIY camera "tally light" system. Basically so the subject knows which camera to look at while we're filming, and when the light blinks, they know they're about to need to look at the other camera.

Hello faurien

Test this code suggestion and report back.

//https://forum.arduino.cc/t/help-with-alternating-on-blink-off-led-code/1220546
//https://europe1.discourse-cdn.com/arduino/original/4X/7/e/0/7e0ee1e51f1df32e30893550c85f0dd33244fb0e.jpeg
#define ProjectName "Help with alternating ON, BLINK, OFF, LED code"
#define NotesOnRelease "Arduino MEGA tested"
// make names
enum TimerEvent {NotExpired, Expired};
enum TimerControl {Halt, Run};
enum ButtonEvent {Released,Pressed};
enum Stages {LedOneOn, LedOneBlink, LedTwoOn, LedTwoBlink, StageMax};
enum LedNames {LedOne, LedTwo};
// make variables
constexpr uint8_t OutPut[] {10,11};
constexpr uint8_t InPut {4};
uint8_t stages = LedOneOn;
// make structures
struct TIMER
{
  uint32_t interval;
  uint8_t control;
  uint32_t now;
  void make (uint32_t interval_)
  {
    interval = interval_;
  }
  void launch(uint32_t currentMillis)
  {
    control = Run;
    now = currentMillis;
  }
  uint8_t expired(uint32_t currentMillis)
  {
    uint8_t timerEvent = currentMillis - now >= interval and control;
    if (timerEvent == Expired) now = currentMillis;
    return timerEvent;
  }
};
TIMER debounce;
TIMER ledBlink;
// make support
void heartBeat(const uint8_t LedPin, uint32_t currentMillis)
{
  static bool setUp = false;
  if (setUp == false) pinMode (LedPin, OUTPUT), setUp = true;
  digitalWrite(LedPin, (currentMillis / 500) % 2);
}
// make application
void setup()
{
  Serial.begin(115200);
  Serial.print("Source: "), Serial.println(__FILE__);
  Serial.print(ProjectName), Serial.print(" - "), Serial.println(NotesOnRelease);
  debounce.make(20);
  debounce.launch(millis());
  ledBlink.make(1000);
  ledBlink.launch(millis());
  for (auto i : OutPut)
  {
    pinMode(i, OUTPUT);
    digitalWrite(i, HIGH);
    delay(1000);
    digitalWrite(i, LOW);
    delay(1000);
  }
  pinMode(InPut, INPUT_PULLUP);
  Serial.println(" =-> and off we go\n");
}
void loop()
{
  static uint8_t ledValue = LOW;
  uint32_t currentMillis = millis();
  heartBeat(LED_BUILTIN, currentMillis);
  if (ledBlink.expired(currentMillis) == Expired) ledValue = ledValue ? LOW : HIGH;
  if (debounce.expired(currentMillis) == Expired)
  {
    static uint8_t stateOld=digitalRead(InPut)?LOW:HIGH;
    uint8_t stateNew=digitalRead(InPut)?LOW:HIGH;
    if(stateOld != stateNew) 
    {
      stateOld = stateNew;
      if (stateOld == Pressed)
      {
        stages=(stages+1)%StageMax;
        for (auto i:OutPut) digitalWrite(i,LOW); 
      }
    }
  }
  switch (stages)
  {
    case LedOneOn:
      digitalWrite(OutPut[LedOne], HIGH);
      break;
    case LedOneBlink:
      digitalWrite(OutPut[LedOne], ledValue);
      break;
    case LedTwoOn:
      digitalWrite(OutPut[LedTwo], HIGH);
      break;
    case LedTwoBlink:
      digitalWrite(OutPut[LedTwo], ledValue);
      break;
    default:
      break;
  }
}

Have a nice day and enjoy coding in C++.

1 Like

Amazing Paul! Thank you. Works like a charm.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.