Call functions with creating stateMachine

Hi. i was wondering if i could call functions in a certain order, it could have been very usable. So i created 3 leds with arduino in tinkercad. Visual image is below. İf image is not visible ->Only three leds connected to the 2. , 3. and 4. pins.

The main idea is like that :

0-> we send '1' character from serial monitor and its start a sequence ->stateMachine = 0
1-> call blinkLed1 function ->stateMachine = 1
2-> when blinkLed1 function ended, call blinkLed3 function ->stateMachine = 2
3-> when blinkLed3 function ended, call blinkLed2 function ->stateMachine = 3
4-> when blinkLed2 function ended, call blinkLed3 function ->stateMachine = 4
5-> when blinkLed3 function ended, call blinkLed1 function ->stateMachine = 5
6-> when blinkLed1 function ended, call blinkLed3 function ->stateMachine = 6
7-> nothing happens until stateMachine is 0

if you create a circuit like in the picture and copy-paste code, it will work. What i wonder, is this coding way is efficient or not. if it is not efficient, than how must be the right coding method.

Sorry for my poor english. Thanks.

#define led1 2
#define led2 3
#define led3 4

bool led1On = false;
bool led2On = false;
bool led3On = false;
bool startLedSequence = false;
bool led1End = false;
bool led2End = false;
bool led3End = false;
int  stateMachine = 0;

void setup()
{
  Serial.begin(9600);
  
  pinMode(led1, OUTPUT);
  digitalWrite(led1, LOW);
  pinMode(led2, OUTPUT);
  digitalWrite(led2, LOW);
  pinMode(led3, OUTPUT);
  digitalWrite(led3, LOW);
}

void loop()
{
  blinkLed1();
  blinkLed2();
  blinkLed3();
  blinkLedSequence();
  serialDebug();
}

void blinkLed1()
{
  if(led1On == true)
  {
  	digitalWrite(led1, HIGH);
    delay(1000);
    digitalWrite(led1, LOW);
    led1On = false;
    led1End = true;
    led2End = false;
    led3End = false;
  }	
}

void blinkLed2()
{
  if(led2On == true)
  {
  	digitalWrite(led2, HIGH);
    delay(1000);
    digitalWrite(led2, LOW);
    led2On = false;
    led1End = false;
    led2End = true;
    led3End = false;
  }	
}

void blinkLed3()
{
    if(led3On == true)
  {
  	digitalWrite(led3, HIGH);
    delay(1000);
    digitalWrite(led3, LOW);
    led3On = false;
    led1End = false;
    led2End = false;
    led3End = true;
  }	
}

void blinkLedSequence()
{
  if(startLedSequence == true)
  {
	led1On = true;
    stateMachine = 1;
    startLedSequence = false;
  }
  
  if(led1End == true && stateMachine == 1)
  {
  	led3On = true;
    stateMachine = 2;
  }
  
  if(led3End == true && stateMachine == 2)
  {
  	led2On = true;
    stateMachine = 3;
  }
  
  if(led2End == true && stateMachine == 3)
  {
  	led3On = true;
    stateMachine = 4;
  }
  
  if(led3End == true && stateMachine == 4)
  {
  	led1On = true;
	stateMachine = 5;
  }
  
  if(led1End == true && stateMachine == 5)
  {
  	led3On = true;
	stateMachine = 6;
  }
}


void serialDebug()
{
  if(Serial.available() > 0)
  {
  	char serChar = Serial.read();
    if(serChar == '1')
    {
      startLedSequence = true;    	
    }
  }
}

You can do a lot of stuff in state machines. In the future, you might learn about how to use a pointer to functions and call whatever function you want from an array of such pointers. For this task, I wouldn’t use separate functions for each LED; arrays might be more efficient.

Your code uses lots of delay() calls which is pretty inefficient. It seems “circular” in some ways. Try to centralize more of your code in the state machine.

I haven’t tried this but it compiles. If it works for you, compare it to what you’re doing for an alternate perspective on state machine implementation:

/*
    0-> we send '1' character from serial monitor and its start a sequence   ->stateMachine = 0
    1-> call blinkLed1 function                                                                  ->stateMachine = 1
    2-> when blinkLed1 function ended, call blinkLed3 function                   ->stateMachine = 2
    3-> when blinkLed3 function ended, call blinkLed2 function                   ->stateMachine = 3
    4-> when blinkLed2 function ended, call blinkLed3 function                   ->stateMachine = 4
    5-> when blinkLed3 function ended, call blinkLed1 function                   ->stateMachine = 5
    6-> when blinkLed1 function ended, call blinkLed3 function                   ->stateMachine = 6
    7-> nothing happens until stateMachine is 0
 */

#define NUM_LEDS        3   //number of pins with LEDs
#define led1            2   //pin numbers
#define led2            3  
#define led3            4

#define LED_BLINK_TIME          1000ul      //number of milliseconds LED is to be on
#define SEQUENCE_END_MARKER     0x7f        //character that marks the end of the sequence of blinking LEDs

//array of pins (handy for initialization and indexing)
byte grLEDPins[NUM_LEDS] = 
{
    led1,
    led2,
    led3  
};

//array that describes the sequence of LED blinks
//each entry is a pin; sequence is ended with the SEQUENCE_END_MARKER
byte grLEDSequence[] = 
{
    led1, led3, led2, led3, led1, led3, SEQUENCE_END_MARKER    
};

void setup()
{
    Serial.begin(9600);

    //init the outputs
    for( byte i=0; i<NUM_LEDS; i++ )
    {
        pinMode( grLEDPins[i], OUTPUT );
        digitalWrite( grLEDPins[i], LOW );
        
    }//for
    
}//setup

//state names
#define ST0_WAIT_START      0
#define ST1_LED_SEQUENCER   1
#define ST2_END_SEQUENCE    2
//
void SequenceStateMachine( void )
{
    static unsigned long
        timeSeq;
    static byte
        stateIndex = 0,
        stateSeq = ST0_WAIT_START;

    switch( stateSeq )
    {
        case    ST0_WAIT_START:
            //wait for '1' on the serial port
            if( Serial.available() > 0 )
            {
                if( Serial.read() == '1' )
                {
                    //when we get it, kick off the sequence by turning on the first LED
                    digitalWrite( grLEDSequence[stateIndex], HIGH );
                    //get the time now so we can time the duration of the blink
                    timeSeq = millis();

                    //the next state will blink the LEDs in sequence
                    stateSeq = ST1_LED_SEQUENCER;                 
                    
                }//if
                
            }//if
            
        break;

        case    ST1_LED_SEQUENCER:
            //has this LED's time expired?
            if( (millis() - timeSeq) >= LED_BLINK_TIME )
            {
                //yes, turn it off
                //post-increment the index to point to the next element in the sequence array
                digitalWrite( grLEDPins[stateIndex++], LOW );    

                //is the next element the marker that tells us we're done?
                if( grLEDSequence[stateIndex] == SEQUENCE_END_MARKER )
                {
                    //yes, just go to the "end" state where we do nothing
                    stateSeq = ST2_END_SEQUENCE;
                    
                }//if
                else
                {
                    //not the end yet; turn on the next LED and get the time again
                    //next pass through the state machine we'll be timing this LED
                    digitalWrite( grLEDSequence[stateIndex], HIGH );
                    timeSeq = millis();
                    
                }//if
                
            }//if
            
        break;

        case    ST2_END_SEQUENCE:
            //reached the end of the sequence; do nothing as in original code...
            
        break;
        
    }//switch
    
}//SequenceStateMachine


void loop()
{
    //all we do in loop is call the state machine
    SequenceStateMachine();

}//loop

You can even give your states more interesting names..

enum states { this, that, andTheOther };

states wereDoing;

Then your switch statment looks more like..

switch(wereDoing) {
   case this  : firstFunction() : break;
   case that  : secondtFunction() : break;
   case andTheOther : theOtherFunction() : break;
}

Although "this" won't work because its a reserved word.

-jim lee

jimLee:
Although "this" won't work because its a reserved word.

Then may I respectfully suggest that you change your example. IMHO giving newbies examples that don't work can be very confusing because they may assume that some arcane knowledge (which they don't have) is essential to get it to work.

Perhaps "here" "there" and "elsewhere" would work.

Enum example

...R

Blackfin. i will search about pointer to functions. Code is compiling but not works. Becouse “SEQUENCE_END_MARKER” is always same. So first led1 is On than goes Off, second led3 is On but not going Off. At least led1 and led3 is always On. Using array is useful.

You have spend time. With all respect. Thanks Blackfin :slight_smile:

Blackfin:
You can do a lot of stuff in state machines. In the future, you might learn about how to use a pointer to functions and call whatever function you want from an array of such pointers. For this task, I wouldn’t use separate functions for each LED; arrays might be more efficient.

Your code uses lots of delay() calls which is pretty inefficient. It seems “circular” in some ways. Try to centralize more of your code in the state machine.

I haven’t tried this but it compiles. If it works for you, compare it to what you’re doing for an alternate perspective on state machine implementation:

/*

0-> we send ‘1’ character from serial monitor and its start a sequence  ->stateMachine = 0
    1-> call blinkLed1 function                                                                  ->stateMachine = 1
    2-> when blinkLed1 function ended, call blinkLed3 function                  ->stateMachine = 2
    3-> when blinkLed3 function ended, call blinkLed2 function                  ->stateMachine = 3
    4-> when blinkLed2 function ended, call blinkLed3 function                  ->stateMachine = 4
    5-> when blinkLed3 function ended, call blinkLed1 function                  ->stateMachine = 5
    6-> when blinkLed1 function ended, call blinkLed3 function                  ->stateMachine = 6
    7-> nothing happens until stateMachine is 0
*/

#define NUM_LEDS        3  //number of pins with LEDs
#define led1            2  //pin numbers
#define led2            3 
#define led3            4

#define LED_BLINK_TIME          1000ul      //number of milliseconds LED is to be on
#define SEQUENCE_END_MARKER    0x7f        //character that marks the end of the sequence of blinking LEDs

//array of pins (handy for initialization and indexing)
byte grLEDPins[NUM_LEDS] =
{
    led1,
    led2,
    led3 
};

//array that describes the sequence of LED blinks
//each entry is a pin; sequence is ended with the SEQUENCE_END_MARKER
byte grLEDSequence =
{
    led1, led3, led2, led3, led1, led3, SEQUENCE_END_MARKER   
};

void setup()
{
    Serial.begin(9600);

//init the outputs
    for( byte i=0; i<NUM_LEDS; i++ )
    {
        pinMode( grLEDPins[i], OUTPUT );
        digitalWrite( grLEDPins[i], LOW );
       
    }//for
   
}//setup

//state names
#define ST0_WAIT_START      0
#define ST1_LED_SEQUENCER  1
#define ST2_END_SEQUENCE    2
//
void SequenceStateMachine( void )
{
    static unsigned long
        timeSeq;
    static byte
        stateIndex = 0,
        stateSeq = ST0_WAIT_START;

switch( stateSeq )
    {
        case    ST0_WAIT_START:
            //wait for ‘1’ on the serial port
            if( Serial.available() > 0 )
            {
                if( Serial.read() == ‘1’ )
                {
                    //when we get it, kick off the sequence by turning on the first LED
                    digitalWrite( grLEDSequence[stateIndex], HIGH );
                    //get the time now so we can time the duration of the blink
                    timeSeq = millis();

//the next state will blink the LEDs in sequence
                    stateSeq = ST1_LED_SEQUENCER;               
                   
                }//if
               
            }//if
           
        break;

case    ST1_LED_SEQUENCER:
            //has this LED’s time expired?
            if( (millis() - timeSeq) >= LED_BLINK_TIME )
            {
                //yes, turn it off
                //post-increment the index to point to the next element in the sequence array
                digitalWrite( grLEDPins[stateIndex++], LOW );

//is the next element the marker that tells us we’re done?
                if( grLEDSequence[stateIndex] == SEQUENCE_END_MARKER )
                {
                    //yes, just go to the “end” state where we do nothing
                    stateSeq = ST2_END_SEQUENCE;
                   
                }//if
                else
                {
                    //not the end yet; turn on the next LED and get the time again
                    //next pass through the state machine we’ll be timing this LED
                    digitalWrite( grLEDSequence[stateIndex], HIGH );
                    timeSeq = millis();
                   
                }//if
               
            }//if
           
        break;

case    ST2_END_SEQUENCE:
            //reached the end of the sequence; do nothing as in original code…
           
        break;
       
    }//switch
   
}//SequenceStateMachine

void loop()
{
    //all we do in loop is call the state machine
    SequenceStateMachine();

}//loop

Robin2 motorState example is really useful thanks :slight_smile:

Robin2:
Then may I respectfully suggest that you change your example. IMHO giving newbies examples that don’t work can be very confusing because they may assume that some arcane knowledge (which they don’t have) is essential to get it to work.

Perhaps “here” “there” and “elsewhere” would work.

Enum example

…R

kackarli:
Blackfin. i will search about pointer to functions. Code is compiling but not works. Becouse "SEQUENCE_END_MARKER" is always same. So first led1 is On than goes Off, second led3 is On but not going Off. At least led1 and led3 is always On. Using array is useful.

You have spend time. With all respect. Thanks Blackfin :slight_smile:

Sorry. I think the problem with my code is here:

                //yes, turn it off
                //post-increment the index to point to the next element in the sequence array
                digitalWrite( grLEDPins[stateIndex++], LOW );

I'm accidentally referencing the pin array, not the sequence array when I turn the LED off. Change it to:

                //yes, turn it off
                //post-increment the index to point to the next element in the sequence array
                digitalWrite( grLEDSequence[stateIndex++], LOW );