[058] Mierzymy wilgotność

[058] Mierzymy wilgotność

Żyjemy w tych pięknych czasach, gdy chyba wszystko, co nas otacza, możemy w łatwy sposób mierzyć. Dziś zajmiemy się pewnym parametrem związanym z powietrzem, czyli jego wilgotnością. Kiedyś stworzenie elementu jako tako dającego wiarygodne wyniki co do nasycenia parą wodną powietrza, praktycznie było niemożliwe. Po wielu bojach zadowalano się kilkudziesięcioprocentową wręcz dokładnością, niestabilną w czasie.


Higroskop z powyższego zdjęcia wykorzystywał do tego celu końskie włosie, zmieniające długość proporcjonalnie do stopnia wilgotności. O tym jakie było to niedokładne, pisać chyba nie muszę.

Obecnie za niewielkie pieniądze możemy stać się posiadaczami modułów nieporównywalnie dokładniejszych, wyposażonych w interfejs cyfrowy, a na dodatek w gratisie zaopatrzonych dodatkowo w termometr. Mam tu na myśli chyba najpopularniejszy standard takich urządzeń, zwany pod nazwami DHT11, 21 i 22. Są one bliźniaczo podobne, a różnią się dokładnością i zakresem pracy.

Czujnik ma postać małej kostki z perforacją i sprzedawany jest często wraz z małą płytką, zaopatrzoną w rezystor podciągający linię danych i kondensator filtrujący zasilanie. Posiada cztery nóżki, z czego jedna jest atrapą. Spójrzmy na parametry. Czujniki mogą pracować przy obu standardach napięć, czyli 3,3 V oraz 5 V. Dwudziestki mierzą pełen zakres wilgotności od zera do 100% z dokładnością dwuprocentową oraz temperaturę od -40 do +80 stopni z dokładnością półprocentową. Rozdzielczość pomiarów jest wyższa i ograniczona ośmiobitową rozdzielczością zakresów.

Jedenastka to tańsza wersja przetwornika, ale ograniczona do zakresu 20-90% wilgotności oraz 0-50 stopni. Dokładność także jest niższa. Co ciekawe, urządzenie to, wbrew specyfikacji mierzy bez problemu temperatury ujemne, lecz prawdopodobnie jego trwałość będzie wtedy ograniczona. W zależności od potrzeb można sobie wybrać czujnik, który będzie bardziej odpowiedni do własnych projektów. Tak naprawdę wiedza o dokładnym poziomie wilgotności rzadko jest niezbędna, zwykle trzeba znać tylko jej orientacyjny przedział.

Czujnik porozumiewa się ze światem zewnętrznym standardem podobnym do już poznanego przy okazji omawiania termometru, nieco zmodyfikowanym interfejsem 1-wire. O ile sprzętowo niczym się ów interfejs nie różni, programowo wygląda inaczej, wymaga specyficznych ramek czasowych i przesyła dane w czterdziestobitowych pakietach. Ale nie musimy tego wiedzieć, gdyż cała transmisja jest realizowana biblioteką, których mamy kilka do wyboru. Maksymalna długość połączenia nie została określona z góry, lecz z pewnością może przekraczać 20 metrów.

Ponieważ użyłem czujnika DTH11 na małej płytce, zawierającej już podciągający rezystor, całość podłączymy identycznie jak termometr z poprzedniego artykułu, oczywiście już bez dołączania dodatkowego rezystora. Także i tutaj nie ma ograniczeń co do portu danych, dlatego podłączymy się jak poprzednio, na port jedenasty. Do zilustrowania danych użyję także, jak poprzednio, wyświetlacza. Temat mamy dokładnie omówiony, więc w razie potrzeby odsyłam do poprzednich artykułów.

#include <DHT.h>
#include <LiquidCrystal.h>

Oba czujniki wymagają biblioteki ich obsługi. Jak wspomniałem, mamy ich wiele, a na jakąś trzeba się zdecydować. Wybrałem najpopularniejszą, o nazwie po prostu DHT. Jak to już bywało nieraz, nie znajdziemy jej w systemie, więc wpisujemy w wyszukiwarkę, odnajdujemy, instalujemy i próbnie kompilujemy nasz zupełnie pusty szkic. Jeśli błędów nie będzie, znaczy to, że biblioteka się zainstalowała bez problemów. Oczywiście będzie nam potrzebna także biblioteka obsługi wyświetlacza.

const byte oneWireBus = 11;  // Tutaj jest określony port magistrali 1-wire.
DHT dht(oneWireBus, DHT11);  // Tutaj dostarcza się bibliotece obsługi wilgotnościomierza wiedzy, gdzie co jest podłączone i z jakim typem mamy do czynienia.

Teraz zadeklaruję port, który będzie obsługiwał magistralę naszego wilgotnościomierza. I powiadomię o tym bibliotekę jego obsługi, a także o typie czujnika, bo biblioteka obsługuje zarówno mniej dokładną jedenastkę, jak i dokładniejsze dwudziestki.

const byte lcdRS = 2;  // Tutaj są określone poszczególne adresy linii wyświetlacza.
const byte lcdEN = 3;
const byte lcdD4 = 4;
const byte lcdD5 = 5;
const byte lcdD6 = 6;
const byte lcdD7 = 7;
const byte lcdKolumny = 16;                                   // To jest ilość kolumn w naszym wyświetlaczu.
const byte lcdWiersze = 2;                                    // To jest ilość wierszy w naszym wyświetlaczu.
LiquidCrystal lcd(lcdRS, lcdEN, lcdD4, lcdD5, lcdD6, lcdD7);  // Tutaj dostarcza się bibliotece obsługi wyświetlacza wiedzy, gdzie co jest podłączone.

float temperatura;  // Tutaj przechowuje się wartość temperatury odczytaną z termometru.

Pozostanie nam dopisanie znanego już fragmentu kodu deklarującego dane związane z wyświetlaczem i zadeklarowanie zmiennej przechowującej wartość temperatury, bo i tą będziemy mierzyć.

void setup() {
  dht.begin();                        // Inicjuj wilgotnościomierz.
  lcd.begin(lcdKolumny, lcdWiersze);  // Inicjuj wyświetlacz, powiadamiając go o ilości kolumn i wierszy.
}

Czas na przygotowanie podzespołów. Inicjuję wilgotnościomierz oraz termometr.

void loop() {
  lcd.home();                        // Ustaw kursor na początku.
  lcd.print(F("Wilgotnosc   "));     // Rysuj komunikat.
  lcd.print(dht.readHumidity(), 0);  // Wyświetl wilgotność.
  lcd.print(F("% "));                // Rysuj znak % i spację.

Ze względu na ograniczoną dokładność wskazań nie będę tutaj stosować zaokrągleń. Albowiem zaokrąglony wynik już otrzymujemy z samego urządzenia, które pracuje z rozdzielczością jedynie ośmiobitową. Zacznę więc od górnego wiersza: przed wartością umieszczam napis „Wilgotnosc” wraz z trzema spacjami. Ale nie wyglądałoby to dobrze, ponieważ ciągną się tu niepotrzebnie dwie pozycje po przecinku, wynikające z typu danej, która jest zmiennoprzecinkowa. My co prawda widzimy tutaj tylko samą kropkę, lecz gdybyśmy mieli dłuższy wyświetlacz, ujrzelibyśmy tam jeszcze dwie cyfry. Domyślnie instrukcja print wyświetla wartości zmiennoprzecinkowe z dwoma miejscami po przecinku. Rozwiązaniem byłaby zmiana formatu wartości na całkowitą, ale można to zrobić jeszcze prościej. W instrukcji print wystarczy zadeklarować ilość miejsc po przecinku. Zero zlikwiduje nam nie tylko owe cyfry, ale i sam przecinek.

Ponieważ wilgotność mierzy się w procentach, ten znak należy dopisać na końcu. Dobrym zwyczajem jest dołożenie także spacji, gdyby wilgotność spadła do wartości jednocyfrowej. Gdyby jej nie było, mielibyśmy na końcu dwa znaki procenta. Co prawda czujnik DHT11 nie podaje tak niskich wartości, jednak lepiej się zabezpieczyć, tym bardziej że nie kosztuje to nic. I jeszcze temperatura.

lcd.setCursor(0, 1);                  // Ustaw kursor w nowym wierszu.
lcd.print(F("Cieplo    "));           // Rysuj komunikat.
temperatura = dht.readTemperature();  // Odczytaj temperaturę.

if (temperatura >= 0) {  // Gdy wartość jest nieujemna...
  lcd.print(F(" "));     // ...rysuj dodatkową spację.
}

if (abs(temperatura) < 10) {  // Gdy wartość bezwzględna temperatury jest mniejsza od 10...
  lcd.print(F(" "));          // ...rysuj dodatkową spację.
}

lcd.print(temperatura, 1);  // Wyświetl temperaturę.
lcd.print((char)223);       // Rysuj znak stopni.

delay(500);  // Pętla opóźniająca mająca na celu wyeliminowanie niestabilności odczytów.

Przejdźmy do drugiego wiersza i zajmijmy się wyświetlaniem temperatury. Słowo owo niestety nie zmieści się wraz z jej wartością na 16 znakach. Zabawię się w poezję i zamiast niego użyję słowa „Ciepło”. Tradycjonalistom polecam skrócić oryginał do słowa „Temp.” Tym razem spacje będą cztery. Zastosuję sposób na znak minusa, znany z poprzedniego projektu. Rzecz w tym, by wynik nam się nie przesuwał na wypadek wykrycia wartości ujemnych.

Ponieważ na wartościach temperatury będziemy przeprowadzać pewne operacje, musimy zadeklarować dla niej zmienną temperatura, co uczyniłem na początku projektu. Teraz zmodyfikuję część odpowiedzialną za wyświetlanie temperatury. Na początek jej wartość przeniosę do zmiennej temperatura. Zmodyfikuję także wiersz, który będzie ją wyświetlał – już nie wprost z sensora, lecz zmienną.

Użyję teraz znanej już z poprzedniego projektu „pułapki na minus”, tylko uproszczę ją. Jeśli wynik będzie nieujemny, dodatkową spacją będzie się przesuwać w prawo. Kolejną spację dorzucę także, gdy temperatura będzie wyrażana jedną cyfrą przed przecinkiem. Unikniemy dzięki temu sytuacji, gdy po spadku temperatury z 10 na 9 stopni wynik przesunąłby się nam w lewo. Będę operował na wartości bezwzględnej, by zasada obowiązywała także dla temperatur ujemnych.

Jest już prawie dobrze. Znanym nam formatowaniem usunę teraz drugą cyfrę po przecinku i dołożę, w sposób omówiony w poprzednim filmie, znak stopnia.

Teraz jest idealnie. Na koniec dołożę pętlę opóźniającą, ponieważ wypisywanie wartości w kółko z pełną szybkością, na jaką pozwala procesor, nie ma sensu. Dane z sensora i tak są odświeżane mniej więcej co sekundę, więc ich rysowanie co pół sekundy zupełnie nie wpłynie na szybkość odczytów, a pozwoli choćby w symbolicznym stopniu ograniczyć powstawanie smogu elektronicznego i zużycie energii. W każdym razie dopasowywanie tempa działań do najwolniejszej operacji w ich łańcuchu należy do dobrego zwyczaju programistycznego. Użycie instrukcji delay nie jest dobrym rozwiązaniem, ale wyjątkowo tam, gdzie i tak komputer nie ma nic do roboty, dopuszczalnym. Nasza mała stacja pogodowa już działa, ale czy na pewno?

Rzut oka na wyświetlacz, gdy czujnik znajduje się w pokoju – ot tak, na biurku. Zarówno wilgotność jak i temperatura są bardzo przeciętne. Dzień jest wiosenny, za oknem padało, więc wartość nieco przekracza średnią.

Zróbmy pierwsze doświadczenie, zawieszę teraz czujnik nad gorącą wodą. Oczywiście nie wolno go zamoczyć.

Temperatura wzrosła do 42 stopni, a wilgotność w szklance osiąga pełne nasycenie, którego nasz czujnik nie wskaże, pokazując wartość maksymalną, czyli 95%, o pięć procent większą od deklarowanej w dokumentacji.

Czas na doświadczenie drugie, w którym użyłem środka osuszającego. Należy go najpierw wygrzać w piekarniku. Jeszcze ciepły umieściłem w szklance, w której wytworzył się stosowny mikroklimat: wilgotność spadła poniżej 20%.

Mniejszych wartości ten czujnik nie wykrywa, a poza tym poza warunkami laboratoryjnymi trudno jest uzyskać zerową wilgotność powietrza.

#include <DHT.h>
#include <LiquidCrystal.h>

const byte oneWireBus = 11;  // Tutaj jest określony port magistrali 1-wire.
DHT dht(oneWireBus, DHT11);  // Tutaj dostarcza się bibliotece obsługi wilgotnościomierza wiedzy, gdzie co jest podłączone i z jakim typem mamy do czynienia.

const byte lcdRS = 2;  // Tutaj są określone poszczególne adresy linii wyświetlacza.
const byte lcdEN = 3;
const byte lcdD4 = 4;
const byte lcdD5 = 5;
const byte lcdD6 = 6;
const byte lcdD7 = 7;
const byte lcdKolumny = 16;                                   // To jest ilość kolumn w naszym wyświetlaczu.
const byte lcdWiersze = 2;                                    // To jest ilość wierszy w naszym wyświetlaczu.
LiquidCrystal lcd(lcdRS, lcdEN, lcdD4, lcdD5, lcdD6, lcdD7);  // Tutaj dostarcza się bibliotece obsługi wyświetlacza wiedzy, gdzie co jest podłączone.

float temperatura;  // Tutaj przechowuje się wartość temperatury odczytaną z termometru.

void setup() {
  dht.begin();                        // Inicjuj wilgotnościomierz.
  lcd.begin(lcdKolumny, lcdWiersze);  // Inicjuj wyświetlacz, powiadamiając go o ilości kolumn i wierszy.
}

void loop() {
  lcd.home();                        // Ustaw kursor na początku.
  lcd.print(F("Wilgotnosc   "));     // Rysuj komunikat.
  lcd.print(dht.readHumidity(), 0);  // Wyświetl wilgotność.
  lcd.print(F("% "));                // Rysuj znak % i spację.

  lcd.setCursor(0, 1);                  // Ustaw kursor w nowym wierszu.
  lcd.print(F("Cieplo    "));           // Rysuj komunikat.
  temperatura = dht.readTemperature();  // Odczytaj temperaturę.

  if (temperatura >= 0) {  // Gdy wartość jest nieujemna...
    lcd.print(F(" "));     // ...rysuj dodatkową spację.
  }

  if (abs(temperatura) < 10) {  // Gdy wartość bezwzględna temperatury jest mniejsza od 10...
    lcd.print(F(" "));          // ...rysuj dodatkową spację.
  }

  lcd.print(temperatura, 1);  // Wyświetl temperaturę.
  lcd.print((char)223);       // Rysuj znak stopni.

  delay(500);  // Pętla opóźniająca mająca na celu wyeliminowanie niestabilności odczytów.
}

Płytka edukacyjna TME-EDU-ARD-2Płytka edukacyjna TME-EDU-ARD-2Sprawdź tutaj

Przeczytaj również

Nasi partnerzy

TMETech Master EventTME EducationPoweredby
Copyright © 2024 arduino.pl