L’aereo di Cirso: in questo aereo il comportamento delle luci e’ e predeterminato (non dipende da nessun inupt) ma e’ stato abilitato un interruttore della radio per accendere e spegnere le luci.

L’interruttore a due stati e’ gestito da un interrupt.

In un primo esempio questo e’ un semplice ON/OFF impostato con un ciclo if, nel secondo invece viene implementata una FSM (macchina a stati) per gestire anche le transizioni tra i vari stati.

ON / OFF

/* Aereo di Cirso

Output:
   2 LED ai lati con lampeggio alternato
   1 LED in coda lampeggio a freq doppia

Input:
   1 interruttore su interrupt 0 per accensione / spegnimento luci

Note:
   Realizzato con un semplice ciclo IF per ON / OFF,
   lo sketch successsivo ha un macchina a stati per gestire
   la transizione ON <-> OFF con una dissolvenza.
*/

#include <common.h>

// Variabili per interrupt 0
volatile unsigned int chValue = 1500; // Valore computato
volatile unsigned int chStart = 1500; // Inizio rilevamento

// Instanziamo un LED fuori dal loop
Lampeggiatore left = 5;
Lampeggiatore right = 6;
Lampeggiatore coda = 9;

void setup() {
    // I PINs vengono impostati dal constructor al momento
    // della dichiarazione dell'ogetto.

    attachInterrupt(0, chRise, RISING); // PIN 2 su 328p / 168
    right.Invert() ;  // Opzionale: inverte l'ordine del lampeggio da
    // HI -> LOW --> LOW -> HI
    // per avere 2 LED che lampeggiano alternativamente
}

void loop() {

    if (chValue > 1500) {
        left.Blink();   // Lampeggia con un default di 1sec (0.5 HI 0.5 LOW)
        right.Blink();
        coda.Blink(1000); // Lampeggio in 1000ms = 1 secondo
    } else {
// sarebbe carino mettere una transizione da on -> off con un fade down...
        left.Low();
        right.Low();
        coda.Low();
    } ;
}

// Functions
void chRise() {
    attachInterrupt(0, chFall, FALLING);
    chStart = micros();
};

void chFall() {
    attachInterrupt(0, chRise, RISING);
    chValue = micros() - chStart;
};

FSM

C’e’ una transizione tra gli stati On <-> Off: una dissolvenza in PWM a salire e a scendere quando si accende e si spegne le luci.

/* Cirso TransStates Focke-Wulf Fw 190

Output:
   2 LED ai lati con lampeggio alternato
   1 LED in coda lampeggio a freq doppia

Input:
   1 interruttore su interrupt 0 per accensione / spegnimento luci

FSM per la gesrione delle transizioni tra i 2 stati.

*/

#include <common.h>

// FSM gestione interruttore luci
enum  { // Stati della FMS
    On,     // Acceso
    toOff,  // Trans On -> Off
    Off,    // Spento
    toOn    // Trans OFF -> On
} toggle  = Off;

// Variabili per interrupt 0
volatile unsigned int chValue = 1500; // Valore computato
volatile unsigned int chStart = 1500; // Inizio rilevamento
const int soglia = 1500; // soglia per scatto toggle a 2 posizioni

// Var FSM
unsigned long FSM_lastMillis = 0 ; // Timestamp per la FSM degli alettoni
unsigned long pausa = 2000;  // Pausa per la transizione durante gli stati 2, 4 della FSM
unsigned long currentMillis = 0;

// Instanziamo gli oggetti per gli stati On / Off
Lampeggiatore left = 5;
Lampeggiatore right = 6;
Lampeggiatore coda = 9;

// Instanziamo gli oggetti per gli stati di transizione
Pwm leftPWM = 5;
Pwm rightPWM = 6;
Pwm codaPWM = 9;

void setup() {
attachInterrupt(0, chRise, RISING); // PIN 2 su 328p / 168
    right.Invert() ;  // Invertiamo uno dei due lampeggiatori
}

void loop() {
    currentMillis = millis();

switch (toggle) {
    case Off:
    // Spento
        left.Low();
        right.Low();
        coda.Low();

        if (chValue > soglia) {
            FSM_lastMillis = currentMillis;
            toggle = toOn ; 
        leftPWM.Set(0);   
        rightPWM.Set(0);
        codaPWM.Set(0);
        }
        break;

    case On:
    // Acceso
        left.Blink();   // Lampeggia con un default di 1sec (0.5 HI 0.5 LOW)
        right.Blink();
        coda.Blink(1000); // Lampeggio in 1000ms = 1 secondo

        if (chValue <= soglia) {
            FSM_lastMillis = currentMillis;
            toggle = toOff ; 
        leftPWM.Set(255);   
        rightPWM.Set(255);
        codaPWM.Set(255);
        }
        break;

    case toOn:
    // Trans off -> on
        leftPWM.lUp(pausa);   
        rightPWM.lUp(pausa);
        codaPWM.lUp(pausa);

        if (chValue > soglia && currentMillis - pausa > FSM_lastMillis ) { 
            toggle = On ; 
        } else if  (chValue <= soglia) {
            toggle = Off ; 
        }
        break;

    case toOff:
    // Trans on -> off
        leftPWM.lDown(pausa);   
        rightPWM.lDown(pausa);
        codaPWM.lDown(pausa);

        if (chValue <= soglia && currentMillis - pausa > FSM_lastMillis ) { 
            toggle = Off ; 
        } else if  (chValue > soglia) {
            toggle = On ; 
        }
        break;
} ;
}

// Functions
void chRise() {
    attachInterrupt(0, chFall, FALLING);
    chStart = micros();
};

void chFall() {
    attachInterrupt(0, chRise, RISING);
    chValue = micros() - chStart;
};