Provo a buttare sul piatto i miei 2 cents, nella speranza di essere utile

La dura realtà è che un software che gestisca tastiera (nel senso di alcuni pulsanti), LCD, RTC, eventi temporizzati (allarmi), cioè operazioni svolte in base ad un calendario, ed eventualmente comunicazioni seriali, richiede di essere progettato a stati / eventi (spiego meglio dopo), senza l'uso di delay() (come già sottolineato anche da altri). Questo richiede uno sforzo concettuale non piccolo per chi non ha una formazione nell'ambito della programmazione.
Trovo
http://www.cplusplus.com/doc/tutorial/ ben fatto come introduzione al linguaggio, ma non conosco risorse dello stesso livello che spieghino in modo accessibile ma completo come passare dalla temporizzazione di una sola operazione con delay() all'uso della ipercitata ma imprescindibile (perché scalabile) tecnica "blik without delay".
Un veloce accenno al discorso programmazione sequenziale / programmazione a stati / eventi...
Prendiamo il solito esempio del led lampeggiante.
Modo sequenziale:
loop()
accendi led
attendi 1 s
spegni led
attendi 1 s
Modo ad eventi:
RIT = 1000ms
loop()
if dall'ultima volta in cui ho pilotato il led sono passati RIT millisecondi
inverti stato led
pilota led
memorizza istante attuale
endif
Per capire la fondamentale differenza tra i due esempi, bisogna ricordare che delay() è
bloccante, cioè l'esecuzione del codice si ferma per il numero di millisecondi specificati, e null'altro viene eseguito durante l'attesa.
Questo è un grosso problema, perché impedisce al programma di eseguire due o più operazioni contemporaneamente.
Diventa un inferno già soltanto far lampeggiare due led in maniera indipendente.
Nel secondo esempio, invece, il test "se è trascorso un tempo D dall'istante T" richiede un tempo brevissimo, così come l'operazione di pilotaggio del led e di aggiornamento di T.
E' così possibile eseguire altre istruzioni contenute in loop().
Inoltre è possibile inserire altri costrutti analoghi, ciascuno con il suo istante T e il suo valore D, potenzialmente diverso, ottenendo così temporizzazioni contemporanee ed indipendenti.
Esempio:
// temporizzazione led A
unsigned long ledA_prevMillis;
unsigned long ledA_delay = 835;
byte ledA_pin;
// stato led A
boolean ledA_acceso = false;
// temporizzazione led B
unsigned long ledB_prevMillis;
unsigned long ledB_delay = 140;
byte ledB_pin;
// stato led B
boolean ledB_acceso = false;
// supponiamo che entrambi i led siano collegati
// in modo tale che pin alto = led acceso,
// pin basso = led spento
void pilotaLed(byte pin, boolean acceso) {
if (acceso) {
digitalWrite(pin, HIGH);
}
else {
digitalWrite(pin, LOW);
}
}
// gestione stato led A
void ledA_run() {
if (ledA_acceso) {
ledA_acceso = false;
}
else {
ledA_acceso = true;
}
pilotaLed(ledA_pin, ledA_acceso);
}
// gestione stato led B
void ledB_run() {
if (ledB_acceso) {
ledB_acceso = false;
}
else {
ledB_acceso = true;
}
pilotaLed(ledB_pin, ledB_acceso);
}
void setup() {
pinMode(ledA_pin, OUTPUT);
pinMode(ledB_pin, OUTPUT);
pilotaLed(ledA_pin, ledA_acceso);
pilotaLed(ledB_pin, ledB_acceso);
}
void loop() {
// temporizzazione led A
if (millis() - ledA_prevMillis > ledA_delay) {
ledA_prevMillis = millis();
ledA_run();
}
// temporizzazione led B
if (millis() - ledB_prevMillis > ledB_delay) {
ledB_prevMillis = millis();
ledB_run();
}
}
La buona notizia è che ci sono diverse librerie già pronte che implementano questo modello o utilizzano altre tecniche funzionalmente equivalenti per temporizzare delle funzioni in modo non bloccante. La stessa Time (tramite la libreria complementare TimeAlarms), SimpleTimer, looper, leOS / leOS2, ecc. Cercare nella sezione Playground / Timing.
Questo per rispondere al discorso "blink without delay = nebbia"

e per mostrare un abbozzo di "programmazione a stati" e "astrazione dall'hardware": notare infatti che lo sketch non opera direttamente con digitalWrite(), ma lavora su una variabile di stato slegata dall'hardware per ogni led da controllare. La funzione pilotaLed() serve da "cuscinetto separatore" tra lo stato logico (led acceso o spento) e come tale stato venga
mappato sull'hardware (il led potrebbe essere acceso con HIGH o con LOW a seconda dei circuiti a valle del pin dell'Arduino).
Eventuali estensioni dello sketch sono lasciate al lettore come esercizio
