Serwisy partnerskie:
Close icon
Serwisy partnerskie

Kurs Arduino odcinek 5 - biblioteki do trzyfunkcyjnego czujnika BME280

W piątym odcinku, zgodnie z zapowiedzią, nadal będziemy zajmować się pomiarami ciśnienia, wilgotności i temperatury, ale dodatkowo wcześniej niż planowałem omówimy pewien ważny problem, jaki bardzo często napotykają użytkownicy Arduino.
Article Image
1. Kurs Arduino: wprowadzenie 2. Kurs Arduino odcinek 1 - co to jest i jak zacząć? (sprzęt, schematy, programowanie) 3. Kurs Arduino odcinek 2 - termometry: 'diodowy', pokojowy oraz 'scalony' analogowy 4. Kurs Arduino odcinek 3 - moduł wyświetlacza LCD (HD44780) 5. Kurs Arduino odcinek 4 - czujnik BME280 (pomiar ciśnienia, wilgotności i temperatury) 6. Kurs Arduino odcinek 5 - biblioteki do trzyfunkcyjnego czujnika BME280 7. Kurs Arduino odcinek 6 - wykorzystanie łącza I2C (TWI) 8. Kurs Arduino odcinek 7 - wykorzystanie łącza SPI (karty pamięci, MAX31865, MAX31855) 9. Kurs Arduino odcinek 8 - wykorzystanie czujnika dwutlenku węgla (MH-Z19) 10. Kurs Arduino odcinek 9 - wykorzystanie modułów do odmierzania czasu 11. Kurs Arduino odcinek 10 - wykorzystanie czujników temperatury (DS18B20) 12. Kurs Arduino odcinek 11 - budowa loggera (rejestratora danych) 13. Kurs Arduino odcinek 12 - rejestracja i prezentacja danych oraz obsługa karty SD 14. Kurs Arduino odcinek 13 - rejestracja danych (wykorzystanie modułu OpenLog) 15. Kurs Arduino odcinek 14 - czym zastąpić płytkę Arduino Uno? 16. Kurs Arduino odcinek 15 - budowa rejestratora (chiński klon Arduino Pro Mini) 17. Kurs Arduino odcinek 16 - problemy z kwadratowym modułem Strong 18. Kurs Arduino odcinek 17 - czujniki do pomiaru wilgotności gleby (instalacja, konfiguracja) 19. Kurs Arduino odcinek 18 - protokół MODBUS i łącze RS-485 20. Kurs Arduino odcinek 19 - wyświetlacze od podstaw (matrycowe, 7-segmentowe, MAX7219) 21. Kurs Arduino odcinek 20a - wyświetlacze matrycowe i biblioteki MD_MAX 22. Kurs Arduino odcinek 20b - przyciski i biblioteki do obsługi wyświetlaczy 23. Kurs Arduino odcinek 20c - biblioteki do obsługi wyświetlaczy graficznych 24. Kurs Arduino odcinek 21 - moduł wyświetlacza OLED 25. Kurs Arduino odcinek 22 - moduł wyświetlacza 1,3 cala 26. Kurs Arduino odcinek 23 - przygotowanie bitmap do wyświetlania 27. Kurs Arduino odcinek 24 - omówienie fontu podstawowego (Adafruit GFX) 28. Kurs Arduino odcinek 25 - font podstawowy biblioteki Adafruit GFX 29. Kurs Arduino odcinek 26 - wykorzystanie bitmapowych fontów GFX 30. Kurs Arduino odcinek 27 - polskie znaki w glcdfont.c 31. Kurs Arduino odcinek 28 - zmiana ulepszonych fontów GFX

Zaawansowane obliczenia - czujnik BME280

W poprzednim odcinku cieszyliśmy się, że błyskawicznie udało się zrealizować prostą stację pogodową. Docelowo chcemy jednak wykorzystać Arduino i dostępne czujniki do zdecydowanie poważniejszych celów, mianowicie do monitorowania, a może i regulacji klimatu w mieszkaniu. Dlatego chcemy opanować zaawansowane sposoby wykorzystania czujników temperatury, wilgotności, a także czujników zawartości dwutlenku węgla.

Jak pokazuje zamieszczony w tym numerze artykuł z serii „Wokół Arduino”, uzyskana z czujnika wartość wilgotności względnej RH (Relative Humidity) niesie niezbyt dużo informacji, a nawet może wprowadzać w błąd. Często potrzebna jest informacja o wilgotności bezwzględnej (AH – Absolute Humidity) oraz o temperaturze punktu rosy (Dew Point).

Rys.1 Bibioteka Tylera Glenna - obliczenia 'środowiskowe'

Dlatego szukając w Internecie bibliotek do trzyfunkcyjnego czujnika BME280, wybrałem bibiotekę Tylera Glenna, która jak pokazuje to rysunek 1, zrzut ze strony: https://github.com/finitespace/BME280, oferuje takie „obliczenia środowiskowe” (Environment Calculations).

Pakiet Arduino IDE ma wbudowany mechanizm do łatwego, automatycznego pobierania i instalowania bibliotek (Szkic-DołączBibliotekę-ZarządzajBibliotekami). Ja wykorzystałem tę możliwość, instalując najnowszą dostępną aktualnie wersję 2.3.0 tej biblioteki, jak pokazuje rysunek 2.

Rys.2 Najnowsza wersja biblioteki Tylera Greena

Napisałem krótki Szkic 1 (A0501). Na początku dołączone są biblioteki, w tym EnvironmentCalculations. Ponieważ program z poprzedniego odcinka kursu działa, znacznie skróciłem szkic. Program odczytuje tylko temperaturę oraz wilgotność do zmiennych tmp i wilg.

Szkic 1

#include <BME280I2C.h>
#include <EnvironmentCalculations.h>
#include <Wire.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(2, 3, 4, 5, 6, 7); // obiekt "lcd"
BME280I2C czujnik; // wartości domyślne obiektu "czujnik"
float tmp, wilg, cis; // tworzymy zmienne globalne typu float
void setup() { //incjalizujemy obiekty:
lcd.begin(16, 2); Wire.begin(); czujnik.begin(); }
void loop() { //w petli co około 1 sekundę odczytujemy:
tmp = czujnik.temp(0);
wilg = czujnik.hum();
// oraz obliczamy temperaturę punktu rosy i wilgotność absolutną:
float dewPoint = EnvironmentCalculations::DewPoint(tmp, wilg, 0); // w °Celsjusza
float aH = EnvironmentCalculations::AbsoluteHumidity (tmp, wilg, 0);
lcd.clear();
lcd.print("Punkt rosy:"); lcd.print(dewPoint, 1); lcd.write(223); lcd.print('C');
lcd.setCursor(0, 1); //w dolnej linii:
lcd.print("AH:"); lcd.print(aH, 1); lcd.print("g/m3");
delay(1000); }

Następnie wywoływane są funkcje – metody, należace do biblioteki EnvironmentCalculations, służące do obliczania punktu rosy i wilgotności bezwzględnej. Obliczone wyniki wpisywane są do tymczasowych zmiennych dewPoint i aH, a następnie wyświetlane na wyświetlaczu LCD.

Gdy jednak spróbowałem skompilować ten szkic, wykorzystujący pokazaną na rysunku 1 funkcję – metodę float AbsoluteHumidity(), kompilator zgłosił dziwny błąd, jak pokazuje rysunek 3. Mówiąc najprościej, stwierdził, że funkcja – metoda AbsoluteHumidity()... w ogóle nie należy do biblioteki Environment Calculations! Ale wcześniej przepuścił zawartą w poprzedniej linijce analogiczną funkcję-metodę DewPoint()!

Rys.3. Błąd zgłoszony przez kompilator

Opis ze strony gihub.com nie zgadza się ze stanem faktycznym!

Korzystajac z Arduino i dostępnych bibliotek, należy się spodziewać licznych tego rodzaju przykrych niespodzianek. Między innymi dlatego, że jest to system otwarty, rozwijany przez hobbystów. Niestety, opisy i dokumentacja zwykle nie są najwyższej jakości, a brak znajomości angielskiego to kolejny poważny problem. Część problemów trzeba usuwać metodą prób i błędów, ale dużą zaletą jest fakt, że jest to system otwarty (open source), więc dostępne są wszystkie pliki źródłowe. I trzeba się nauczyć do nich zaglądać. Im wcześniej, tym lepiej.

Aby wyjaśnić zagadkę z rysunku 3, a przy tym wiele się nauczyć, trzeba zajrzeć do plików bibliotecznych. Biblioteki dołączane przez użytkownika znajdują się w katalogu Dokumenty/Arduino, u mnie: C:\Users\Piotr\Documents\Arduino/libraries

Rys.4 Plik library.properties

Warto zajrzeć do katalogu z biblioteką BME280-master i najpierw do pliku library.properties (rysunek 4). Po otwarciu tego pliku tekstowego (rysunek 5) za pomocą Notepad++ albo np. Notatnika przekonałem się, że istotnie jest to wersja 2.3.0 biblioteki.

Rys.5 Zawartość pliku library.properties

Następnie trzeba wejść niżej do katalogu /src (source), gdzie znajdują się pliki źródłowe – rysunek 6. Tu są właściwe biblioteki, natomiast w katalogu /examples znajdziemy przykłady.

Rys.6 Pliki źródłowe biblioteki BME280-master

W naszym szkicu, wykorzystując dyrektywę preprocesora #include, na początku dołączamy dwie biblioteki. A konkretnie wskazujemy dwa pliki pokazane na rysunku 6, o nazwach <BME280I2C.h> oraz <EnvironmentCalculations.h>. Nawias trójkątny < > wskazuje, że preprocesor ma szukać tych plików właśnie w katalogu /Dokumenty/ Arduino.

Biblioteki Arduino - jak są skonstruowane?

Kolejny raz okazuje się, że Arduino IDE to tylko parawan, zasłona, która przykrywa fakt, że korzystamy z języka C (C++). Mianowicie ściślej biorąc, nie ma tu żadnych arduinowych bibliotek!

Biblioteki Arduino okazują się statycznymi bibliotekami języka C++.

Dla najmniej zorientowanych przypomnienie: aby zwiększyć przejrzystość i klarowność programu, można i warto wydzielić standardowe kawałki programu do oddzielnych plików. Pisząc główny program w języku C i C++, wstawimy w nim tylko niezbędne informacje o tych oddzielnych plikach.

Kompilator C++ podczas kompilacji analizuje nasz główny program, kolejno, począwszy od pierwszej linii. Najogólniej biorąc, jeżeli kompilator podczas takiej analizy kolejnych linijek znajdzie cokolwiek, czego nie zna i o czym nie słyszał, to zgłosi błąd. I tak jest na rysunku 3.

Zapewne jednak już wiesz, że na początku procesu kompilacji zgodnie z instrukcjami #incude, preprocesor dołącza biblioteki.

Jak widać na rysunku 6, interesująca nas teraz arduinowa biblioteka obliczeń środowiskowych to tak naprawdę dwa pliki o nazwach: EnvironmentCalculations.h oraz EnvironmentCalculations.cpp.

Ściślej biorąc, właściwe kawałki kodu bibliotecznego zawarte są w plikach .cpp (C++) i zostaną one dołączone dopiero na końcu procesu kompilacji, gdy konsolidator – linker będzie tworzył finalną, kompletną wersję programu, którą zamieni na kod maszynowy procesora.

Natomiast w naszym szkicu 1 mamy polecenie dołączenia jedynie pliku z rozszerzeniem .h. Jest to tak zwany plik nagłówkowy (h od header, nagłówek). Plik nagłówkowy .h nie zawiera „właściwego kodu”, a jedynie informacje wstępne, żeby uspokoić kompilator podczas analizy szkicu. Aby kompilator nie zgłaszał błędów, że czegoś nie zna, w pliku nagłówkowym .h są podane tylko tak zwane prototypy funkcji, inaczej mówiąc deklaracje funkcji. Nie są to właściwe, pełne funkcje, bo jak już wiemy tzw. ciało, definicja czyli finalny kod poszczególnych funkcji danej biblioteki znajduje się w pliku o tej samej nazwie, ale z rozszerzeniem .ccp. W naszym przypadku kompilator ma problem z funkcją-metodą AbsoluteHumidity(), a nie zgłosił błędu w poprzedniej linijce, gdzie jest pokrewna funkcja DewPoint().

Zaglądamy więc do pliku nagłówkowego EnvironmentCalculations.h i znajdujemy tam m.in. prototypy dostępnych funkcji bibliotecznych, w tym prototyp – deklarację funkcji DewPoint(), co jest pokazane na rysunku 7.

Rys.7 Deklaracji funkcji DewPoint()

Nie ma tu właściwej funkcji, ale jest informacja dla kompilatora, że obliczająca punkt rosy funkcja DewPoint() zwraca obliczoną wartość typu float, a przy jej wywołaniu trzeba jej podać trzy argumenty: wartość temperatury i wilgotności (typu float) oraz wartość logiczną (bool), która określi, czy zwracana wartość będzie „metryczna”. „Metryczna”, „europejska”, a wtedy temperatura punktu rosy będzie wyrażona w stopniach Celsjusza. A „niemetryczna”, „imperialna” da temperaturę w stopniach Fahrenheita.

W pliku nagłówkowym EnvironmentCalculations.h nie znajdziemy natomiast propotypu funkcji AbsoluteHumidity()! Nic więc dziwnego, że kompilator wyrzucił (zgłosił) błąd!

Zainstalowaliśmy automatycznie teoretycznie najnowszą bibliotekę, a oto okazało się, że w Githubie w tym czasie była już dostępna nowsza wersja o większych możliwościach!

Arduino - operacje na bibliotekach

Ściągnąłem więc ze strony: https://github.com/finitespace/BME280 plik .ZIP według rysunku 8.

Rys.8 Biblioteka BME280 na githubie

Bez żadnego odinstalowania po prostu skasowałem katalog z biblioteką BME280, a ściągnięty plik ZIP rozpakowałem do katalogu

Dokumenty/Arduino/libraries/

Okazało się, że rozpakowany katalog ma nazwę BME280-master i że pojawił się dodatkowy podkatalog .docs, jak pokazuje rysunek 9.

Rys.9 Zawartość ZIPa z biblioteką

Po ponownym uruchomieniu szkic 1 (A0501.ino) skompilował się bez problemu. Rysunek 10 dodatkowo udowadnia, że nowa biblioteka nie wymaga szczególnej instalacji i jest widoczna w Arduino IDE.

Rys.10 Informacja o zainstalowanej bibliotece

Mamy tu dwa bardzo ważne wnioski.

Po pierwsze nie zawsze warto korzystać z wbudowanego w Arduino IDE mechanizmu automatycznego pobierania i aktualizowania bibliotek.

Po drugie okazało się, iż ręczna (de)instalacja bibliotek jest bardzo prosta.

Tylko dla dociekliwych

Gdy znów zajrzymy do pliku nagłówkowego EnvironmentCalculations.h, w nowej wersji oczywiście znajdziemy prototyp funkcji AbsoluteHumidity(), jak pokazuje rysunek 11.

Porównaj go z rysunkiem 7. Także i ta funkcja zwraca wynik typu float, i też przyjmuje trzy argumenty. Zwróć uwagę, że trzeci argument przekazywany do funkcji to jednostka temperatury (TempUnit). W nowej wersji zmieniono też deklarację funkcji DewPoint(), jak pokazuje rysunek 12.

W starej wersji biblioteki (rysunek 7) za pomocą wartości logicznej (bool) określaliśmy, czy temperatura punktu rosy ma być wyrażona w stopniach Celsjusza czy Fahrenheita, co jest potrzebne w Ameryce.

Rys.11 Prototyp funkcji AbsoluteHumidity()

W nowej wersji korzystamy z parametru TempUnit. Okazuje się, że jest to wewnętrzna, (prywatna) zmienna, ale nie zmienna logiczna typu bool (boolean), tylko niepotrzebnie straszącego początkujących typu enum.

Enum to tak zwany typ wyliczeniowy i jak pokazuje to rysunek 13, w tym wypadku pierwsza wyliczeniowa wartość, czyli liczba 0 będzie oznaczać temperaturę w stopniach Celsjusza, a następna wartość, czyli 1, będzie oznaczać stopnie Fahrenheita.

Rys.12 Deklaracja funkcji DewPoint() - nowsza wersja biblioteki
Rys.13 Enum - typ wyliczeniowy

Możesz się samodzielnie zastanowić, czy podanie jako trzeciego argumentu funkcji DewPoint() wartości 0 oznacza to samo w starej i nowej wersji biblioteki?

Możesz też poeksperymentować ze szkicem 1: w funkcjach DewPoint() i AbsoluteHumidity() jako trzeci argument podaj 1, albo podaj tylko dwa argumenty, bez trzeciego.

Nasuwa się tu trzeci wniosek: biblioteki Arduino przygotowane przez autorów o zróżnicowanym poziomie wiedzy i doświadczenia mogą sprawić rozmaite niespodzianki. Na szczęście przy odrobinie wnikliwości pojawiające się problemy można przezwyciężyć. Zazwyczaj wystarczy zajrzeć do bibliotek, ale trzeba mieć trochę wiedzy na temat języka C (i C++).

Fot.14 Miernik punktu rosy i zawartości wody w powietrzu-gotowy model 

A jeśli już weszliśmy tak głęboko, to aż prosi się, żeby bliżej przyjrzeć się bibliotekom. Jednak to szeroki temat i zrobimy to przy innej okazji.

A teraz cieszymy się sukcesem: zbudowaliśmy miernik, który pokazuje punkt rosy i zawartość wody w powietrzu. Mój model zamieszczony jest na fotografii 14. Jeśli chcesz, możesz rozbudować szkic 1 (A0501), żeby miernik co kilka sekund wyświetlał na przemian temperaturę i wilgotność względną oraz punkt rosy i wilgotność absolutną.

Fot.15 Czujniki

W następnych odcinkach kursu spróbujemy dodać do naszego systemu więcej czujników temperatury, wilgotności i ciśnienia. Będziemy się też przymierzać do pomiaru zawartości dwutlenku węgla za pomocą czujnika MH-Z19B (fotografia 15).

Do pobrania
Download icon Materiały do: Kurs Arduino odcinek 5 - biblioteki do trzyfunkcyjnego czujnika BME280
1. Kurs Arduino: wprowadzenie 2. Kurs Arduino odcinek 1 - co to jest i jak zacząć? (sprzęt, schematy, programowanie) 3. Kurs Arduino odcinek 2 - termometry: 'diodowy', pokojowy oraz 'scalony' analogowy 4. Kurs Arduino odcinek 3 - moduł wyświetlacza LCD (HD44780) 5. Kurs Arduino odcinek 4 - czujnik BME280 (pomiar ciśnienia, wilgotności i temperatury) 6. Kurs Arduino odcinek 5 - biblioteki do trzyfunkcyjnego czujnika BME280 7. Kurs Arduino odcinek 6 - wykorzystanie łącza I2C (TWI) 8. Kurs Arduino odcinek 7 - wykorzystanie łącza SPI (karty pamięci, MAX31865, MAX31855) 9. Kurs Arduino odcinek 8 - wykorzystanie czujnika dwutlenku węgla (MH-Z19) 10. Kurs Arduino odcinek 9 - wykorzystanie modułów do odmierzania czasu 11. Kurs Arduino odcinek 10 - wykorzystanie czujników temperatury (DS18B20) 12. Kurs Arduino odcinek 11 - budowa loggera (rejestratora danych) 13. Kurs Arduino odcinek 12 - rejestracja i prezentacja danych oraz obsługa karty SD 14. Kurs Arduino odcinek 13 - rejestracja danych (wykorzystanie modułu OpenLog) 15. Kurs Arduino odcinek 14 - czym zastąpić płytkę Arduino Uno? 16. Kurs Arduino odcinek 15 - budowa rejestratora (chiński klon Arduino Pro Mini) 17. Kurs Arduino odcinek 16 - problemy z kwadratowym modułem Strong 18. Kurs Arduino odcinek 17 - czujniki do pomiaru wilgotności gleby (instalacja, konfiguracja) 19. Kurs Arduino odcinek 18 - protokół MODBUS i łącze RS-485 20. Kurs Arduino odcinek 19 - wyświetlacze od podstaw (matrycowe, 7-segmentowe, MAX7219) 21. Kurs Arduino odcinek 20a - wyświetlacze matrycowe i biblioteki MD_MAX 22. Kurs Arduino odcinek 20b - przyciski i biblioteki do obsługi wyświetlaczy 23. Kurs Arduino odcinek 20c - biblioteki do obsługi wyświetlaczy graficznych 24. Kurs Arduino odcinek 21 - moduł wyświetlacza OLED 25. Kurs Arduino odcinek 22 - moduł wyświetlacza 1,3 cala 26. Kurs Arduino odcinek 23 - przygotowanie bitmap do wyświetlania 27. Kurs Arduino odcinek 24 - omówienie fontu podstawowego (Adafruit GFX) 28. Kurs Arduino odcinek 25 - font podstawowy biblioteki Adafruit GFX 29. Kurs Arduino odcinek 26 - wykorzystanie bitmapowych fontów GFX 30. Kurs Arduino odcinek 27 - polskie znaki w glcdfont.c 31. Kurs Arduino odcinek 28 - zmiana ulepszonych fontów GFX
Tematyka materiału: czujnik BME280
AUTOR
Źródło
Elektronika dla Wszystkich lipiec 2018
Udostępnij
UK Logo