copiare la cartella ``libraries/common`` dentro ``libraries`` dello sketchbook
attuale.
-Aggiornamenti
+Download
===============
Download tramite git:
* `Browse on line <https://aerei.piffa.net/repo/>`_
* `Interfaccia git Web <https://git.andreamanni.com/web?p=aerei>`_
* `Foum di Discussione <https://forum.piffa.net/viewforum.php?f=4&sid=aef380599d890d6e7b9f92743fab9d7e>`_
-
+
+Libreria
+------------
+
+La sola libreria Common contenete gli oggetti base puo' essere scaricata direttamente nella vostra cartella libraries da:
+ git clone git://git.andreamanni.com/common
+
+* `Download manuale archivio <https://git.andreamanni.com/web?p=common;a=snapshot;h=HEAD;sf=tgz>`_
+* `Browse on line <https://aerei.piffa.net/repo/libraries/common/>`_
+* `Interfaccia git Web <https://git.andreamanni.com/web?p=common>`_
Links
+* Pubblicare la libreria common su arduino, via github
+
* aggiungere uno snippet per sniffing canale RX con interrupt
* mettere questo e quello in pulsein in una funzione / oggetto
* Ailerons RGB: creare un metodo per lo stato intermedio
# Creare un PWM con correzione di luminosita' su look table da 32 / 256 valori,
eventualmente uno con coseno.
+
+* Flasher con sequenza arbitraria di lampeggio
+* oggetti che lavorino contemporaneamente su piu' PIN
+* Link a Schemi / Schemi
+** battery voltage reader -> RGB
+** digital compass e RGB
+** barometer
+** 6 axis
+** Neopixel
+++ /dev/null
-/* Aereo di Cirso
-
- Esempio base:
- 2 LED ai lati con lampeggio alternato
- 1 LED in coda lampeggio a freq doppia
-*/
-
-#include <common.h>
-
-// 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.
-
- right.Invert() ; // Opzionale: inverte l'ordine del lampeggio da
- // HI -> LOW --> LOW -> HI
- // per avere 2 LED che lampeggiano alternativamente
-}
-
-void loop() {
- left.Blink(); // Lampeggia con un default di 1sec (0.5 HI 0.5 LOW)
- right.Blink();
- coda.Blink(1000); // Lampeggio in 1000ms = 1 secondo
-}
--- /dev/null
+/* Aereo di Cirso
+
+ Esempio base:
+ 2 LED ai lati con lampeggio alternato
+ 1 LED in coda lampeggio a freq doppia
+*/
+
+#include <common.h>
+
+// 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.
+
+ right.Invert() ; // Opzionale: inverte l'ordine del lampeggio da
+ // HI -> LOW --> LOW -> HI
+ // per avere 2 LED che lampeggiano alternativamente
+}
+
+void loop() {
+ left.Blink(); // Lampeggia con un default di 1sec (0.5 HI 0.5 LOW)
+ right.Blink();
+ coda.Blink(1000); // Lampeggio in 1000ms = 1 secondo
+}
--- /dev/null
+/* 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
+*/
+
+#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.
+
+ right.Invert() ; // Opzionale: inverte l'ordine del lampeggio da
+ // HI -> LOW --> LOW -> HI
+ // per avere 2 LED che lampeggiano alternativamente
+}
+
+void loop() {
+
+ if (chValue > 1400) {
+ 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;
+};
--- /dev/null
+/* Cirso TransStates
+
+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 = 1400; // 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
+
+// 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 righatPWM = 6;
+Pwm codaPWM = 9;
+
+void setup() {
+ // I PINs vengono impostati dal constructor al momento
+ // della dichiarazione dell'ogetto.
+
+ right.Invert() ; // Opzionale: inverte l'ordine del lampeggio da
+ // HI -> LOW --> LOW -> HI
+ // per avere 2 LED che lampeggiano alternativamente
+}
+
+void loop() {
+
+switch (toggle) {
+ case Off:
+ // Spento
+ left.Low();
+ right.Low();
+ coda.Low();
+
+ if (chValue > soglia) {
+ FSM_lastMillis = millis();
+ toggle = toOn ;
+ }
+ 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 = millis();
+ toggle = toOff ;
+ }
+ 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;
+};
unsigned long currentMillis; // timestamp reference per millis per tutto il loop
// Un LED RGB
-RGBLed ailerons(11,10,9,255);
+RGBLed ailerons(11,10,9,255); // Common Cat
+
+// Transizione: Pwm
+Pwm sxLamp(10); // Lampeggiatore
+Pwm dxLamp(9); // Lampeggiatore
+
// Variabili per lettura canale servo
const byte ailPin = A4;
dx // dx
} ailstate = middle;
+// Vars FSM
unsigned long FSM_lastMillis = 0 ; // Timestamp per la FSM degli alettoni
unsigned long pausa = 1000; // Pausa per la transizione durante gli stati 2, 4 della FSM
+
+// Vars Alettoni
int mid_point = 1560 ; // centro del segnale, trimmato nel setup
const int deviation = 50 ; // deviazione dal punto medio
//per entrare nello stato successivo dal centro
///////////////////////////////////////////////////////////
void setup() {
-// Serial.begin(9600);
// #define DEBUG
+#ifdef DEBUG
+ Serial.begin(9600);
+#endif
+
// Funzione relativa a calibrazione:
mid_point = calibraTrim(ailPin) ; // + LED di servizio per monitor calibrazione
}
// Lettura ailerons channel ogni 200ms
if (currentMillis - ailTimer>= 200) {
- ailTimer = currentMillis ;
ailIn = pulseIn(ailPin, HIGH, 25000);
- if (ailIn != 0 && ailIn > 960 && ailIn <2000) {
+ if (ailIn > 960 && ailIn <2000) {
// get only resonable values
ail = ailIn;
+ ailTimer = currentMillis ;
} ;
-// Lettura Aileron channel: FAKE con un potenziometro 10K
-// ailIn = analogRead(3);
-// ail = 1000 + ailIn
}
switch (ailstate) {
case middle:
+ ailerons.White();
// Alettoni piatti
if (ail > mid_point + deviation + deviation /3) {
// extra margine per avere un po' di gioco
ailstate = dxin;
FSM_lastMillis = currentMillis ;
} ;
- ailerons.Red();
break;
case sxin:
// Transizione a sx
- ailerons.Off();
+ sxLamp.(200);
if (currentMillis - pausa > FSM_lastMillis ) {
ailstate = sx;
}
case dxin:
// Transizione a dx
- ailerons.Off();
+ dxLamp.(200);
if (currentMillis - pausa > FSM_lastMillis ) {
ailstate = dx;
}
// Variabili
const byte thrPin = 3; // PIN collegato al CH3
-byte thr ; // Throttle
-int thrIn ;
+byte thr ; // Valore a 8bit per il throttle
+int thrIn ; // Valore rilevato del 3 Ch della RX
+const int thMin = 983; // In genere il valore minimo del TH resta costante,
+// per calcolarlo si puo' usare la funzione di calibrazione nel setup
+
void setup() {
// I PINs vengono impostati dal constructor al momento
void loop() {
// Lettura CH3
thrIn = pulseIn(thrPin, HIGH, 25000);
- if (thrIn != 0 && ailIn > 983 && ailIn < 2000) { // clean up
- thr = map(thrIn, 983, 2000, 0, 255); // mappato su 8bit per PWM
- }
+ if (thrIn >= thMin && thrIn < 2000) { // clean up
+ thr = map(thrIn, thMin, 2000, 0, 255); // mappato su 8bit per PWM
+ };
// Attivazione LEDs
left.Blink(100 + thr);
right.Blink(100 + thr);
sotto.lSet(thr); // Luminosita' proporzionale al throttle
- delay(10); // Opzionale
}
// Variabili
const byte thrPin = 3; // PIN collegato al CH3
-byte thr ; // Throttle
-int thrIn ;
+byte thr ; // Valore a 8bit per il throttle
+int thrIn ; // Valore rilevato del 3 Ch della RX
+const int thMin = 983; // In genere il valore minimo del TH resta costante,
+// per calcolarlo si puo' usare la funzione di calibrazione nel setup
+
byte caso;
void setup() {
- // I PINs vengono impostati dal constructor al momento
- // della dichiarazione dell'ogetto.
+ // I PINs vengono impostati dal constructor al momento
+ // della dichiarazione dell'ogetto.
- right.Invert() ; // Opzionale: inverte l'ordine del lampeggio da
- // HI -> LOW --> LOW -> HI
- // per avere 2 LED che lampeggiano alternativamente
+ right.Invert() ; // Opzionale: inverte l'ordine del lampeggio da
+ // HI -> LOW --> LOW -> HI
+ // per avere 2 LED che lampeggiano alternativamente
- randomSeed(analogRead(0));
+ randomSeed(analogRead(0));
}
void loop() {
- // Lettura CH3
- thrIn = pulseIn(thrPin, HIGH, 25000);
- thr = constrain(map(thrIn, 983, 2000, 0, 255), 0, 255) ;
+ // Lettura CH3 con pulsein, per usare interrupts vedi ../snippets.
+ thrIn = pulseIn(thrPin, HIGH, 25000);
+ if (thrIn >= thMin && thrIn < 2000) { // clean up
+ thr = thrIn ;
+ };
// Gestione throttle
- if (thr > 0 && thr < 15) {
- // IDLE
-
- rpwm.UD(2000);
- lpwm.UD(2000);
- sotto.lDown(1500);
- } else if (thr < 245) {
- // Throttle medio
-
- right.Blink(1120 - 4 * thr );
- left.Blink(1120 - 4 * thr );
- sotto.lSet(thr); // Luminosita' proporzionale al throttle
- } else {
- // Throttle al massimo: LED laterali lampeggiano a caso,
- // Sotto luminosita' a caso
+ if (thr < 1050) {
+ // IDLE
- caso = random(20, 240) ;
- right.Swap();
- left.Swap();
- sotto.lSet(caso);
- delay(caso);
- }
+ rpwm.UD(2000);
+ lpwm.UD(2000);
+ sotto.lDown(1500);
+ }
+ else if (thr < 1900) {
+ // Throttle medio
+ right.Blink(1120 - 4 * thr );
+ left.Blink(1120 - 4 * thr );
+ sotto.lSet(map(thrIn, thMin, 2000, 0, 255)); // Luminosita' proporzionale al throttle
+ }
+ else {
+ // Throttle al massimo: LED laterali lampeggiano a caso,
+ // Sotto luminosita' a caso
+ caso = random(20, 240) ;
+ right.Swap();
+ left.Swap();
+ sotto.lSet(caso);
+ }
}
+++ /dev/null
-
-/* Lettura di un canale servo della RX
-
- Lettura tramite la funzione pulsein
- Utilizzabile su qualunque PIN
-
- Il codice e' blocking fin tanto che il segnale passa da RISE a FALL
- quindi blocca per 1-2ms a ogni esecuzione. Con la variabile freq
- si imposta ogni quanto fare una lettura.
-
-
-*/
-
-#include <common.h>
-
-unsigned long currentMillis; // timestamp reference per millis per tutto il loop
-
-// Variabili
-const byte chPin = A4; // PIN su cui e' collegato il canale
-long unsigned chStamp = 0; // Timestamp per
-unsigned int chIn = 1500; // Valore catturato
-unsigned int chValue = 1500; // Valore computato
-unsigned int freq = 200 ; // Ogni quanti millisecondi leggere il valore
-// Attenzione che pulsein e' blocking
-
-void setup() {
- // Funzione relativa a calibrazione:
-// mid_point = calibraTrim(chPin) +10 ; // Con pulse in c'e' una traslazione ~10
-//Serial.begin(9600); // Warning: interrupts e serial potrebbero dare problemi
-} ;
-
-void loop() {
- currentMillis = millis(); // Timestamp per tutto il loop
-
-// Lettura ailerons channel ogni 200ms
- if (currentMillis - chStamp >= freq) {
- chStamp = currentMillis ;
-
- chIn = pulseIn(chPin, HIGH, 25000);
- if (chIn != 0 && chIn > 1000 && chIn <2000) {
- // get only resonable values
- chValue = chIn;
- } ;
- };
-
-// do something with chValue
-// Serial.print(chValue);
-// Serial.print(" - base: ");
-// Serial.println(mid_point);
-// delay(200);
-
-}
--- /dev/null
+
+/* Lettura di un canale servo della RX
+
+ Lettura tramite la funzione pulsein
+ Utilizzabile su qualunque PIN
+
+ Il codice e' blocking fin tanto che il segnale passa da RISE a FALL
+ quindi blocca per 1-2ms a ogni esecuzione. Con la variabile freq
+ si imposta ogni quanto fare una lettura.
+
+
+*/
+
+#define DEBUG
+#include <common.h>
+
+unsigned long currentMillis; // timestamp reference per millis per tutto il loop
+
+// Variabili
+const byte chPin = A4; // PIN su cui e' collegato il canale
+long unsigned chStamp = 0; // Timestamp per
+unsigned int chIn = 1500; // Valore catturato
+unsigned int chValue = 1500; // Valore computato
+unsigned int freq = 200 ; // Ogni quanti millisecondi leggere il valore
+// Attenzione che pulsein e' blocking
+
+void setup() {
+ // Funzione relativa a calibrazione:
+// mid_point = calibraTrim(chPin) +10 ; // Con pulse in c'e' una traslazione ~10
+#ifdef DEBUG
+Serial.begin(9600); // Warning: interrupts e serial potrebbero dare problemi
+} ;
+#endif
+
+void loop() {
+ currentMillis = millis(); // Timestamp per tutto il loop
+
+// Lettura ailerons channel ogni 200ms
+ if (currentMillis - chStamp >= freq) {
+
+ chIn = pulseIn(chPin, HIGH, 25000);
+ if (chIn != 0 && chIn > 1000 && chIn <2000) {
+ // get only resonable values
+ chValue = chIn;
+ chStamp = currentMillis ;
+ } ;
+ };
+
+// do something with chValue
+#ifdef DEBUG
+ Serial.print(chValue);
+ Serial.print(" - base: ");
+ Serial.println(mid_point);
+ delay(200);
+#endif
+
+}
*/
#include <common.h>
-
+#define DEBUG
// Variabili per interrupt 0
volatile unsigned int chValue = 1500; // Valore computato
// Funzione relativa a calibrazione con pulsein:
mid_point = calibraTrim(chPin) ; // Calibrazione del TRIM attivo sul canale
attachInterrupt(0, chRise, RISING); // PIN 2 su 328p / 168
+#ifdef DEBUG
Serial.begin(9600); // Warning: interrupts e serial potrebbero dare problemi
} ;
+#endif
+} ;
void loop() {
+#ifdef DEBUG
Serial.print(chValue);
Serial.print(" - base: ");
Serial.println(mid_point);
delay(200);
+#endif
}
// Functions
*/
#include <common.h>
+#define DEBUG
// Variabili per interrupt 0 si PIN 2
mid_point3 = calibraTrim(chPin3) ; // Calibrazione del TRIM attivo sul canale
attachInterrupt(0, chRise2, RISING); // PIN 2 su 328p / 168
attachInterrupt(1, chRise3, RISING); // PIN 3 su 328p / 168
-Serial.begin(9600); // Warning: interrupts e serial potrebbero dare problemi
+#ifdef DEBUG
+Serial.begin(9600);
} ;
+#endif
void loop() {
-
+// Il loop fa solo debug
+#ifdef DEBUG
Serial.print("PIN2: ");
Serial.print(chValue2);
Serial.print(" -base: ");
Serial.print(" -base: ");
Serial.println(mid_point3);
delay(200);
+#endif
}
// Functions
// Due LED con lampeggio alternato:
Lampeggiatore right = 3;
Lampeggiatore left = 5;
-Pwm motor = 7;
+Pwm motore = 7;
const byte thrPin = A3;
byte thr ; // Valore a 8bit per il throttle
int thrIn ; // Valore rilevato del 3 Ch della RX
-
+const int thMin = 983; // In genere il valore minimo del TH resta costante,
void setup() {
//thr = constrain(thrIn / 4 , 0, 255) ;
// Lettura Throttle channel
- thrIn = pulseIn(thrPin, HIGH, 25000);
- thr = constrain(map(thrIn, 983, 2000, 0, 255), 0, 255) ; // 983 potrebbe cambiare
- // con un altra ricevente, fare una calibrazione nel caso.
+ thrIn = pulseIn(thrPin, HIGH, 25000);
+ if (thrIn >= thMin && thrIn < 2000) { // clean up
+ thr = map(thrIn, thMin, 2000, 0, 255); // mappato su 8bit per PWM
+ } ;
// FMS dispatcher
if ( thr < 10 ) {
// lampeggi e PWM a caso
right.Swap();
left.Swap();
- motore.lSet(random(0,255);
+ motore.lSet(random(0,255));
delay(random(20, 100));
break;
}
--- /dev/null
+/* Toggle con transizioni tra On | OFF
+
+Output esempio:
+ 1 Lampeggiatore in coda.
+
+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 = 1400; // 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
+
+// Instanziamo gli oggetti per gli stati On / Off
+Lampeggiatore coda = 9;
+
+// Instanziamo gli oggetti per gli stati di transizione
+Pwm codaPWM = 9;
+
+void setup() {
+ // I PINs vengono impostati dal constructor al momento
+ // della dichiarazione dell'ogetto.
+
+ right.Invert() ; // Opzionale: inverte l'ordine del lampeggio da
+ // HI -> LOW --> LOW -> HI
+ // per avere 2 LED che lampeggiano alternativamente
+}
+
+void loop() {
+
+switch (toggle) {
+ case Off:
+ // Spento
+ coda.Low();
+
+ if (chValue > soglia) {
+ FSM_lastMillis = millis();
+ toggle = toOn ;
+ }
+ break;
+
+ case On:
+ // Acceso
+ coda.Blink(1000); // Lampeggio in 1000ms = 1 secondo
+
+ if (chValue <= soglia) {
+ FSM_lastMillis = millis();
+ toggle = toOff ;
+ }
+ break;
+
+ case ToOn:
+ // Trans off -> on
+ codaPWM.lUp(pausa);
+
+ if (chValue > soglia && currentMillis - pausa > FSM_lastMillis ) {
+ toggle = On ;
+ } else if (chValue <= soglia) {
+ toggle = Off ;
+ }
+ break;
+
+ case ToOff:
+ // Trans on -> off
+ 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;
+};
-* aggiungere un displace temporale ai blink / pwm
* Flasher con sequenza arbitraria di lampeggio
* oggetti che lavorino contemporaneamente su piu' PIN
* Link a Schemi / Schemi
-* esempio con state machine per flight modes
-** battery voltage reader -> RGB
-** digital compass e RGB
-** barometer
-** 6 axis
-** Neopixel
void Lampeggiatore::High() {
// Accende il LED
-
digitalWrite(ledPin, HIGH);
}
void Lampeggiatore::Low() {
// Spegne il LED
-
digitalWrite(ledPin, LOW);
}
void Lampeggiatore::Swap() {
// Inverte lo stato del LED
-
digitalWrite(ledPin, !digitalRead(ledPin));
}
--- /dev/null
+name=Common: oggetti comuni non blocking
+version=1.0
+author=Andrea Manni <andrea@piffa.net>
+maintainer=Andrea Manni <andrea@piffa.net>
+sentence=Vari oggetti e funzioni per la gestione delle luci.
+paragraph=Elementi di base per lampeggi, fade e sequenze di luci tramite codice non blocking. Realizzati durante i corsi di Arduino di Andrea Manni su piffa.net .
+category=Display
+url=https://piffa.net
+architectures=*