Tutorial di Arduino e C++
Per scaricare tutti le spiegazioni e i progetti basta andare sulla pagina principale del progetto, premere sul pulsante verde Code
in alto a destra, e poi su Download ZIP
. Serve poi spacchettare/estrarre i file dalla ZIP così che Arduino riesca ad aprirli correttamente.
I file .ino
sono quelli che si possono aprire con l'Arduino IDE, mentre i file .md
sono quelli con le spiegazioni e si possono aprire con un editor di testo o il Blocco Note.
Spiegazioni
Nei vari file ci sono le spiegazioni dei vari concetti assieme ad esempi. Ci sono poi anche alcuni progetti esemplificativi caricabili sulla scheda di Arduino nelle sottocartelle.
- Conosciamo la scheda: informazioni riguardo alla scheda e ai sensori in dotazione della scuola
- Introduzione_Arduino: scheletro di un programma di Arduino, comandi per gestire i pin, comunicazione base su seriale
- C++ base: commenti, variabili, operazioni, condizioni, cicli in C++ (progetto Arduino allegato: cpp_base.ino)
- Seriale: più funzionalità della seriale, plotter seriale per fare grafici
- C++ funzioni: funzioni e procedure in C++, utili principalmente per sapere cosa succede (progetto Arduino allegato: cpp_funzioni.ino)
Conosciamo la scheda
In laboratorio di informatica sono presenti delle schede Arduino UNO
(grandi classici), ma in dotazione al laboratorio di fisica ci sono anche le schede Arduino Nano 33 BLE Sense
.
Arduino UNO
Questa scheda opera a 5v e non possiede nessun sensore integrato. È l'ideale per interfacciarsi con sensori esterni, in quanto spesso questi sono a 5v. La connessione di pin è più semplice rispetto ad un Nano, in quanto ci sono direttamente sulla scheda i fori in cui inserire i cavi (non serve una breadboard).
Pinout
I pin PWM sono indicati con la tilde ~
.
Su Arduino IDE
Arduino UNO non richiede alcun setup iniziale all'interno di Arduino IDE.
Arduino Nano 33 BLE Sense
Alcune risorse comode per una rapida consultazione:
Questa scheda opera a 3.3v, quindi attenzione a non far andare voltaggi maggiori nei pin. Se un sensore che volete connettere richiede 5v, potrebbe convenirvi usare un Arduino UNO. Parrebbe che questa scheda abbia talvolta problemi a connettersi ai computer, richiedendo di impostare ripetutamente la porta nelle impostazioni di Arduino IDE (l'UNO non ha questo problema invece).
Pinout
- 13 pin digitali + 1 led sulla board (Tx, Rx, D2-D13)
- D2-D13 sono in teoria tutti gestibili con il PWM, ma è meglio controllare, data l'imprecisione nella documentazione
- 8 entrate analogiche (A0-A7, 12 bit, 200 kHz)
I sensori presenti sulla scheda
Questa scheda, a differenza dell'Arduino UNO, ha a bordo vari sensori:
- Accelerometro, Giroscopio, Magnetometro: LSM9DS1
- Microfono: MP34DT05
- Luce, Colore: APDS9960
- Pressione: LPS22HB
- Umidità, Temperatura: HTS221
Installazione della scheda su Arduino IDE
Questa scheda richiede un'installazione all'interno di Arduino IDE prima che possano esserci caricati dei programmi. Bisogna andare in Strumenti -> Scheda -> Gestore schede
, e poi installare il pacchetto chiamato Arduino Mbed OS Nano Boards.
Collegamento al computer
- Collegare l'usb
- All'interno di Arduino IDE impostare la scheda e la porta a cui è connessa dal menù
Strumenti
- La scheda sarà o Arduino Uno, oppure Arduino Nano 33 BLE
- Per verificare se il programma è scritto correttamente si può usare il pulsante "Verifica", mentre per caricare un programma sulla scheda si preme sul pulsante "Carica"
- Non è necessario premere "Verifica" prima di caricare
- La scheda Arduino Nano 33 BLE Sense potrebbe disconnettersi dopo un caricamento, pertanto bisogna riconnettersi selezionando nuvamente la porta nel menù
Strumenti
Introduzione ad Arduino
Struttura di un programma per Arduino
In Arduino la struttura base di un programma è impostata in questo modo:
//inclusione librerie
#include<Wire.h>//libreria di esempio
// Funzione che verrà chiamata automaticamente all'avvio del programma
void setup(){
}
// Funzione che verrà chiamata ripetutamente una volta terminato il setup
void loop(){
}
Scrittura e lettura di pin digitali
Su tutte le schede Arduino ci sono molti pin digitali, e per prima cosa dobbiamo imparare a riconoscerli.
I pin digitali possono essere identificati da un numero, oppure per rendere la sintassi più chiara con una D davanti. Ad esempio D10 è il pin digitale 10. Nella maggior parte dei casi le porte sono numerate correttamente sulla scheda, ma in alcuni casi non è così. Pertanto quando si inizia ad utilizzare una nuova scheda bisogna accertarsi di come vengono identificati i pin.
Inoltre è possibile utilizzare anche i pin di entrata analogica (ad esempio A0) come un pin digitale (dopo una corretta configurazione con pinMode
).
Funzione pinMode
Una volta identificati i pin è necessario configurarli correttamente con: pinMode(pin, modalità);
.
Il parametro "modalità" accetta i seguenti parametri:
OUTPUT
: Semplice modalità di output(3.3V, massimo 15 mA)INPUT
: Semplice modalità di input (di solito i pin in modalità lettura hanno una resistenza nell'ordine dei 100MOhm)INPUT_PULLUP
: 10kOhm. Se è scollegato segna HIGH
Nel caso di pullup o pulldown particolari sarà necessario realizzarli con un circuito esterno.
Funzione digitalWrite
Se è stata impostata la modalità OUTPUT si può scrivere con la funzione digitalWrite(pin, valore)
. Il valore può essere solo HIGH
(3.3V) o LOW
(0.0V).
Funzione digitalRead
Se è stata impostata la modalità INPUT oppure INPUT_PULLUP si può leggere il valore del pin con la funzione digitalRead(pin)
.
In caso il voltaggio sia vicino a 3.3V ritorna HIGH
, altrimenti LOW
.
Se il pin è scollegato, oppure non è possibile campionare correttamente il valore, la funzione restituirà valori randomici. Per evitare questo comportamento esiste INPUT_PULLUP
, che grazie al pullup interno imposta sempre un valore definito correttamente.
Un esempio
void setup(){
// imposto il pin 13 (ovvero il led sulla scheda) in modalità output
pinMode(D13, OUTPUT);
// imposto il pin 13 a high, accendendo il led.
digitalWrite(D13, HIGH);
}
void loop(){
}
Delay
Spesso un programma deve interfacciarsi con persone e/o sensori che non riescono a funzionare a velocità paragonabili al clock del controllore. Ed ecco che arrivano in nostro soccorso le funzioni delay
e delayMicroseconds
della libreria standard di Arduino. Entrambe prendono come parametro la quantità di tempo da attendere, la prima in millisecondi, e la seconda in microsecondi.
void setup(){
pinMode(D13, OUTPUT);
}
void loop() {
digitalWrite(D13, HIGH); // accende il led
delay(500); // aspetta mezzo secondo
digitalWrite(D13, LOW); // spegne il led
delay(500); // aspetta mezzo secondo
}
In generale questo tipo di funzioni sono precise e non causano problemi "strani" su piccoli delay, però se si vuole eseguire del codice con un periodo preciso non sono l'ideale, in quanto l'esecuzione del codice non è istantanea e quindi andrebbe ad aggiungere man mano del ritardo. Quando possibile il programma andrebbe quindi migrato usando le funzioni millis()
e micros()
.
Seriale
Per far parlare il nostro programma con un computer collegato è necessario scrivere sulla seriale. Tutti i controllori hanno della componentistica dedicata, ed è necessario solo imparare la sintassi base per saperli usare.
Funzione Serial.begin
Serial.begin(baud)
serve per inizializzare la connessione: prima di poter usare la seriale dobbiamo decidere un baudrate con cui inviare i dati.
Entrambi i terminali (computer e scheda) devono usare lo stesso baud, e baud più alti significa comunicazioni più veloci. Se a qualcuno interessano maggiori dettagli li può trovare qui. Il baudrate deve essere un baudrate standard, ecco una lista di quelli più comuni:
- 300
- 600
- 1200
- 2400
- 4800
- 9600
- 14400
- 19200
- 28800
- 31250
- 38400
- 57600
- 115200
Funzione Serial.print e println
Serial.print(parametro)
scrive il parametro in seriale. Serial.println(parametro)
dopo aver scritto un valore va a capo.
Esempio di uso della seriale
void setup() {
// apre la comunicazione seriale con baudrate di 9600
Serial.begin(9600);
// scrive "Setup!" e poi va a capo
Serial.println("Setup!");
}
void loop() {
// millis() restituisce il numero di millisecondi dall'inizio del programma
int millisecondi = millis();
// scrive "...ms" ad ogni iterazione di loop(), dove ... è il valore ottenuto qui sopra
Serial.print(millisecondi);
Serial.println("ms");
// aspetta un secondo prima di ripetere
delay(1000);
}
C++ base
Progetto di esempio: cpp_base
Commenti
I commenti servono per aggiungere delle note al codice: non verranno mai eseguiti. Ci sono due formati:
// commento
crea un commento a partire da//
e fino alla fine della linea/* commento */
crea un commento a partire da/*
e fino a*/
Variabili
Le variabili servono per tenere salvati dei dati o dei passi parziali durante l'esecuzione del programma. Ad esempio, per la risoluzione di un'equazione di secondo grado, prima calcoliamo il delta, poi lo scriviamo a parte e infine lo utilizziamo nella formula.
Le variabili esistono solo dal momento in cui le dichiariamo, hanno un tipo e hanno un nome per identificarle. Il tipo può essere, per il momento
- intero:
int
- decimale:
float
// variabile di tipo intero con nome x e valore 0
int x = 6;
// variabile di tipo intero con nome y e valore non impostato
int y;
// variabile di tipo decimale con nome temperatura e valore 19.5
float temperatura = 19.5;
// si può usare Serial.print() anche con le variabili!
// dato che y non ha un valore impostato potrebbe venir scritto un numero a caso
Serial.print("x e' uguale a ");
Serial.print(x);
Serial.print(", y e' uguale a ");
Serial.print(y);
Serial.print(" e la temperatura e' di ");
Serial.print(temperatura);
Serial.println("°C");
Il valore contenuto nelle variabili può essere cambiato durante l'esecuzione usando l'operatore =
. Attenzione: x = y
significa "assegna il valore della variabile y alla variabile x". NON significa che d'ora in poi la variabile x sarà sempre uguale a y!
// si possono dichiarare piu' variabili sulla stessa riga
int z = 0, w = 5;
z = w; // <- z ora contiene il valore 5
w = -7; // <- w ora contiene il valore -7
// scrive sulla seriale le linee "z = 5 - w = -7"
Serial.print("z = ");
Serial.println(z);
Serial.print(" - w = ");
Serial.println(w);
Operazioni
Le operazioni matematiche di base sono disponibili:
x + y
somma-x
opposto di xx - y
differenzax * y
moltiplicazionex / y
divisionex % y
resto della divisione di x per y
Si possono raggrupare le operazioni con le parentesi tonde ()
.
Attenzione: l'operatore ^
non esegue l'elevamento a potenza. Per elevare a potenza puoi scrivere pow(base, esponente)
invece.
int p = 5;
int q = p * p - (p + 7);
Serial.print("p = ");
Serial.print(p);
Serial.print("; q = p^2 - (p+7) = ");
Serial.print(q);
Serial.print("; il resto della divisione di q per 6 e' ");
Serial.println(q % 6);
Questo codice un po' più complicato risolve un'equazione di secondo grado:
float a = 6, b = -5, c = 1; // i coefficienti dell'equazione
float delta = b * b - 4 * a * c; // il delta (viene uguale a 1)
// sqrt(valore) serve per calcolare la radice quadrata
float x1 = (-b + sqrt(delta)) / (2 * a);
float x2 = (-b - sqrt(delta)) / (2 * a);
Serial.print("L'equazione ");
Serial.print(a);
Serial.print("x^2 + ");
Serial.print(b);
Serial.print("x + ");
Serial.print(c);
Serial.print(" = 0 ha come soluzioni x1 = ");
Serial.print(x1);
Serial.print(" e x2 = ");
Serial.println(x2);
Alcune scorciatoie sono elencate qui di seguito:
x += y
equivale ax = x + y
x -= y
equivale ax = x - y
x *= y
equivale ax = x * y
x /= y
equivale ax = x / y
x %= y
equivale ax = x % y
++x
ex++
equivalgono ax = x + 1
ma:int y = ++x
-> y assume il valore di x dopo l'incrementoint y = x++
-> y assume il valore di x prima dell'incremento
--x
ex--
equivalgono ax = x - 1
e si comportano come++x
e `x++
int i = 6;
i += 7; // i ora vale 13
--i; // i ora vale 12
i %= 5; // i ora vale 2
float f = -5.2;
f /= -6.7; // f ora vale 0.776...
Serial.print("i = ");
Serial.print(i);
Serial.print("; f = ");
Serial.println(f);
Condizioni
Talvolta si vuole compiere una scelta e cambiare le operazioni da eseguire in base ad una condizione: ad esempio, se il delta risulta minore di zero in un'equazione di secondo grado si scrive che è impossibile invece di continuare la risoluzione. In C++ questo concetto si esprime con le istruzioni if
ed else
. La sintassi è:
if (condizione) {
// se la condizione e' vera viene eseguito questo codice
} else {
// se la condizione e' falsa viene eseguito quest'altro codice
}
Le parentesi grafe possono essere omesse se si scrive una sola istruzione. Il blocco dell'else
può essere omesso nel caso non si sia interessati ad eseguire del codice quando la condizione è falsa. Nel caso si vogliano controllare più condizioni si può mettere un altro if
direttamente dopo l'else
, in questo modo:
if (condizione1) {
// ...
} else if (condizione2) {
// ...
} else {
// ...
}
Per scrivere le condizioni esistono le seguenti operazioni:
x <= y
,x < y
,x >= y
,x > y
fanno ciò che ci si aspetterebbex == y
restituisce vero sex
è uguale ay
x != y
restituisce vero sex
è diverso day
!a
(NOT) restituisce l'opposto dia
, quindi sea
è vero!a
è falsoa && b
(AND) restituisce vero solo quando siaa
cheb
sono vere, altrimenti restituisce falsoa || b
(OR) restituisce vero quando almeno una traa
eb
è vera, mentre se siaa
cheb
sono false restituisce falso- le parentesi
()
funzionano come con le altre operazioni
Esiste inoltre un tipo bool
per le variabili, che può assumere solo i valori true
e false
e serve per tenere salvato il valore di una condizione, ovvero un valore di verità. I valori bool
possono essere usati direttamente all'interno degli if
al posto della condizione.
Da ricordare che secondo le leggi di De Morgan !(a && b)
è la stessa cosa di (!a) || (!b)
, e !(a || b)
è la stessa cosa di (!a) && (!b)
.
float h = 5.3, k = 7.1;
// variabile di tipo bool per salvare il risultato di una condizione
bool hkSonoUguali = (h == k);
if (h < k) { // condizione tra le parentesi tonde
Serial.println("h e' minore di k");
} else if (hkSonoUguali) { // la condizione e' salvata nella variabile xySonoUguali
Serial.println("h e' uguale a k");
} else {
Serial.println("h e' maggiore di k");
}
Cicli
Talvolta può essere utile eseguire del codice più volte. Per fare ciò esistono i cicli.
for
Il ciclo for
comprende tre elementi:
- inizializzazione: viene eseguita prima di eseguire il ciclo, e serve per dichiarare e inizializzare la variabile da usare per gestire il ciclo
- condizione: viene controllata prima di ogni iterazione; se è vera allora il ciclo continua, altrimenti si interrompe
- incremento: viene eseguito al termine di ogni iterazione, e serve solitamente per incrementare la variabile usata per gestire il ciclo
for (inizializzazione; condizione; incremento) {
// ...
}
Ad esempio, il seguente ciclo scrive i numeri da 0 a 7:
for (int i = 0; i < 8; i++) {
Serial.println(i);
}
while
Talvolta non si ha bisogno di una variabile per gestire il ciclo, come nel caso del for
, ma si vuole semplicemente continuare ad eseguire del codice fintantochè una condizione rimane vera. Per questo esiste il ciclo while
:
while (condizione) {
// ...
}
Ad esempio, il seguente ciclo aspetta finchè non ci sono dei caratteri pronti alla lettura sulla seriale, controllando circa una volta al secondo:
while (Serial.available() <= 0) {
delay(1000); // aspetta un secondo prima di ricontrollare
}
break e continue
Talvolta si ha la necessità di saltare un'iterazione oppure uscire da un ciclo in anticipo. Pertanto esistono i seguenti costrutti:
break
esce dal ciclocontinue
termina l'iterazione corrente
Esempio complessivo
Serial.println("Se a = 5 m/(s^2) e m = 6 kg, quanto vale Ftot?");
bool corretto = false;
for (int tentativi = 0; tentativi < 5; tentativi++) {
int valore = Serial.parseInt();
while (Serial.available()) {
// se assieme al valore l'utente ha scritto anche dell'altro, facciamo in modo che sia tolto tutto
Serial.read();
}
if (valore == 5 * 6) {
corretto = true;
break; // esce dal ciclo
} else {
if (valore <= 0) {
Serial.print("Non ha senso che una forza sia negativa! ");
}
Serial.println("Riprova");
}
}
if (corretto) {
Serial.println("Corretto!");
} else {
Serial.println("Il risultato era 30");
}
Seriale
L'introduzione alla comunicazione seriale è su 01_introduzione_Arduino.
Altri comandi utili
Funzione Serial.available
Se ci sono dei dati nel buffer della seriale, Serial.available()
ritorna il numero di byte in coda nel buffer.
Funzione Serial.read
Serial.read()
ritorna il primo byte dal buffer, rimuovendolo dalla coda. Se non ci sono altri elementi nel buffer ritorna -1;
Un esempio riassuntivo
Ecco un esempio che risponde su seriale qualsiasi cosa riceva.
void setup(){
//apre la seriale con baudrate di 9600
Serial.begin(9600);
}
void loop() {
if (Serial.available() > 0) { // se ho dei caratteri nel buffer della seriale
//leggo il valore, e lo salvo nella variabile tmp
char tmp = Serial.read();
//scrivo il carattere tmp in seriale
Serial.write(tmp);
}
}
Plotter seriale per fare grafici
La seriale si può usare anche per tracciare dei grafici dell'evoluzione di una variabile nel tempo. Questo può essere utile per monitorare l'andamento di un sensore oppure visualizzare delle statistiche.
Se durante l'esecuzione di un programma su Arduino ogni linea della seriale contiene lo stesso numero di valori separati da spazi, quando l'Arduino è connesso al computer è possibile selezionare Strumenti -> Plotter Seriale
nel menù dell'Arduino IDE e visualizzare dei grafici sovrapposti per ogni colonna di valori. Sull'asse x si ha il tempo (o meglio, il numero di linea ricevuta dalla scheda), mentre sull'asse y si hanno i valori assunti dalle varie colonne.
Ad esempio un codice del genere...
void setup() {
Serial.begin(9600);
}
void loop() {
int tempo = millis();
Serial.print(tempo);
Serial.print(" ");
Serial.println(sqrt(tempo));
delay(500); // aspettiamo mezzo secondo prima di ripetere
}
...produrrebbe sulla seriale un output simile al seguente...
12 3.46
512 22.62
1013 31.83
1514 38.91
...
...che quindi produrrebbe due grafici (sovrapposti):
- il primo composto dai punti:
(0, 12)
,(1, 512)
,(2, 1013)
,(3, 1514)
- il secondo composto dai punti:
(0, 3.46)
,(1, 22.62)
,(2, 31.83)
,(3, 38.91)
Le funzioni
Progetto di esempio: cpp_funzioni
Immaginate se un architetto, nel momento in cui gli viene chiesto di costruire una casa, dovesse fare tutto da solo: progettare, comprare i materiali, costruire la struttura, fare l'impianto elettrico, ... Probabilmente impazzirebbe dopo poco, perchè è difficile saper fare bene tutti quei lavori tenendo tutto sotto controllo. Le aziende edili hanno infatti una gerarchia: l'architetto progetta, sulla base del progetto gli operai costruiscono l'edificio, poi arriva l'elettricista, ...
Anche quando si scrive un programma conviene separare le varie funzionalità in diversi "sottoprogrammi" chiamati dal "programma" principale quando serve. Questo rende il codice più leggibile, chiaro e testabile (un esame che verifica che una persona sappia fare il costruttore di case a tuttotondo sarebbe molto più difficile da scrivere di tanti esami più piccoli per le varie mansioni, come operaio o elettricista). Vediamo quindi come ottenere questo risultato con le funzioni di C++.
Sintassi
Quando un architetto viene chiamato dall'azienda edile gli vengono fornite varie informazioni su ciò che deve progettare, e lui dopo aver svolto il suo lavoro restituisce all'azienda il progetto che ha prodotto. Una funzione di un programma funziona nello stesso modo: viene chiamata con una lista di parametri e (di solito) restituisce un risultato. Nell'esempio qui sotto la funzione somma
riceve due parametri interi, x
e y
, e ne restituisce la somma, un'altro intero, grazie all'istruzione return
. La funzione viene scritta all'esterno del main
, e viene poi chiamata nel main
utilizzando le parentesi tonde e mettendo al loro interno i due valori da assegnare ai parametri x
e y
, in questo caso 7
e 10
.
int somma(int x, int y) {
int risultato = x + y;
return risultato;
}
// scrive "La somma e' 17"
Serial.print("La somma e': ");
Serial.println(somma(7, 10));
In generale, quindi, la sintassi è la seguente. Ci possono essere più return
(ad esempio all'interno di un if) e, nel momento in cui viene incontrato un return
l'esecuzione della funzione termina immediatamente e ritorna il valore specificato al chiamante.
tipo_di_ritorno nome_funzione(tipo_parametro_1 nome_parametro_1, tipo_parametro_2 nome_parametro_2, ...) {
// calcola tutto ciò che serve basandosi sui parametri
return /* ... */;
}
La prima linea del codice qui sopra si chiama "segnatura" (signature) della funzione, in quanto contiene le informazioni che permettono di interagire con essa dall'esterno. Infatti, in un altro punto del codice si può chiamare tale funzione in questo modo:
tipo_di_ritorno risultato = nome_funzione(parametro_1, parametro_2, ...);
La variabile "risultato" conterrà quindi il valore di ritorno assunto dalla chiamata alla funzione dopo che essa ha completato la sua esecuzione. Non è davvero necessario salvare tale valore direttamente in una variabile, ma si può in realtà usare come qualsiasi altra espressione, un po' come le funzioni matematiche (ad esempio, all'interno di un if
, oppure in una somma, oppure anche nella chiamata ad un'altra funzione).
Procedure
Quando una funzione non "restituisce" nulla, essa è detta essere una procedura. La sintassi è uguale a quella vista qui sopra, eccetto per il tipo di ritorno, che in questo caso sarà void
, ovvero "nulla".
void saluta(int numeroDiVolte) {
for(int i = 0; i < numeroDiVolte; ++i) {
Serial.println("Ciao!");
}
}
Ovviamente una funzione può ricevere 0 parametri, ad esempio:
void errore() {
Serial.println("C'e' stato un errore");
}
Se si vuole uscire da una procedura prima della fine (ad esempio all'interno di un if
) si può usare return;
senza nessun valore di ritorno.
In Arduino
Si può notare che setup()
e loop()
, le due strutture che devono esserci in ogni programma Arduino, sono delle funzioni, e in particolare delle procedure senza parametri.
Anche pinMode()
, digitalWrite()
e digitalRead()
sono delle funzioni.
Funzioni di oggetti
Per interagire con il seriale, si usano Serial.begin()
, Serial.print()
, ... Anche tali costrutti sono delle chiamate a funzioni. Se si scrivesse solo begin()
e print()
, però, il programma non sarebbe valido: serve infatti anche il Serial.
davanti. Infatti quelle funzioni sono "di proprietà" dell'oggetto Serial
, che appunto si occupa della comunicazione seriale.
Capiterà di applicare funzioni ad un oggetto anche quando si gestiscono dei sensori. Ad esempio, per leggere valori dall'accelerometro integrato nella scheda, si usa la funzione readAcceleration
applicata all'oggetto IMU
("inertial measurement unit"), e si scrive quindi IMU.readAcceleration(x, y, z)
.
Esperienze
Le spiegazioni dei vari sensori, assieme a delle esperienze di laboratorio base già funzionanti, sono i seguenti:
- Ultrasuoni: sensore ad ultrasuoni per misurare distanze (progetto Arduino allegato: ultrasuoni.ino)
- Accelerometro: accelerometro del sensore LSM9DS1 (progetto Arduino allegato: accelerometro.ino)
- Giroscopio: giroscopio del sensore LSM9DS1 (progetto Arduino allegato: giroscopio.ino)
- Magnetometro: magnetometro del sensore LSM9DS1 (progetto Arduino allegato: magnetometro.ino)
- Magnetometro calibrazione: magnetometro con calibrazione (progetto Arduino allegato: magnetometro calibrazione.ino)
Magnetometro esterno: magnetometro del professor Colonna, non in dotazione della scuola (progetto Arduino allegato: magnetometro_esterno.ino)- Barometro: sensore di pressione (progetto Arduino allegato: barometro.ino)
- Colore: sensore di colore e luce (progetto Arduino allegato: colore.ino)
- Momento inerzia: uso del magnetometro per calcolare il momento d'inerzia di un magnete sospeso ad un filo attorcigliato (progetto Arduino allegato: momento_inerzia.ino)
- Temperatura e umidità: uso del sensore esterno di temperatura e umidità DHT11 (progetto Arduino allegato: temperatura_umidita.ino)
Sensore ad ultrasuoni
Progetto di esempio: ultrasuoni
int pin_trig = 9; // pin TRIG (trigger)
int pin_echo = 8; // pin ECHO
void setup() {
// inizializza la seriale su cui inviare i dati
Serial.begin(9600);
// configura il pin TRIG trigger ad output
pinMode(pin_trig, OUTPUT);
// configura in pin ECHO ad input
pinMode(pin_echo, INPUT);
}
void loop() {
// impulso di 10 microsecondi sul pin TRIG
digitalWrite(pin_trig, HIGH);
delayMicroseconds(10);
digitalWrite(pin_trig, LOW);
// Quando il sensore riceve un segnale su TRIG, esegue i seguenti passi, in ordine:
// - trasmette un segnale acustico
// - imposta ECHO ad HIGH
// - attende finche' non riceve il segnale acustico riflesso
// - imposta ECHO a LOW
// La funzione pulseIn serve per misurare per quanto tempo ECHO rimane ad HIGH.
float tempo_microsecondi = pulseIn(pin_echo, HIGH);
// il tempo sara' quello di andata e poi ritorno del suono, quindi per ottenere la
// distanza basta dividere per due e moltiplicare per la velocita del suono
// (che e' di 340.19m/s = 34019cm/s = 0.034019cm/us)
float distanza_centimetri = (tempo_microsecondi / 2) * 0.034019;
// scrive il valore sul monitor seriale
Serial.println(distanza_centimetri);
// aspetta mezzo secondo, per non sparare dati a raffica
delay(500);
}
- Il sensore ad ultrasuoni in dotazione della scuola è il HC-SR04.
- Opera a 5v, pertanto si può connettere solo ad un Arduino Uno (il Nano 33 BLE opera a 3.3v, quindi richiederebbe un convertitore 3.3v-5v).
- Invia segnali acustici a 40kHz, ha un'angolo di misurazione di e ha un range di misurazione tra i e i .
- Il datasheet è accessibile qui (scaricato) o qui (fonte originale).
PIN
- VCC va connesso alla 5v
- GND va connesso alla terra
- TRIG è il pin di innesco, e va connesso ad un pin digitale, su cui poi si farà
pinMode(.., OUTPUT)
- ECHO è il pin di risposta, e va connesso ad un pin digitale, su cui poi si farà
pinMode(.., INPUT)
Tempi
Come spiegato all'interno del codice, il sensore opera così:
- aspetta di ricevere un impulso di 10 microsecondi sul pin TRIG
- emette un segnale acustico a 40kHz
- attiva il pin ECHO
- disattiva il pin ECHO non appena riceve un segnale acustico riflesso
Pertanto misurando il tempo in cui è stato acceso il pin ECHO si può ottenere il tempo trascorso da quando il suono è stato trasmesso a quando è stato ricevuto.
LSM9DS1
- Il modulo inerziale LSM9DS1 è integrato nell'Arduino Nano 33 BLE Sense e pertanto si può usare solo con tale scheda.
- Il datasheet è accessibile qui (scaricato) o qui (fonte originale).
- Per l'uso dei sensori su questa scheda è necessario installare la libreria omonima. Si può fare in due modi:
- Il modo più comodo per perdere meno tempo con gli studenti in laboratorio è copiare i file Arduino_LSM9DS1.h, LSM9DS1.h e LSM9DS1.cpp nella cartella del progetto, quella in cui è presente anche il file .ino. Poi il progetto sarà portabile a tutti i computer senza ulteriore setup necessario. I tre file sono già presenti nei progetti di esempio per accelerometro, giroscopio e magnetometro, quindi basta copiare le relative cartelle e modificarle.
- Altrimenti basta andare in
Strumenti -> Gestione librerie
, cercare "LSM9DS1" ed installare "Arduino_LSM9DS1". Bisognerà però ripetere questa azione su ogni computer su cui si vuole usare il progetto.
- Per interagire con la libreria all'interno del codice bisogna includerla con
#include "Arduino_LSM9DS1.h"
. La documentazione della libreria è disponibile qui. - All'interno del
setup()
, per inizializzare la connessione con il modulo, si usaIMU.begin()
.
Accelerometro
Progetto di esempio: accelerometro
// include la libreria che mette a disposizione l'oggetto IMU
#include "Arduino_LSM9DS1.h"
void setup() {
// inizializza il seriale
Serial.begin(9600);
// inizializza il LSM9DS1
IMU.begin();
}
void loop() {
// le misurazioni sono a 104Hz, quindi piuttosto lente rispetto alla velocità di esecuzione di
// codice dell'Arduino, pertanto bisogna controllare se sono arrivati dei dati prima di leggerli
if (IMU.accelerationAvailable()) {
// crea le variabili x, y e z, inizialmente senza alcun valore
float x, y, z;
// legge l'accelerazione lungo x, y e z nelle tre variabili x, y e z
// (unita' di misura: g)
IMU.readAcceleration(x, y, z);
// scrive sulla seriale una linea contenente i tre valori letti separati da uno spazio, così
// che si possano visualizzare col Plotter Seriale
Serial.print(x);
Serial.print(" ");
Serial.print(y);
Serial.print(" ");
Serial.println(z);
}
}
- Fornisce misurazioni ad una frequenza di 104Hz.
- Riesce a leggere accelerazioni da a , con una precisione di .
- Fornisce i dati nell'unità di misura , cioè rispetto all'accelerazione di gravità.
Più informazioni sull'accelerometro sono disponibili nel tutorial ufficiale di Arduino.
LSM9DS1
- Il modulo inerziale LSM9DS1 è integrato nell'Arduino Nano 33 BLE Sense e pertanto si può usare solo con tale scheda.
- Il datasheet è accessibile qui (scaricato) o qui (fonte originale).
- Per l'uso dei sensori su questa scheda è necessario installare la libreria omonima. Si può fare in due modi:
- Il modo più comodo per perdere meno tempo con gli studenti in laboratorio è copiare i file Arduino_LSM9DS1.h, LSM9DS1.h e LSM9DS1.cpp nella cartella del progetto, quella in cui è presente anche il file .ino. Poi il progetto sarà portabile a tutti i computer senza ulteriore setup necessario. I tre file sono già presenti nei progetti di esempio per accelerometro, giroscopio e magnetometro, quindi basta copiare le relative cartelle e modificarle.
- Altrimenti basta andare in
Strumenti -> Gestione librerie
, cercare "LSM9DS1" ed installare "Arduino_LSM9DS1". Bisognerà però ripetere questa azione su ogni computer su cui si vuole usare il progetto.
- Per interagire con la libreria all'interno del codice bisogna includerla con
#include "Arduino_LSM9DS1.h"
. La documentazione della libreria è disponibile qui. - All'interno del
setup()
, per inizializzare la connessione con il modulo, si usaIMU.begin()
.
Giroscopio
Progetto di esempio: giroscopio
// include la libreria che mette a disposizione l'oggetto IMU
#include "Arduino_LSM9DS1.h"
void setup() {
// inizializza il seriale
Serial.begin(9600);
// inizializza il LSM9DS1
IMU.begin();
}
void loop() {
// le misurazioni sono a 104Hz, quindi piuttosto lente rispetto alla velocità di esecuzione di
// codice dell'Arduino, pertanto bisogna controllare se sono arrivati dei dati prima di leggerli
if (IMU.gyroscopeAvailable()) {
// crea le variabili x, y e z, inizialmente senza alcun valore
float x, y, z;
// legge la velocita' angolare lungo x, y e z nelle tre variabili x, y e z
// (unita' di misura: gradi al secondo)
IMU.readGyroscope(x, y, z);
// scrive sulla seriale una linea contenente i tre valori letti separati da uno spazio, così
// che si possano visualizzare col Plotter Seriale
Serial.print(x);
Serial.print(" ");
Serial.print(y);
Serial.print(" ");
Serial.println(z);
}
}
- Fornisce misurazioni ad una frequenza di 104Hz.
- Riesce a leggere velocità angolari da a , con una precisione di .
- Fornisce i dati nell'unità di misura , ovvero , ovvero gradi al secondo.
Più informazioni sul giroscopio sono disponibili nel tutorial ufficiale di Arduino.
LSM9DS1
- Il modulo inerziale LSM9DS1 è integrato nell'Arduino Nano 33 BLE Sense e pertanto si può usare solo con tale scheda.
- Il datasheet è accessibile qui (scaricato) o qui (fonte originale).
- Per l'uso dei sensori su questa scheda è necessario installare la libreria omonima. Si può fare in due modi:
- Il modo più comodo per perdere meno tempo con gli studenti in laboratorio è copiare i file Arduino_LSM9DS1.h, LSM9DS1.h e LSM9DS1.cpp nella cartella del progetto, quella in cui è presente anche il file .ino. Poi il progetto sarà portabile a tutti i computer senza ulteriore setup necessario. I tre file sono già presenti nei progetti di esempio per accelerometro, giroscopio e magnetometro, quindi basta copiare le relative cartelle e modificarle.
- Altrimenti basta andare in
Strumenti -> Gestione librerie
, cercare "LSM9DS1" ed installare "Arduino_LSM9DS1". Bisognerà però ripetere questa azione su ogni computer su cui si vuole usare il progetto.
- Per interagire con la libreria all'interno del codice bisogna includerla con
#include "Arduino_LSM9DS1.h"
. La documentazione della libreria è disponibile qui. - All'interno del
setup()
, per inizializzare la connessione con il modulo, si usaIMU.begin()
.
Magnetometro
Progetto di esempio: magnetometro
// include la libreria che mette a disposizione l'oggetto IMU
#include "Arduino_LSM9DS1.h"
void setup() {
// inizializza il seriale
Serial.begin(9600);
while (!Serial);
// inizializza il LSM9DS1
IMU.begin();
}
void loop() {
// le misurazioni sono a 20Hz, quindi piuttosto lente rispetto alla velocità di esecuzione di
// codice dell'Arduino, pertanto bisogna controllare se sono arrivati dei dati prima di leggerli
if (IMU.magneticFieldAvailable()) {
// crea le variabili x, y e z, inizialmente senza alcun valore
float x, y, z;
// legge il valore del campo magnetico lungo x, y e z nelle tre variabili x, y e z
// (unita' di misura: uT/microTesla)
IMU.readMagneticField(x, y, z);
// scrive sulla seriale una linea contenente i tre valori letti separati da uno spazio, così
// che si possano visualizzare col Plotter Seriale
Serial.print(x);
Serial.print(" ");
Serial.print(y);
Serial.print(" ");
Serial.println(z);
}
}
- Fornisce misurazioni ad una frequenza di 20Hz.
- Riesce a leggere valori di campo magnetico da a , con una precisione di .
- Fornisce i dati nell'unità di misura , ovvero microTesla.
Nel caso in cui si voglia fare una calibrazione iniziale del magnetometro, così da rimuovere il campo magnetico terrestre ed altre interferenze dalle misurazioni, si può fare riferimento al progetto magnetometro_calibrazione
Più informazioni sul magnetometro sono disponibili nel tutorial ufficiale di Arduino.
LSM9DS1
- Il modulo inerziale LSM9DS1 è integrato nell'Arduino Nano 33 BLE Sense e pertanto si può usare solo con tale scheda.
- Il datasheet è accessibile qui (scaricato) o qui (fonte originale).
- Per l'uso dei sensori su questa scheda è necessario installare la libreria omonima. Si può fare in due modi:
- Il modo più comodo per perdere meno tempo con gli studenti in laboratorio è copiare i file Arduino_LSM9DS1.h, LSM9DS1.h e LSM9DS1.cpp nella cartella del progetto, quella in cui è presente anche il file .ino. Poi il progetto sarà portabile a tutti i computer senza ulteriore setup necessario. I tre file sono già presenti nei tre progetti di esempio per accelerometro, giroscopio e magnetometro.
- Altrimenti basta andare in
Strumenti -> Gestione librerie
, cercare "LSM9DS1" ed installare "Arduino_LSM9DS1". Bisognerà però ripetere questa azione su ogni computer su cui si vuole usare il progetto.
- Per interagire con la libreria all'interno del codice bisogna includerla con
#include "Arduino_LSM9DS1.h"
. La documentazione della libreria è disponibile qui. - All'interno del
setup()
, per inizializzare la connessione con il modulo, si usaIMU.begin()
.
Magnetometro con calibrazione iniziale
Progetto di esempio: magnetometro_calibrazione
// include la libreria che mette a disposizione l'oggetto IMU
#include "Arduino_LSM9DS1.h"
// le variabili che contengono i dati di calibrazione, accessibili sia dal setup() che dal loop()
float mx, my, mz;
// il numero di misurazioni di cui fare la media per ottenere i dati di calibrazione (e' piu'
// comodo riutilizzare una variabile costante invece che scrivere "20" dappertutto)
const int MISURAZIONI_CALIBRAZIONE = 20;
void setup() {
// inizializza il seriale
Serial.begin(9600);
while (!Serial);
// inizializza il LSM9DS1
IMU.begin();
// il codice qui sotto calcola i dati di calibrazione e li salva in mx, my ed mz,
// sulla base della media di MISURAZIONI_CALIBRAZIONE misurazioni iniziali
// inizializza mx, my ed mz a 0, per sicurezza
mx = 0;
my = 0;
mz = 0;
// questo e' un ciclo for: la variabile i, che conta le misure effettuate, inizialmente e' 0;
// prima di ogni iterazione viene controllato se i e' minore di MISURAZIONI_CALIBRAZIONE, e se non
// lo e' si esce dal ciclo
for (int i = 0; i < MISURAZIONI_CALIBRAZIONE; ) {
// le misurazioni sono a 20Hz, quindi piuttosto lente rispetto alla velocità di esecuzione di
// codice dell'Arduino, pertanto bisogna controllare se sono arrivati dei dati prima di leggerli
if (IMU.accelerationAvailable()) {
float x, y, z;
IMU.readMagneticField(x, y, z);
mx = mx + x;
my = my + y;
mz = mz + z;
// quando e' avvenuta una misurazione, incrementa i di 1
i = i + 1;
}
}
// per ottenere la media divide per MISURAZIONI_CALIBRAZIONE
mx = mx / MISURAZIONI_CALIBRAZIONE;
my = my / MISURAZIONI_CALIBRAZIONE;
mz = mz / MISURAZIONI_CALIBRAZIONE;
}
void loop() {
// le misurazioni sono a 20Hz, quindi piuttosto lente rispetto alla velocità di esecuzione di
// codice dell'Arduino, pertanto bisogna controllare se sono arrivati dei dati prima di leggerli
if (IMU.magneticFieldAvailable()) {
// crea le variabili x, y e z, inizialmente senza alcun valore
float x, y, z;
// legge il valore del campo magnetico lungo x, y e z nelle tre variabili x, y e z
// (unita' di misura: uT/microTesla)
IMU.readMagneticField(x, y, z);
// sottrae i valori di calibrazione iniziali per ottenere una misurazione relativa
x = x - mx;
y = y - my;
z = z - mz;
// scrive sulla seriale una linea contenente i tre valori letti separati da uno spazio, così
// che si possano visualizzare col Plotter Seriale
Serial.print(x);
Serial.print(" ");
Serial.print(y);
Serial.print(" ");
Serial.println(z);
}
}
- Fornisce misurazioni ad una frequenza di 20Hz.
- Riesce a leggere valori di campo magnetico da a , con una precisione di .
- Fornisce i dati nell'unità di misura , ovvero microTesla.
Il progetto in questa cartella fa una calibrazione iniziale del magnetometro, così da rimuovere il campo magnetico terrestre ed altre interferenze dalle misurazioni. È quindi una buona idea tenere il sensore fermo durante l'esecuzione del programma, così che i dati di calibrazione restino validi. Se non si vuole questo tipo di calibrazione iniziale, si puo' usare il progetto magnetometro invece.
Più informazioni sul magnetometro sono disponibili nel tutorial ufficiale di Arduino.
KY-024 Linear magnetic Hall sensor - SS49E
- Il sensore KY-024 fornisce due output: uno analogico e uno digitale. I datasheet di questo sensore sono piuttosto confusionari e non contengono dati tecnici: scheda tecnica, manuale.
- L'output analogico proviene dal chip SS49E:
- permette la misurazione del campo magnetico lungo un solo asse
- riesce a leggere valori di campo magnetico anche grandi, da a , ma la precisione è piuttosto carente (se la lettura analogica di Arduino fornisce solo valori da 0 a 1024, allora la precisione massima è di )
- i dati letti da Arduino con
analogRead
saranno invertiti rispetto al campo magnetico, ovvero valori più alti letti corrispondono a valori più bassi del campo magnetico - il datasheet del SS49E è qui
- L'output digitale proviene da un comparatore:
- dice semplicemente se il campo magnetico ha superato uno specifico valore
- tale valore è impostabile girando la vite
Progetto di esempio: magnetometro_esterno
// i pin da cui leggiamo il valore del campo magnetico
int pin_analog = A0; // pin per lettura analogica
int pin_digital = 3; // pin per lettura digitale
void setup ()
{
// inizializza il seriale
Serial.begin(9600);
// abilita i pin alla lettura
pinMode(pin_analog, INPUT);
pinMode(pin_digital, INPUT);
}
void loop ()
{
// i dati di analogRead vanno da 0 a 1023 e coprono il range da 0v a 5v
int letturaAnalogica = analogRead(pin_analog);
// conversione in volt della lettura analogica
float letturaAnalogicaVolt = letturaAnalogica / 1023.0 * 5.0;
// se vogliamo trasformare letturaAnalogicaVolt in Tesla dobbiamo fare riferimento
// al datasheet dell'SS49E (il primo grafico a pagina 3)
float campoMagneticoTesla = (letturaAnalogica - 2.5) * 0.2 / 3;
// la lettura digitale dice solo se il campo magnetico ha superato il threshold
// impostato girando la vite sul sensore
bool letturaDigitale = digitalRead(pin_digital);
// scriviamo il campo magnetico in tesla sulla seriale
Serial.println(campoMagneticoTesla);
// aspettiamo 50ms per non sparare letture troppo velocemente
delay(50);
}
Queste sono le connessioni da fare se si usa un Arduino UNO. Se si usa un altro arduino (ad esempio il Nano 33 BLE) l'importante è collegare il pin analogico in uscita dal sensore ad un pin analogico di Arduino, altrimenti la lettura non potrà essere analogica.
Nel manuale online sono presenti più informazioni.
Utilizzo del sensore barometrico sul nano 33 ble sense
- Il sensore integrato sulla scheda è un LPS22HB.
- Il datasheet è accessibile qui (scaricato) o qui (fonte originale).
- In particolare questo sensore contiene un diaframma, che con il variare della pressione si deforma aumentando/diminuendo la resistenza interna.
La libreria del barometro, BARO.h ci converte già i dati in , e non ci resta che sfruttare i dati per ottenere qualche informazione.
di cui noi conosciamo
- P = pressione
- P0 = pressione al livello del mare
- g = accelerazione di gravità
- M = massa molare aria =
- R =
e ci manca da conoscere solo h, invertendo otteniamo
e questa sarà la formula che faremo calcolare all'arduino nell'esempio.
#include"BARO.h"
#include<math.h>
// importare la libreria dalla cartella locale
void setup() {
//inizializzo la seriale
Serial.begin(9600);
while (!Serial);
if (!BARO.begin()) {
Serial.println("Impossibile connettersi al sensore!");
while (1);
}
}
void loop() {
// leggere il sensore (ritorna la pressione in kPa)
float pressure = BARO.readPressure();
//calcolo l'altitudine dalla pressione
float altitude = -293.15*8.31/(9.81*0.02896)*log(pressure/101.3);
// visualizzo su serial
Serial.print("Altitudine in base alla pressione = ");
Serial.print(altitude);
Serial.println(" m");
// attendo 1 secondo
delay(1000);
}
Utilizzo del sensore di colore GY_31
Con la libreria fornita all'interno di qusta cartella l'inizializzazione e la lettura dei vari parametri viene automatizzata. L'unico compito che spetta all'utilizzatore è di mappare i dati con una scala che abbia senso per come sta usando il sensore. Ad esempio se si usa il sensore al buio, oppure fuori al sole, oppure illuminando con i led sopra la scheda i dati di calibrazione cambiano enormemente.
Per questo motivo consiglio di decidere una modalità di lettura, impostare il programma con quella modalità e scrivere i dati su un plotter seriale. Ora osserviamo come si comporta il sensore quando mettiamo davanti al sensore dei cartoncini di controllo (rosso, blu e verde). E mappiamo con il comando map(value, sx, dx, mappedsx, mappedDx)
.
Ad esempio se vediamo che quando inseriamo un cartoncino nero davanti al sensore il valore sale a 90, e quando invece mettiamo un cartoncino rosso scende a 15, possiamo usare il comando:
map(value, 90, 15, 0, 100)
per fare in modo che quando vede nero ci dia un valore prossimo allo 0, e quando vede del rosso ci dia valori vicini al 100.
#include"GY_31.h"
GY_31 sensore;
void setup() {
/*nella libreria ci sono 2 diversi setup:
setup(s0, s1, s2, s3, out)
setup(s0, s1, s2, s3, out, led) //inizializza anche il pin Led
e leggere i valori con:
read(mod)dove mod può essere RED GREEN BLUE CLEAR
attenzione, il sensore non è calibrato, nel 90% dei casi bisogna calibrare il sensore e rimapparlo con dei valori sensati. sotto vedete dei parametri che dovrebbero andare bene, ma potrebbero non essere perfetti
set_led(mod) come da nome, si decide se accendere o meno i led
*/
//S0, S1, S2, S3, out
sensore.setup(8, 9, 10, 11, 12, 13);
sensore.set_led(HIGH);
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
Serial.print("Rosso: ");
Serial.println(sensore.read(RED)); // dato grezzo
Serial.print("Rosso calibrato: ");
Serial.println(map(sensore.read(RED), 60, 15, 0, 100)); // dato calibrato
/*
stando al datasheet, le calibrazioni corrette sono:
rosso: map(data,60,15,0,100)
blu: map(data,80,11,0,100)
verde: map(data,80,20,0,100)
ma sentitevi liberi di cambiarle a vostro piacimento
*/
}
Uso del sensore esterno di temperatura e umidità DHT11
- Il sensore che ha la scuola si è il DHT11.
- Il datasheet è accessibile qui (scaricato) o qui (fonte originale).
Collegamento PIN su Arduino
L'immagine qui sotto mostra come attaccare i cavi all'arduino. I PIN alle estremità sono per l'alimentazione. L'altro PIN è per i dati, e in questo caso verrà usato il PIN 2 dell'Arduino UNO, ma qualsiasi altro PIN numerato può andare.
Attenzione che le connessioni sul sensore sono fatte in riferimento al sensore direzionato nel modo raffigurato.
Installazione libreria
Per poter leggere le informazioni inviate dal sensore sul PIN dai dati, è necessario usare una libreria.
- andare in
Strumenti -> Gestione librerie
- cercare "DHT sensor library" ed installare "DHT sensor library" di Adafruit (ce ne sono altre ma scegliere proprio quella)
- se compare una finestra di conferma, dire
Install all
- ora la libreria si può includere nei progetti con
#include "DHT.h"
Codice
La linea DHT dht(2, DHT11);
specifica la configurazione del sensore collegato, quindi il 2
va cambiato se abbiamo usato un PIN di arduino diverso per collegare il PIN dati del sensore.
// include la libreria per il sensore DHT11
#include "DHT.h"
// qui si specifica la configurazione del sensore:
// - il primo parametro e' il PIN, in questo caso 2
// (va cambiato in base a dove e' attaccato il pin di dati)
// - il secondo parametro e' il modello del sensore collegato
// (dato che la scuola possiede solo DHT11, non va mai cambiato)
DHT dht(2, DHT11);
void setup() {
// inizializziamo la connessione seriale con il computer
Serial.begin(9600);
// inizializziamo la connessione con il sensore (importante!)
dht.begin();
}
void loop() {
// crea la variable h e ci salva la lettura dell'umidita dal sensore (in %)
float h = dht.readHumidity();
// crea la variabile t e ci salva la lettura della temperatura dal sensore (in °C)
float t = dht.readTemperature();
// Scrive delle linee formattate cosi': UMIDITA TEMPERATURA
// Mettendo due valori separati da spazio su ogni riga potremo
// visualizzarli contemporaneamente aprendo il "Plotter seriale".
Serial.print(h); // scrive h senza andare a capo
Serial.print(" "); // scrive uno spazio dopo h
Serial.println(t); // scrive t e poi va a capo (perche' c'e' il println)
}