A finite state machine is diagram used to organise tasks to control several insdustrial systems (production, heater, pump, conveyors...).
All these sytems include states (associated with an "action", ie: start, run, stop) some of them are "wanted" or said "stable" others are "unwanted" or unstable. The finite state machine method or diagram organizes only stable states. When a trigger or a transition is true (ie: sensor ON, button pushed), the previous state is turned off and the following state is turned on.
Other diagrams have almost the same running: Moore machine, Mealy machine, SFC diagram (GRAFCET in french).
In this instructable I will talk about to implement a state machine in an arduino uno using SM library. This library allows you to run "concurent states" or parallel tasks (real time machines): you can control many different machine or independant system with only a microcontroller. It 's very powerfull and doesn't need too many lines of code.
In my previous instructables I use a simple way to run a finite state machine on my arduino light dimmer (without any special library) but I think it's impossible to run concurent state and it's very difficult to use emergency stop (essential and usefull in indstrial systems for security).
The editor I used, draws diagrams with SYSML or UML 2 rules and makes finites states machines like a Moore/Mealy mix.
I implemented 3 "real" examples of state machine to explore most of the capabilities of the library SM.h.
PS: This method is suitable, common and well known for people working in automation, many computer developper don't like it. See this article:
Step 1: The First State Machine: 1 Master and 3 Concurent Slaves
The control interface:
I use an arduino uno with a small interface (2 buttons (ATU1, ATU2) for trigger switch on and 3 LEDS (11, 12, 13) for output action) and a LCDKeypad.
The microcontroller can control a Master machine which can launch 3 differents slave machines:
-the FB machine blink a led at 1Hz. If ATU1 is pushed, it disables the FB machine, if ATU1 is pulled, it restarts the FB machine
-the SB machine blink a led at a faster frequence with no synchronization or interaction with the FB machine. If LEFT is pressed (on the rising edge), it disables the SB machine, if SELECT is pressed (on the rising edge), it restarts the SB machine.
-the PUMP machine which is run stop of an output or a relay to start a pump. If UP is pressed (on the rising edge), the output is HIGH, if ATU2 is pressed (on the rising edge) the output is switched OFF.
This called an encapsulation : when you disable an encapsulation state, every encapsulated states are disable at the same time.
When you launch parallel states ,in automation, you do a Divergence of Simultaneous Sequences or machines.
Because of the LCDkeypad shield, a lot of pins are used: pins 4, 5, 6, 7, 8, 9, 10. The keypad push buttons are analog on pin A0.
So it remains a few amount of pins to control a system. This the reason why I have added an I2C I/O expansion circuit used in the next steps. You will ignore it at this step: just keep on your mind ATU1, ATU2, Keypad Buttons, and the pin 11, 12, 13 digital outputs.
A lot of comments are inside.
The messages displayed:
The first line displays which machine is launched.
The second line displays if actions are running (coin moving from state to state).
Step 2: The Second Machine: 1 Master (with Emergency Stop) and 3 Slave With a Synchronization State
You have to push the DOWN button to start the Master machine and another time (the same button) to stop it and so on.
When the 3 machines are launched and running, if at one moment, the 3 leds are on (a state called "synchro" is scanning this all the time), the Master machine is disable. Push the DOWN button to restart it.
The state synchro is called a Convergence of Simultaneous Sequences or machines.
It 's an emergency stop on the master, very used in industrial machine to protect the devices and the human bodies.
Step 3: The Third Machine: 1 Master (with Emergency Stop) and 3 Slaves Synchronized and I2C I/O Expansions
I use 2 kind of I2C IC:
- 2 x PCF8591P: to give 2 x 4 analog inputs and 2 x1 analog outputs
-2 x PCF8574P: to give 1 x 8 digital inputs and 1 x 8 digital outputs.
The I2C adresses are claculated with the table supplied.
According to the schematic, I found the following adresses:
- 73 dec for the first analog output (IC PCF8591P)
- 74 dec for the second analog output (IC PCF8591P)
- 59 dec for the digital inputs (IC PCF8574P)
- 60 dec for the digital outputs (IC PCF8574P)
Now the 3 independant machines are actioning 3 different byte registers FBx, SBx and PUMPx on which I put an XOR mask to give a unique register "x" which updates the IC outputs on the adress 60.
See the source code, there are many comments on it.
WARNING!! When you power up the PCF8574 all the digital outputs go HIGH quickly and then LOW: it can injured your system. Be carefull!! To fix this you do use a complement of the bytes to send and an inverting buffer behind the PCF8574. I will correct it asap.
Step 4: To Conclude...
It 's a very powerfull library and don't forget to reset the output when you disable a machine.
If you don't want to use I2C expansion you can adapt it on my famous (I think so!) arduino atmega644/1284 clone.
Thanx to several interesting running amazing and shared tutorial on the net.
Step 5: I2C Power Up Bug Fixed!!
I used an IC like CD4049 or 74HCT540 to complement byte of the 8 outputs of the PCF8574P because when power up this circuit all the outputs went HIGH. It 's dangerous and could destroy your system with unwanted initial tasks.
So now you have to send on the I2C bus a complement of the x value, written like this in C: x= ~ ((FBx ^ SBx) ^ PUMPx)).
I give you the new schematic and the last source version.