Οι αισθητήρες θερμοκρασίας/υγρασίας DHT11 και DHT22 (AM2302) χρησιμοποιούνται σε
πολλές εφαρμογές λόγω της χαμηλής τιμής τους σε σχέση με την υψηλή ακρίβεια και
αξιοπιστία τους, καθώς επίσης και την ευκολία σύνδεσης με μονάδες επεξεργασίας.
Η σύνδεση γίνεται με μια αμφίδρομη γραμμή δεδομένων[1] και η τροφοδοσία
τους είναι 3-5.5V με μέση
κατανάλωση ρεύματος 0.2-1mA.
Η ανάλυσή τους είναι 1%RH (σχετική
υγρασία) και 1οC (βαθμοί
Κελσίου) για το DHT11 και 0.1%RH
και 0.1οC αντίστοιχα για το DHT22. Κατά την επικοινωνία με τη μονάδα επεξεργασίας το DHT στέλνει ένα πακέτο 40 bit από τα οποία τα 16 είναι για την
υγρασία, τα 16 επόμενα για τη θερμοκρασία και τα τελευταία 8 για έλεγχο
ισοτιμίας (Πίνακας Ι).
Πίνακας Ι.
Format πακέτου απάντησης του DHT.
0011 0101
|
0000 0000
|
0001 1000
|
0000 0000
|
0100 1101
|
Humidity High
|
Humidity Low
|
Temp. High
|
Temp. Low
|
Parity
|
Calculate Parity: 0011
0101 + 0000 0000 + 0001 1000
+ 0000 0000
= 0100 1101
|
Στο DHT11 τα 16 bit της υγρασίας χωρίζονται σε δύο τμήματα των 8 bit εκ των οποίων το ψηλότερο
περιέχει την πληροφορία της υγρασίας ενώ το χαμηλότερο είναι πάντα μηδέν. Το
εύρος μέτρησης της υγρασίας είναι 20-90%RH. Το ίδιο
ισχύει και για την πληροφορία της θερμοκρασίας όπου όμως το εύρος μέτρησης για
αυτήν είναι 0-50οC.
Στο DHT22 τα 16 bit της υγρασίας περιέχουν την
πληροφορία σε δέκατα της μονάδας μέτρησης και το εύρος τιμών είναι 0 – 999
αντιστοιχώντας σε υγρασία 0 – 99.9%RH. Τα 16 bit της θερμοκρασίας περιέχουν την πληροφορία
με διαφορετικό τρόπο γιατί η θερμοκρασία μπορεί να πάρει και αρνητικές τιμές.
Το πρόσημο καθορίζεται από το MSB, το οποίο όταν είναι
1 η μέτρηση αντιστοιχεί σε αρνητική θερμοκρασία[2].
Τα υπόλοιπα 15 bit περιέχουν την πληροφορία σε δέκατα
της μονάδας μέτρησης και το εύρος τιμών είναι 0 – 800. Η περιοχή μέτρησης της
θερμοκρασίας είναι -40 – 80οC. Τα bit ισοτιμίας υπολογίζονται και στους
δύο αισθητήρες με τον ίδιο τρόπο, αθροίζοντας δηλαδή τα τέσσερα 8bit μέρη σα να
είναι ανεξάρτητα μεταξύ τους.
Η επικοινωνία με τη μονάδα επεξεργασίας ακολουθεί ένα συγκεκριμένο
χρονοδιάγραμμα. Σε κανονική λειτουργία το DHT βρίσκεται
σε κατάσταση αναμονής παρακολουθώντας το δίαυλο. Ο επεξεργαστής αιτείται
επικοινωνία με τον αισθητήρα κατεβάζοντας το δίαυλο σε χαμηλή λογική στάθμη για
18ms και στη συνέχεια ανεβάζοντάς
τον σε υψηλή για 40μs. Το DHT απαντά κατεβάζοντας το δίαυλο σε χαμηλή λογική στάθμη για
54μs και στη συνέχεια ανεβάζοντάς
τον σε υψηλή για 80μs. Στη συνέχεια αρχίζει το DHT να αποστέλλει τα 40 bit που περιέχουν τα δεδομένα της
τελευταίας μέτρησης του. Το 0 ή 1 των
δεδομένων καθορίζεται από τη διάρκεια της υψηλής λογικής στάθμης στο δίαυλο.
Όταν είναι 24μs αντιστοιχεί σε 0 ενώ όταν είναι 70μs αντιστοιχεί σε 1. Το ενδιάμεσο διάστημα χαμηλής λογικής
στάθμης είναι πάντα 54μs. Πρώτο bit του πακέτου λαμβάνεται το MSB του Humidity High και ακολουθούν τα υπόλοιπα προς τα δεξιά όπως
καταγράφονται στον Πίνακα Ι. Στο σχήμα 1 παρουσιάζεται γραφικά το
χρονοδιάγραμμα της επικοινωνίας.
Σχήμα
1. Χρονοδιάγραμμα επικοινωνίας DHT
με MCU.
Το DHT κάνει μια μέτρηση
περίπου κάθε δύο δευτερόλεπτα και τον ενδιάμεσο χρόνο βρίσκεται σε κατάσταση
χαμηλής κατανάλωσης ενέργειας (100 – 150μΑ). Κατά την αρχική τροφοδοσία με τάση
πρέπει να δοθεί χρόνος εκκίνησης στον αισθητήρα τουλάχιστο 1s και μετά να γίνει αίτηση επικοινωνίας. Επίσης το χρονικό
διάστημα μεταξύ δύο αιτημάτων πρέπει να είναι μεγαλύτερο του 1s.
Στη συνέχεια παρουσιάζεται ένα παράδειγμα επικοινωνίας με DHT11
γραμμένο σε γλώσσα προγραμματισμού C:
#include <avr/io.h>
#include <util/delay.h>
uint8_t dhtreg[5];
uint8_t rdf;
int16_t hum;
int16_t tmp;
/* Your
code here */
int main(void)
{
/* Your
code here */
while (1)
{
_delay_ms(1000); // 1s
for DHT start up
DDRC |= (1<<0); // MCU Port turns to output
PORTC &= ~(1<<0); // MCU Request (PORT = 0)
_delay_ms(18);
PORTC |= (1<<0); // MCU Request (PORT = 1)
_delay_us(40);
DDRC &= ~(1<<0); // MCU Port turns to input
PORTC |= (1<<0); // Enable pull up resistor
_delay_us(20);
while (!(bit_is_set(PINC,0))); // DHT
Response PC0 = 0
_delay_us(100); // DHT Response PC0 = 1
for (uint8_t rgi = 0; rgi < 5; rgi++) // Start reading DHT packet
{
for (uint8_t bti = 0; bti < 8; bti++) // Start reading byte
{
while (!(bit_is_set(PINC,0))); // Wait
while PC0 = 0
_delay_us(40);
dhtreg[rgi] = dhtreg[rgi]<<1; // Shift register
if (bit_is_set(PINC,0)) // Read 1
{
dhtreg[rgi] |= (1<<0); // Load value 1
rdf = 0; // Reset fault counter
while (bit_is_set(PINC,0)) // Wait
while PC0 = 1
{
rdf++; // Increase fault counter
_delay_us(5);
if (rdf > 100) // If time out
{
/* Your
code here */
break; // Break previous “while”
}
}
}
}
}
hum = 0; hum = dhtreg[0]; //
DHT11 humidity
tmp = 0; tmp = dhtreg[2]; //
DHT11 temperature
/* Your code here */
}
}
Στην αρχή του κυκλικού βρόχου υπάρχει μια καθυστέρηση ώστε να δοθεί
χρόνος εκκίνησης στο DHT. Στη συνέχεια το pin που είναι συνδεδεμένο στον
αισθητήρα (στο παράδειγμα PC0) γίνεται έξοδος και με την επόμενη
εντολή περνάει σε χαμηλή λογική στάθμη και παραμένει εκεί για 18ms. Μετά αλλάζει σε υψηλή λογική για 40μs και ακολουθούν οι εντολές που γίνεται είσοδος και
ενεργοποιείται η pull up αντίσταση[3]. Με αυτήν την
αλληλουχία ολοκληρώνεται η αίτηση προς DHT το οποίο απαντάει κατεβάζοντας το δίαυλο σε χαμηλή λογική. Η
καθυστέρηση των 20μs υπάρχει
για να προλάβει να σταθεροποιηθεί ο δίαυλος στη χαμηλή λογική (η οποία
αναμένεται να διαρκέσει 54μs). Με την επόμενη εντολή το
πρόγραμμα περιμένει όσο διαρκεί χαμηλή και όταν γίνει υψηλή εκτελεί μια
καθυστέρηση 100μs ώστε να ολοκληρωθεί ο παλμός των 80μs. Μετά την ολοκλήρωση του παλμού αρχίζει η αποστολή του
πακέτου 40bit[4].
Το πρόγραμμα περιμένει να ολοκληρωθεί η χαμηλή λογική που προηγείται του bit της πληροφορίας και στη συνέχεια
εκτελεί μια ακόμα καθυστέρηση 40μs και κάνει αριστερή
ολίσθηση κατά μία θέση στη μεταβλητή που θα υποδεχθεί το bit.
Αν το λαμβανόμενο bit είναι 0 κλείνει ο κύκλος της εσωτερική for αφού με την παραπάνω
καθυστέρηση έχει ολοκληρωθεί ο παλμός των 24μs που αντιστοιχεί σε 0
και δεν εκτελείται η εντολή if (bit_is_set(PINC,0)).
Από την αριστερή ολίσθηση το LSB έχει
συμπληρωθεί με 0 και έτσι δε
χρειάζεται καμία άλλη παρέμβαση.
Αν το λαμβανόμενο bit είναι
1 εκτελείται η εντολή if (bit_is_set(PINC,0)), αφού με την καθυστέρηση των 40μs δεν έχει προλάβει να ολοκληρωθεί ο
παλμός των 70μs που αντιστοιχεί
σε 1. Στο μπλοκ της εντολής
τοποθετείται το LSB της
μεταβλητής και το πρόγραμμα περιμένει την ολοκλήρωση του παλμού ώστε να κλείσει
ο κύκλος της for. Αν υπάρξει μια αστοχία στη
συνδεσμολογία του αισθητήρα, το πρόγραμμα θα μείνει για πάντα σε αυτό το σημείο,
εξ αιτίας της pull up αντίστασης του μικροελεγκτή. Για
αυτό το λόγο η μεταβλητή rdf αυξάνει
συνεχώς το περιεχόμενό της μέσα στην while και όταν ξεπεράσει ένα όριο που έχουμε επιλέξει ως time out κάνει break[5] σε αυτήν, ώστε
να κλείσει αναγκαστικά ο κύκλος της for. Όταν
ολοκληρωθούν και οι δύο for έχουν
ληφθεί τα 40bit μπορεί να γίνει
η επεξεργασία τους.
Αν ο αισθητήρας είναι DHT-11 οι μεταβλητές hum και tmp μπορούν να
είναι 8bit ή να μη
χρησιμοποιηθούν καθόλου, αφού η πληροφορίες της υγρασίας και της θερμοκρασίας
θα βρίσκονται ήδη, από τη ρουτίνα ανάγνωσης, στις dhtreg[0] και dhtreg[2]
αντίστοιχα. Εναλλακτικά μπορούν να παραμείνουν ως 16bit ώστε να έχουμε τη δυνατότητα να χρησιμοποιήσουμε στη
συνέχεια τη συνάρτηση[6]
itoa.
Σε αυτήν την περίπτωση καλό είναι να μηδενίζουν πριν την ανάθεση της νέας
τιμής.
Αν ο αισθητήρας είναι DHT-22 οι μεταβλητές hum και tmp είναι
απαραίτητες και πρέπει να είναι 16bit. Οι τελευταίες
δύο σειρές πρέπει να τροποποιηθούν ως εξής:
hum = 0; // DHT22
hum = dhtreg[0]<<8; // DHT22
hum |= dhtreg[1]; // DHT22
tmp = 0; // DHT22
tmp = dhtreg[2]<<8; // DHT22
tmp |= dhtreg[3]; // DHT22
Με τις παραπάνω εντολές φορτώνονται οι 8bit μεταβλητές του πίνακα dhtreg
στα αντίστοιχα τμήματα των 16bit μεταβλητών
hum και tmp. Η μετατροπή τους στη συνέχεια σε χαρακτήρες ASCII για απεικόνιση ή αποστολή
μπορεί να γίνει με τη συνάρτηση itoa. Θα
πρέπει να ληφθεί όμως υπόψη ότι οι μεταβλητές hum και tmp
περιέχουν την πληροφορία σε δέκατα της μονάδας μέτρησης και έτσι χρειάζεται να
γίνει διαχείριση της υποδιαστολής με λογισμικό κατά την απεικόνιση. Επίσης θα
πρέπει να γίνει ανάλογη διαχείριση του αρνητικού πρόσημου για τη θερμοκρασία
αφού για να παράγει η itoa αρνητικό
πρόσημο θα πρέπει ο αρνητικός αριθμός να έχει τη μορφή του συμπληρώματος ως
προς 2, κάτι που δεν ισχύει για τις αρνητικές τιμές του DHT.
Μια βολική προσέγγιση είναι να καθαρίσουμε το bit του πρόσημου, ώστε να εκτελεστεί η itoa σε θετικό αριθμό και να εμφανίσουμε το
πρόσημο με ανάλογη εντολή πριν την απεικόνιση των υπόλοιπων ψηφίων. Στη
συνέχεια παρουσιάζεται (χωρίς σχολιασμό) ένα παράδειγμα απεικόνισης για το DHT22 γραμμένο σε γλώσσα προγραμματισμού C[7]:
char humasc[6];
char tmpasc[6];
SeCu (L1R1); _delay_ms (5); //
Send cursor to 1st line 1st rank
WrDa('H'); // Display H
WrDa('='); // Display =
itoa (hum, humasc, 10); // Binary integer to decimal ASCII string
if (hum<10) // For values lower than 1.0
WrDa ('0'); // Display 0 before
decimal point
for (uint8_t idht = 0; idht < ((unsigned)strlen(humasc)-1); idht++)
WrDa (humasc[idht]); // Send ASCII
string to LCD
WrDa('.'); //
Display . for decimal point
WrDa (humasc[((unsigned)strlen(humasc)-1)]); // Display last digit (decimal)
WrDa('%'); //
Display %
WrDa('R'); //
Display R
WrDa('H'); //
Display H
for (uint8_t idht = (unsigned)strlen(humasc); idht < 6; idht++)
WrDa('
'); // Complete with blanks
SeCu (L2R1); _delay_ms (5); //
Send cursor to 2nd line 1st rank
WrDa('T'); // Display T
WrDa('='); // Display =
if (bit_is_set(dhtreg[2],7)) // If negative temperature
{
WrDa('-'); //
Display -
tmp &= ~(1<<15); // Clear negative bit
}
itoa (tmp, tmpasc, 10); // Binary integer to decimal ASCII string
if (tmp<10) // For values lower than 1.0
WrDa ('0'); // Display 0
for (uint8_t idht = 0; idht < ((unsigned)strlen(tmpasc)-1); idht++)
WrDa (tmpasc[idht]); //
Send ASCII string to LCD
WrDa('.'); // Display .
WrDa (tmpasc[((unsigned)strlen(tmpasc)-1)]); // Display last digit (decimal)
WrDa(223); //
Display degree symbol o
WrDa('C'); // Display C
for (uint8_t idht = (unsigned)strlen(tmpasc); idht < 6; idht++)
WrDa('
'); // Complete with
blanks
©2017 Πορλιδάς Δημήτριος
Download files: Atmel Studio 7.0 prj .c files basic flowchart
|