DHT11, oraz DHT22 to czujniki temperatury i wilgotności powietrza. Często wykorzystuje się je, choćby do budowy amatorskich stacji pogodowych. Czujniki oferują całkiem dobrą jakość odczytów, a ich obsługa jest bardzo prosta. W tym wpisie pokażę jak je obsługiwać, na przykładzie mikrokontrolera esp8266 i „języka” Arduino. Jednak bez większych problemów przepiszesz całość do innego standardu.
Kod github: https://github.com/mcinm/arduino/tree/main/DHT11_22
DHT11/22 Komunikacja
Czujniki te posiadają tylko cztery wyprowadzenia. Oczywiście, VCC i GND do zasilenia układu, pin zazwyczaj oznaczony jako „S” od słowa „Signal”, oraz czwarty pin, który nie pełni żadnej funkcji. W przypadku płytek przeznaczonych dla arduino, wyprowadzone są najczęściej tylko trzy piny.
Mimo, że do sterowania używa się tylko jednego pinu, transmisja nie jest realizowana za pośrednictwem protokołu 1-Wire. Co często, błędnie jest podawane w różnych źródłach.
Poniżej zamieszczam grafikę przedstawiającą proces komunikacji z modułem. Schematy pochodzą z jednej z wielu dostępnych w Internecie dokumentacji.
Na samym początku, musimy wysłać polecenie start (zapytanie) do modułu. Jest to dobrze przedstawione na grafice – wystarczy wystawić stan niski na pinie Signal, przez co najmniej 18 ms.
Kolejno, z powrotem przywrócić stan wysoki i odczekać ok. 20 – 40 us. I w ten sposób powstaje nasza pierwsza funkcja „request”.
#define DHT_GPIO 0 void request(void) { pinMode(DHT_GPIO, OUTPUT); digitalWrite(DHT_GPIO, LOW); delay(20); digitalWrite(DHT_GPIO, HIGH); delayMicroseconds(35); }
Następnym krokiem będzie odebranie odpowiedzi od modułu. Ten wystawia stan niski na 80 us, a następnie stan wysoki, także na 80 us. W kodzie nie użyłem teraz funkcji opóźniających, a po prostu pętle. Przed nimi, trzeba jeszcze zmienić tryb pracy wyprowadzenia mikrokontrolera na wejściowy.
void response(void) { pinMode(DHT_GPIO, INPUT); while (digitalRead(DHT_GPIO)); while (!(digitalRead(DHT_GPIO))); while (digitalRead(DHT_GPIO)); }
Odczyt danych
Po tej prostej sekwencji, mikrokontroler powinien być gotowy na przyjęcie nadchodzących danych.
Z modułu nadejdzie pięć bajtów. Będą to kolejno:
- Wilgotność powietrza (wartość po przecinku)
- Wilgotność powietrza (wartość całkowita)
- Temperatura (wartość po przecinku)
- Temperatura (wartość całkowita)
- Suma kontrolna (Checksum)
Suma kontrolna to wartość sumy wszystkich czterech wartość (bajty 1-4). W ten sposób sprawdzać będziemy, czy odczyt został poprawnie odebrany.
Samo odbieranie danych jest bardzo proste. Układ wystawia najpierw stan niski, a następnie wysoki, to czy nadchodzący bit jest zerem, czy jedynką weryfikujemy przez sprawdzenie czasu trwania impulsu wysokiego. Jeżeli trwa on 26-28 us, to bit jest zerem, a jeżeli trwa 70 us – jedynką. W taki sposób układ czujnika wysyła 8 bitów, jeden po drugim.
Powtarza to 5 razy (5 bajtów). Tak będzie wyglądał kod odbioru bajtu:
unsigned char get_data(void) { unsigned char data = 0; for (unsigned char i=0; i<8; i++) { while (!(digitalRead(DHT_GPIO))); delayMicroseconds(30); if (digitalRead(DHT_GPIO)) data = (data<<1) | (0x01); else data = (data<<1); while (digitalRead(DHT_GPIO)); } return data; }
DHT11 / DHT22 przykład
To w zasadzie wszystko, teraz wystarczy w kodzie programu dodać naszą bibliotekę i stworzyć tablice przechowującą dane, oraz funkcję je pobierającą. Ja zrobiłem to w taki sposób:
unsigned char tab[5]; void get_mes(void) { request(); response(); tab[0] = get_data(); tab[1] = get_data(); tab[2] = get_data(); tab[3] = get_data(); tab[4] = get_data(); unsigned char control = tab[0] + tab[1] + tab[2] + tab[3]; if (control != tab[4]) get_mes(); }
Funkcja ta będzie pobierała odczyty z modułu i wstawiała je w utworzoną wcześniej tabelę. Z tymi danymi możemy już zrobić cokolwiek potrzebujemy. Poniżej podałem przykład zastosowania z użyciem mikrokontrolera esp8266, jako prosty czujnik ze zdalnym dostępem. Kod tego programu także znajduje się na github’ie.
Nasz program obsługujący czujnik DHT, nie jest oczywiście zbyt pewnym rozwiązaniem. Brakuje w nim zabezpieczeń przeciwko błędom w odczycie. Przykładowo, jeżeli podczas odbioru danych wystąpią jakieś zakłócenia i nie przejdzie jeden bit, mikrokontroler może zostać zablokowany w nieskończonej pętli.
Ale akurat rozwiązać ten problem jest bardzo prosto – wystarczy dodać kilka sekwencji sprawdzających w kodzie.
Kod ten bez większych problemów można oczywiście przepisać na dowolny język/mikrokontroler.
Dodaj komentarz