# Combine multiple state machines

**URL:** <https://forum.arduino.cc/t/combine-multiple-state-machines/1220978>\
**Category:** Programming\
**Created:** [February 7, 2024, 6:27am UTC](https://forum.arduino.cc/t/combine-multiple-state-machines/1220978 "2024-02-07T06:27:07Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![kted](https://avatars.discourse-cdn.com/v4/letter/k/e480ec/32.png) [@kted](https://forum.arduino.cc/u/kted)\
**Post date:** [February 7, 2024, 6:27am UTC](https://forum.arduino.cc/t/combine-multiple-state-machines/1220978/1 "2024-02-07T06:27:07Z")

</div>

Hello,  
I'm a new user and and new to code programing.

I need a program to blink two LEDs completely independent of one another with two outputs. I found this code on Digi-Key. It works as advertised, but I need the two on/off times to run consecutively. The program I have here runs the two blink times concurrently.

Here's the code:

// These variables store the flash pattern  
// and the current state of the LED

int ledPin1 = 12; // the number of the LED pin  
int ledState1 = LOW; // ledState used to set the LED  
unsigned long previousMillis1 = 0; // will store last time LED was updated  
long OnTime1 = 250; // milliseconds of on-time  
long OffTime1 = 750; // milliseconds of off-time

int ledPin2 = 13; // the number of the LED pin  
int ledState2 = LOW; // ledState used to set the LED  
unsigned long previousMillis2 = 0; // will store last time LED was updated  
long OnTime2 = 330; // milliseconds of on-time  
long OffTime2 = 400; // milliseconds of off-time

void setup()  
{  
// set the digital pin as output:  
pinMode(ledPin1, OUTPUT);  
pinMode(ledPin2, OUTPUT);  
}

void loop()  
{  
// check to see if it's time to change the state of the LED  
unsigned long currentMillis = millis();

if((ledState1 == HIGH) && (currentMillis - previousMillis1 \>= OnTime1))  
{  
ledState1 = LOW; // Turn it off  
previousMillis1 = currentMillis; // Remember the time  
digitalWrite(ledPin1, ledState1); // Update the actual LED  
}  
else if ((ledState1 == LOW) && (currentMillis - previousMillis1 \>= OffTime1))  
{  
ledState1 = HIGH; // turn it on  
previousMillis1 = currentMillis; // Remember the time  
digitalWrite(ledPin1, ledState1); // Update the actual LED  
}

if((ledState2 == HIGH) && (currentMillis - previousMillis2 \>= OnTime2))  
{  
ledState2 = LOW; // Turn it off  
previousMillis2 = currentMillis; // Remember the time  
digitalWrite(ledPin2, ledState2); // Update the actual LED  
}  
else if ((ledState2 == LOW) && (currentMillis - previousMillis2 \>= OffTime2))  
{  
ledState2 = HIGH; // turn it on  
previousMillis2 = currentMillis; // Remember the time  
digitalWrite(ledPin2, ledState2); // Update the actual LED  
}  
}

---

<div class="post-metadata">

**Author:** ![J-M-L](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/j-m-l/32/766245_2.png) [@J-M-L](https://forum.arduino.cc/u/J-M-L)\
**Post date:** [February 7, 2024, 6:37am UTC](https://forum.arduino.cc/t/combine-multiple-state-machines/1220978/2 "2024-02-07T06:37:36Z")

</div>

Hello, do yourself a favour and please read [How to get the best out of this forum](https://forum.arduino.cc/t/how-to-get-the-best-out-of-this-forum/679966) and post accordingly (including code with code tags and necessary documentation for your ask like your exact circuit and power supply, links to components etc).

* * *

To your question For information and examples look at

- [Using millis() for timing. A beginners guide](https://forum.arduino.cc/index.php?topic=503368.0)
- [Several things at the same time](https://forum.arduino.cc/index.php?topic=223286.0)
- [Flashing multiple LEDs at the same time](https://forum.arduino.cc/t/flashing-multiple-leds-at-the-same-time/1065564)

you might benefit from studying state machines. Here is a small introduction to the topic: [Yet another Finite State Machine introduction](https://forum.arduino.cc/t/yet-another-finite-state-machine-introduction/1198997)

---

<div class="post-metadata">

**Author:** ![sterretje](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/sterretje/32/391294_2.png) [@sterretje](https://forum.arduino.cc/u/sterretje)\
**Post date:** [February 7, 2024, 6:45am UTC](https://forum.arduino.cc/t/combine-multiple-state-machines/1220978/3 "2024-02-07T06:45:37Z")

</div>

If that is all your code has to do, just use delay() instead of a millis() based approach (and maybe a for-loop; your requirement is not quite clear).

If it needs to be more future proof, you need to keep track if the blink sequence of the first LED is finished (e.g. set a boolean variable). If it is, don't do the first LED but the second one. When the second one is finished, clear the variable and it will again do the first one.

Based on your requirement I can not say what the sequence should be  
1 on  
1 off  
2 on  
2 off  
back to the beginning

or

blink 1 10 times  
blink 2 22 times  
back to the beginning

or something else

Please edit your post, select all code and next click the `<CODE/>` button to apply code tags. This makes the code easier to read and copy and the forum software will not mangle it.

---

<div class="post-metadata">

**Author:** ![gcjr](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/gcjr/32/314015_2.png) [@gcjr](https://forum.arduino.cc/u/gcjr)\
**Post date:** [February 7, 2024, 12:18pm UTC](https://forum.arduino.cc/t/combine-multiple-state-machines/1220978/4 "2024-02-07T12:18:47Z")

</div>

> [@kted](#):
>
> I'm a new user and and new to code programing.

the following code may be a little too much for someone "new" because it uses features of C that you may not have read about yet, but i'm going to post it and let you decide

you can read in [The C Programming Language](http://cslabcms.nju.edu.cn/problem_solving/images/c/cc/The_C_Programming_Language_%282nd_Edition_Ritchie_Kernighan%29.pdf) about

- struct in chap 6
- pointer in chap 5
- enum pg 39

```arduino
// generic timer

struct LedTimer {
    byte Pin;
    unsigned long MsecOn;
    unsigned long MsecOff;

    int state;
    unsigned long msecPeriod;
    unsigned long msec;
};

LedTimer tmr [] = {
    { 12, 250, 750 },
    { 13, 330, 400 },
};
const int Ntmr = sizeof(tmr) / sizeof(LedTimer);

enum { Off = HIGH, On = LOW };

char s [90];

// -----------------------------------------------------------------------------
void loop()
{
    unsigned long currentMillis = millis();
    
    LedTimer *p = tmr;
    for (int n = 0; n < Ntmr; n++, p++) {
        if (currentMillis >= p->msec) {
            if (Off == p->state) {
                p->msecPeriod = p->MsecOn;
                p->state = On;
            }
            else {
                p->msecPeriod = p->MsecOff;
                p->state = Off;
            }

            p->msec += p->msecPeriod;
            digitalWrite (p->Pin, p->state);
        }
    }
}

// -----------------------------------------------------------------------------
void setup()
{
    Serial.begin (9600);
    
    for (int n = 0; n < Ntmr; n++) {
        tmr [n].state = Off;
        tmr [n].msecPeriod = tmr [n].MsecOff;
        tmr [n].msec = tmr [n].msecPeriod;
        pinMode (tmr [n].Pin, OUTPUT);
        digitalWrite (tmr [n].Pin, tmr [n].state);
    }
}

```

---

<div class="post-metadata">

**Author:** ![alto777](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/alto777/32/317385_2.png) [@alto777](https://forum.arduino.cc/u/alto777)\
**Post date:** [February 7, 2024, 1:50pm UTC](https://forum.arduino.cc/t/combine-multiple-state-machines/1220978/5 "2024-02-07T13:50:43Z")

</div>

> [@sterretje](#):
>
> just use delay() instead of a millis() based approach

LOL! I knew that one day the advice would be tipped over.

> [@kted](#):
>
> two LEDs completely independent of one another
> 
> but consecutively.

This some like a contradiction. But as @J-M-L says, you could plan the entire co-dependent sequence of the LEDs as multiple states in one finite state machine or you could as @sterretje suggests have your two current mechanisms share at least one variable that would allow each to run or run, and then pass control to the other.

With the addition of a counter they could similarly share, one LED could blink a number of times at its rate before allowing the other to do the same for a different number of times.

But mostly, you need to be able to describe this independent and consecutive concept.

a7

---

<div class="post-metadata">

**Author:** ![paulpaulson](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/paulpaulson/32/363643_2.png) [@paulpaulson](https://forum.arduino.cc/u/paulpaulson)\
**Post date:** [February 7, 2024, 8:36pm UTC](https://forum.arduino.cc/t/combine-multiple-state-machines/1220978/6 "2024-02-07T20:36:56Z")

</div>

Hello [kted](https://forum.arduino.cc/u/kted)

Check:

```arduino
//https://forum.arduino.cc/t/combine-multiple-state-machines/1220978
//https://europe1.discourse-cdn.com/arduino/original/4X/7/e/0/7e0ee1e51f1df32e30893550c85f0dd33244fb0e.jpeg
#define ProjectName "Combine multiple state machines"
#define NotesOnRelease "Arduino MEGA tested"
// make names
enum TimerControl {Halt, Run};
enum OnOff {Off, On};
enum Numbers {One, Two};
// make variables
constexpr uint8_t LedPins[] {12, 13};
constexpr uint32_t OnOffInterval [] [2]
{
  {750, 250},
  {400, 330},
};
constexpr uint32_t NumberOfBlinks [] {3, 1};
// make structures
struct BLINKLED
{
  uint8_t pin;
  uint32_t interval[2];
  uint8_t control;
  uint8_t numerOfBlinks;
  uint32_t now;
  void make(uint8_t pin_, uint32_t offTime, uint32_t onTime, uint8_t numerOfBlinks_)
  {
    pin = pin_;
    pinMode(pin, OUTPUT);
    digitalWrite(pin, HIGH);
    delay(1000);
    digitalWrite(pin, LOW);
    delay(1000);
    interval[Off] = offTime;
    interval[On] = onTime;
    numerOfBlinks = 2 * numerOfBlinks_;
  }
  void start(uint32_t now_)
  {
    now = now_;
    control = numerOfBlinks;
    digitalWrite(pin, HIGH);
  }
} ledBlinks[sizeof(LedPins)];

// 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);
  uint8_t element = 0;
  for (auto &ledBlink : ledBlinks)
  {
    ledBlink.make(LedPins[element], OnOffInterval [element] [Off], OnOffInterval [element] [On], NumberOfBlinks[element]);
    element++;
  }
  ledBlinks[One].start(millis());
  Serial.println(" =-> and off we go\n");
}
void loop()
{
  uint32_t currentMillis = millis();
  heartBeat(LED_BUILTIN, currentMillis);
  static uint8_t blinkNumber = 0;
  for (auto &ledBlink : ledBlinks)
  {
    if (currentMillis - ledBlink.now >= ledBlink.interval[digitalRead(ledBlink.pin)] and ledBlink.control)
    {
      if ((--ledBlink.control) != 0)
      {
        digitalWrite(ledBlink.pin, digitalRead(ledBlink.pin) ? LOW : HIGH);
        ledBlink.now = currentMillis;
      }
      else
      {
        blinkNumber = (blinkNumber + 1) % (sizeof(ledBlinks) / sizeof(ledBlinks[0]));
        ledBlinks[blinkNumber].start(currentMillis);
      }
    }
  }
}

```

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

---

<div class="post-metadata">

**Author:** ![codingapacalyspe](https://avatars.discourse-cdn.com/v4/letter/c/b38774/32.png) [@codingapacalyspe](https://forum.arduino.cc/u/codingapacalyspe)\
**Post date:** [February 8, 2024, 2:39am UTC](https://forum.arduino.cc/t/combine-multiple-state-machines/1220978/7 "2024-02-08T02:39:43Z")

</div>

To achieve the effect of having two LEDs blink consecutively, you need to modify the existing code so that one LED starts blinking after the other has completed its cycle. You can accomplish this by adding a condition to check if both LEDs have completed their cycles before starting the next cycle for the first LED. Here's how you can adjust the `loop()` function to implement this behavior:

```cpp
void loop()
{
  unsigned long currentMillis = millis();

  // Check if both LEDs have completed their cycles
  bool bothCompleted = false;

  // Update LED1 state
  if((ledState1 == HIGH) && (currentMillis - previousMillis1 >= OnTime1))
  {
    ledState1 = LOW;
    previousMillis1 = currentMillis;
    digitalWrite(ledPin1, ledState1);
  }
  else if ((ledState1 == LOW) && (currentMillis - previousMillis1 >= OffTime1))
  {
    ledState1 = HIGH;
    previousMillis1 = currentMillis;
    digitalWrite(ledPin1, ledState1);
  }
  // Check if LED1 has completed its cycle
  if(ledState1 == HIGH && currentMillis - previousMillis1 >= OnTime1 + OffTime1)
  {
    bothCompleted = true;
  }

  // Update LED2 state
  if((ledState2 == HIGH) && (currentMillis - previousMillis2 >= OnTime2))
  {
    ledState2 = LOW;
    previousMillis2 = currentMillis;
    digitalWrite(ledPin2, ledState2);
  }
  else if ((ledState2 == LOW) && (currentMillis - previousMillis2 >= OffTime2))
  {
    ledState2 = HIGH;
    previousMillis2 = currentMillis;
    digitalWrite(ledPin2, ledState2);
  }
  // Check if LED2 has completed its cycle
  if(ledState2 == HIGH && currentMillis - previousMillis2 >= OnTime2 + OffTime2)
  {
    bothCompleted = true;
  }

  // If both LEDs have completed their cycles, reset their timers
  if(bothCompleted)
  {
    previousMillis1 = currentMillis;
    previousMillis2 = currentMillis;
    bothCompleted = false; // Reset flag for the next cycle
  }
}

```

I added a boolean variable `bothCompleted` to track whether both LEDs have completed their blinking cycles. I then added checks after updating each LED's state to determine if the LED has finished its cycle (`OnTime + OffTime`). If both LEDs have completed their cycles, we reset the timers for both LEDs, ensuring that the next cycle starts immediately after the previous one completes.

---

<div class="post-metadata">

**Author:** ![kted66](https://avatars.discourse-cdn.com/v4/letter/k/9fc29f/32.png) [@kted66](https://forum.arduino.cc/u/kted66)\
**Post date:** [February 8, 2024, 3:50am UTC](https://forum.arduino.cc/t/combine-multiple-state-machines/1220978/8 "2024-02-08T03:50:38Z")

</div>

> [@sterretje](#):
>
> or

Thanks for your reply.

I know it will work using delay, but I will be adding a LCD to display remaining "on" times for each output. If I use delay it's a blocking code, it won't do anything else.

---

<div class="post-metadata">

**Author:** ![StefanL38](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/stefanl38/32/713548_2.png) [@StefanL38](https://forum.arduino.cc/u/StefanL38)\
**Post date:** [February 8, 2024, 5:01am UTC](https://forum.arduino.cc/t/combine-multiple-state-machines/1220978/9 "2024-02-08T05:01:57Z")

</div>

> [@kted66](#):
>
> I know it will work using delay, but I will be adding a LCD to display remaining "on" times for each output. If I use delay it's a blocking code, it won't do anything else.

So next thing you should do is describing the **complete** functionality in **normal words** that you want to have in the end.

If you only describe parts of the wanted functionality you are fooling your potential helpers to suggest solutions that may turn out to be not suitable.

best regards Stefan

---

<div class="post-metadata">

**Author:** ![kted66](https://avatars.discourse-cdn.com/v4/letter/k/9fc29f/32.png) [@kted66](https://forum.arduino.cc/u/kted66)\
**Post date:** [February 8, 2024, 5:51am UTC](https://forum.arduino.cc/t/combine-multiple-state-machines/1220978/10 "2024-02-08T05:51:55Z")

</div>

Thank you for your help.

I'm totally lost. I'm new to Arduino programing. In other words I'm wet behind the ears!

The code does not work in the way I want it to. Perhaps I did not explain just what I'm trying to do. So I will try to explain.

I need 2 separate timers on 2 separate output pins.  
I will call the timers as T1 & T2.  
The timers can not be "on" at the same time.  
If T1's on time is set for 10,000ms and the off time is set for 30,000ms then T1"s total time would be 4sec.

At the end of T1's total time ( 4sec ) then T2's timer would start. At the end of T2's total time, Then loop to the beginning.

When I get that portion of the code to work, I will attempt to add a LCD to show the remaining time of each timer. The approximate timer times are T1 "on" = 6hr, "off" = 0. I know that it can't be 0, so I will use 1ms. T2's "on" time = 240hrs.  
Now you now why I need a LCD. I don't need to show milliseconds on the LCD, only HHH:MM:SS

---

<div class="post-metadata">

**Author:** ![kted66](https://avatars.discourse-cdn.com/v4/letter/k/9fc29f/32.png) [@kted66](https://forum.arduino.cc/u/kted66)\
**Post date:** [February 8, 2024, 5:58am UTC](https://forum.arduino.cc/t/combine-multiple-state-machines/1220978/11 "2024-02-08T05:58:34Z")

</div>

Thank you for your help.

I'm totally lost. I'm new to Arduino programing. In other words I'm wet behind the ears!

The code does not work in the way I want it to. Perhaps I did not explain just what I'm trying to do. So I will try to explain.

I need 2 separate timers on 2 separate output pins.  
I will call the timers as T1 & T2.  
The timers can not be "on" at the same time.  
If T1's on time is set for 10,000ms and the off time is set for 30,000ms then T1"s total time would be 4sec.

At the end of T1's total time ( 4sec ) then T2's timer would start. At the end of T2's total time, Then loop to the beginning.

When I get that portion of the code to work, I will attempt to add a LCD to show the remaining time of each timer. The approximate timer times are T1 "on" = 6hr, "off" = 0. I know that it can't be 0, so I will use 1ms. T2's "on" time = 240hrs.  
Now you now why I need a LCD. I don't need to show milliseconds on the LCD, only HHH:MM:SS  
[/quote]

---

<div class="post-metadata">

**Author:** ![StefanL38](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/stefanl38/32/713548_2.png) [@StefanL38](https://forum.arduino.cc/u/StefanL38)\
**Post date:** [February 8, 2024, 6:57am UTC](https://forum.arduino.cc/t/combine-multiple-state-machines/1220978/12 "2024-02-08T06:57:43Z")

</div>

Just to make sure I understand right I describe with my own words using example-numbers

You have two timers called "T1" and "T2" these timers shall run mutually exclusive. This means:

- whenever T1 is active T2 must stay deactivated
- whenever T2 is active T1 must stay deactivated

A timing-cycle starts with T1 beeing active let's say:  
T1-on-time 120 hours / T1-off-time 180 hours

If T1 has finished its cycle T2 starts its own cycle  
T2-on-time 80 hours / T2-off-time 220 hours

Whenever T1 or T2 is running show the **remaining** time on a LCD in Format HHH:MM:SS

Is this a correct description of the wanted functionality?  
Are the numbers how many hours the timers shall run a typical example of the times you want the timers to be on/off.

> [@kted66](#):
>
> Now you now why I need a LCD. I don't need to show milliseconds on the LCD, only HHH:MM:SS

So this means in the final state you need a timer that runs more than 100 hours. In your example 240 hours which are 10 days.

Well if you need so long time-intervals I recommend to use a **R** eal **T** ime **C** lock in short RTC.

Beause the function millis() will deviate for 10 or 20 seconds or even more over such a long period of time. If you can live with such a deviation you could still use function millis() as the clockbase for a software-RTC.

Here is a demo-Code for a millis() / software-based RTC

```arduino
/* This software belongs to the public domain
 * Attention: a software-RTC like this one 
 * which uses the onboard-oscillator of the microcontroller-board
 * has a deviation from exact time of up to multiple seconds per day
 * This means of you want real time with a higher precision use a
 * hardware based RTC which will be much more precise
 */

unsigned long RTC_Timer = 0;
unsigned long MyTestTimer;

int RTC_Hour = 0;
int RTC_Minute = 59;
int RTC_Second = 50;
int RTC_10nth_Seconds = 0;
int minutesOfDay;
long secondsOfDay;

// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &periodStartTime, unsigned long TimePeriod) {
  unsigned long currentMillis = millis();
  if ( currentMillis - periodStartTime >= TimePeriod )
  {
    periodStartTime = currentMillis; // set new expireTime
    return true; // more time than TimePeriod) has elapsed since last time if-condition was true
  }
  else return false; // not expired
}

void PrintRTC_Data() {
  Serial.print("Software RTC time: ");
  Serial.print(RTC_Hour);
  Serial.print(":");
  Serial.print(RTC_Minute);
  Serial.print(":");
  Serial.print(RTC_Second);

  minutesOfDay = RTC_Hour * 60 + RTC_Minute;
  secondsOfDay = RTC_Hour * 3600 + RTC_Minute * 60 + RTC_Second;

  Serial.print(" minutesOfDay:");
  Serial.print(minutesOfDay);

  Serial.print(" secondsOfDay:");
  Serial.print(secondsOfDay);  
  Serial.println();
  
}

void SoftRTC() {
  if ( TimePeriodIsOver(RTC_Timer, 100) ) { // once every 100 milliseconds 
    RTC_10nth_Seconds ++; // increase 1/10th-seconds counter
    
    if (RTC_10nth_Seconds == 10) { // if 1/10th-seconds reaches 10
      RTC_10nth_Seconds = 0; // reset 1/10th-seconds counterto zero
      RTC_Second++; // increase seconds counter by 1

      if (RTC_Second == 60) { // if seconds counter reaches 60
        RTC_Minute++; // increase minutes counter by 1
        RTC_Second = 0; // reset seconds counter to zero
      }
    }

    if (RTC_Minute == 60) { // if minutes counter reaches 60
      RTC_Hour++; // increase hour counter by 1
      RTC_Minute = 0; // reset minutes counter to zero
    }

    if (RTC_Hour == 24) { // if hours counter reaches 24 
      RTC_Hour = 0; // reset hours counter to zero
    }
  }
}

void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");
}

void loop() {
  SoftRTC(); // must be called very regular and repeatedly to update the 0.1 second time-ticks
             // this means you CAN'T use delay(). 
             // Each and every single delay() must be replaced NON-blocking timing
  if ( TimePeriodIsOver(MyTestTimer, 1000) ) { // if 1000 milliseconds have passed by
    PrintRTC_Data(); // print time
  }
}
```

If you combine this software-RTC with a state-machine you can realise the wanted functionality

A state-machine is based on a switch-case-break-statement where the " **break**" makes code-execution mutually exclusive.

The **case** -part is a very simple equivalent to an if-condition  
as simple as

```arduino
if (myVariable == 1) {
// execute some code
}

if (myVariable == 2) {
// execute some code
}

if (myVariable == 3) {
// execute some code
}

```

```arduino
switch (myVariable) {
  case 1:
    // execute some code

  case 2:
    // execute some code

  case 3:
    // execute some code

}

```

best regards Stefan

---

<div class="post-metadata">

**Author:** ![sterretje](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/sterretje/32/391294_2.png) [@sterretje](https://forum.arduino.cc/u/sterretje)\
**Post date:** [February 8, 2024, 7:30am UTC](https://forum.arduino.cc/t/combine-multiple-state-machines/1220978/13 "2024-02-08T07:30:01Z")

</div>

You have things that need to happen in sequence. The below uses a sequencer implemented in a finite state machine.

Your LEDs in can in one of four states. The four states are

1. LED1 ON
2. LED1 OFF
3. LED2 ON
4. LED2 OFF

I have added a fifth one (START) to make sure that the timing at first run is correct; this state is only used once.

Each time that a state has done what it has to do, the code switches to the next state. For the START state you do not have conditions, it sets the pins correctly, stores the time and changes to LED1\_ON. In LED1\_ON, the basics is the millis() based timing; if the time has lapsed, it switches the first LED off, remembers the time and switches to LED1\_OFF. And so on. In the last state (LED2\_OFF), the code switches back to LED1\_ON.

```cpp
int ledPin1 = 12; // the number of the LED pin
int ledState1 = LOW; // ledState used to set the LED
unsigned long OnTime1 = 1250; // milliseconds of on-time
unsigned long OffTime1 = 1750; // milliseconds of off-time

int ledPin2 = 13; // the number of the LED pin
int ledState2 = LOW; // ledState used to set the LED
unsigned long OnTime2 = 1330; // milliseconds of on-time
unsigned long OffTime2 = 1400; // milliseconds of off-time

void setup()
{
  // set the digital pin as output:
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  
  Serial.begin(115200);
}

void loop()
{
  fsmLEDs();
}

/*
Finite state machine for LEDs
*/
void fsmLEDs()
{
  // the various states
  enum FSMSTATES
  {
    START,
    LED1_ON,
    LED1_OFF,
    LED2_ON,
    LED2_OFF,
  };

  // current state of state machine
  static FSMSTATES fsmState = START;
  // last time that a change of state happened
  static uint32_t lastUpdateTime; // note: uint32_t is the same as unsigned long

  switch (fsmState)
  {
    case START:
      Serial.println("fsm START");

      // switch led 1 on
      digitalWrite(ledPin1, HIGH);
      // switch led 2 on
      digitalWrite(ledPin2, LOW);
      // go to next state
      fsmState = LED1_ON;
      // remember the time that we switched to the next state
      lastUpdateTime = millis();
      Serial.println("fsm switching to LED1_ON");
      break;
    case LED1_ON:
      if (millis() - lastUpdateTime >= OnTime1)
      {
        digitalWrite(ledPin1, LOW);
        lastUpdateTime = millis();
        fsmState = LED1_OFF;
        Serial.println("fsm switching to LED1_OFF");
      }
      break;
    case LED1_OFF:
      if (millis() - lastUpdateTime >= OffTime1)
      {
        digitalWrite(ledPin2, HIGH);
        lastUpdateTime = millis();
        fsmState = LED2_ON;
        Serial.println("fsm switching to LED2_ON");
      }
      break;
    case LED2_ON:
      if (millis() - lastUpdateTime >= OnTime2)
      {
        digitalWrite(ledPin2, LOW);
        lastUpdateTime = millis();
        fsmState = LED2_OFF;
        Serial.println("fsm switching to LED2_OFF");
      }
      break;
    case LED2_OFF:
      if (millis() - lastUpdateTime >= OffTime2)
      {
        digitalWrite(ledPin1, HIGH);
        lastUpdateTime = millis();
        fsmState = LED1_ON;
        Serial.println("fsm switching to LED1_ON");
      }
      break;
  }
}

```

Study it and ask what you don't understand.

Notes

1. There is no longer a need for the `previousMillis` variables.
2. Your onTime and offTime should be unsigned longs.
3. The function fsmLeds() can return values; e.g. the remaining time. You need to adjust for that.

Code can be improved by using structs or classes to combine the related info for a LED (pin, on time and off time).

---

<div class="post-metadata">

**Author:** ![JCA34F](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/jca34f/32/340148_2.png) [@JCA34F](https://forum.arduino.cc/u/JCA34F)\
**Post date:** [February 8, 2024, 9:26am UTC](https://forum.arduino.cc/t/combine-multiple-state-machines/1220978/14 "2024-02-08T09:26:34Z")

</div>

Here's my sawed off attempt, prob'ly don't adhere to the Arduino "API" but it works. 😁

```arduino
const byte
  ledPin1 = 12, //the number of the LED pin
  ledPin2 = 13;

const uint16_t // unsigned int
  onTime1 = 250, // milliseconds of on-time
  offTime1 = 750, // milliseconds of off-time
  cycleTime1 = onTime1 + offTime1,
  onTime2 = 330, // milliseconds of on-time
  offTime2 = 400, //milliseconds of off-time
  cycleTime2 = onTime2 + offTime2;
unsigned long
  previousMillis, // will store last time LED was updated
  elapsed, // millis() - previousMillis
  totalTime = cycleTime1 + cycleTime2;
  
void setup()
{
  // set the digital pin as output:
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
}

void loop()
{
  elapsed = millis() - previousMillis;
  if(elapsed >= totalTime)
  {
    previousMillis += totalTime; 
  }
  digitalWrite(ledPin1, elapsed < onTime1);
  digitalWrite(ledPin2, elapsed > cycleTime1 &&
   elapsed < cycleTime1 + onTime2);
}
```

---

<div class="post-metadata">

**Author:** ![gcjr](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/gcjr/32/314015_2.png) [@gcjr](https://forum.arduino.cc/u/gcjr)\
**Post date:** [February 8, 2024, 2:10pm UTC](https://forum.arduino.cc/t/combine-multiple-state-machines/1220978/15 "2024-02-08T14:10:46Z")

</div>

> [@kted66](#):
>
> I need 2 separate timers on 2 separate output pins.  
> I will call the timers as T1 & T2.  
> The timers can not be "on" at the same time.  
> If T1's on time is set for 10,000ms and the off time is set for 30,000ms then T1"s total time would be 4sec.
> 
> At the end of T1's total time ( 4sec ) then T2's timer would start. At the end of T2's total time, Then loop to the beginning.

```arduino
// generic timer

struct LedTimer {
    byte Pin;
    byte OnOff;
    unsigned long Period;
};

enum { Off = HIGH, On = LOW };

LedTimer tmr [] = {
    { 12, On, 250 },
    { 12, Off, 750 },
    { 13, On, 330 },
    { 13, Off, 330 },
};
const int Ntmr = sizeof(tmr) / sizeof(LedTimer);
      int tmrIdx;

unsigned long msecPeriod;
unsigned long msec0;

char s [90];

// -----------------------------------------------------------------------------
void loop()
{
    unsigned long msec = millis();
    
    if (msec - msec0 >= msecPeriod) {
        msec0 = msec;

        if (Ntmr <= ++tmrIdx)
            tmrIdx = 0;

        msecPeriod = tmr [tmrIdx].Period;

        digitalWrite (tmr [tmrIdx].Pin, tmr [tmrIdx].OnOff);

        Serial.println (tmrIdx);
    }
}

// -----------------------------------------------------------------------------
void setup()
{
    Serial.begin (9600);
    
    for (int n = 0; n < Ntmr; n++) {
        pinMode (tmr [n].Pin, OUTPUT);
        digitalWrite (tmr [n].Pin, Off);
    }
}

```

---

<div class="post-metadata">

**Author:** ![alto777](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/alto777/32/317385_2.png) [@alto777](https://forum.arduino.cc/u/alto777)\
**Post date:** [February 8, 2024, 3:30pm UTC](https://forum.arduino.cc/t/combine-multiple-state-machines/1220978/16 "2024-02-08T15:30:35Z")

</div>

Shouldn't this

```arduino
        if (Ntmr <= ++tmrIdx)
            tmrIdx = 0;

```

come after you've used _tmrIdx_ to time one of the steps?

TBH I would not have noticed, but I had to run your code to see if and how it even works.

a7

---

<div class="post-metadata">

**Author:** ![gcjr](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/gcjr/32/314015_2.png) [@gcjr](https://forum.arduino.cc/u/gcjr)\
**Post date:** [February 8, 2024, 3:41pm UTC](https://forum.arduino.cc/t/combine-multiple-state-machines/1220978/17 "2024-02-08T15:41:10Z")

</div>

> [@alto777](#):
>
> come after you've used _tmrIdx_ to time one of the steps?

sure

---

<div class="post-metadata">

**Author:** ![alto777](https://dub1.discourse-cdn.com/arduino/user_avatar/forum.arduino.cc/alto777/32/317385_2.png) [@alto777](https://forum.arduino.cc/u/alto777)\
**Post date:** [February 8, 2024, 3:43pm UTC](https://forum.arduino.cc/t/combine-multiple-state-machines/1220978/18 "2024-02-08T15:43:11Z")

</div>

You're welcome.

a7

---

<div class="post-metadata">

**Author:** ![kted66](https://avatars.discourse-cdn.com/v4/letter/k/9fc29f/32.png) [@kted66](https://forum.arduino.cc/u/kted66)\
**Post date:** [February 9, 2024, 4:56am UTC](https://forum.arduino.cc/t/combine-multiple-state-machines/1220978/19 "2024-02-09T04:56:58Z")

</div>

Thank you,

The code does to appear work.

I set the timer "times" as:

```arduino
    { 12, On, 10000 },
    { 12, Off, 1 },
    { 13, On, 20000 },
    { 13, Off, 1 },

```

I used the stopwatch on my phone to check the LED "ON" times. I measured 10sec on the pin 12 LED and 21sec  
on the pin 13 LED. Both within my reaction time.

In the next few days I will attempt to write code to add an LCD to display the remaining time for each  
timer.

The final project "ON" time will be 6hrs and 240hrs respectively. That's why I need an LCD. I have a  
I²C LCD that I will use.

The final project will be put in a project case. I'm using the Arduino Pro Mini.

Thanks again,  
Ted

P.S., maybe someday I can return the info favor. I have some experience in Analog, discrete digital,  
RF, and power supplies.

I don't understand

---

<div class="post-metadata">

**Author:** ![kted66](https://avatars.discourse-cdn.com/v4/letter/k/9fc29f/32.png) [@kted66](https://forum.arduino.cc/u/kted66)\
**Post date:** [February 9, 2024, 6:15am UTC](https://forum.arduino.cc/t/combine-multiple-state-machines/1220978/20 "2024-02-09T06:15:50Z")

</div>

I believe your description is mostly correct. I don't need ( or want ) a RTC. Any inaccurate display times are moot. At 240 hrs ( 10 days ), a few minutes or hours either way won't do anything to my project.  
If the deviation is more than I want, I can adjust the time in milliseconds for the ON time.  
The timer will run continuously and I don't care what time of day or night the outputs go high or low.

I also don't need a serial monitor, the completed board and LCD will go into a project case along with the electronics.

Ted

[Next page](https://forum.arduino.cc/t/combine-multiple-state-machines/1220978.md?page=2)
