/* Semaforo con doppia FSM Due FSM indipendenti per la gestione di ognuno dei 2 semafori che costituiscono un incrocio. Le due FSM possono modificare i rispettivi stati. Un singolo semaforo costruito col paradigma delle macchine a stato. Viene utilizzato un oggetto della libreria common per gestire il LED. Uno stimolo esterno rappresentato dalla pressione di un bottone causa il passaggio di stato. Implementata con millis() invece che con delay(), sono stati aggiuntu due stati per meglio gestire lo stato yellow. - Schema per un led RGB: https://lab.piffa.net/schemi/rgb.jpg - Schema per un bottone: https://www.arduino.cc/en/uploads/Tutorial/inputPullupButton.png */ #include const byte input = 2; // PIN del bottone int pausa = 3000; long timer ; enum states_available { // Stati della FMS turn_green, // Transizione green, // Statico wait_button, // Evento - Stimolo turn_yellow, // transizione yellow, // Statico turn_red, // transizione red // Statico }; states_available FSM1 ; states_available FSM2 ; void setup() { pinMode(input, INPUT_PULLUP); Serial.begin(9600); timer = millis(); } RGBLed led1(11, 10, 9); //Istanziamo un oggetto led facente parte RGBLed led2(8,7,6); //Istanziamo un oggetto led facente parte // della classe RGBLed void loop() { switch (FSM1) { case turn_green : led1.Green(); FSM1 = green ; // Setta il prossimo state FSM2 = red ; // Setta il prossimo state break; case green: if (millis() - timer >= pausa * 2/3) { FSM1 = wait_button ; timer += pausa * 2/3; } break; case wait_button: if (digitalRead(input) == LOW) { delay(20); // Debouncing, si potrebbe fare con millis() o un interrupt FSM1 = turn_yellow ; timer = millis(); }; break; case turn_yellow : led1.Yellow(); FSM1 = yellow ; break; case yellow : if (millis() - timer >= pausa * 1/3) { FSM1 = turn_red ; timer += pausa * 1/3 ; } break; case turn_red : led1.Red(); FSM1 = red ; FSM2 = turn_green ; break; case red : break; default: // In caso di default si fa giallo lampeggiante led1.Yellow(); delay(pausa/3); led1.Off(); delay(pausa/3); break; } switch (FSM2) { case turn_green : led2.Green(); FSM2 = green ; // Setta il prossimo state break; case green: if (millis() - timer >= pausa * 2/3) { FSM2 = turn_yellow; timer += pausa * 2/3; } break; case turn_yellow : led2.Blue(); FSM2 = yellow ; break; case yellow : if (millis() - timer >= pausa / 3) { FSM2 = turn_red ; //timer += pausa * 2/3; } break; case turn_red : FSM2 = red ; FSM1 = turn_green; timer = millis(); break; case red : led2.Red(); // Aggiorniamo il LED in questo stato invece che nel precedente // per entrare nel primo ciclo di esecuzione con il LED rosso break; default: // In caso di default si fa giallo lampeggiante led2.Yellow(); delay(pausa/3); led2.Off(); delay(pausa/3); break; } Serial.print(millis()); Serial.print(" \t Stato attuale FSM1: "); Serial.print(FSM1); Serial.print(" - FSM2: "); Serial.println(FSM2); } /* Domande: 1. E' piu' semplice ora inserire degli altri oggetti nello sketch? 2. Gli eventi sono condivisi? Le varie FSM hanno modo di scambiarsi informazioni sui relativi stati? 3. Creare un dispatcher degli eventi al quale le varie FSM possono riferirsi. . . . . . . . . . . Soluzioni 1. Si, per quanto le 2 FSM non siano indipendenti l'una dall'altra. 2. No, c'e' un solo flusso degli eventi, il blocco di una delle FSM puo' causare lo stop di tutto il sistema. */