Do you want to read this article in English? Click here!
Ero ancora un ragazzo da pochi anni iscritto alle superiori quando mio padre ed un suo caro amico hanno deciso di realizzare una piccola stazione meteorologica, costruendo di fatto un anemometro con anemoscopio. Negli anni poi la stazione meteo si è evoluta, andando ad ospitare un igrometro ed un termometro. Il tempo è trascorso, nel frattempo esigenze famigliari hanno imposto un trasferimento della stazione meteo la quale, per alcuni anni, è rimasta spenta e coperta da un telo antipolvere, fino a che, a fine 2015, mio papà ed il suo amico hanno deciso di ripristinarla. La sezione riguardante il vento ha ripreso bene il suo funzionamento, l'igrometro invece è stato abbandonato ed il termometro purtroppo misurava temperature improponibili. Ci ho pensato su un po' e alla fine ho voluto rimediare alla mancanza della misura di umidità e temperatura dell'aria: ho acquistato il sensore DHT22.
Indice |
Il sensore DHT22 (aka AM2302)
Si tratta di un sensore che, come tanti, nasce nell'era degli Arduini (al plurale, intendendo i diversi modelli sia originale quanto i cloni) e per gli amanti di quella piattaforma presumo siano disponibili le opportune interfacce hardware/software per la gestione del sensore. È il fratello di DHT11 e DHT21, benché questi sensori non li conosca e nemmeno li abbia usati.
Il pinout è semplice: quattro pin, uno non è usato (NC), due sono dedicati alle alimentazioni (VCC e GND) e sull'ultimo si fanno transitare i dati da e per il sensore (DATA).
Trattandosi di un sensore digitale oltre ai dispositivi sensibili alle grandezze da misurare (termistore NTC per la temperatura ed sensore di umidità) al suo interno trova posto un integrato (probabilmente un microcontrollore) in grado di dialogare con un certo protocollo con la periferica connessa al sensore. Tale periferica non necessariamente deve essere un Arduino. Anzi!
Schema
La specifica che mi sono dato era quella di poter leggere due temperature e due umidità, tanto in un ambiente interno quanto all'esterno, sostituendo i due LM35Z con i DHT22 (sì, ne ho acquistati due). Inoltre i valori sarebbero dovuti comparire su un display, meglio se alfanumerico, con un meccanismo tale da poter visualizzare le quattro grandezze. Al comando di tutto ho previsto un PIC; sì, ma quale? I pin impiegati erano davvero pochi, ma frugando nei miei cassetti ho individuato un PIC18F2620 che poteva fare al caso mio. Un cannone per sparare alle mosche, si potrebbe obiettare. Condivido. Ma tant'è: quello avevo e quello ho usato. Avevo inoltre dei vincoli dimensionali, pertanto a parte il PIC ed il regolatore di tensione, ho impiegato solamente componenti SMD.
Il display è di tipo retroilluminato, quindi ho previsto un transistor comandato dal micro per regolare la luminosità del display, a scalare da un massimo ad un minimo senza mai spegnere la luminosità. Il ripristino della luminosità piena avviene dopo aver premuto un pulsante posto su pannello.
L'Hardware
Dallo schema al PCB il passo benché banale, non è stato breve (ho stampato il PCB 3 volte, la quarta volta ho chiesto ad un amico gentilmente di stamparmi il PCB), ho montato tutto et voilà! Già vedevo il PIC18 scalpitare in attesa delle poche righe di codice che gli avrei fatto eseguire per la gestione di due sensori.
Protocollo
Prima di addentrarsi nel codice C è bene illustrare come funziona il protocollo di comunicazione tra DHT22 e il microcontrollore che lo va ad interfacciare. Il DHT22 ha quattro pin, come detto, ma solo uno è dedicato alla comunicazione, quindi va capito come fare per interrogare il sensore e farsi dire temperatura ed umidità. Benché la comunicazione avvenga su un filo solo, non si tratta di protocollo one-wire, come citato nei documenti. L'avvio della comunicazione avviene mediante un preambolo codificato, nel quale il microcontrollore agisce sulla linea DATA con tempistiche definite. Successivamente avviene il trasferimento dati dal sensore al micro. Il sensore restituisce quattro byte di dati più un quinto byte contenente un checksum. Ecco qualche dettaglio.
Preambolo
Ogni volta che il micro interroga il sensore deve avviare la comunicazione secondo questo schema: dato che a riposo la linea DATA è mantenuta alta dal pull-up, il segnale di start-of-trasmission viene fornito dal micro portando la linea dati a livello logico basso per almeno 1ms. Dopo di che a la linea viene portata alta (il micro commuta il proprio pin di comunicazione da output a input) e resta a livello logico alto per almeno 20-40 us, dopo di che ancora un balletto su e giù, comandato dal sensore, con le tempistiche indicate in figura.
Figura 8 - Preambolo
Trasmissione dati
A preambolo concluso inizia l'invio dei dati dal sensore al micro. Come detto vengono inviati 5 byte, per un totale di 40 bit. Ciascun bit è codificato come segue:
- ciascun bit vale 0 se la sequenza low-high ha tempistiche di rispettivamente 50us e 70us
- ciascun bit vale 1 se la sequenza low-high ha tempistiche di rispettivamente 50us e 26-28us
Figura 9 - Bit 0 e bit 1
Umidità relativa, temperatura e checksum
I primi due byte ricevuti dal sensore rappresentano il valore di umidità relativa espressa non in valori percentuali ma in parti su mille. Quindi il 37.5% di umidità viene ricevuto come valore 375. A seguire c'è la temperatura, espressa in decimi di grado cengtigrado, compreso il segno. Dato che DHT22 misura temperature da -40°C a +80°C, sarà opportuno valutare in primis il segno e poi trasformare il valore letto da decimi di grado a grado. L'ultimo dei cinque byte ricevuti è il checksum, calcolato come somma a 8 bit dei quattro byte precedenti (i due dell'umidità e i due della temperatura).
Figura 10 - Il payload
Quattro righe di codice
Il progetto è stato scritto impiegando l'ambiente di sviluppo di Microchip MPLABX ed il compilatore XC8 ed è davvero semplibe. Dopo aver inizializzato il PIC (oscillatore, porte, ecc) ed aver avviato la routine di inizializzazione del display LCD, si passa al loop infinito di acquisizione dei dati e visualizzazione. Ad ogni acquisizione si esegue la procedura del preambolo di comunicazione (startup sequence) che, per ciascun sensore, è realizzata così:
/* Attendo che la linea si porti a 0 */ if (validEdge(INTERNAL, FALLING_EDGE) == false) { return false; } /* Attendo che la linea si porti a 1 */ if (validEdge(INTERNAL, RISING_EDGE) == false) { return false; } /* Attendo che la linea si porti a 0 */ if (validEdge(INTERNAL, FALLING_EDGE) == false) { return false; } return true;
L'attesa di cambio di stato da parte della porta dati è realizzata con un while(); per evitare che il firmware resti bloccato nel while() in attesa del cambio di stato del pin della porta ho inserito un timer in guardia, al fine di evitare un'attesa infinita in caso di guasto. In alternativa si poteva realizzare una macchina a stati, ma questo metodo è risultato più immediato.
Se TIMER 0 è andato in overflow significa che qualcos aè ndato storto. Il periodo di overflow di TMR0 è superiore ai valori necessairi per discriminare i bit 0 e 1 del payload.
La funzione che controlla il cambio di stato del pin della porta è la seguente:
boolean validEdge(uint8_t intOrExt, boolean edgeType) { TMR0 = 0; T0CONbits.TMR0ON = 1; INTCONbits.TMR0IF = 0; if (intOrExt == INTERNAL) { while ((DHT_INT_READ == edgeType) && (INTCONbits.TMR0IF ==0)); } else { while ((DHT_EXT_READ == edgeType) && (INTCONbits.TMR0IF ==0)); } T0CONbits.TMR0ON = 0; if (INTCONbits.TMR0IF == 1) { return false; } else { return true; } }
La decodifica dei bit è eseguita semplicemente in questo modo: ogni volta che la linea dati è a valore basso, vado a leggere il valore del registro TMR0 e agisco di conseguenza.
/* Con linea bassa, arresto il timer e vedo quanto vale */ T0CONbits.TMR0ON = 0; if ((TMR0>=50) && (TMR0<=80)) /* Questo è un bit che vale 1 */ { DHT22payLoad[nByte]|=bitPosition; } else if ((TMR0>=20) && (TMR0<=35)) /* Questo è un bit che vale 0 */ { /* do nothing */ }
Nella routine sotto interrupt viene controllato il tempo che scorre, per far sostanzialmente due cose:
- contare due secondi tra un'acquisizione e l'altra del medesimo sensore (quindi li alterno con cadenza di 1 secondo);
- contare "fino a 10" e dopo 10 secondi abbassare la luminosità del display di un pochino; la pressione del pulsante ripristina la massima luminosità.
How it works
Per installare il tutto si è resa necessaria qualche modifica, tra cui anche il fatto di dover chiudere l'apertura dove trovava posto il display dell'igrometro.
Sotto al display si trova il pulsante per il ripristino della luminosità, il pulsante ha preso posto del deviatore che veniva impiegato precedentemente per la commutazione tra la lettura della temperatura interna ed esterna. Ora la commutazione è automatica, ed avviene ogni secondo.
Un paio di raccomandazioni
Il sensore non concede lunghezze di cavo elevate, pena il rischio di perdita di dati durante la trasmissione. Sul datasheet è ben visibile un dato che potrebbe invece non essere osservato: tra una acquisizione e la successiva devono trascorrere almeno due secondi (paragrafo 7 a pagina 5 del datasheet), sotto la voce collecting period.
Migliorie
Come detto il PIC18F2620 che è stato usato è fin esagerato, per fargli fare quattro conti; un PIC16F poteva essere sufficiente. Nell'ipotesi di cambiare il PIC ho lasciato l'impronta per un eventuale oscillatore esterno. Sulla linea seriale (non implementata) manca un line-driver (probabilmente lo si può omettere nel caso in cui si usino baud-rate bassi). L'antirimbalzo del tasto è spartano ma funziona: da non farsi così quando i pulsanti sono molti!
Firmware
Puoi scaricare il codice C a questo link
Approfondimenti e fonti
Segnalo l'articolo comparso su SettoreZero.com che propone l'impiego di DHT22 con un PIC connesso al PC attraverso la porta seriale; l'articolo sottolinea alcuni aspetti legati alle tempistiche che l'autore ha sviscerato con opportuna strumentazione.
Licenza
Questo articolo, foto e diagrammi pubblicati rientrano nell'ambito della licenza CREATIVE COMMONS BY-NC-ND 3.0, secondo quanto indicato nelle note legali qui riportate.