Archivi categoria: arduino

Arduino – realizzare un sensore di seduta a pressione con un tubo di gomma

Questa mattina, durante la realizzazione e l’analisi dei problemi per il progetto di PCTO: “misura di sedentarietà delle persone sedute alla scrivania” che stanno realizzando i miei studenti di 3′ Elettronica, è nata l’esigenza di associare un doppio controllo per la valutazione della presenza della persona seduta alla scrivania, un controllo effettuato con PIR HC-SR501 ed un sensore di forza resistivo (FSR) inserito all’interno del cuscino della seduta.

Per evitare l’acquisto di un sensore di forza resistivo e non pesare sulle finanze dei ragazzi le modalità sono tre:

  • richiesta alla scuola
  • compra il Prof.
  • farlo costruire ai ragazzi

l’acquisto da parte della scuola o mia non è un problema, ma la terza soluzione è quella che in questo momento prediligo, perché può essere realizzata in 5 minuti, credo che possa gratificare di più lo studente Maker in erba 🙂 , inoltre ritengo importante che gli allievi assumano la capacità di costruire il sensore perché ne dovranno ottimizzare l’uso, scontrandosi inevitabilmente con una serie di variabili fisiche che dovranno gestire.

Ma come si costruisce il sensore?

E’ indispensabile piccolo tubo cilindrico non trasparente, preferibilmente nero che possa essere compresso e al termine della compressioni ritorni abbastanza velocemente nella sua posizione di riposo. Possiamo ricavare il tubo sguainando un cavo elettrico o cavo di rete, oppure come ho fatto in questo tutorial, prendendo una guaina termorestingente.

Inserire un diodo LED ad un’estremità del cilindro e dalla parte opposta inserire un LDR.
Collegare il sistema nella solita modalità, inserendo in serie al LED un resistore da 220 Ohm e creando un partitore di tensione tra l’LDR e un resistore da 10KOhm, così come indicato nel circuito indicato di seguito.

Come test di funzionamento utilizzare il semplice sketch che trovate di seguito, nei commenti la spiegazione di tutte le parti del codice.

Aprite la Serial Monitor e premete e rilasciate il tubo

1/*
2 * Prof. Michele Maffucci
3 * Data 01.03.2021
4 *
5 * Oggetto: sensore di seduta a pressione
6 *
7*/
8 
9// variabile in cui verrà memorizzato il valore presente sul pin A0
10const int misura = A0;
11 
12// valore restituito dall'analogRead
13int val = 0;
14 
15// pin a cui è connesso il LED del sensore di seduta
16int pinLed = 2;
17 
18// LED che segnala la seduta della persona
19int pinLedAlert = 13;
20 
21void setup() {
22  // Inizializzazione della Serial Monitor
23  Serial.begin(9600);
24 
25  // ledPin è il pin a cui è connesso il LED del sensore di seduta
26  pinMode(pinLed, OUTPUT);
27 
28  // pinLedAlert è il pin a cui è connesso il LED che segnala la seduta della persona
29  pinMode(pinLedAlert, OUTPUT);
30 
31  // Attivazione del LED del sensore di seduta
32  digitalWrite(pinLed, HIGH);
33 
34  // Messaggio di avvio
35  Serial.println("Sistema di rilevazione seduta");
36  Serial.println("-----------------------------");
37  Serial.println("");
38  delay(1000);
39}
40 
41void loop() {
42  // analogRead leggerà il valore su A0 restituendo un valore tra 0 e 1023
43  val = analogRead(misura);
44 
45  // il valore di controllo nell'if deve essere sperimentato in funzione
46  // delle necessità costruttive (ad es. la lunghezza del tubo)
47 
48  // se vero la persona è seduta
49  if (val >= 100) {
50    digitalWrite(pinLedAlert, HIGH);                      // accensione del LED di avviso
51    Serial.println("Persona NON seduta alla scrivania");  // segnalazione di assenza persona
52    Serial.print("Valore letto dal sensore = ");          // Stringa di stampa
53    Serial.println(val);                                  // Valore restituito dall'AnalogRead
54    Serial.println("");                                   // Stampa linea vuota di separazione
55    delay(1000);                                          // Intervallo di 1 secondo tra ogni stampa
56  }
57  else
58  {
59    digitalWrite(pinLedAlert, LOW);                       // spegnimento del LED di avviso
60    Serial.println("Persona seduta alla scrivania");      // segnalazione di presenza persona
61    Serial.print("Valore letto dal sensore = ");          // Stringa di stampa
62    Serial.println(val);                                  // Valore restituito dall'AnalogRead
63    Serial.println("");                                   // Stampa linea vuota di separazione
64    delay(1000);                                          // Intervallo di 1 secondo tra ogni stampa
65  }
66}

Il risultato sulla Serial Monitor è il seguente

Il valore di soglia scelto deve essere ricavato sperimentalmente in funzione della lunghezza e della trasparenza del tubo.

Buon Making a tutti 🙂

Arduino – usare un PIR HC-SR501

Noto spesso nei progetti dei miei studenti il divertimento che nasce nell’utilizzo di un sensore ad infrarossi passivo che viene utilizzato per realizzare dei semplici dispositivi antintrusione, attualmente alcuni allievi li stanno utilizzando in due diversi progetti:

  • all’interno del kit EduRobot Home in cui il PIR HC-SR501 viene utilizzato come sensore di rilevamento per realizzare un antifurto
  • attività di PCTO in cui i ragazzi devono implementare un misuratore di sedentarietà, la rilevazione dell’essere umano davanti la computer avviene mediante un PIR.

Questa tipologia di sensore è molto diffuso, li utilizziamo ogni giorno: antifurto di casa, interruttori automatici di luci e molto altro in generale in tutti quei sistemi in cui è indispensabile attivare un’azione nel caso in cui venga rilevata la presenza di un essere umano o di un animale.

Come funziona il sensore di movimento PIR?

Come sicuramente saprete tutti gli oggetti con una temperatura superiore allo zero assoluto (0 Kelvin / -273,15 ° C) emettono energia termica sotto forma di radiazione infrarossa, inclusi i corpi umani. Più un oggetto è caldo, più radiazioni emette.

Il sensore PIR è appositamente progettato per rilevare tali livelli di radiazione infrarossa, è in grado di percepire oggetti caldi in movimento con uno lunghezza d’onda compreso tra i 700 nm e 1 mm . Nel caso della rilevazione di esseri umani la lunghezza d’onda da rilevare è compresa tra 8-14 micrometri.

Il mercato offre diverse tipologie di PIR in funzione del campo di impiego, i più comuni, quelli a lente di Fresnel hanno un range tra i 10 m e i 12 m con un campo di visivo di 300°. E’ possibile trovare sul mercato PIR con un campo visivo che raggiunge i 360° e distanze dell’oggetto rilevato fino a 30 m.

Il PIR fondamentalmente si compone di due parti principali: un sensore piroelettrico e una lente speciale chiamata lente di Fresnel che focalizza i segnali a infrarossi sul sensore piroelettrico.

Un sensore piroelettrico è dotato di due fessure rettangolari al suo interno fatte di un materiale che permette il passaggio della radiazione infrarossa, ciò che verrà rilevato dal sensore sarà la variazione della quantità di raggi infrarossi causata ad esempio dal passaggio di un essere umano e non la quantità di infrarossi totale dell’ambiente.
Le due fessure sono da considerare come due finestre che verranno colpite dai raggi infrarossi e se attraverso le due fessure viene rilevata la stessa quantità di infrarosso allora il segnale risultante di uscita sarà pari a zero, ovvero corpo non rilevato.
Quando però davanti al sensore passa un corpo caldo, come un essere umano, attraverso una finestra verrà rilevata una certa quantità di infrarosso che causerà una differenza di potenziale positiva tra le due finestra, quando il corpo caldo lascia l’area di rilevamento, avviene il contrario, per cui il sensore genera una variazione differenziale negativa. L’impulso di segnali corrispondente fa sì che il sensore imposti il pin di uscita alto, indicandoci quindi la presenza di una persona.

Il sensore HC-SR501, trattandosi di un sensore molto economico, possiede caratteristiche  limitate rispetto a quelli che potremo utilizzare per scopi civili o industriali, ma il loro principio di funzionamento è il medesimo.

Analizziamo la scheda

Pinout

Caratteristiche tecniche

  • Tensione continua di lavoro compresa tra i 4,5V e i 20V
  • Livelli di tensione di uscita: 3,3V HIGH – 0V LOW
  • Massimo angolo di visione 110°
  • Distanza rilevata compresa tra i 3 m e i 7 m

Sulla scheda sono presenti i due trimmer

  • PIR Range Adjustment (Sensibilità)
    Ruotando in senso orario si avrà una diminuzione della sensibilità con decremento della distanza di rilevamento, a fine corsa si avranno approssimativamente una sensibilità di 3 metri.
    Ruotando in senso antiorario aumentiamo la sensibilità per raggiungere approssimativamente 7 m.
  • Time Delay Adjustment (Tempo di delay)
    determina la quantità di tempo in cui l’output del sensore PIR rimarrà alto dopo il rilevamento del movimento. L’intervallo è compreso tra circa 3 secondi e 5 minuti. Girando in senso orario, a fine corsa si avrà un delay di 5 minuti, ruotando in senso antiorario, a fine corsa si otterrà un delay di circa 3 secondi.

Si ricordi che impostato il tempo di delay, ad esempio a 5 secondi, ciò comporterà che se viene rilevato il passaggio di un essere umano l’uscita del sensore sarà alta per 5 secondi e in questi 5 secondi il sensore è bloccato, cioè non sarà in grado di rilevare altri movimenti causati da altri corpi.

IMPORTANTE
Dopo il completamento del Time Delay  l’uscita sarà a LOW (off)  per circa 3 secondi , ciò vuol dire che in questi 3 secondi non verrà rilevato nulla dal sensore.

Sulla scheda è presente un jumper che ha la seguente funzionalità:

Con questo Jumper è possibile impostare le seguenti modalità:

Single Trigger Mode
Il Time Delay viene avviato immediatamente al rilevamento del movimento e il rilevamento continuo viene bloccato.
Questo vuol dire che se ad esempio viene impostato un Time Delay di 5 secondi, al rilevamento di una persona l’uscita passa ad HIGH, se nei 5 secondi passano davanti al sensore un’altra persone questa non viene rilevata e non viene aggiunto un’ulteriore Time Delay.

Immaginate di essere in modalità Single Trigger Mode con un Time Delay di 5 secondi.

  • Il PIR rileverà il movimento e lo imposterà ad HIGH per 5 secondi.
  • Dopo cinque secondi il PIR imposta la sua uscita bassa per circa 3 secondi.
  • Durante i tre secondi, il PIR non rileverà il movimento.
  • Dopo tre secondi di di LOW, il PIR è abilitato nuovamente al rilevamento di movimenti, al passaggio di una persona verrà impostata nuovamente l’uscita alta per il Time Delay impostato.

Repetable Trigger
Ogni movimento rilevato ripristina il Time Delay, pertanto il Time Delay inizia con l’ultimo movimento rilevato.
Questo vuol dire che se ad esempio viene impostato un Time Delay di 5 secondi, al rilevamento di una persona l’uscita passa ad HIGH se nei 5 secondi viene rilevato il passaggio di un’altra persona il Time Delay riparte nuovamente. Quindi supponendo che:

  • Persona 1 passa davanti al PIR, parte il Time Delay
  • Persona 2 passa davanti al PIR al secondo 3, se non passa nessuna persona il Time Delay cesserà ad 8 secondi ed il sensore potrà leggere nuovamente il passaggio di una persona al secondo 11.

IMPORTANTE

Prima di progettare un sistema in cui sono presenti dei PIR ricordare che questi sensori richiedono un po’ di tempo prima di adattarsi alla quantità di energia infrarossa presente nella stanza in cui vengono inseriti, per l’HC-SR501 sono necessari dai 30 ai 60 secondi da quando il sensore viene alimentato.
Ricordare inoltre che il sensore ha un periodo di reset che può oscillare dai 3 ai 6 secondi dopo aver effettuato la lettura, durante tale periodo non verrà rilevato nessun movimento.

Esempio 01
Lettura dello stato del PIR e relativa accensione del LED 13

Schema di collegamento

Il codice per l’utilizzo del sensore è estremamente semplice, è necessario solamente rilevare se il pin OUT si trova a valore alto o basso. Il funzionamento è dettagliato nei commenti.

1/*
2 * Prof. Michele Maffucci
3 * data: 28.02.2021
4 *
5 * Esempio 01
6 * Utilizzo del sensore PIR: PIR HC-SR501
7 * Lettura dello stato del PIR e relativa accensione
8 * del LED 13
9 *
10 */
11  
12byte pinLed = 13;   // pin a cui è collegato il LED
13byte pinInput = 8;  // pin di input a cui è collegato l'OUT del PIR
14bool valPIR = 0;    // variabile utilizzata per memorizzre lo stato del PIR
15  
16void setup() {
17  pinMode(pinLed, OUTPUT);    // pin a cui è collegato il LED è un output
18  pinMode(pinInput, INPUT);   // pin a cui è collegato il PIR è un input
19  
20  Serial.begin(9600);
21}
22 
23void loop() {
24  valPIR = digitalRead(pinInput);  // viene letto il valore restituito dal PIR
25  digitalWrite(pinLed, valPIR);    // il LED sulla scheda verrà acceso se viene
26                                   // rilevata una persona altrimenti il LED
27                                   // resterà spento. valPIR assume i valori 0 o 1
28 }

Esempio 02
Lettura dello stato del PIR e relativa accensione del LED 13 e stampa dello stato sulla Serial Monitor

1/*
2 * Prof. Michele Maffucci
3 * data: 28.02.2021
4 *
5 * Esempio 02
6 * Utilizzo del sensore PIR: PIR HC-SR501
7 * Lettura dello stato del PIR e relativa accensione
8 * del LED 13 e stampa dello stato sulla Serial Monitor
9 */
10  
11byte pinLed = 13;   // pin a cui è collegato il LED
12byte pinInput = 8;  // pin di input a cui è collegato l'OUT del PIR
13bool valPIR = 0;    // variabile utilizzata per memorizzre lo stato del PIR
14  
15void setup() {
16  pinMode(pinLed, OUTPUT);    // pin a cui è collegato il LED è un output
17  pinMode(pinInput, INPUT);   // pin a cui è collegato il PIR è un input
18  
19  Serial.begin(9600);
20}
21 
22void loop() {
23  valPIR = digitalRead(pinInput);  // viene letto il valore restituito dal PIR
24  Serial.println(valPIR);          // stampa sulla Serial Monitor il valore letto
25  delay(150);                      // ritardo per rallentare la frequenza di stampa
26                                   // sulla Serial Monitor
27 
28  // Viene controllato se il PIR rileva una persona
29  // Nota: scrivere "if (valPIR)" è analogo che scrivere
30  // "if (valPIR == HIGH)" in quanto valPIR assume i valori 0 o 1
31   
32  if (valPIR) {
33    digitalWrite(pinLed, HIGH);
34    Serial.println("Rilevata una persona");
35  }
36  else
37  {
38    digitalWrite(pinLed, LOW);
39    Serial.println("Non è presente nessuno");
40  }
41 }

Esercizio 01

Realizzare un semplice sistema di allarme costituito dal sensore PIR, un buzzer e due LED uno rosso ed uno verde.

  • Se il PIR non rileva nessuna persona il LED verde risulta acceso, il LED rosso spento ed il buzzer non emette nessun suono.
  • Se il PIR rileva una persona il LED verde risulta spento, il LED rosso acceso ed il buzzer emette un suono.

Esercizio 02

Realizzare le medesime funzionalità dell’esercizio 01 ed aggiungere un display I2C su cui inviare l’output:

  • Allarme
  • No presenza

Buon Making a tutti 🙂

Arduino – Sensore di temperatura digitale DS18B20 utilizzo in modalità singola

Nelle attività di laboratorio di Sistemi e TPSEE usiamo molto spesso il sensore di temperatura TMP36, ma un’alternativa interessante al TPM36 è il sensore temperatura digitale DS18B20 utilizzato in modalità diversa dal TPM36.
Questo tipo di sensore è adatto per misure di temperatura ambiente, ma anche del terreno o per rilevare temperature nei liquidi.
Il sensore di solito è disponibile in due form factor, uno che viene fornito nel package TO-92, forma ampiamente utilizzato per i  transistor, mentre un’altro, quello utilizzato da me è inserito all’interno di una sonda impermeabile a forma di siluro, utilissimo quando si ha la necessità di misurare temperature sottoterra, sott’acqua, o lontane dal microcontrollore.

Particolarmente utile inoltre in queste settimane in cui i miei studenti di 4′ automazione stanno realizzando come progetto di PCTO una serra idroponica in cui è essenziale misurare la temperatura dell’acqua del sistema.

Il DS18B20 è abbastanza preciso può misurare temperature da -55 ° C a + 125 ° C con una precisione di ± 0,5 ° C.

Il sensore si basa sul protocollo OneWire introdotto da Dallas Semiconductor ora Maxim e richiede due librerie. La prima è la libreria e la DallasTemperature di Miles Burton, la seconda è la libreria OneWire.
La prima libreria da installare è la DallasTemperature di Miles Burton. Sono disponibili diverse librerie con il nome OneWire, quella che vi consiglio di utilizzare è la Wire Library di Jim Studt, Tom Pollard e altri.

Noterete comunque che durante l’installazione della libreria DallasTemperature vi verrà chiesto in automatico se volete installare anche la OneWire, procedete installando in automatico entrambe le librerie. Leggete attentamente le fasi descritte di seguito in cui riporto tutte le schermate delle fasi di installazione.

Il collegamento è estremamente semplice, come indicato nell’immagine che segue collegate il cavo rosso a 5V o a 3,3V su schede a 3,3V, il cavo nero va connesso al GND e il cavo del segnale “Out”, in genere di colore giallo, bianco o di altro colore, collegatelo ad un pin digitale, nell’esempio viene connesso al pin 2 con una resistenza da 4,7 K Ohm tra il segnale e il pin di alimentazione (5 V o 3,3 V).

Pinout

GND: collegamento al ground
Out: Bus Dati 1-Wire, deve essere collegato a un pin digitale sul microcontrollore.
Vdd: da collegare alla tensione di alimentazione (3,3 – 5 V)

Per tutti i dati tecnici del sensore vi rimando al datasheet.

Schema di collegamento

Circuito – sensore con package TO-92

Circuito – sonda impermeabile

Installazione delle librerie

Il protocollo Dallas OneWire è piuttosto complesso e per nascondere questa complessità installeremo  la libreria DallasTemperature.h in modo da poter impartire semplici comandi per ottenere letture di temperatura dal sensore.

Per installare la libreria, Sketch > Include Library > Manage Libraries

Inserite nel campo di ricerca: ds18b20. Dovrebbero esserci un paio di voci. Tra le varie possibilità selezionate, quella indicata nell’immagine

Il sensore per poter comunicare ha necessità anche della libreria OneWire, libreria che non è specifica per questo sensore, ma viene utilizzata con tutti i dispositivi che utilizzano il protocollo One Wire.

Nel momento in cui installate la prima libreria della Dallas Semiconductor viene chiesto con una finestra aggiuntiva se volete installare anche la libreria OneWire fate click su Install all.

Nel caso in cui avete dimenticato di installare la libreria OneWire potrete cercare sempre attraverso il Manage Libraries inserendo nel campo di ricerca

Esempio 01

Stampa della temperatura rilevata in gradi Celsius.
Il funzionamento del codice è dettagliato nei commenti.

1/*
2 *  Prof. Maffucci Michele
3 *  data: 24.02.2021
4 *  Utilizzo del sensore di temperatura
5 *  resistente all'acqua DS18B20
6 
7 *  Sketch 01: stampa delle temperature rilevate
8 *  in gradi Celsius
9*/
10 
11// librerie per il funzionamento del sensore
12#include <OneWire.h>
13#include <DallasTemperature.h>
14 
15#define ONE_WIRE_BUS 2 // Pin Arduino a cui colleghiamo il pin DQ del sensore
16const int pinLed = LED_BUILTIN; // Utilizzo del LED su scheda
17 
18const int soglia = 25; // Accende il LED su scheda se si superano i 25°C
19 
20OneWire oneWire(ONE_WIRE_BUS); // Imposta la connessione OneWire
21 
22DallasTemperature sensore(&oneWire); // Dichiarazione dell'oggetto sensore
23 
24void setup(void)
25{
26  Serial.begin(9600);       // Inizializzazione della serial monitor
27  sensore.begin();          // Inizializzazione del sensore
28  pinMode(pinLed, OUTPUT);  // pinLed definito come OUTPUT
29 
30  // Stampa del messaggio di avvio
31  Serial.println("Temperatura rilevata dal sensore DS18B20");
32  Serial.println("----------------------------------------");
33  delay(1000);
34}
35 
36void loop()
37{
38  sensore.requestTemperatures(); // richiesta lettura temperatura
39   
40  // Restituzione della temperatura letta
41  // in gradi Celsius
42 
43  // temperatura in Celsius
44  float celsius = sensore.getTempCByIndex(0);
45   
46  // Visualizzazione delle letture
47  // della temperatura sulla Serial monitor
48   
49  Serial.print("C:");
50  Serial.println(celsius);
51 
52  // se la temperatura è oltre la soglia
53  // viene accesso il LED su scheda
54  // altrimenti rimane spento
55   
56  if (celsius > soglia) {
57    digitalWrite(pinLed, HIGH);
58  } else {
59    digitalWrite(pinLed, LOW);
60  }
61  // stampe delle temperature ogni secondo
62  delay(1000);
63}

All’interno del loop, lo sketch richiede una lettura della temperatura, quindi legge la temperatura in Celsius. Notare che non è necessario eseguire alcuna conversione aritmetica su
i risultati ottenuti dal sensore, tutto viene gestito dalla libreria. Tenete in conto che non è necessario apportare modifiche al codice, ma assicurati di cablare correttamente l’alimentazione del sensore, 3,3 V su schede che funzionano a questa tensione di riferimento o a 5V per schede che funzionano a 5V.

Esempio 02

Stampa della temperatura rilevata in gradi Celsius e Fahrenheit
Il funzionamento del codice è dettagliato nei commenti.

1/*
2 *  Prof. Maffucci Michele
3 *  data: 24.02.2021
4 *  Utilizzo del sensore di temperatura
5 *  resistente all'acqua DS18B20
6 
7 *  Sketch 02: stampa delle temperature rilevate
8 *  in gradi Celsius e gradi Fahrenheit
9*/
10 
11// librerie per il funzionamento del sensore
12#include <OneWire.h>
13#include <DallasTemperature.h>
14 
15#define ONE_WIRE_BUS 2 // Pin Arduino a cui colleghiamo il pin DQ del sensore
16const int pinLed = LED_BUILTIN; // Utilizzo del LED su scheda
17 
18const int soglia = 25; // Accende il LED su scheda se si superano i 25°C
19// La soglia di 25°C corrisponde a 77 °F
20// Formula di conversione (Tc°C × 9/5) + 32 = Tf°F
21// dove:
22// Tc: temperatura in gradi Celsius
23// Tf: temperatura in gradi Fahrenheit
24 
25OneWire oneWire(ONE_WIRE_BUS); // Imposta la connessione OneWire
26 
27DallasTemperature sensore(&oneWire); // Dichiarazione dell'oggetto sensore
28 
29void setup(void)
30{
31  Serial.begin(9600);       // Inizializzazione della serial monitor
32  sensore.begin();          // Inizializzazione del sensore
33  pinMode(pinLed, OUTPUT);  // pinLed definito come OUTPUT
34 
35  // Stampa del messaggio di avvio
36  Serial.println("Temperatura rilevata dal sensore DS18B20");
37  Serial.println("----------------------------------------");
38  delay(1000);
39}
40 
41void loop()
42{
43  sensore.requestTemperatures(); // richiesta lettura temperatura
44   
45  // Restituzione della temperatura letta
46  // in gradi Celsius e gradi Fahrenheit
47 
48  // temperatura in Celsius
49  float celsius = sensore.getTempCByIndex(0);
50 
51  // temperatura in Fahrenheit
52  float fahrenheit = sensore.getTempFByIndex(0);
53   
54  // Visualizzazione delle letture
55  // della temperatura sulla Serial monitor
56   
57  Serial.print("C:");
58  Serial.print(celsius);
59  Serial.print(",");
60  Serial.print(" F:");
61  Serial.println(fahrenheit);
62 
63  // se la temperatura è oltre la soglia
64  // viene accesso il LED su scheda
65  // altrimenti rimane spento
66   
67  if (celsius > soglia) {
68    digitalWrite(pinLed, HIGH);
69  } else {
70    digitalWrite(pinLed, LOW);
71  }
72  // stampe delle temperature ogni secondo
73  delay(1000);
74}

Il codice è molto simile al precedente, all’interno del loop, lo sketch richiede una lettura della temperatura, quindi legge la temperatura in Celsius, poi Fahrenheit.

Sono disponibili alcune utili funzioni che possono essere usate con l’oggetto DallasTemperature di seguito il dettaglio di alcune di esse:

La funzione setResolution() function imposta la risoluzione del convertitore Analogico-Digitale del DS18B20 a 9, 10, 11, or 12-bit, che corrispondono ad incrementi di  0.5°C, 0.25°C, 0.125°C e  0.0625°C.

La funzione setHighAlarmTemp() e setLowAlarmTemp () imposta gli allarmi interni di alta e bassa temperatura in gradi Celsius. L’intervallo valido è compreso tra -55 e 125 ° C

La funzione bool hasAlarm () restituisce true se il sensore rileva una condizione di superamento dei limiti minimo o massimo di temperatura.

Esercizio 1

  • Rilevare ogni 2 secondi 10 misurazioni, memorizzare questi valori in un Array
  • Visualizzare la temperatura minima, media e massima ogni 10 secondi su un display 16×2 I2C
  • Se la temperatura scende sotto il valore minimo o supera il valore massimo impostati viene emesso un allarme (messaggio su display, emissione di un suono, accensione di un LED rosso per il superamento del valore massimo, azzurro se la temperatura scende al di sotto del valore minimo impostato)

Esercizio 2

Realizzare le medesime funzionalità dell’esercizio precedente aggiungendo:

  • Ridurre la luminosità del display dopo 15 secondi di funzionamento
  • Alla pressione di un pulsante viene attivata la retroilluminazione del display
  • Se viene attivato un allarme si attiva la retroilluminazione

Nella prossima lezione vedremo come collegare sullo stesso bus più sensori DS18B20.

Buon Coding a tutti 🙂

Errori comuni nell’uso di Arduino – ordine esecuzione operazioni matematiche e overflow nei calcoli


In realtà l’errore che viene commesso non è di carattere informatico, ma puramente matematico, dimenticando l’ordine con cui vengono eseguite le operazioni matematiche.
L’ordine delle operazioni segue le regole di base: moltiplicazioni e divisioni hanno precedenza massima seguono addizioni e sottrazioni. Se si vuole cambiare l’ordine di precedenza bisogna utilizzare le parentesi. Vediamo alcuni esempi.

1int valore = 1 + 2 * 3 + 4;

il risultato sarà 11.

1// Prof. Michele Maffucci
2// Data: 08.02.2020
3// Esempio 01: Ordine di esecuzione operazioni matematiche in C
4 
5// per stampare una sola volta il messaggio sulla Serial Monitor 
6bool abilitaMessaggio = 0;
7 
8void setup() {
9  // inizializzazione della comunicazione seriale
10  Serial.begin(9600);
11}
12 
13void loop() {
14  // consente di visualizzare sulla Serial Monitor
15  // una sola stampa delle stringa
16  if (abilitaMessaggio == 0) {
17    // ritardo che evita la doppia stampa del messaggio
18    delay(200);
19    Serial.println("Calcolo:");
20    Serial.println("valore = 1 + 2 * 3 + 4");
21    int valore = 1 + 2 * 3 + 4;
22    Serial.print("valore = ");
23    Serial.println(valore);
24    abilitaMessaggio = 1;
25  }
26}

Per rendere più evidente la sequenza di esecuzione del calcolo possiamo usare le parentesi, pertanto otterremo:

1int valore = 1 + (2 * 3) + 4;

Che fornisce sempre il valore 11.

1// Prof. Michele Maffucci
2// Data: 08.02.2020
3// Esempio 02: Ordine di esecuzione operazioni matematiche in C
4 
5// per stampare una sola volta il messaggio sulla Serial Monitor 
6bool abilitaMessaggio = 0;
7 
8void setup() {
9  // inizializzazione della comunicazione seriale
10  Serial.begin(9600);
11}
12 
13void loop() {
14  // consente di visualizzare sulla Serial Monitor
15  // una sola stampa delle stringa
16  if (abilitaMessaggio == 0) {
17    // ritardo che evita la doppia stampa del messaggio
18    delay(200);
19    Serial.println("Calcolo:");
20    Serial.println("valore = 1 + (2 * 3) + 4");
21    int valore = 1 + (2 * 3) + 4;
22    Serial.print("valore = ");
23    Serial.println(valore);
24    abilitaMessaggio = 1;
25  }
26}

Per modificare la precedenza utilizziamo le parentesi:

1int valore = ((1 + 2) * 3) + 4;

il risultato sarà 13. Viene eseguito prima il calcolo della parentesi più interna (1+2), poi si passa alla parentesi immediatamente successiva, quindi (3 * 3) e poi il risultato viene sommato a 4.

1// Prof. Michele Maffucci
2// Data: 08.02.2020
3// Esempio 03: Ordine di esecuzione operazioni matematiche in C
4 
5// per stampare una sola volta il messaggio sulla Serial Monitor 
6bool abilitaMessaggio = 0;
7 
8void setup() {
9  // inizializzazione della comunicazione seriale
10  Serial.begin(9600);
11}
12 
13void loop() {
14  // consente di visualizzare sulla Serial Monitor
15  // una sola stampa delle stringa
16  if (abilitaMessaggio == 0) {
17    // ritardo che evita la doppia stampa del messaggio
18    delay(200);
19    Serial.println("Calcolo:");
20    Serial.println("valore = ((1 + 2) * 3) + 4");
21    int valore = ((1 + 2) * 3) + 4;
22    Serial.print("valore = ");
23    Serial.println(valore);
24    abilitaMessaggio = 1;
25  }
26}

Ovviamente, come già spiegato precedentemente, bisognerà sempre fare attenzione che il risultato faccia parte del tipo di dati giusto, ad esempio quando effettuate una divisione tra interi il cui risultato è un numero decimale, o ancora se superate il valore massimo del tipo di dato che state utilizzando. In entrambi i casi il compilatore non vi segnalerà nessun errore.

Vediamo un esempio:

1// 60 secondi in un minuto, 60 minuti in un'ora, 24 ore in un giorno
2long secondi_in_un_giorno = 60 * 60 * 24;

In teoria, poiché il risultato è 86.400, questo valore potrà essere contenuto in un tipo long.
Ma in realtà il valore realmente memorizzato in “secondi_in_un_giorno” è 20.864.
86.400  supera più di due volte la dimensione di un intero, il calcolo fatto dal compilatore sarà il seguente:
86.400 – 32.768 * 2 = 20.864

1// Prof. Michele Maffucci
2// Data: 08.02.2020
3// Esempio 04: Ordine di esecuzione operazioni matematiche in C
4//             errore di calcolo dovute al tipo del dato (dimensione massima).
5 
6// per stampare una sola volta il messaggio sulla Serial Monitor 
7bool abilitaMessaggio = 0;
8 
9void setup() {
10  // inizializzazione della comunicazione seriale
11  Serial.begin(9600);
12}
13 
14void loop() {
15  // consente di visualizzare sulla Serial Monitor
16  // una sola stampa delle stringa
17  if (abilitaMessaggio == 0) {
18    // ritardo che evita la doppia stampa del messaggio
19    delay(200);
20    Serial.println("Calcolo (errato) numero di secondi in un giorno:");
21    Serial.println("secondi_in_un_giorno = 60 * 60 * 24");
22    long secondi_in_un_giorno = 60 * 60 * 24;
23    Serial.print("Secondi in un giorno = ");
24    Serial.println(secondi_in_un_giorno);
25    Serial.println("Errore! Il valore doveva essere: 86.400");
26    Serial.println("L'errore si verifica perchè il compilatore considera i numeri di tipo int.");
27    abilitaMessaggio = 1;
28  }
29}

Ciò accade perché il compilatore C dell’IDE di Arduino vede un’espressione aritmetica composta da soli numeri interi e quindi considera il risultato come tipo int. Per evitare questo problema bisogna dire al compilatore che deve trattare l’intera espressione come un long aggiungendo L al primo valore che viene valutato nell’espressione:

1long secondi_in_un_giorno = 60L * 60 * 24;
1// Prof. Michele Maffucci
2// Data: 08.02.2020
3// Esempio 05: Ordine di esecuzione operazioni matematiche in C
4//             Uso corretto del tipo long.
5 
6// per stampare una sola volta il messaggio sulla Serial Monitor 
7bool abilitaMessaggio = 0;
8 
9void setup() {
10  // inizializzazione della comunicazione seriale
11  Serial.begin(9600);
12}
13 
14void loop() {
15  // consente di visualizzare sulla Serial Monitor
16  // una sola stampa delle stringa
17  if (abilitaMessaggio == 0) {
18    // ritardo che evita la doppia stampa del messaggio
19    delay(200);
20    Serial.println("Calcolo corretto del numero di secondi in un giorno:");
21    Serial.println("secondi_in_un_giorno = 60L * 60 * 24");
22    long secondi_in_un_giorno = 60L * 60 * 24;
23    Serial.print("Secondi in un giorno = ");
24    Serial.println(secondi_in_un_giorno);
25    Serial.println("Giusto! Abbiamo detto con la L che l'intera espressione è da trattate come un long.");
26    Serial.println("");
27    abilitaMessaggio = 1;
28  }
29}

Attenzione sempre alle parentesi!
Se le utilizzate ad esempio come nell’esempio che segue farà andare in overflow il risultato:

1long secondi_in_un_giorno_piu_uno = 1L + 60 * (60 * 24);
1// Prof. Michele Maffucci
2// Data: 08.02.2020
3// Esempio 06: Ordine di esecuzione operazioni matematiche in C
4//             L'uso non corretto delle parentesi fa andare in overflow il risultato.
5 
6// per stampare una sola volta il messaggio sulla Serial Monitor 
7bool abilitaMessaggio = 0;
8 
9void setup() {
10  // inizializzazione della comunicazione seriale
11  Serial.begin(9600);
12}
13 
14void loop() {
15  // consente di visualizzare sulla Serial Monitor
16  // una sola stampa delle stringa
17  if (abilitaMessaggio == 0) {
18    // ritardo che evita la doppia stampa del messaggio
19    delay(200);
20    Serial.println("Calcolo errato somma 1 al numero di secondi in un giorno");
21    Serial.println("secondi_in_un_giorno_piu_uno = 1L + 60 * (60 * 24)");
22    long secondi_in_un_giorno_piu_uno = 1L + 60 * (60 * 24);
23    Serial.print("Secondi in un giorno + 1 = ");
24    Serial.println(secondi_in_un_giorno_piu_uno);
25    Serial.println("Sbagliato! Attenzione sempre alle parentesi!");
26    Serial.println("Se le utilizzate ad esempio come indicato farà andare in overflow il risultato");
27    abilitaMessaggio = 1;
28  }
29}

mentre la seguente espressione non farà andare in overflow il calcolo:

1long secondi_in_un_giorno_piu_uno = 1 + 60 * (60L * 24);
1// Prof. Michele Maffucci
2// Data: 08.02.2020
3// Esempio 07: Ordine di esecuzione operazioni matematiche in C
4//             L'ordine del calcolo viene stabilito dalle parentesi, in questo modo
5//             il calcolo non farà andare in overflow il risultato.
6 
7// per stampare una sola volta il messaggio sulla Serial Monitor 
8bool abilitaMessaggio = 0;
9 
10void setup() {
11  // inizializzazione della comunicazione seriale
12  Serial.begin(9600);
13}
14 
15void loop() {
16  // consente di visualizzare sulla Serial Monitor
17  // una sola stampa delle stringa
18  if (abilitaMessaggio == 0) {
19    // ritardo che evita la doppia stampa del messaggio
20    delay(200);
21    Serial.println("Calcolo errato somma 1 al numero di secondi in un giorno");
22    Serial.println("secondi_in_un_giorno_piu_uno = 1 + 60 * (60L * 24)");
23    long secondi_in_un_giorno_piu_uno = 1 + 60 * (60L * 24);
24    Serial.print("Secondi in un giorno + 1 = ");
25    Serial.println(secondi_in_un_giorno_piu_uno);
26    Serial.println("Corretto! Il calcolo inizierà dalle parentesi tonde.");
27    Serial.println("E' stata aggiunta la L al primo operando tra le parentesi tonde.");
28    abilitaMessaggio = 1;
29  }
30}

Buon Coding a tutti 🙂

Arduino – Utilizzo dell’LCD1602 Keypad Shield della Keyestudio

Questo post è dedicato ai miei allievi Paolo e Sami 🙂 della 3B Automazione, che amano i videogiochi platform a cui ho assegnato un’attività di PCTO in cui è richiesto appunto la progettazione di un gioco elettronico di tipo platform con Arduino.
A tal proposito, per ridurre i tempi di prototipazione verrà usato un LCD Keypad Shield della Keystudio, il tutto verrà poi inserito in un contenitore stampato in 3D, sempre progettato dai due studenti e che dovrà ricordare un Game Boy.

Per le specifiche tecniche della scheda seguire il link allegato, seguono alcune indicazioni  della scheda ricavati dalla pagina del prodotto ed alcuni link a risorse per la produzione di semplici videogiochi con Arduino.

La shield della Keyestudio integra su di esso un display  LCD 1602 e sei pulsanti ed si inserisce su qualdsiasi scheda Arduino UNO R3 compatibile. Il display può comunicare con la scheda Arduino in due modi: ad 8 bit o a 4 bit, la connessione predefinita del display è a 4 bit. Come riportato nell’immagine che segue, al di sotto del display sono presenti  5 pulsanti di controllo (Seleziona, Su, Giù, Sinistra, Destra) e un pulsante di reset, che è collegato direttamente al reset della scheda Arduino.

I 5 pulsanti sono collegati all’ingresso analogico A0, quindi potrete monitorare lo stato dei pulsanti utilizzando un solo ingresso analogico di Arduino. Attenzione però che potrete monitorare solamente la pressione di un pulsante alla volta, quaindi la pressione contemporanea di due o più pulsanti non potrà essere identificata. La shield è inoltre dotata di un trimmer che permette la regolazione della retroilluminazione dell’LCD.

Nel caso si abbia la necessità di utilizzare i restanti pin di Arduino, non utilizzati per il controllo del display, è possibile saldare sulla scheda pin passanti femmina.

Nello sketch che segue, modificato leggermente rispetto a quello usato da Keystudio, la pressione di ogni singolo pulsante, ad esclusione del reset, corrisponderà ad uno specifico valore restituito dall’analogRead sul pin A0, la pressione di ogni pulsante restituirà un valore numerico all’interno di un intervallo specificato, così come indicato nell’immagine precedente, ciò permetterà quindi di intercettare quale pulsante è stato premuto.
I valori dell’analogRead corrispondenti al pulsante premuto verranno visualizzati anche sulla SerialMonitor.

Nei commenti nel codice la spiegazione di ogni sezione.

1/*
2 * Prof. Michele Maffucci
3 * Utilizzo dell'LCD Keypad Shield della Keystudio
4 * Data: 08.02.2021
5 */
6  
7// inclusione della libreria LiquidCrystal.h
8#include <LiquidCrystal.h>
9 
10// inizializza la libreria con i numeri dei pin dell'interfaccia
11LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
12 
13void setup() {
14  // impostazione del numero di colonne e righe del display
15  lcd.begin(16, 2);
16  Serial.begin(9600);
17  // Stampa 5 puntini per dare la sensazione di avvio programma
18  for (int i = 0; i < 4; i++) {
19    lcd.print(".");
20    delay(250);
21  }
22  // Posiziona il cursore in colonna 0 e riga 0
23  lcd.setCursor(0, 0);
24  // Stampa il messaggio
25  lcd.print("Salve Mondo!");
26}
27 
28void loop() {
29  // Posiziona il cursore in colonna 0 e riga 0
30  lcd.setCursor(0, 1);
31  // Stampa il numero di secondi dall'avvio
32  lcd.print(millis() / 1000);
33 
34  // Memorizza in val il valore presente su A0
35  int val = analogRead(A0);
36 
37  // Stampa il valore di val sulla Serial Monitor
38  Serial.println(val);
39 
40  // In funzione del pulsante premuto val assumerà valori diversi
41  if (val >= 0 && val <= 50)
42  {
43    lcd.setCursor(5, 1);
44    lcd.print("Destra  ");
45  }
46  else if (val >= 50 && val <= 150)
47  {
48    lcd.setCursor(5, 1);
49    lcd.print("Su'     ");
50  }
51  else if (val >= 150 && val <= 300)
52  {
53    lcd.setCursor(5, 1);
54    lcd.print("Giu'    ");
55  }
56  else if (val >= 300 && val <= 500)
57  {
58    lcd.setCursor(5, 1);
59    lcd.print("Sinistra");
60  }
61  else if (val >= 500 && val <= 750)
62  {
63    lcd.setCursor(5, 1);
64    lcd.print("Set     ");
65  }
66}

Di seguito alcuni link a giochi in cui viene sfruttato un l’LCD 1602 e in cui potreste utilizzata la shield della Keyestudio.

Nel caso in cui fosse necessario realizzare caratteri o icone personalizzate consultare: Disegnare caratteri personalizzati con Arduino per un LCD 16×2

Buon divertimento 🙂