The blinking led

In order to understand how to work with Finite-State machines and Generino, we shall start immediately with an example.

The code below is an example that shows a blining led:

01: int ledPin = 13;                 // LED connected to digital pin 13
02:
03: void setup()
04: {
05:   pinMode(ledPin, OUTPUT);      // sets the digital pin as output
06: }
07:
08: void loop()
09: {
10:   digitalWrite(ledPin, HIGH);   // sets the LED on
11:   delay(1000);                  // waits for a second
12:   digitalWrite(ledPin, LOW);    // sets the LED off
13:   delay(1000);                  // waits for a second
14: }

Indeed, it works and it looks easy to understand: turn on the led (line 10), wait for one second (line 11), turn off the led (line 12), wait again for another second (line 13). Then execution loops back to line 10 and the led blinks with a 2-seconds period.

Good. Now, before going on, try on your Arduino a simple exercise: using the method above, have two leds blinking with different periods. One with a 2s period and another one with a 1.7s period. It should not be that hard. Or not?

The button

Let's show another example, this time that connects a button to a led:

01: int ledPin = 13; // LED connected to digital pin 13
02: int inPin = 7;   // pushbutton connected to digital pin 7
03: int val = 0;     // variable to store the read value
04:
05: void setup()
06: {
07:   pinMode(ledPin, OUTPUT);    // sets the digital pin 13 as output
08:   pinMode(inPin, INPUT);      // sets the digital pin 7 as input
09: }
10:
11: void loop()
12: {
13:   val = digitalRead(inPin);   // read the input pin
14:   digitalWrite(ledPin, val);  // sets the LED to the button's value
15: }

In this case, there is a led that lits when we press a button. As soon as the button is released, the led goes off.

Now, again, try to modify this code to have the led blinking and when you press the button, the led goes off. If pressed again, the led must start blink again and so on.

Does your button work even if you press and release it quickly while the led is on or you have to keep it pressed for a while to have it working? And if you hold it down continuosly, what happens?

So, what's wrong?

As you probably already guessed, there are two logical problems:

Change your point of view

The solution that the industry took long ago is to use a different programming point of view.

In these examples, we are reasoning imperatively: turn the led on, now wait, now turn the led off, now wait again...

Instead, we should learn to reason in a event-driven way: when the led is off and one second is elapsed, turn it on; when the led is on and a secondo has elapsed, turn it off. With this technique, you can state as many rules that all work together.

Ok, but how to translate it to code?

Generino language

Let's start immediately to see how a blinking led is implemented in Generino.

001: FILE "example1\\example1.ino"
002:
003: DECLARE DIGITAL OUTPUT ledPin = 13
004:
005: CLASS BlinkingLed
006:   TIMER timer1
007:
008:   START
009:     SET TIMER timer1 TO 0
010:   END START
011:
012:   STATE ledOff
013:     ON EVENT timer1
014:       DIGITAL WRITE HIGH TO PIN ledPin
015:       SET TIMER timer1 TO 1000
016:       SET STATE ledOn
017:     END
018:   END STATE
019:
020:   STATE ledOn
021:     ON EVENT timer1
022:       DIGITAL WRITE LOW TO PIN ledPin
023:       SET TIMER timer1 TO 1000
024:       SET STATE ledOff
025:     END
026:   END STATE
027:
028: END CLASS
029:
030: OBJECT BlinkingLed led1

Download example1.zip 

Line 3 declares pin 13 as a digital output.

At line 5, we define a "class" BlinkingLed: it will a "container" that will take care of all the logic related to that blinking led.

At line 6 we declare that a blinking led needs a "timer" that we shall call timer1.

At line 8-10 we declare that when started, the timer timer1 must be set to expiry immediately (i.e. after 0 ms).

Once started, the blinking led object will go automatically to its first listed state, ledOff.

When in state ledOff (line 12), if we receive the timer1 event (line 13), we turn on the led (line 18), set the timer to expire after 1000ms from now (line 15) and move to the state ledOn.

When in state ledOn (line 20), if we receive the timer1 event (line 21), we turn off the led (line 22), set again the timer to expire after 1000ms from now (line 23) and move to the state ledOff.

Then, at line 30 we declare that we have an object named led1 that implements the logic defined by class BlinkingLed.

Download and try this example using the procedure described in the quickstart page: you will see that the led blinks with a 2-seconds period.

Two blinking leds

We shall see now the real power of FSM and Generino having two blinking leds. Let's take this code:

001: // EXAMPLE 2
002: FILE "example2\\example2.ino"
003:
004: DECLARE DIGITAL OUTPUT ledPin1 = 13
005: DECLARE DIGITAL OUTPUT ledPin2 = 12
006:
007: CLASS BlinkingLed
008:   REQUIRES DIGITAL OUTPUT pinNumber
009:   REQUIRES NUMBER blinkTimeMs
010:
011:   TIMER timer1
012:
013:   START
014:     SET TIMER timer1 TO 0
015:   END START
016:
017:   STATE ledOff
018:     ON EVENT timer1
019:       DIGITAL WRITE HIGH TO PIN pinNumber
020:       SET TIMER timer1 TO blinkTimeMs
021:       SET STATE ledOn
022:     END
023:   END STATE
024:
025:   STATE ledOn
026:     ON EVENT timer1
027:       DIGITAL WRITE LOW TO PIN pinNumber
028:       SET TIMER timer1 TO blinkTimeMs
029:       SET STATE ledOff
030:     END
031:   END STATE
032:
033: END CLASS
034:
035: OBJECT BlinkingLed led1 pinNumber=ledPin1 blinkTimeMs=1000
036: OBJECT BlinkingLed led2 pinNumber=ledPin2 blinkTimeMs=370

Download example2.zip 

In this example, we modified class BlinkingLed to make its output port and blink time parametric (see code marked in red).

Lines 4-5 contain the usual ports setup. At line 8 we define parameter pinNumber that will contain the pin number to use. At line 9 we do the same with blinkTimeMs.

Note that digitalWrites at lines 19 and 27 are now using pinNumber, which is the parameter declared at line 8, instead of the fixed global value ledPin being used in the previous example.

Note also that SET TIMER commands at lines 20 and 28 are now using the blinkTimeMs parameter instead of the fixed value 1000 used before.

At lines 35 and 36 we are creating two BlinkingLed objects named led1 and led2 with the added parameter values.

Adding buttons

In the following example, we extend the previous exercise to have two independent buttons that will activate/deactivate a led each.

This is the setup part:

001: // EXAMPLE3
002: FILE "example3\\example3.ino"
003:
004: DECLARE DIGITAL OUTPUT ledPin1 = 13
005: DECLARE DIGITAL OUTPUT ledPin2 = 12
006: DECLARE DIGITAL INPUT btnPin1 = 10
007: DECLARE DIGITAL INPUT btnPin2 = 11

This is the modified BlinkingLed class; the changes are evidenced in bold:

009: CLASS BlinkingLed
010:   REQUIRES DIGITAL OUTPUT pinNumber
011:   REQUIRES NUMBER blinkTimeMs
012:
013:   // Receives the "toggle" event that activates/deactivates the led
014:   PORT IN commandsInput RECEIVES toggle
015:
016:   TIMER timer1
017:
018:   START
019:     // Start from "inactive" mode
020:     SET STATE ledInactive
021:   END START
022:
023:   STATE ledInactive
024:     ON EVENT toggle
025:       DIGITAL WRITE HIGH TO PIN pinNumber
026:       SET TIMER timer1 TO blinkTimeMs
027:       SET STATE ledOn
028:     END
029:   END STATE
030:
031:   STATE ledOff
032:     ON EVENT timer1
033:       DIGITAL WRITE HIGH TO PIN pinNumber
034:       SET TIMER timer1 TO blinkTimeMs
035:       SET STATE ledOn
036:     END
037:
038:     ON EVENT toggle
039:       CLEAR TIMER timer1
040:       SET STATE ledInactive
041:     END
042:   END STATE
043:
044:   STATE ledOn
045:     ON EVENT timer1
046:       DIGITAL WRITE LOW TO PIN pinNumber
047:       SET TIMER timer1 TO blinkTimeMs
048:       SET STATE ledOff
049:     END
050:
051:     ON EVENT toggle
052:       DIGITAL WRITE LOW TO PIN pinNumber
053:       CLEAR TIMER timer1
054:       SET STATE ledInactive
055:     END
056:   END STATE
057: END CLASS

At line 14 we added the first new concept: an input port. An input port is a logical channel where the BlinkingLed will receive "events" from other objects. In this case, this port is enabled to receive an event named toggle.

At line 23 we added a new state: ledInactive. So our led can be ledInactive, i.e. permanently off, ledOff, i.e. off because in the unlit part of the blinking, and ledOn, i.e. lit.

At line 20 we specified that the led must start in the ledInactive state; since ledInactive is the first specified state, it would have been the default anyway, but in this way the behaviour is defined explicitely.

At line 24, we defined that, while in state ledInactive, the object must react to the toggle event by turining on the led (line 27), activating the timer (line 26) and going in the ledOn state.

From now on the behaviour is the same of the previous example, except that both states ledOn and ledOff react to the toggle event (lines 38 and 51).

When toggle is received, they clear the timer timer1: in this way the timer will not trigger anymore (lines 39 and 53). Then, they move to state ledInactive.

With this implementation, a blinking led can be turned on or off at any time by sending a toggle to it. When activated, the led will start its blinking cycle from the beginning.

This is the new ToggleButton class:

059: CLASS ToggleButton
060:   // Holds the pin number
061:   REQUIRES DIGITAL INPUT pinNumber
062: 
063:   PORT OUT commandsOutput SENDS toggle
064:   
065:   STATE buttonPressed
066:     WHEN digitalRead (pinNumber) == LOW
067:       SET STATE buttonReleased
068:     END WHEN
069:   END STATE
070: 
071:   STATE buttonReleased
072:     WHEN digitalRead (pinNumber) == HIGH
073:       SET STATE buttonPressed
074:       SEND toggle TO PORT commandsOutput
075:     END WHEN
076:   END STATE
077: END CLASS

The ToggleButton implements a button that emits an event toggle every time the button is pressed. The button has to be released and pressed again in order to send another toggle event.

At line 63, we declared the an output port named commandsOutput enabled to send the toggle event.

The button has two states: buttonPressed (line 65) and buttonReleased (line 71).

The action executed inside those states is a WHEN statement: a "when" is an action executed as often as possible meant to monitor the change in state of an input hardware device. At line 65 the machine is in state buttonPressed: this means that in order to change state, we must detect when the input pin goes low (line 66): when that happens, the state is changed to buttonReleased at line 67.

When in state buttonReleased, instead, we have to detect when the input pin goes high (line 72). In this case, besides of changing state again (line 73), we send the toggle event (line 74).

Note that, in order to emit a toggle event, the button must change from released to pressed, then go to released again.

And finally, where objects are declared and connected:

079: OBJECT BlinkingLed led1 pinNumber=ledPin1 blinkTimeMs=1000
080: OBJECT BlinkingLed led2 pinNumber=ledPin2 blinkTimeMs=370
081: OBJECT ToggleButton btn1 pinNumber=btnPin1
082: OBJECT ToggleButton btn2 pinNumber=btnPin2
083: 
084: CONNECT commandsOutput@btn1 TO commandsInput@led1
085: CONNECT commandsOutput@btn2 TO commandsInput@led2

Download example3.zip 

At lines 79-82 we do the usual objects declaration, and at lines 84/85 we connect them together. In this case, we connect the commandsOutput port of btn1 to the commandsInput input port of led1; at line 085, we do the same with btn2 and led2.