C++
Glossario e non solo…
Documento confidenziale
Sommario
1 Introduzione al linguaggio C++ nei microcontrollori 5
2 Funzioni 6
2.1 digitalRead(): 6
2.2 digitalWrite(): 7
2.3 pinMode(): 7
2.4 analogRead(): 7
2.5 analogReference(): 8
2.6 analogWrite(): 8
2.7 abs(): 8
2.8 constrain(): 9
2.9 map(): 9
2.10 max(): 9
2.11 min(): 10
2.12 pow(): 10
2.13 sq(): 10
2.14 sqrt(): 10
2.15 random(): 11
2.16 randomSeed(): 11
2.17 bit(): 12
2.18 bitClear(): 12
2.19 bitRead(): 12
2.20 bitSet(): 12
2.21 bitWrite(): 13
2.22 highByte(): 13
2.23 lowByte(): 13
2.24 cos(): 14
2.25 sin(): 14
2.26 tan(): 14
2.27 attachInterrupt(): 15
2.28 detachInterrupt(): 15
2.29 noTone(): 15
2.30 pulseIn(): 16
2.31 pulseInLong(): 16
2.32 shiftIn(): 16
2.33 shiftOut(): 17
2.34 tone(): 17
2.35 interrupts(): 17
2.36 noInterrupts(): 17
2.37 delay(): 18
2.38 delayMicroseconds(): 18
2.39 micros(): 18
2.40 millis(): 19
2.41 Serial: 19
2.42 SPI: 20
2.43 Stream: 20
2.44 Wire: 20
3 Variabili 21
3.1 HIGH | LOW: 21
3.2 INPUT | OUTPUT | INPUT_PULLUP: 21
3.3 LED_BUILTIN: 21
3.4 true | false: 22
3.5 Floating Point Constants: 22
3.6 Integer Constants: 22
3.7 (unsigned int): 22
3.8 (unsigned long): 22
3.9 byte(): 22
3.10 char(): 23
3.11 float(): 23
3.12 long(): 23
3.13 word(): 23
3.14 array: 24
3.15 boolean: 24
3.16 byte: 24
3.17 double: 24
3.18 float: 25
3.19 int: 25
3.20 long: 25
3.21 short: 25
3.22 string: 25
3.23 String(): 25
3.24 unsigned int: 26
3.25 const: 26
3.26 scope: 27
3.27 static: 27
3.28 volatile: 27
3.29 PROGMEM: 28
3.30 sizeof(): 28
3.31 setup(): 28
4 Strutture. 29
4.1 loop(): 29
4.2 % (remainder): 29
4.3 (addition): 30
4.4 (subtraction): 30
4.5 & (reference operator): 31
4.6 (dereference operator): 31
4.7 break: 32
4.8 continue: 32
4.9 do...while: 32
4.10 else: 33
4.11 for: 33
4.12 goto: 33
4.13 label: 33
4.14 if: 33
4.15 return: 34
4.16 switch...case: 34
4.17 while: 34
4.18 & (bitwise and): 35
4.19 << (bitshift left): 35
4.20 (bitshift right): 35
4.21 ^ (bitwise xor): 36
4.22 | (bitwise or): 36
4.23 ~ (bitwise not): 36
4.24 != (not equal to): 37
4.25 < (less than): 37
4.26 <= (less than or equal to): 37
4.27 == (equal to): 37
4.28 (greater than): 38
4.29 = (greater than or equal to): 38
4.30 #define (define): 38
4.31 #include (include): 39
4.32 ; (semicolon): 39
4.33 ! (logical not): 40
4.34 && (logical and): 40
4.35 || (logical or): 40
4.36 %= (compound remainder): 41
4.37 &= (compound bitwise and): 41
4.38 *= (compound multiplication): 41
4.39 += (compound addition): 42
4.40 -- (decrement): 42
4.41 -= (compound subtraction): 42
4.42 /= (compound division): 42
4.43 ^= (compound bitwise xor): 43
4.44 |= (compound bitwise or): 43
5 Esempi pratici 43
5.1 costruire un orologio. 43
5.2 Dado Elettronico. 47
I microcontrollori sono dispositivi elettronici compatti e potenti che combinano un microprocessore, una memoria e periferiche di input/output, tutto su un singolo chip. Questi componenti sono fondamentali per il funzionamento di molti dispositivi elettronici, come smartphone, elettrodomestici intelligenti, veicoli e molto altro.
Il linguaggio di programmazione C++ è una scelta comune per lo sviluppo di applicazioni nei microcontrollori. C++ offre una combinazione di funzionalità di programmazione ad alto livello e di accesso al livello di sistema, rendendolo adatto per progetti che richiedono un controllo preciso delle risorse hardware.
Una delle caratteristiche principali di C++ è la sua capacità di fornire una programmazione orientata agli oggetti. Ciò significa che il codice può essere organizzato in classi e oggetti, consentendo una progettazione modulare e una migliore gestione delle complessità. Questa flessibilità rende C++ un linguaggio potente per la programmazione di microcontrollori, consentendo lo sviluppo di codice efficiente, modulare e facilmente manutenibile.
Con C++, è possibile accedere direttamente alle periferiche hardware del microcontrollore, come i pin di input/output, le interfacce di comunicazione seriale, SPI o I2C e molto altro ancora. Ciò consente di controllare i componenti e i sensori esterni collegati al microcontrollore, permettendo la creazione di sistemi interattivi e intelligenti.
Inoltre, C++ offre una vasta gamma di librerie e framework che semplificano lo sviluppo di applicazioni per microcontrollori. Queste librerie forniscono funzionalità predefinite per compiti comuni, come la comunicazione seriale, la gestione dei timer, la lettura di sensori, l'interfacciamento con display e molto altro ancora. L'utilizzo di queste librerie può accelerare lo sviluppo del progetto e ridurre il tempo di scrittura del codice.
Un altro vantaggio di C++ nei microcontrollori è la possibilità di ottimizzare il codice per le prestazioni. Con C++, è possibile utilizzare tecniche come l'inline assembly, la gestione diretta della memoria e l'ottimizzazione del codice per ridurre al minimo l'utilizzo delle risorse e migliorare le prestazioni del sistema.
Tuttavia, è importante tenere presente che la programmazione nei microcontrollori richiede una comprensione approfondita dell'architettura hardware del dispositivo e delle restrizioni di memoria e risorse. È necessario considerare le limitazioni di spazio, consumo energetico e velocità di esecuzione per ottenere un codice efficiente e affidabile.
In conclusione, il linguaggio di programmazione C++ offre un'ampia gamma di funzionalità e vantaggi per lo sviluppo di applicazioni nei microcontrollori. Con C++, è possibile creare codice modulare, ottimizzato e di alta qualità per controllare e gestire le periferiche hardware, consentendo la realizzazione di sistemi e dispositivi intelligenti e interattivi.
La funzione digitalRead() viene utilizzata per leggere il valore di un pin digitale su un microcontrollore. I pin digitali possono essere configurati come input o output, e digitalRead() consente di leggere lo stato di un pin configurato come input.
La sintassi della funzione digitalRead() è la seguente:
int digitalRead(int pin);
pin rappresenta il numero del pin che si desidera leggere.
La funzione restituisce un valore intero che può essere 0 o 1, corrispondente allo stato basso (LOW) o alto (HIGH) del pin digitale letto. Ad esempio, se si utilizza digitalRead(2) per leggere il valore del pin 2, la funzione restituirà 0 se il pin è a livello basso e 1 se è a livello alto.
La funzione digitalWrite() viene utilizzata per scrivere un valore su un pin digitale configurato come output su un microcontrollore. Consente di impostare il livello del pin digitale su basso (LOW) o alto (HIGH).
La sintassi della funzione digitalWrite() è la seguente:
void digitalWrite(int pin, int value);
pin rappresenta il numero del pin a cui si desidera scrivere il valore.
value rappresenta il valore da scrivere sul pin, che può essere LOW (0) o HIGH (1).
La funzione non restituisce alcun valore. Ad esempio, se si utilizza digitalWrite(3, HIGH), si imposterà il pin 3 a livello alto, inviando un segnale di tensione corrispondente all'alimentazione del microcontrollore.
La funzione pinMode() viene utilizzata per configurare il modo in cui un pin digitale su un microcontrollore deve essere utilizzato: come input o output. Prima di poter leggere un pin con digitalRead() o scrivere su un pin con digitalWrite(), è necessario impostare la modalità del pin utilizzando pinMode().
La sintassi della funzione pinMode() è la seguente:
void pinMode(int pin, int mode);
pin rappresenta il numero del pin che si desidera configurare.
mode rappresenta la modalità che si desidera assegnare al pin, che può essere INPUT o OUTPUT.
La funzione non restituisce alcun valore. Ad esempio, se si utilizza pinMode(4, OUTPUT), si configura il pin 4 come output, consentendo l'uso di digitalWrite() per scrivere su quel pin.
La corretta configurazione dei pin digitali utilizzando pinMode() è fondamentale per garantire che il microcontrollore legga o scriva i valori correttamente. È importante specificare attentamente le modalità dei pin per il corretto funzionamento del sistema.
La funzione analogRead() viene utilizzata per leggere il valore di un pin analogico su un microcontrollore. I pin analogici consentono di misurare tensioni continue variabili su una scala da 0 a una tensione di riferimento specifica.
La sintassi della funzione analogRead() è la seguente:
int analogRead(int pin);
pin rappresenta il numero del pin analogico da cui si desidera leggere il valore.
La funzione restituisce un valore intero compreso tra 0 e una scala massima definita dalla risoluzione ADC (Analog-to-Digital Converter) del microcontrollore. Ad esempio, se si utilizza analogRead(A0) per leggere il valore dal pin analogico A0, la funzione restituirà un valore compreso tra 0 e 1023 (se il microcontrollore ha una risoluzione ADC di 10 bit).
La funzione analogReference() viene utilizzata per impostare la tensione di riferimento per le letture analogiche su un microcontrollore. La tensione di riferimento determina la scala di tensione che può essere misurata sui pin analogici.
La sintassi della funzione analogReference() è la seguente:
void analogReference(int mode);
mode rappresenta la modalità di riferimento che si desidera impostare, che può essere DEFAULT, INTERNAL o EXTERNAL.
La funzione non restituisce alcun valore. La modalità di riferimento predefinita è solitamente la tensione di alimentazione del microcontrollore. Tuttavia, è possibile impostare una tensione di riferimento interna o utilizzare un riferimento esterno per misurazioni più precise.
La funzione analogWrite() viene utilizzata per scrivere un valore analogico su un pin digitale su un microcontrollore. Questa funzione consente di generare una forma d'onda PWM (Pulse Width Modulation) per simulare un segnale analogico.
La sintassi della funzione analogWrite() è la seguente:
void analogWrite(int pin, int value);
pin rappresenta il numero del pin digitale a cui si desidera scrivere il valore analogico.
value rappresenta il valore analogico da scrivere sul pin, che può essere compreso tra 0 (livello basso) e una scala massima definita dalla risoluzione PWM del microcontrollore (tipicamente 255 per un microcontrollore a 8 bit).
La funzione non restituisce alcun valore. AnalogWrite() simula un segnale analogico utilizzando la modulazione della larghezza di impulso, variando la percentuale di tempo in cui il segnale è alto rispetto al periodo dell'onda. Questo consente di controllare la luminosità di un LED, la velocità di un motore o la tensione di uscita in base al valore specificato.
È importante notare che non tutti i pin digitali su un microcontrollore supportano l'uscita analogica tramite analogWrite(). Solo alcuni pin specifici sono designati come pin PWM e possono generare segnali PWM.
La funzione abs() viene utilizzata per calcolare il valore assoluto di un numero. Restituisce il valore positivo di un numero negativo e lascia invariato il valore se è già positivo.
La sintassi della funzione abs() è la seguente:
int abs(int x);
float abs(float x);
x rappresenta il numero di cui si desidera calcolare il valore assoluto.
La funzione restituisce il valore assoluto di x come un intero o un float, a seconda del tipo di dato passato come argomento.
La funzione constrain() viene utilizzata per limitare un valore entro un intervallo specifico. Se il valore supera l'intervallo, viene ridimensionato al valore massimo o minimo consentito.
La sintassi della funzione constrain() è la seguente:
int constrain(int value, int min, int max);
float constrain(float value, float min, float max);
value rappresenta il valore da limitare.
min rappresenta il valore minimo consentito.
max rappresenta il valore massimo consentito.
La funzione restituisce il valore value se rientra nell'intervallo specificato da min e max. Se value è inferiore a min, viene restituito il valore min. Se value è superiore a max, viene restituito il valore max.
La funzione map() viene utilizzata per mappare un valore da un intervallo a un altro intervallo. Converte un valore in ingresso nell'intervallo desiderato utilizzando una regola di proporzionalità.
La sintassi della funzione map() è la seguente:
long map(long value, long fromLow, long fromHigh, long toLow, long toHigh);
value rappresenta il valore da mappare.
fromLow e fromHigh rappresentano l'intervallo di origine in cui si trova value.
toLow e toHigh rappresentano l'intervallo di destinazione in cui si desidera mappare value.
La funzione restituisce il valore mappato corrispondente a value nell'intervallo di destinazione specificato.
La funzione max() viene utilizzata per determinare il valore massimo tra due o più valori.
La sintassi della funzione max() è la seguente:
int max(int a, int b);
long max(long a, long b);
float max(float a, float b);
a e b rappresentano i valori da confrontare.
La funzione restituisce il valore massimo tra a e b. Può essere utilizzata per confrontare due valori o più valori contemporaneamente.
La funzione min() viene utilizzata per determinare il valore minimo tra due o più valori.
La sintassi della funzione min() è la seguente:
int min(int a, int b);
long min(long a, long b);
float min(float a, float b);
a e b rappresentano i valori da confrontare.
La funzione restituisce il valore minimo tra a e b. Può essere utilizzata per confrontare due valori o più valori contemporaneamente.
La funzione pow() viene utilizzata per calcolare una potenza di un numero specificato.
La sintassi della funzione pow() è la seguente:
double pow(double base, double exponent);
base rappresenta la base della potenza.
exponent rappresenta l'esponente a cui elevare la base.
La funzione restituisce il risultato della potenza calcolata.
La funzione sq() viene utilizzata per calcolare il quadrato di un numero.
La sintassi della funzione sq() è la seguente:
int sq(int x);
float sq(float x);
x rappresenta il numero di cui si desidera calcolare il quadrato.
La funzione restituisce il quadrato di x come un intero o un float, a seconda del tipo di dato passato come argomento.
La funzione sqrt() viene utilizzata per calcolare la radice quadrata di un numero.
La sintassi della funzione sqrt() è la seguente:
double sqrt(double x);
x rappresenta il numero di cui si desidera calcolare la radice quadrata.
La funzione restituisce la radice quadrata di x.
Queste funzioni matematiche sono utili per eseguire calcoli comuni nei microcontrollori, come operazioni aritmetiche, limitazioni di valori, mappatura di input e molto altro ancora. Spero che questa descrizione dettagliata ti sia stata utile per comprendere come utilizzare le funzioni math nel contesto dei microcontrollori.
La funzione random() viene utilizzata per generare numeri casuali su un microcontrollore. Restituisce un numero intero casuale compreso tra 0 e il valore massimo possibile (tipicamente 32767).
La sintassi della funzione random() è la seguente:
long random();
La funzione restituisce un numero intero casuale compreso tra 0 e il valore massimo possibile. Ogni volta che la funzione viene chiamata, restituisce un numero casuale diverso. Per generare numeri casuali in un intervallo specifico, puoi utilizzare la formula random(min, max) % (max - min + 1) + min, dove min e max rappresentano l'intervallo desiderato.
La funzione randomSeed() viene utilizzata per inizializzare il generatore di numeri casuali con un valore di seme. Il seme è un valore di inizializzazione che determina la sequenza di numeri casuali generati.
La sintassi della funzione randomSeed() è la seguente:
void randomSeed(unsigned long seed);
seed rappresenta il valore di seme da utilizzare per inizializzare il generatore di numeri casuali.
La funzione non restituisce alcun valore. Di solito, è consigliabile chiamare la funzione randomSeed() una sola volta all'inizio del programma, utilizzando un valore di seme che cambia nel tempo, come ad esempio il valore di un pin analogico non utilizzato.
Chiamare randomSeed() con lo stesso valore di seme garantirà che la sequenza di numeri casuali generata sia sempre la stessa. Ciò può essere utile quando si desidera riprodurre una determinata sequenza di numeri casuali.
È importante notare che la generazione di numeri casuali su un microcontrollore potrebbe non essere veramente casuale nel senso matematico, ma può essere sufficientemente casuale per molte applicazioni pratiche.
Queste funzioni per i numeri casuali possono essere utilizzate per generare numeri casuali o pseudo-casuali su un microcontrollore, che possono essere utilizzati in giochi, algoritmi di selezione casuale, sequenze casuali e molto altro ancora.
La funzione bit() viene utilizzata per ottenere il valore di un bit specifico all'interno di un byte. Restituisce il valore del bit richiesto come 0 o 1.
La sintassi della funzione bit() è la seguente:
boolean bit(byte value, int n);
value rappresenta il byte da cui estrarre il bit.
n rappresenta l'indice del bit desiderato (0-7).
La funzione restituisce il valore del bit richiesto come un booleano (true o false), in cui true corrisponde a 1 e false corrisponde a 0.
La funzione bitClear() viene utilizzata per impostare a 0 il valore di un bit specifico all'interno di un byte. Modifica il byte originale.
La sintassi della funzione bitClear() è la seguente:
void bitClear(byte& value, int n);
value rappresenta il byte in cui si desidera cancellare il bit.
n rappresenta l'indice del bit da cancellare (0-7).
La funzione modifica il byte value, impostando il bit specificato a 0.
La funzione bitRead() viene utilizzata per leggere il valore di un bit specifico all'interno di un byte. Restituisce il valore del bit richiesto come 0 o 1.
La sintassi della funzione bitRead() è la seguente:
boolean bitRead(byte value, int n);
value rappresenta il byte da cui leggere il bit.
n rappresenta l'indice del bit desiderato (0-7).
La funzione restituisce il valore del bit richiesto come un booleano (true o false), in cui true corrisponde a 1 e false corrisponde a 0.
La funzione bitSet() viene utilizzata per impostare a 1 il valore di un bit specifico all'interno di un byte. Modifica il byte originale.
La sintassi della funzione bitSet() è la seguente:
void bitSet(byte& value, int n);
value rappresenta il byte in cui si desidera impostare il bit.
n rappresenta l'indice del bit da impostare (0-7).
La funzione modifica il byte value, impostando il bit specificato a 1.
La funzione bitWrite() viene utilizzata per scrivere un valore specifico (0 o 1) in un bit specifico all'interno di un byte. Modifica il byte originale.
La sintassi della funzione bitWrite() è la seguente:
void bitWrite(byte& value, int n, boolean bitvalue);
value rappresenta il byte in cui si desidera scrivere il bit.
n rappresenta l'indice del bit da scrivere (0-7).
bitvalue rappresenta il valore del bit da scrivere (true o false, 1 o 0).
La funzione modifica il byte value, scrivendo il valore specificato nel bit specificato.
La funzione highByte() viene utilizzata per estrarre l'ottetto più significativo (byte superiore) da una variabile a due byte. Restituisce il byte superiore come un valore unsigned.
La sintassi della funzione highByte() è la seguente:
byte highByte(word value);
value rappresenta la variabile a due byte da cui estrarre l'ottetto più significativo.
La funzione restituisce l'ottetto superiore di value come un byte unsigned.
La funzione lowByte() viene utilizzata per estrarre l'ottetto meno significativo (byte inferiore) da una variabile a due byte. Restituisce il byte inferiore come un valore unsigned.
La sintassi della funzione lowByte() è la seguente:
byte lowByte(word value);
value rappresenta la variabile a due byte da cui estrarre l'ottetto meno significativo.
La funzione restituisce l'ottetto inferiore di value come un byte unsigned.
Queste funzioni per i bit e i byte sono utili per manipolare i dati a livello di bit e byte sui microcontrollori. Possono essere utilizzate per leggere e scrivere valori specifici di bit, ottenere byte superiori e inferiori da variabili a due byte e altro ancora.
La funzione cos() viene utilizzata per calcolare il coseno di un angolo specificato in radianti. Restituisce il valore del coseno come un numero compreso tra -1 e 1.
La sintassi della funzione cos() è la seguente:
double cos(double angle);
angle rappresenta l'angolo in radianti di cui si desidera calcolare il coseno.
La funzione restituisce il valore del coseno dell'angolo specificato come un numero in virgola mobile.
La funzione sin() viene utilizzata per calcolare il seno di un angolo specificato in radianti. Restituisce il valore del seno come un numero compreso tra -1 e 1.
La sintassi della funzione sin() è la seguente:
double sin(double angle);
angle rappresenta l'angolo in radianti di cui si desidera calcolare il seno.
La funzione restituisce il valore del seno dell'angolo specificato come un numero in virgola mobile.
La funzione tan() viene utilizzata per calcolare la tangente di un angolo specificato in radianti. Restituisce il valore della tangente come un numero reale.
La sintassi della funzione tan() è la seguente:
double tan(double angle);
angle rappresenta l'angolo in radianti di cui si desidera calcolare la tangente.
La funzione restituisce il valore della tangente dell'angolo specificato come un numero in virgola mobile.
Queste funzioni trigonometriche sono utili per calcolare valori associati agli angoli, come la posizione, l'altezza, l'orientamento e altro ancora. Possono essere utilizzate in applicazioni come la grafica, la robotica, la navigazione e molti altri campi.
È importante notare che le funzioni trigonometriche nei microcontrollori lavorano generalmente con valori in radianti, quindi potrebbe essere necessario convertire gli angoli in radianti utilizzando le formule appropriate.
La funzione attachInterrupt() viene utilizzata per collegare una funzione di interrupt a un pin specifico su un microcontrollore. Gli interrupt consentono al microcontrollore di interrompere l'esecuzione del programma principale e gestire eventi esterni in modo tempestivo.
La sintassi della funzione attachInterrupt() è la seguente:
void attachInterrupt(uint8_t pin, void (*ISR)(), int mode);
pin rappresenta il numero del pin a cui si desidera collegare l'interrupt.
ISR rappresenta il nome della funzione di interrupt che verrà chiamata quando si verifica l'evento.
mode rappresenta il tipo di evento che scatena l'interrupt. Può essere LOW, CHANGE, RISING o FALLING.
La funzione permette di collegare una specifica funzione di interrupt (ISR) a un pin specifico (pin) e specificare il tipo di evento (mode) che attiverà l'interrupt. Quando si verifica l'evento specificato, la funzione di interrupt verrà chiamata.
La funzione detachInterrupt() viene utilizzata per disabilitare un interrupt collegato a un pin specifico su un microcontrollore. Questo permette di interrompere l'esecuzione della funzione di interrupt associata a quel pin.
La sintassi della funzione detachInterrupt() è la seguente:
void detachInterrupt(uint8_t pin);
pin rappresenta il numero del pin da cui disabilitare l'interrupt.
La funzione detachInterrupt() disabilita l'interrupt collegato al pin specificato, interrompendo l'esecuzione della funzione di interrupt associata a quel pin. Dopo aver chiamato detachInterrupt(), il pin non genererà più interrupt fino a quando non verrà nuovamente collegato utilizzando attachInterrupt().
Le funzioni attachInterrupt() e detachInterrupt() sono utili per gestire eventi esterni in tempo reale su un microcontrollore. Possono essere utilizzate per rilevare segnali di input da sensori, pulsanti, encoder e altro ancora, consentendo al microcontrollore di rispondere immediatamente a tali eventi.
È importante notare che non tutti i pin dei microcontrollori supportano la funzionalità di interrupt. È necessario consultare la documentazione specifica del microcontrollore per identificare i pin che supportano gli interrupt.
La funzione noTone() viene utilizzata per interrompere la generazione di un segnale di tono su un pin specifico su un microcontrollore. È utile quando si desidera interrompere la riproduzione di un tono prima della sua naturale durata.
La sintassi della funzione noTone() è la seguente:
void noTone(uint8_t pin);
pin rappresenta il numero del pin su cui interrompere la generazione del tono.
La funzione noTone() ferma la generazione del tono sul pin specificato, interrompendo la riproduzione del suono.
La funzione pulseIn() viene utilizzata per misurare la durata di un impulso su un pin specifico su un microcontrollore. Restituisce la durata dell'impulso in microsecondi.
La sintassi della funzione pulseIn() è la seguente:
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000);
pin rappresenta il numero del pin da cui leggere l'impulso.
state rappresenta lo stato dell'impulso da misurare: HIGH o LOW.
timeout (opzionale) rappresenta il limite di tempo massimo per attendere l'impulso, in microsecondi.
La funzione restituisce la durata dell'impulso in microsecondi come un valore unsigned long.
La funzione pulseInLong() è una variante della funzione pulseIn(), che viene utilizzata per misurare la durata di un impulso su un pin specifico su un microcontrollore. Restituisce la durata dell'impulso in microsecondi come un valore unsigned long.
La sintassi della funzione pulseInLong() è la seguente:
unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout = 1000000);
pin rappresenta il numero del pin da cui leggere l'impulso.
state rappresenta lo stato dell'impulso da misurare: HIGH o LOW.
timeout (opzionale) rappresenta il limite di tempo massimo per attendere l'impulso, in microsecondi.
La funzione restituisce la durata dell'impulso in microsecondi come un valore unsigned long.
La funzione shiftIn() viene utilizzata per leggere una sequenza di dati seriali da un registro a scorrimento (shift register) collegato a un microcontrollore.
La sintassi della funzione shiftIn() è la seguente:
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder);
dataPin rappresenta il pin di dati a cui è collegato il registro a scorrimento.
clockPin rappresenta il pin di clock del registro a scorrimento.
bitOrder rappresenta l'ordine di lettura dei bit: LSBFIRST o MSBFIRST.
La funzione restituisce un valore di tipo uint8_t, che rappresenta i dati letti dal registro a scorrimento.
La funzione shiftOut() viene utilizzata per inviare una sequenza di dati seriali a un registro a scorrimento (shift register) collegato a un microcontrollore.
La sintassi della funzione shiftOut() è la seguente:
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t value);
dataPin rappresenta il pin di dati a cui è collegato il registro a scorrimento.
clockPin rappresenta il pin di clock del registro a scorrimento.
bitOrder rappresenta l'ordine di invio dei bit: LSBFIRST o MSBFIRST.
value rappresenta il valore da inviare al registro a scorrimento.
La funzione invia il valore specificato al registro a scorrimento.
La funzione tone() viene utilizzata per generare un segnale di tono su un pin specifico su un microcontrollore. È utile per generare segnali acustici, come suoni e note musicali.
La sintassi della funzione tone() è la seguente:
void tone(uint8_t pin, unsigned int frequency, unsigned long duration = 0);
pin rappresenta il numero del pin su cui generare il tono.
frequency rappresenta la frequenza del tono in Hz.
duration (opzionale) rappresenta la durata del tono in millisecondi. Se omesso o impostato a 0, il tono continuerà a suonare fino a quando non verrà fermato manualmente con noTone().
La funzione genera il tono specificato sulla frequenza e per la durata specificata (se specificata).
Queste funzioni avanzate di I/O sono utili per operazioni più complesse di input e output sui microcontrollori, come la generazione di toni, la lettura e scrittura di dati seriali e altro ancora.
La funzione interrupts() viene utilizzata per abilitare gli interrupt su un microcontrollore. Gli interrupt consentono al microcontrollore di interrompere l'esecuzione del programma principale e gestire eventi esterni in modo tempestivo.
La sintassi della funzione interrupts() è la seguente:
void interrupts();
La funzione interrupts() abilita gli interrupt, consentendo al microcontrollore di gestire gli eventi esterni che generano interrupt.
La funzione noInterrupts() viene utilizzata per disabilitare gli interrupt su un microcontrollore. Ciò significa che il microcontrollore non interromperà l'esecuzione del programma principale per gestire eventi esterni fino a quando gli interrupt non verranno riabilitati.
La sintassi della funzione noInterrupts() è la seguente:
void noInterrupts();
La funzione noInterrupts() disabilita gli interrupt, evitando che il microcontrollore interrompa l'esecuzione del programma principale per gestire eventi esterni.
Queste funzioni interrupts() e noInterrupts() sono utili quando si desidera controllare esplicitamente il comportamento degli interrupt su un microcontrollore. Disabilitando gli interrupt con noInterrupts(), è possibile garantire che certe sezioni critiche del codice vengano eseguite senza essere interrotte. Successivamente, è possibile riabilitare gli interrupt utilizzando interrupts() per consentire la gestione degli eventi esterni.
Tuttavia, è importante fare un uso oculato delle funzioni interrupts() e noInterrupts() per evitare problemi di sincronizzazione o ritardi indesiderati nel programma.
La funzione delay() viene utilizzata per sospendere l'esecuzione del programma per un determinato periodo di tempo in millisecondi. È utile per creare ritardi o pause nel programma.
La sintassi della funzione delay() è la seguente:
void delay(unsigned long milliseconds);
milliseconds rappresenta il numero di millisecondi per cui sospendere l'esecuzione del programma.
La funzione delay() blocca l'esecuzione del programma per il periodo di tempo specificato in millisecondi.
La funzione delayMicroseconds() viene utilizzata per sospendere l'esecuzione del programma per un determinato periodo di tempo in microsecondi. È utile per creare ritardi precisi a livello di microsecondi.
La sintassi della funzione delayMicroseconds() è la seguente:
void delayMicroseconds(unsigned int microseconds);
microseconds rappresenta il numero di microsecondi per cui sospendere l'esecuzione del programma.
La funzione delayMicroseconds() blocca l'esecuzione del programma per il periodo di tempo specificato in microsecondi.
La funzione micros() restituisce il numero di microsecondi trascorsi dall'accensione del microcontrollore o dall'ultima reinizializzazione. È utile per misurare intervalli di tempo molto brevi con una precisione di microsecondi.
La sintassi della funzione micros() è la seguente:
unsigned long micros();
La funzione micros() restituisce il numero di microsecondi trascorsi dall'accensione del microcontrollore o dall'ultima reinizializzazione come un valore unsigned long.
La funzione millis() restituisce il numero di millisecondi trascorsi dall'accensione del microcontrollore o dall'ultima reinizializzazione. È utile per misurare intervalli di tempo più lunghi con una precisione di millisecondi.
La sintassi della funzione millis() è la seguente:
unsigned long millis();
La funzione millis() restituisce il numero di millisecondi trascorsi dall'accensione del microcontrollore o dall'ultima reinizializzazione come un valore unsigned long.
Le funzioni delay(), delayMicroseconds(), micros() e millis() sono utili per gestire il tempo su un microcontrollore. Consentono di creare ritardi, misurare intervalli di tempo e sincronizzare azioni nel programma.
Tuttavia, è importante notare che l'utilizzo prolungato della funzione delay() può causare ritardi nell'esecuzione del programma e rendere il microcontrollore non reattivo ad altri eventi. Pertanto, è consigliabile evitare l'utilizzo di delay() in applicazioni che richiedono una risposta immediata a eventi esterni.
La libreria Serial viene utilizzata per la comunicazione seriale tra il microcontrollore e un dispositivo esterno, come un computer o un altro microcontrollore. Consente di inviare e ricevere dati tramite un'interfaccia seriale come UART (Universal Asynchronous Receiver/Transmitter).
Per utilizzare la libreria Serial, è necessario includere la sua dichiarazione all'inizio del programma:
#include <Serial.h>
Una volta inclusa la libreria, è possibile utilizzare le funzioni e i metodi forniti per la comunicazione seriale, come ad esempio:
Serial.begin(baudRate): Inizializza la comunicazione seriale con una specifica velocità di baud rate.
Serial.print(data): Invia dati alla porta seriale.
Serial.println(data): Invia dati alla porta seriale seguiti da un ritorno a capo (new line).
Serial.available(): Restituisce il numero di byte disponibili per la lettura dalla porta seriale.
Serial.read(): Legge il prossimo byte disponibile dalla porta seriale.
La libreria Serial è ampiamente utilizzata per il debugging, il monitoraggio dei dati e la comunicazione con altri dispositivi tramite la porta seriale.
La libreria SPI viene utilizzata per la comunicazione seriale sincrona tra il microcontrollore e dispositivi esterni tramite l'interfaccia SPI (Serial Peripheral Interface). L'interfaccia SPI permette la comunicazione ad alta velocità con dispositivi come sensori, display e schede di memoria.
Per utilizzare la libreria SPI, è necessario includere la sua dichiarazione all'inizio del programma:
#include <SPI.h>
Una volta inclusa la libreria, è possibile utilizzare le funzioni e i metodi forniti per la comunicazione SPI, come ad esempio:
SPI.begin(): Inizializza la comunicazione SPI.
SPI.beginTransaction(settings): Inizia una nuova transazione SPI con le impostazioni specificate.
SPI.transfer(data): Trasmette un byte di dati sulla linea SPI e riceve un byte in risposta.
SPI.endTransaction(): Termina la transazione SPI corrente.
SPI.end(): Termina la comunicazione SPI.
La libreria SPI fornisce funzioni per inviare e ricevere dati tramite l'interfaccia SPI e configurare le impostazioni della comunicazione, come la velocità di trasferimento e l'ordine dei bit.
La classe Stream fornisce un'interfaccia comune per la lettura e scrittura di dati da diverse sorgenti e destinazioni, come la porta seriale, la memoria EEPROM e altre periferiche di I/O. È una classe base astratta che viene utilizzata da altre classi per implementare la comunicazione con diverse sorgenti di dati.
La libreria Stream fornisce metodi comuni per la lettura e scrittura di dati, come ad esempio:
available(): Restituisce il numero di byte disponibili per la lettura.
read(): Legge il prossimo byte disponibile.
peek(): Restituisce il prossimo byte disponibile senza rimuoverlo dalla sorgente.
flush(): Svuota il buffer di output.
La classe Stream viene utilizzata principalmente come base per altre classi di comunicazione, come la classe Serial.
La libreria Wire viene utilizzata per la comunicazione I2C (Inter-Integrated Circuit) tra il microcontrollore e dispositivi esterni. L'I2C è un protocollo di comunicazione seriale a due fili che consente al microcontrollore di comunicare con più dispositivi utilizzando lo stesso bus.
Per utilizzare la libreria Wire, è necessario includere la sua dichiarazione all'inizio del programma:
#include <Wire.h>
Una volta inclusa la libreria, è possibile utilizzare le funzioni e i metodi forniti per la comunicazione I2C, come ad esempio:
Wire.begin(): Inizializza la comunicazione I2C.
Wire.beginTransmission(address): Inizia una nuova trasmissione I2C all'indirizzo specificato.
Wire.write(data): Scrive dati nella trasmissione I2C corrente.
Wire.endTransmission(): Termina la trasmissione I2C corrente.
Wire.requestFrom(address, quantity): Richiede una certa quantità di byte dal dispositivo I2C all'indirizzo specificato.
Wire.available(): Restituisce il numero di byte disponibili per la lettura dalla trasmissione I2C corrente.
Wire.read(): Legge il prossimo byte disponibile dalla trasmissione I2C corrente.
La libreria Wire fornisce funzioni per inviare e ricevere dati tramite l'interfaccia I2C e gestire la comunicazione con dispositivi I2C esterni.
HIGH e LOW sono costanti predefinite utilizzate per rappresentare lo stato logico alto (1) e lo stato logico basso (0), rispettivamente. Queste costanti vengono spesso utilizzate per impostare o leggere lo stato di un pin digitale su un microcontrollore.
INPUT, OUTPUT e INPUT_PULLUP sono costanti predefinite utilizzate per impostare la modalità di un pin digitale su un microcontrollore.
INPUT: Imposta il pin come input, consentendo di leggere il valore in ingresso su quel pin.
OUTPUT: Imposta il pin come output, consentendo di inviare un segnale in uscita su quel pin.
INPUT_PULLUP: Imposta il pin come input con resistenza di pull-up interna attivata. È utile quando si collega un pulsante o un interruttore e si desidera utilizzare la resistenza di pull-up interna per mantenere un valore di default alto quando il pulsante non viene premuto.
LED_BUILTIN è una costante predefinita che rappresenta il numero del pin su cui è collegato il LED integrato sul microcontrollore. Questo può variare a seconda del modello di microcontrollore utilizzato. È utile quando si desidera controllare il LED integrato senza dover specificare il numero del pin manualmente.
true e false sono costanti predefinite utilizzate per rappresentare i valori booleani di vero e falso, rispettivamente. Sono utilizzate principalmente in espressioni condizionali, cicli e altre operazioni logiche.
Le costanti di punto floating sono utilizzate per rappresentare numeri in virgola mobile su un microcontrollore. Le costanti possono essere scritte come numeri decimali, ad esempio 3.14, o utilizzando la notazione scientifica, ad esempio 1.5e-3 (corrispondente a 0.0015).
Le costanti intere sono utilizzate per rappresentare numeri interi su un microcontrollore. Possono essere scritte come numeri decimali, esadecimali (preceduti da 0x) o ottali (preceduti da 0).
Le costanti sopra menzionate sono ampiamente utilizzate nella programmazione dei microcontrollori per rappresentare valori specifici, configurazioni dei pin e condizioni logiche.
La conversione (unsigned int) viene utilizzata per convertire un valore in un tipo di dato unsigned integer (intero senza segno a 16 bit) su un microcontrollore. Questa conversione viene spesso utilizzata per garantire che un valore venga trattato come un numero senza segno.
Esempio:
unsigned int myValue = (unsigned int)12345;
La conversione (unsigned long) viene utilizzata per convertire un valore in un tipo di dato unsigned long (lungo senza segno a 32 bit) su un microcontrollore. Questa conversione viene spesso utilizzata per garantire che un valore venga trattato come un numero senza segno a lungo termine.
Esempio:
unsigned long myValue = (unsigned long)987654321;
La funzione byte() viene utilizzata per convertire un valore in un tipo di dato byte (8 bit) su un microcontrollore. Questa conversione viene spesso utilizzata per ottimizzare l'utilizzo di memoria quando è necessario memorizzare valori che rientrano nell'intervallo da 0 a 255.
Esempio:
csharp
Copy code
byte myValue = byte(42);
La conversione char() viene utilizzata per convertire un valore in un tipo di dato carattere (ASCII) su un microcontrollore. Questa conversione viene spesso utilizzata per gestire valori carattere, come lettere, numeri e simboli.
Esempio:
char myValue = char(65); // Il valore 65 rappresenta il carattere 'A' in ASCII
La conversione float() viene utilizzata per convertire un valore in un tipo di dato float (numero in virgola mobile a 32 bit) su un microcontrollore. Questa conversione viene spesso utilizzata per eseguire calcoli con numeri decimali.
Esempio:
float myValue = float(3.14159);
int():
La conversione int() viene utilizzata per convertire un valore in un tipo di dato intero (signed int) su un microcontrollore. Questa conversione viene spesso utilizzata per trattare un valore come un numero intero con segno.
Esempio:
int myValue = int(-42);
La conversione long() viene utilizzata per convertire un valore in un tipo di dato long (lungo a 32 bit) su un microcontrollore. Questa conversione viene spesso utilizzata per gestire numeri interi a lungo termine.
Esempio:
long myValue = long(987654321);
La conversione word() viene utilizzata per convertire un valore in un tipo di dato word (16 bit) su un microcontrollore. Questa conversione viene spesso utilizzata per gestire valori interi nel range da 0 a 65535.
Esempio:
word myValue = word(12345);
Queste conversioni di variabili sono utilizzate per adattare i valori a tipi di dati specifici e per garantire che vengano trattati correttamente durante le operazioni e i calcoli.
Un array è una struttura di dati che contiene una collezione di elementi dello stesso tipo. Gli elementi dell'array sono memorizzati in posizioni consecutive di memoria e possono essere accessibili utilizzando un indice numerico. Gli array vengono utilizzati per organizzare e manipolare dati correlati in modo efficiente.
Esempio:
int myArray[5] = {1, 2, 3, 4, 5};
bool:
Il tipo di dato bool rappresenta un valore booleano che può essere vero (true) o falso (false). È utilizzato per rappresentare condizioni logiche e risultati di confronti.
Esempio:
bool isOn = true;
Il tipo di dato boolean è un sinonimo di bool. Viene utilizzato in modo intercambiabile con bool per rappresentare un valore booleano.
Il tipo di dato byte rappresenta un numero intero senza segno a 8 bit. Può contenere valori nel range da 0 a 255. Viene utilizzato principalmente per risparmiare memoria quando è necessario memorizzare valori interi di piccole dimensioni.
Esempio:
byte myByte = 42;
char:
Il tipo di dato char rappresenta un carattere singolo. Può rappresentare caratteri ASCII come lettere, numeri e simboli. I caratteri sono rappresentati utilizzando il codice ASCII corrispondente.
Esempio:
char myChar = 'A';
Il tipo di dato double rappresenta un numero in virgola mobile a precisione doppia. È utilizzato per rappresentare numeri decimali con una maggiore precisione rispetto al tipo float. Occupa più spazio di memoria rispetto al float, ma offre una maggiore precisione.
Esempio:
double myDouble = 3.14159;
Il tipo di dato float rappresenta un numero in virgola mobile a precisione singola. È utilizzato per rappresentare numeri decimali su un microcontrollore. I float richiedono meno spazio di memoria rispetto ai double, ma offrono una precisione leggermente inferiore.
Esempio:
float myFloat = 2.71828;
Il tipo di dato int rappresenta un numero intero con segno a 16 bit. Può contenere valori nel range da -32,768 a 32,767. Viene utilizzato per rappresentare numeri interi su un microcontrollore.
Esempio:
int myInt = -42;
Il tipo di dato long rappresenta un numero intero con segno a 32 bit. Può contenere valori nel range da -2,147,483,648 a 2,147,483,647. Viene utilizzato per rappresentare numeri interi a lungo termine.
Esempio:
long myLong = 987654321;
Il tipo di dato short rappresenta un numero intero con segno a 16 bit. Può contenere valori nel range da -32,768 a 32,767. Viene utilizzato per rappresentare numeri interi su un microcontrollore.
Esempio:
short myShort = -1234;
size_t:
Il tipo di dato size_t rappresenta un tipo senza segno utilizzato per rappresentare la dimensione di un oggetto o una struttura di dati. La dimensione dipende dall'architettura del microcontrollore utilizzato.
Esempio:
size_t dataSize = sizeof(int);
Il tipo di dato string rappresenta una sequenza di caratteri. Viene utilizzato per manipolare e manipolare dati di testo. Nella programmazione dei microcontrollori, le stringhe spesso vengono gestite come array di caratteri terminati da un carattere nullo ('\0').
Esempio:
char myString[] = "Hello";
String() è una classe che rappresenta una stringa di caratteri in modo dinamico. Offre una serie di metodi e funzioni per la manipolazione delle stringhe. È utilizzata principalmente nelle librerie di alto livello che semplificano la manipolazione delle stringhe su un microcontrollore.
Esempio:
String myString = String("Hello");
unsigned char:
Il tipo di dato unsigned char rappresenta un numero intero senza segno a 8 bit. Può contenere valori nel range da 0 a 255. Viene utilizzato principalmente per rappresentare byte di dati senza segno.
Esempio:
unsigned char myByte = 255;
Il tipo di dato unsigned int rappresenta un numero intero senza segno a 16 bit. Può contenere valori nel range da 0 a 65,535. Viene utilizzato per rappresentare numeri interi senza segno su un microcontrollore.
Esempio:
unsigned int myUInt = 12345;
unsigned long:
Il tipo di dato unsigned long rappresenta un numero intero senza segno a 32 bit. Può contenere valori nel range da 0 a 4,294,967,295. Viene utilizzato per rappresentare numeri interi senza segno a lungo termine.
Esempio:
unsigned long myULong = 987654321;
void:
Il tipo di dato void viene utilizzato per indicare l'assenza di tipo. Viene spesso utilizzato per indicare che una funzione non restituisce alcun valore.
Esempio:
void myFunction();
word:
Il tipo di dato word rappresenta un numero intero senza segno a 16 bit. Può contenere valori nel range da 0 a 65,535. Viene utilizzato per rappresentare numeri interi senza segno su un microcontrollore.
Esempio:
word myWord = 12345;
Questi sono alcuni dei tipi di dati comuni utilizzati nella programmazione dei microcontrollori. Ogni tipo di dato ha dimensioni e limiti specifici che devono essere considerati durante lo sviluppo del programma.
Il qualificatore const viene utilizzato per dichiarare una variabile come costante, il che significa che il suo valore non può essere modificato una volta assegnato. Le variabili costanti sono utili per definire valori che devono rimanere immutati durante l'esecuzione del programma.
Esempio:
const int LED_PIN = 13; // Dichiarazione di una costante
Lo scope si riferisce all'ambito di visibilità di una variabile, ovvero la parte del programma in cui una variabile è accessibile e può essere utilizzata. Le variabili possono avere ambiti locali o globali.
Ambito locale: Una variabile con ambito locale è definita all'interno di una specifica funzione o blocco di codice. È accessibile solo all'interno di quella funzione o blocco di codice.
void myFunction() {
int localVar = 42; // Variabile locale
// ...
}
Ambito globale: Una variabile con ambito globale è definita all'esterno di qualsiasi funzione. È accessibile da tutte le funzioni all'interno del programma.
int globalVar = 10; // Variabile globale
void myFunction() {
// Accesso alla variabile globale
int result = globalVar + 5;
// ...
}
Il qualificatore static viene utilizzato per dichiarare una variabile con persistenza dei dati, il che significa che la variabile mantiene il suo valore tra le chiamate successive alla funzione in cui è dichiarata. È utile per conservare lo stato delle variabili tra le chiamate di una funzione.
Esempio:
void myFunction() {
static int counter = 0; // Variabile statica
counter++;
// ...
}
Nell'esempio sopra, la variabile counter mantiene il suo valore tra le chiamate successive alla funzione myFunction().
Il qualificatore volatile viene utilizzato per indicare al compilatore che una variabile può essere modificata da fonti esterne al normale flusso di esecuzione del programma. È spesso utilizzato per dichiarare variabili che possono essere alterate da interrupt o da altre parti del codice che operano in parallelo.
Esempio:
volatile int sensorValue; // Variabile volatile
Nell'esempio sopra, la variabile sensorValue potrebbe essere modificata da un'interrupt o da un'altra parte del codice, e l'utilizzo di volatile avvisa il compilatore di tenere conto di tali modifiche.
Questi concetti di ambito delle variabili e qualificatori sono importanti nella gestione delle variabili nei microcontrollori e nella creazione di programmi efficienti e affidabili.
La parola chiave PROGMEM viene utilizzata per dichiarare che i dati devono essere memorizzati nella memoria di programma invece della memoria RAM. Questo è particolarmente utile quando si desidera conservare grandi quantità di dati costanti, come tabelle di lookup o stringhe, in modo efficiente.
Esempio:
arduino
Copy code
const char myString[] PROGMEM = "Hello";
Nell'esempio sopra, la stringa "Hello" viene memorizzata nella memoria di programma utilizzando la parola chiave PROGMEM. Per accedere ai dati memorizzati in PROGMEM, è necessario utilizzare le funzioni speciali, come pgm_read_byte(), per recuperare i dati dalla memoria di programma.
L'operatore sizeof() viene utilizzato per determinare la dimensione in byte di un tipo di dato o di una variabile. Restituisce il numero di byte richiesti per memorizzare l'oggetto o il tipo di dato specificato.
Esempio:
int myArray[5];
size_t arraySize = sizeof(myArray);
Nell'esempio sopra, sizeof(myArray) restituirà il numero totale di byte necessari per memorizzare l'array myArray, che dipenderà dalla dimensione del tipo di dato dell'array moltiplicato per il numero di elementi.
L'utilità sizeof() è utile per allocare la memoria corretta per le variabili, verificare la dimensione degli array e svolgere altre operazioni che richiedono la conoscenza della dimensione di un oggetto o di un tipo di dato.
È importante notare che sizeof() restituisce la dimensione in byte e può variare a seconda dell'architettura del microcontrollore e del compilatore utilizzati.
La funzione setup() è una funzione predefinita richiamata una volta all'avvio del programma sul microcontrollore. Viene utilizzata per inizializzare le impostazioni iniziali del microcontrollore, come configurare i pin di I/O, inizializzare librerie, impostare la comunicazione seriale, ecc. È anche il punto di partenza per l'esecuzione del programma.
Esempio:
void setup() {
// Inizializzazione delle impostazioni
pinMode(LED_PIN, OUTPUT);
Serial.begin(9600);
}
Nell'esempio sopra, la funzione setup() viene utilizzata per impostare il pin LED come uscita e inizializzare la comunicazione seriale a una velocità di 9600 baud.
La funzione loop() è una funzione predefinita che viene eseguita in continuazione dopo che la funzione setup() è stata eseguita. Questa funzione rappresenta il ciclo principale del programma e contiene le istruzioni che vengono eseguite ripetutamente.
Esempio:
void loop() {
// Codice da eseguire ripetutamente
digitalWrite(LED_PIN, HIGH);
delay(1000);
digitalWrite(LED_PIN, LOW);
delay(1000);
}
Nell'esempio sopra, la funzione loop() viene utilizzata per accendere e spegnere il LED ad intervalli di un secondo.
La struttura di base di uno sketch per microcontrollori consiste nel definire le funzioni setup() e loop(). La funzione setup() viene eseguita solo una volta all'avvio, mentre la funzione loop() viene eseguita continuamente in un ciclo infinito. Questa struttura consente di inizializzare il microcontrollore e gestire il flusso principale del programma.
È importante notare che è possibile aggiungere altre funzioni e librerie personalizzate allo sketch, oltre a setup() e loop(), per estendere le funzionalità del programma.
L'operatore % viene utilizzato per calcolare il resto della divisione tra due numeri interi. Restituisce il resto come risultato dell'operazione.
Esempio:
int remainder = 10 % 3; // Il risultato sarà 1
Nell'esempio sopra, l'operatore % calcola il resto della divisione di 10 per 3, che è 1.
(multiplication):
L'operatore * viene utilizzato per eseguire la moltiplicazione tra due numeri. Restituisce il prodotto dei due numeri come risultato dell'operazione.
Esempio:
int product = 5 * 3; // Il risultato sarà 15
Nell'esempio sopra, l'operatore * moltiplica 5 per 3, ottenendo un prodotto di 15.
L'operatore + viene utilizzato per eseguire l'addizione tra due numeri o per concatenare due stringhe. Restituisce la somma dei numeri o la concatenazione delle stringhe come risultato dell'operazione.
Esempio:
int sum = 2 + 3; // Il risultato sarà 5
String str1 = "Hello";
String str2 = " World!";
String message = str1 + str2; // Il risultato sarà "Hello World!"
Nell'esempio sopra, l'operatore + somma 2 e 3, ottenendo una somma di 5. Inoltre, viene utilizzato per concatenare le due stringhe, ottenendo "Hello World!" come risultato.
L'operatore - viene utilizzato per eseguire la sottrazione tra due numeri. Restituisce la differenza tra i due numeri come risultato dell'operazione.
Esempio:
int difference = 8 - 3; // Il risultato sarà 5
Nell'esempio sopra, l'operatore - sottrae 3 da 8, ottenendo una differenza di 5.
/ (division):
L'operatore / viene utilizzato per eseguire la divisione tra due numeri. Restituisce il risultato della divisione come un numero in virgola mobile (se uno dei numeri è in virgola mobile) o come un numero intero (se entrambi i numeri sono interi).
Esempio:
float quotient = 10.0 / 3.0; // Il risultato sarà 3.33333
int result = 10 / 3; // Il risultato sarà 3
Nell'esempio sopra, l'operatore / esegue la divisione tra 10 e 3. Quando entrambi i numeri sono in virgola mobile, il risultato è in virgola mobile. Quando entrambi i numeri sono interi, il risultato è un numero intero.
= (assignment operator):
L'operatore = viene utilizzato per assegnare un valore a una variabile. Assegna il valore a destra dell'operatore alla variabile a sinistra dell'operatore.
Esempio:
int value = 5; // Assegna il valore 5 alla variabile 'value'
Nell'esempio sopra, l'operatore = assegna il valore 5 alla variabile value.
Gli operatori aritmetici sono ampiamente utilizzati per eseguire calcoli e manipolare i dati nei programmi per microcontrollori. Possono essere utilizzati con variabili di diversi tipi di dati, come interi, numeri in virgola mobile o stringhe, a seconda delle esigenze del programma.
L'operatore & viene utilizzato come operatore di riferimento, che restituisce l'indirizzo di memoria di una variabile. Viene spesso utilizzato per ottenere l'indirizzo di memoria di una variabile e assegnarlo a un puntatore.
Esempio:
int value = 10;
int* ptr = &value; // Assegna l'indirizzo di 'value' al puntatore 'ptr'
Nell'esempio sopra, l'operatore & viene utilizzato per ottenere l'indirizzo di memoria della variabile value e assegnarlo al puntatore ptr.
L'operatore * viene utilizzato come operatore di dereferenziazione, che accede al valore memorizzato all'indirizzo di memoria puntato da un puntatore. Viene spesso utilizzato per accedere o modificare il valore della variabile referenziata dal puntatore.
Esempio:
int value = 10;
int* ptr = &value; // Assegna l'indirizzo di 'value' al puntatore 'ptr'
int dereferencedValue = *ptr; // Accede al valore puntato da 'ptr'
*ptr = 20; // Modifica il valore puntato da 'ptr' a 20
Nell'esempio sopra, l'operatore * viene utilizzato per accedere al valore puntato da ptr e assegnarlo alla variabile dereferencedValue. Inoltre, viene utilizzato per modificare il valore puntato da ptr a 20.
Gli operatori di accesso ai puntatori sono utilizzati per manipolare i puntatori e accedere ai dati memorizzati all'indirizzo di memoria puntato dai puntatori. Consentono di lavorare con indirizzi di memoria direttamente e accedere ai dati in modo efficiente.
L'istruzione break viene utilizzata per terminare immediatamente un loop (for, while, do...while) o un'istruzione switch...case. Quando l'istruzione break viene eseguita, il controllo passa alla dichiarazione successiva all'interno del blocco di controllo.
Esempio:
for (int i = 0; i < 10; i++) {
if (i == 5) {
break; // Termina il loop quando i = 5
}
// ...
}
Nell'esempio sopra, quando i diventa uguale a 5, l'istruzione break viene eseguita e il loop for viene interrotto immediatamente.
L'istruzione continue viene utilizzata per interrompere l'iterazione corrente di un loop e passare alla prossima iterazione. Quando l'istruzione continue viene eseguita, il controllo torna all'inizio del loop per valutare la condizione del loop e procedere con l'iterazione successiva.
Esempio:
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) {
continue; // Salta l'iterazione se i è pari
}
// ...
}
Nell'esempio sopra, quando i è un numero pari, l'istruzione continue viene eseguita e l'iterazione corrente viene saltata, passando alla successiva iterazione del loop.
La struttura do...while viene utilizzata per eseguire un blocco di istruzioni almeno una volta, e successivamente ripeterlo fino a quando una condizione specificata è vera.
Esempio:
int i = 0;
do {
// ...
i++;
} while (i < 5);
Nell'esempio sopra, il blocco di istruzioni viene eseguito almeno una volta, indipendentemente dalla condizione. Dopo ogni esecuzione, la condizione viene valutata e se è vera, il blocco viene ripetuto.
L'istruzione else viene utilizzata in combinazione con l'istruzione if per eseguire un blocco di codice alternativo quando la condizione dell'istruzione if è falsa.
Esempio:
int value = 10;
if (value > 5) {
// Codice da eseguire se value > 5
} else {
// Codice da eseguire se value <= 5
}
Nell'esempio sopra, se value è maggiore di 5, viene eseguito il primo blocco di codice. Altrimenti, viene eseguito il blocco di codice nell'istruzione else.
La struttura for viene utilizzata per eseguire un blocco di istruzioni ripetutamente per un numero specificato di volte. Viene fornito un inizializzatore, una condizione di continuazione e un'istruzione di incremento/decremento per controllare il flusso del loop.
Esempio:
for (int i = 0; i < 10; i++) {
// ...
}
Nell'esempio sopra, il blocco di istruzioni viene eseguito 10 volte, con i che varia da 0 a 9.
L'istruzione goto viene utilizzata per trasferire il controllo a un'etichetta specificata all'interno del codice. Tuttavia, l'uso di goto viene generalmente sconsigliato poiché può rendere il flusso del programma difficile da seguire e da comprendere.
Esempio:
goto label;
// ...
// Blocco di codice etichettato
Nell'esempio sopra, l'istruzione goto label; trasferisce il controllo al punto del codice etichettato come label.
L'istruzione if viene utilizzata per eseguire un blocco di codice se una determinata condizione è vera.
Esempio:
int value = 10;
if (value > 5) {
// Codice da eseguire se la condizione è vera
}
Nell'esempio sopra, se value è maggiore di 5, viene eseguito il blocco di codice all'interno dell'istruzione if.
L'istruzione return viene utilizzata per terminare l'esecuzione di una funzione e restituire un valore opzionale al chiamante della funzione.
Esempio:
int sum(int a, int b) {
int result = a + b;
return result; // Restituisce il risultato della somma
}
Nell'esempio sopra, l'istruzione return result; termina l'esecuzione della funzione sum() e restituisce il valore della variabile result al chiamante della funzione.
La struttura switch...case viene utilizzata per eseguire diverse azioni in base al valore di una variabile o di un'espressione.
Esempio:
int choice = 2;
switch (choice) {
case 1:
// Codice da eseguire se choice == 1
break;
case 2:
// Codice da eseguire se choice == 2
break;
default:
// Codice da eseguire se choice non corrisponde a nessun caso
break;
}
Nell'esempio sopra, il controllo viene trasferito al blocco di codice corrispondente al valore di choice. Se choice è 1, viene eseguito il primo blocco di codice. Se choice è 2, viene eseguito il secondo blocco di codice. Se choice non corrisponde a nessun caso, viene eseguito il blocco di codice nel blocco default.
La struttura while viene utilizzata per eseguire un blocco di istruzioni ripetutamente fintanto che una condizione specificata è vera.
Esempio:
int i = 0;
while (i < 10) {
// ...
i++;
}
Nell'esempio sopra, il blocco di istruzioni viene eseguito fintanto che la condizione i < 10 è vera. Dopo ogni esecuzione, la condizione viene valutata e, se è ancora vera, il blocco viene ripetuto.
Le strutture di controllo sono fondamentali per controllare il flusso di esecuzione del programma. Consentono di prendere decisioni, iterare su un blocco di codice o eseguire azioni specifiche in base alle condizioni specificate.
L'operatore & esegue un'operazione di AND bitwise tra due operandi, bit per bit. Restituisce un valore in cui ogni bit di output è 1 solo se i bit corrispondenti di entrambi gli operandi sono 1.
Esempio:
unsigned int a = 5; // 0000 0101
unsigned int b = 3; // 0000 0011
unsigned int result = a & b; // 0000 0001
Nell'esempio sopra, l'operatore & viene utilizzato per eseguire un'operazione di AND bitwise tra a e b, producendo un risultato in cui solo il bit meno significativo è 1.
L'operatore << esegue uno spostamento bit a sinistra sugli operandi, spostando i bit verso sinistra e riempiendo con zeri i bit vuoti a destra. Ogni spostamento di bit a sinistra di una posizione raddoppia il valore.
Esempio:
unsigned int a = 5; // 0000 0101
unsigned int result = a << 2; // 0001 0100
Nell'esempio sopra, l'operatore << sposta i bit di a di due posizioni a sinistra, riempiendo con zeri i bit vuoti a destra.
L'operatore >> esegue uno spostamento bit a destra sugli operandi, spostando i bit verso destra e riempiendo con zeri i bit vuoti a sinistra. Ogni spostamento di bit a destra di una posizione dimezza il valore.
Esempio:
unsigned int a = 16; // 0001 0000
unsigned int result = a >> 2; // 0000 0100
Nell'esempio sopra, l'operatore >> sposta i bit di a di due posizioni a destra, riempiendo con zeri i bit vuoti a sinistra.
L'operatore ^ esegue un'operazione di XOR bitwise tra due operandi, bit per bit. Restituisce un valore in cui ogni bit di output è 1 solo se i bit corrispondenti di entrambi gli operandi sono diversi.
Esempio:
unsigned int a = 5; // 0000 0101
unsigned int b = 3; // 0000 0011
unsigned int result = a ^ b; // 0000 0110
Nell'esempio sopra, l'operatore ^ viene utilizzato per eseguire un'operazione di XOR bitwise tra a e b, producendo un risultato in cui i bit corrispondenti sono 1 solo se sono diversi.
L'operatore | esegue un'operazione di OR bitwise tra due operandi, bit per bit. Restituisce un valore in cui ogni bit di output è 1 se almeno uno dei bit corrispondenti degli operandi è 1.
Esempio:
unsigned int a = 5; // 0000 0101
unsigned int b = 3; // 0000 0011
unsigned int result = a | b; // 0000 0111
Nell'esempio sopra, l'operatore | viene utilizzato per eseguire un'operazione di OR bitwise tra a e b, producendo un risultato in cui i bit corrispondenti sono 1 se almeno uno dei bit è 1.
L'operatore ~ esegue un'operazione di NOT bitwise su un operando, invertendo ogni bit. Restituisce un valore in cui ogni bit è l'inverso del corrispondente bit dell'operando.
Esempio:
unsigned int a = 5; // 0000 0101
unsigned int result = ~a; // 1111 1010
Nell'esempio sopra, l'operatore ~ viene utilizzato per eseguire un'operazione di NOT bitwise su a, invertendo ogni bit.
Gli operatori bitwise sono utilizzati per eseguire operazioni di manipolazione bit a bit su dati numerici. Sono utili per eseguire operazioni avanzate su bit individuali o gruppi di bit all'interno di un valore.
L'operatore != confronta due valori e restituisce true se i valori non sono uguali, altrimenti restituisce false.
Esempio:
int a = 5;
int b = 3;
bool result = (a != b); // true
Nell'esempio sopra, l'operatore != viene utilizzato per confrontare se a è diverso da b. Poiché 5 non è uguale a 3, il risultato è true.
L'operatore < confronta due valori e restituisce true se il primo valore è inferiore al secondo, altrimenti restituisce false.
Esempio:
int a = 5;
int b = 3;
bool result = (a < b); // false
Nell'esempio sopra, l'operatore < viene utilizzato per confrontare se a è minore di b. Poiché 5 non è inferiore a 3, il risultato è false.
L'operatore <= confronta due valori e restituisce true se il primo valore è minore o uguale al secondo, altrimenti restituisce false.
Esempio:
int a = 5;
int b = 3;
bool result = (a <= b); // false
Nell'esempio sopra, l'operatore <= viene utilizzato per confrontare se a è minore o uguale a b. Poiché 5 non è né minore né uguale a 3, il risultato è false.
L'operatore == confronta due valori e restituisce true se i valori sono uguali, altrimenti restituisce false.
Esempio:
nt a = 5;
int b = 3;
bool result = (a == b); // false
Nell'esempio sopra, l'operatore == viene utilizzato per confrontare se a è uguale a b. Poiché 5 non è uguale a 3, il risultato è false.
L'operatore > confronta due valori e restituisce true se il primo valore è maggiore del secondo, altrimenti restituisce false.
Esempio:
int a = 5;
int b = 3;
bool result = (a > b); // true
Nell'esempio sopra, l'operatore > viene utilizzato per confrontare se a è maggiore di b. Poiché 5 è maggiore di 3, il risultato è true.
L'operatore >= confronta due valori e restituisce true se il primo valore è maggiore o uguale al secondo, altrimenti restituisce false.
Esempio:
int a = 5;
int b = 3;
bool result = (a >= b); // true
Nell'esempio sopra, l'operatore >= viene utilizzato per confrontare se a è maggiore o uguale a b. Poiché 5 è maggiore di 3, il risultato è true.
Gli operatori di confronto sono utilizzati per confrontare valori e determinare le relazioni tra di essi. Restituiscono un valore booleano (true o false) in base al risultato del confronto.
La direttiva #define viene utilizzata per definire una costante di pre-processore. Consente di assegnare un nome a un valore costante che può essere utilizzato nel codice per rendere il codice più leggibile e manutenibile.
Esempio:
cpp
Copy code
#define PI 3.14159
Nell'esempio sopra, la direttiva #define definisce la costante PI con il valore 3.14159. Ovunque nel codice in cui viene utilizzato il nome PI, sarà sostituito con il valore 3.14159 durante la fase di pre-processamento.
La direttiva #include viene utilizzata per includere il contenuto di un file di intestazione o di una libreria nel codice sorgente. Permette di utilizzare funzioni e definizioni di dati da file esterni nel programma.
Esempio:
#include <Servo.h>
Nell'esempio sopra, la direttiva #include viene utilizzata per includere il file di intestazione Servo.h, che fornisce la definizione della libreria Servo per il controllo dei servo motori.
/* */ (block comment):
I commenti di blocco sono utilizzati per inserire commenti di lunghezza arbitraria nel codice. Tutti i testo compreso tra /* e */ viene ignorato dal compilatore.
Esempio:
/*
Questo è un commento di blocco.
Può estendersi su più righe.
*/
Nell'esempio sopra, il testo compreso tra /* e */ viene ignorato dal compilatore e non ha alcun effetto sul programma.
// (single line comment):
I commenti su una singola riga vengono utilizzati per inserire commenti brevi o brevi descrizioni all'interno del codice. Il testo che segue // su una riga viene ignorato dal compilatore.
Esempio:
// Questo è un commento su una singola riga
Nell'esempio sopra, il testo che segue // viene ignorato dal compilatore e non ha alcun effetto sul programma.
Il punto e virgola è utilizzato come simbolo di terminazione di un'istruzione. Ogni istruzione nel codice deve essere seguita da un punto e virgola per indicare la fine dell'istruzione.
Esempio:
int a = 5;
Nell'esempio sopra, il punto e virgola viene utilizzato per terminare l'istruzione di assegnazione che definisce la variabile a con il valore 5.
{} (curly braces):
Le parentesi graffe sono utilizzate per delimitare blocchi di codice. Un blocco di codice può contenere una o più istruzioni ed è spesso utilizzato per definire il corpo di una funzione, un loop o una condizione.
Esempio:
void myFunction() {
// Blocco di codice della funzione
// ...
}
Nell'esempio sopra, le parentesi graffe {} vengono utilizzate per delimitare il blocco di codice della funzione myFunction().
Questi elementi di sintassi sono comuni nella programmazione per microcontrollori e aiutano a strutturare e definire il codice in modo chiaro e leggibile.
L'operatore ! esegue un'operazione di negazione logica su un'espressione booleana. Restituisce true se l'espressione è falsa e false se l'espressione è vera.
Esempio:
bool flag = true;
bool result = !flag; // false
Nell'esempio sopra, l'operatore ! viene utilizzato per negare il valore della variabile booleana flag. Poiché flag è true, il risultato della negazione è false.
L'operatore && esegue un'operazione di AND logico tra due espressioni booleane. Restituisce true solo se entrambe le espressioni sono vere, altrimenti restituisce false.
Esempio:
bool a = true;
bool b = false;
bool result = a && b; // false
Nell'esempio sopra, l'operatore && viene utilizzato per eseguire un'operazione di AND logico tra a e b. Poiché a è true ma b è false, il risultato è false.
L'operatore || esegue un'operazione di OR logico tra due espressioni booleane. Restituisce true se almeno una delle due espressioni è vera, altrimenti restituisce false.
Esempio:
bool a = true;
bool b = false;
bool result = a || b; // true
Nell'esempio sopra, l'operatore || viene utilizzato per eseguire un'operazione di OR logico tra a e b. Poiché a è true, il risultato è true anche se b è false.
Gli operatori booleani sono utilizzati per eseguire operazioni logiche sui valori booleani. Consentono di combinare e valutare le condizioni in base a regole logiche.
L'operatore %= esegue un'operazione di resto tra il valore della variabile sinistra e il valore della variabile destra e assegna il risultato alla variabile sinistra.
Esempio:
int a = 10;
int b = 3;
a %= b; // a diventa 1
Nell'esempio sopra, l'operatore %= viene utilizzato per calcolare il resto della divisione tra a e b (10 % 3), e il risultato (1) viene assegnato a a.
L'operatore &= esegue un'operazione di AND bitwise tra il valore della variabile sinistra e il valore della variabile destra, e assegna il risultato alla variabile sinistra.
Esempio:
int a = 5; // 0000 0101
int b = 3; // 0000 0011
a &= b; // a diventa 1 (0000 0001)
Nell'esempio sopra, l'operatore &= viene utilizzato per eseguire un'operazione di AND bitwise tra a e b, e il risultato (1) viene assegnato a a.
L'operatore *= esegue un'operazione di moltiplicazione tra il valore della variabile sinistra e il valore della variabile destra, e assegna il prodotto alla variabile sinistra.
Esempio:
int a = 5;
int b = 3;
a *= b; // a diventa 15
Nell'esempio sopra, l'operatore *= viene utilizzato per moltiplicare a per b (5 * 3), e il risultato (15) viene assegnato a a.
++ (increment):
L'operatore ++ incrementa il valore di una variabile di 1.
Esempio:
int a = 5;
a++; // a diventa 6
Nell'esempio sopra, l'operatore ++ viene utilizzato per incrementare il valore di a di 1.
L'operatore += esegue un'operazione di somma tra il valore della variabile sinistra e il valore della variabile destra, e assegna la somma alla variabile sinistra.
Esempio:
int a = 5;
int b = 3;
a += b; // a diventa 8
Nell'esempio sopra, l'operatore += viene utilizzato per sommare a e b (5 + 3), e il risultato (8) viene assegnato a a.
L'operatore -- decrementa il valore di una variabile di 1.
Esempio:
int a = 5;
a--; // a diventa 4
Nell'esempio sopra, l'operatore -- viene utilizzato per decrementare il valore di a di 1.
L'operatore -= esegue un'operazione di sottrazione tra il valore della variabile sinistra e il valore della variabile destra, e assegna la differenza alla variabile sinistra.
Esempio:
int a = 5;
int b = 3;
a -= b; // a diventa 2
Nell'esempio sopra, l'operatore -= viene utilizzato per sottrarre b da a (5 - 3), e il risultato (2) viene assegnato a a.
L'operatore /= esegue un'operazione di divisione tra il valore della variabile sinistra e il valore della variabile destra, e assegna il quoziente alla variabile sinistra.
Esempio:
int a = 10;
int b = 2;
a /= b; // a diventa 5
Nell'esempio sopra, l'operatore /= viene utilizzato per dividere a per b (10 / 2), e il risultato (5) viene assegnato a a.
L'operatore ^= esegue un'operazione di XOR bitwise tra il valore della variabile sinistra e il valore della variabile destra, e assegna il risultato alla variabile sinistra.
Esempio:
int a = 5; // 0000 0101
int b = 3; // 0000 0011
a ^= b; // a diventa 6 (0000 0110)
Nell'esempio sopra, l'operatore ^= viene utilizzato per eseguire un'operazione di XOR bitwise tra a e b, e il risultato (6) viene assegnato a a.
L'operatore |= esegue un'operazione di OR bitwise tra il valore della variabile sinistra e il valore della variabile destra, e assegna il risultato alla variabile sinistra.
Esempio:
int a = 5; // 0000 0101
int b = 3; // 0000 0011
a |= b; // a diventa 7 (0000 0111)
Nell'esempio sopra, l'operatore |= viene utilizzato per eseguire un'operazione di OR bitwise tra a e b, e il risultato (7) viene assegnato a a.
Gli operatori composti consentono di combinare un'operazione e un'assegnazione in un'unica istruzione, semplificando il codice e rendendolo più conciso.
Ecco un esempio di codice in linguaggio C++ per costruire un orologio utilizzando i componenti menzionati (Arduino Nano, display OLED 1306, pulsante "Set", pulsante "+", pulsante "-", modulo RTC):
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DS3231.h>
// Inizializza il display OLED
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);
// Inizializza il modulo RTC
DS3231 rtc;
// Variabili per l'orario
byte ora, minuti, secondi;
// Variabili per il controllo del setting dell'orario
bool modalitaSetting = false;
bool impostazioneOra = true;
byte valoreImpostato = 0;
// Costanti per le dimensioni del display OLED
const int DISPLAY_WIDTH = 128;
const int DISPLAY_HEIGHT = 64;
void setup() {
// Inizializzazione del modulo RTC
rtc.begin();
// Inizializzazione del display OLED
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.setTextColor(WHITE);
// Imposta la modalità setting iniziale dell'orario
modalitaSetting = true;
impostazioneOra = true;
valoreImpostato = rtc.getHour(h12, PM);
// Imposta il testo iniziale del display
display.setTextSize(2);
display.setCursor(20, DISPLAY_HEIGHT / 2 - 10);
display.print("Setting");
display.display();
}
void loop() {
// Aggiorna l'orario dal modulo RTC
DateTime now = rtc.now();
ora = now.hour();
minuti = now.minute();
secondi = now.second();
// Verifica se il pulsante "Set" è premuto per entrare o uscire dalla modalità setting
if (digitalRead(SET_BUTTON_PIN) == HIGH) {
delay(50); // Debounce del pulsante
if (modalitaSetting) {
// Esci dalla modalità setting
modalitaSetting = false;
impostazioneOra = true;
valoreImpostato = rtc.getHour(h12, PM);
display.clearDisplay();
} else {
// Entra nella modalità setting
modalitaSetting = true;
impostazioneOra = true;
valoreImpostato = rtc.getHour(h12, PM);
display.clearDisplay();
display.setTextSize(2);
display.setCursor(20, DISPLAY_HEIGHT / 2 - 10);
display.print("Setting");
}
display.display();
}
// Verifica se i pulsanti "+" e "-" sono premuti durante la modalità setting
if (modalitaSetting) {
if (digitalRead(PLUS_BUTTON_PIN) == HIGH) {
delay(50); // Debounce del pulsante
incrementaValoreImpostato();
}
if (digitalRead(MINUS_BUTTON_PIN) == HIGH) {
delay(50); // Debounce del pulsante
decrementaValoreImpostato();
}
}
// Imposta l'orario nel modulo RTC se il pulsante "Set" viene premuto durante la modalità setting
if (modalitaSetting && !impostazioneOra && digitalRead(SET_BUTTON_PIN) == HIGH) {
delay(50); // Debounce del pulsante
rtc.setHour(valoreImpostato, h12, PM);
modalitaSetting = false;
display.clearDisplay();
display.setTextSize(2);
display.setCursor(30, DISPLAY_HEIGHT / 2 - 10);
display.print("Saved");
display.display();
delay(1000); // Mostra "Saved" per 1 secondo
display.clearDisplay();
}
// Mostra l'orario sul display OLED
if (!modalitaSetting) {
display.clearDisplay();
display.setTextSize(2);
display.setCursor(20, DISPLAY_HEIGHT / 2 - 10);
display.print(ora);
display.print(":");
if (minuti < 10) {
display.print("0"); // Aggiunge uno zero iniziale per i minuti a una cifra
}
display.print(minuti);
display.display();
}
// Aggiorna il display OLED ogni secondo
delay(1000);
}
// Funzione per incrementare il valore impostato durante la modalità setting
void incrementaValoreImpostato() {
if (impostazioneOra) {
valoreImpostato++;
if (valoreImpostato > 12) {
valoreImpostato = 1;
}
} else {
valoreImpostato++;
if (valoreImpostato > 59) {
valoreImpostato = 0;
}
}
display.clearDisplay();
display.setTextSize(2);
display.setCursor(45, DISPLAY_HEIGHT / 2 - 10);
display.print(valoreImpostato);
display.display();
}
// Funzione per decrementare il valore impostato durante la modalità setting
void decrementaValoreImpostato() {
if (impostazioneOra) {
valoreImpostato--;
if (valoreImpostato == 0) {
valoreImpostato = 12;
}
} else {
valoreImpostato--;
if (valoreImpostato < 0) {
valoreImpostato = 59;
}
}
display.clearDisplay();
display.setTextSize(2);
display.setCursor(45, DISPLAY_HEIGHT / 2 - 10);
display.print(valoreImpostato);
display.display();
}
Questo esempio di codice utilizza le librerie Wire, Adafruit_GFX, Adafruit_SSD1306 e DS3231 per la gestione dei componenti e delle funzionalità dell'orologio. Assicurati di includere le librerie necessarie nel tuo sketch Arduino.
Nota che il codice sopra è un esempio di base e potrebbe richiedere personalizzazioni aggiuntive per adattarlo esattamente al tuo hardware specifico e alle tue esigenze.
Spero che questo esempio di codice ti sia utile per costruire il tuo orologio utilizzando Arduino Nano, display OLED 1306, pulsanti e modulo RTC.
// Definizione dei pin per i componenti
const int LED_PINS[] = {2, 3, 4, 5, 6, 7, 8}; // Pin per i LED
const int BEEPER_PIN = 9; // Pin per il beeper
const int START_BUTTON_PIN = 10; // Pin per il pulsante "Start"
// Variabili per il controllo del dado elettronico
int numero = 0; // Numero attuale visualizzato dal dado
bool lancioInCorso = false; // Flag per indicare se il dado è in fase di lancio
unsigned long tempoInizioLancio; // Tempo di inizio del lancio
unsigned long tempoTrascorso; // Tempo trascorso dal lancio
// Durata totale del lancio (in millisecondi)
const unsigned long DURATA_LANCIO = 5000;
void setup() {
// Inizializzazione dei pin dei LED come output
for (int i = 0; i < 7; i++) {
pinMode(LED_PINS[i], OUTPUT);
}
// Inizializzazione del pin del beeper come output
pinMode(BEEPER_PIN, OUTPUT);
// Inizializzazione del pin del pulsante "Start" come input con pull-up interno
pinMode(START_BUTTON_PIN, INPUT_PULLUP);
}
void loop() {
// Verifica se il pulsante "Start" è premuto per iniziare un nuovo lancio
if (digitalRead(START_BUTTON_PIN) == LOW && !lancioInCorso) {
delay(50); // Debounce del pulsante
// Inizia un nuovo lancio
lancioInCorso = true;
tempoInizioLancio = millis();
// Resetta il numero e accendi tutti i LED
numero = 0;
accendiLED();
// Riproduci un beep breve per indicare l'inizio del lancio
beep(50);
}
// Se il lancio è in corso, aggiorna il numero visualizzato
if (lancioInCorso) {
tempoTrascorso = millis() - tempoInizioLancio;
// Genera casualmente un nuovo numero ogni 100 millisecondi
if (tempoTrascorso % 100 == 0) {
numero = random(1, 7);
accendiLED();
// Riproduci un beep breve per indicare il cambio di numero
beep(50);
}
// Verifica se è trascorso il tempo totale del lancio
if (tempoTrascorso >= DURATA_LANCIO) {
// Ferma il lancio
lancioInCorso = false;
// Riproduci un beep lungo per indicare la fine del lancio
beep(200);
}
}
}
// Funzione per accendere i LED corrispondenti al numero attuale
void accendiLED() {
for (int i = 0; i < 7; i++) {
digitalWrite(LED_PINS[i], i + 1 == numero ? HIGH : LOW);
}
}
// Funzione per riprodurre un beep con la durata specificata
void beep(int durata) {
tone(BEEPER_PIN, 1000, durata);
delay(durata);
noTone(BEEPER_PIN);
}
Questo esempio di codice utilizza i pin corrispondenti ai LED, al beeper e al pulsante "Start" come specificato. Assicurati di collegare correttamente i componenti all'Arduino Nano.
Durante il lancio del dado, i LED verranno accesi e spenti in sequenza casuale, generando un effetto di rotazione. Ad ogni cambio di numero, verrà riprodotto un beep breve per indicare il cambio. Dopo 5 secondi, il dado si fermerà su un numero e verrà riprodotto un beep più lungo per indicare la fine del lancio.
Spero che questo esempio di codice ti sia utile per costruire il tuo dado elettronico utilizzando Arduino Nano, LED, beeper e il pulsante "Start".
***QUESTA È L’ULTIMA PAGINA DEL DOCUMENTO***