State Machines and Timing – Tyler Tilton

In order to create more complex Arduino programs, without using the delay function, you can use state machines. Using state machines can make your code more efficient (unlike the delay function which puts the Arduino CPU to sleep) and can help you create more organized code.

This week in lab, I worked on two state machines.

The first was based on this diagram.

I was able to recreate this functionality:

I started by defining all of the states and then I began to code for the button A functionality. I felt like that was the easiest thing to start with. Then I started with the button B functionality. This is where I ran into trouble. For some reason I could not get my head around the timing concept. I have a better understanding of it now, but it’s still a bit fuzzy. Basically you’ve go to have a timer start function and compare that to the currentTime depending on what functionality you want, and you have to restart the timer in certain states. That has been my biggest challenge with state machines.

The second state machine looked like this:

Again my biggest problem here was working out the timing, but I also had problems where I accidentally nested some if statements instead of using else if statements. This caused my program to go into one state for like half a second then get stuck in the first state. I used else if statements and it all worked.

Here is the code I used:

State Machine 1

#include <Bounce2.h>

const int led = 8;

const int btnA = 2;
const int btnB = 3;
Bounce debouncerA = Bounce();
Bounce debouncerB = Bounce();

//timer stuff
long startTime = 0;
long endTime = 500;


// define an enumerated type for the states
enum State {
 OG_OFF,
 A_ON,
 B_ON,
 B_OFF
};


// declare variable(s) for remembering state
State currentState;
long timerStart;

void setup() {
 pinMode(led, OUTPUT);

 pinMode(btnA, INPUT);
 pinMode(btnB, INPUT);
 debouncerA.attach(btnA);
 debouncerB.attach(btnB);

 // initialize state variable(s)
 currentState = OG_OFF;
 timerStart = millis();
}

void loop() {
 if(currentState == OG_OFF){
 digitalWrite(led, LOW); 
 } else if (currentState == A_ON){
 digitalWrite(led, HIGH);
 } else if (currentState == B_ON) {
 digitalWrite(led, HIGH);
 } else if (currentState == B_OFF) {
 digitalWrite(led, LOW);
 }

 // update/read inputs
 debouncerA.update();
 debouncerB.update();
 int pressedA = debouncerA.rose();
 int pressedB = debouncerB.rose();
 long currentTime = millis();

 if(currentState == OG_OFF){
 if (pressedA) { currentState = A_ON; startTime = millis(); }
 if (pressedB) { currentState = B_ON; timerStart = currentTime; }
 } else if(currentState == A_ON) {
 if(pressedA) { currentState = OG_OFF; endTime = millis(); }
 } else if(currentState == B_ON) {
 if ( currentTime - timerStart > (endTime - startTime) ) {currentState = B_OFF; timerStart = currentTime; }
 if (pressedB) {currentState = OG_OFF;} 
 } else if (currentState == B_OFF) {
 if ( currentTime - timerStart > (endTime - startTime) ) {currentState = B_ON; timerStart = currentTime; }
 if (pressedB) {currentState = OG_OFF;}
 }
 
}

And State Machine 2:

#include <Bounce2.h>
//LEDs
const int ledStart = 8;
const int ledEnd = 12;

//Buttons
const int btnA = 2;
const int btnB = 3;
Bounce debouncerA = Bounce();
Bounce debouncerB = Bounce();

// State Names
enum State {
 THREE_OFF,
 THREE_ON,
 OUT_ON,
 IN_ON,
 BOTH_ON,
 BOTH_OFF
};

// declare variable(s) for remembering state
State twoState;
State threeState;

//Timer Stuff
long timerStart2;
long timerStart3;

//Pause stuff
int pause2 = 500;
int pause3;

void setup() {
 for (int pin = ledStart; pin <= ledEnd; pin++) {
 pinMode(pin, OUTPUT);
 }

 pinMode(btnA, INPUT);
 pinMode(btnB, INPUT);
 debouncerA.attach(btnA);
 debouncerB.attach(btnB);

 // initialize state variable(s)
 twoState = OUT_ON;
 threeState = THREE_ON;

 pause2 = 500;
 pause3 = 500;

 timerStart2 = millis();
 timerStart3 = millis();

}

void loop() {
 // State Descriptions

 //Three LED States
 if (threeState == THREE_ON) {
 for (int pin = ledStart + 2; pin <= ledEnd; pin++) {
 digitalWrite(pin, HIGH);
 }
 }
 if (threeState == THREE_OFF) {
 for (int pin = ledStart + 2; pin <= ledEnd; pin++) {
 digitalWrite(pin, LOW);
 }
 }

 //Two LED States

 //Outer LED On
 if (twoState == OUT_ON) {
 digitalWrite(8, HIGH);
 digitalWrite(9, LOW);
 }
 //Inner LED On
 if (twoState == IN_ON) {
 digitalWrite(9, HIGH);
 digitalWrite(8, LOW);
 }
 //BOTH LEDs On
 if (twoState == BOTH_ON) {
 digitalWrite(8, HIGH);
 digitalWrite(9, HIGH);
 }
 //BOTH LEDs OFF
 if (twoState == BOTH_OFF) {
 digitalWrite(8, LOW);
 digitalWrite(9, LOW);
 }

 // update/read inputs
 debouncerA.update();
 debouncerB.update();
 int pressedA = debouncerA.rose();
 int pressedB = debouncerB.read();
 long currentTime3 = millis();
 long currentTime2 = millis();


 //State Logic

 //Three LED Pause
 if (pressedB) {
 pause3 = 200;
 }
 else {
 pause3 = 500;
 }

 //Three LED Logic
 if (threeState == THREE_ON) {
 if ( currentTime3 - timerStart3 > pause3 ) {
 threeState = THREE_OFF;
 timerStart3 = currentTime3;
 }
 } else if (threeState == THREE_OFF) {
 if ( currentTime3 - timerStart3 > pause3 ) {
 threeState = THREE_ON;
 timerStart3 = currentTime3;
 }
 }

 //Two LED Logic

 //Outer and Inner
 if ( twoState == OUT_ON) {
 if(pressedA) {twoState = BOTH_ON; timerStart2 = currentTime2; }
 else if (currentTime2 - timerStart2 > pause2) {
 twoState = IN_ON;
 timerStart2 = currentTime2;
 }
 
 }
 else if (twoState == IN_ON) {
 if(pressedA) {twoState = BOTH_ON; timerStart2 = currentTime2; }
 else if (currentTime2 - timerStart2 > pause2) {
 twoState = OUT_ON;
 timerStart2 = currentTime2;
 }
 
 }

 else if(twoState == BOTH_ON) {
 if(pressedA) {twoState = IN_ON; timerStart2 = currentTime2; }
 else if (currentTime2 - timerStart2 > pause2) {
 twoState = BOTH_OFF;
 timerStart2 = currentTime2;
 }
 
 }

 else if(twoState == BOTH_OFF) {
 if(pressedA) {twoState = OUT_ON; timerStart2 = currentTime2; }
 else if (currentTime2 - timerStart2 > pause2) {
 twoState = BOTH_ON;
 timerStart2 = currentTime2;
 }
 
 }
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s