W poprzednim wpisie zająłem się wychodzącym już z produkcji, popularnym czujnikiem ciśnienia oraz temperatury BMP180. Dzisiaj sprawdzę jego młodszych braci – BMP280 mierzący tak samo temperaturę i ciśnienie oraz BME280, który dodatkowo potrafi sprawdzić jak bardzo jest wilgotna…
atmosfera 😉 Jedziemy z koksem!
BMP280
Schemat połączeniowy z płytką Nucleo F401RE w zasadzie się nie zmienił. Chiński moduł z BMP280 nazywa się tym razem GY-BMP280 i posiada 6 pinów. Dwa ostatnie posiadają podciągnięcia na PCB na ich defaultowe pozycje, więc nie ma konieczności podłączania ich gdziekolwiek.
Konfiguracja STM32CubeMX nie zmienia się w niczym w porównaniu do BMP180.
Dokumentacja BMP280 zawiera świetną tabelę porównawczą do swojego starszego odpowiednika. Pozwól, że ją po prostu wkleję.
Z ważniejszych dla mnie różnic są jego wymiary zewnętrzne. Jest wyraźnie mniejszy, co mnie cieszy bo mam już pewien pomysł na zastosowanie tego czujnika. Bosh zaznaczył tutaj sporą różnicę w poborze prądu co jest również wielkim plusem. Rozdzielczości przy zastosowaniu np w stacji pogodowej nie grają tutaj wielkiej roli, ale fajnie, że są większe. Nie podano w tej tabeli dokładności pomiarów. Dlaczego? Bo są takie same jak dla starszego brata. Komunikacja za pomocą SPI. Może komuś się przyda. Chińskie moduły tej na ogół nie wspierają.
Ważną różnicą są tryby pracy. W młodszym BMP280 nie ma możliwości oddzielnej konwersji temperatury i ciśnienia. W poprzednim wpisie sprawdzałem czas konwersji samej temperatury oraz temparatury + ciśnienia. Z pierwszego pomiaru muszę tutaj zrezygnować.
W nowych czujnikach wprowadzono nowy tryb pracy. Trybem zbliżonym to tego, co robiłem przy BMP180 jest tryb forced. Aby skorzystać z tego trybu należy uruchomić czujnik w trybie sleep. Następnie chcąc dokonać konwersji wpisać do rejestru 0xF4 dane odpowiadające trybowi forced. Wtedy startuje proces konwersji który sygnalizowany jest flagą trwania konwersji. W teorii należy poczekać, aż flaga ta zniknie. Tak jest w teorii natomiast BMP280 płatał mi figle. Flaga ta przy zegarze 100 kHz ustawiała się z opóźnieniem trwającym mniej więcej tyle czasu co sprawdzenie, czy interesujący mnie tryb został wywołany. Dało się to przeżyć(byłem pewny wejścia w tryb forced), ale przy 400 kHz nie byłem w stanie określić kiedy ta flaga się ustawi, abym mógł czekać na jej wyzerowanie. Co zrobiłem? Olałem tę flagę. Zamiast niej sprawdzam, czy czujnik wyszedł już z trybu forced. Bowiem po zakończeniu pomiaru, BMP280 samoczynnie wychodzi z tego trybu i ląduje w sleep. No i to działa elegancko! Jak wyglądają przebiegi dla trybu forced?
100 kHz
400 kHz
Różnica między funkcjami odczytu temperatury i ciśnienia jest znikoma. Ma to związek z połączeniem konwersji tych dwóch wielkości stąd też dalsze rozważania osobnej konwersji pominę. Różnice czasowe widoczne na wykresach dotyczą dodatkowego odczytu rejestru ciśnienia oraz przeliczenia danych na właściwą wartość. Dlatego dodałem do biblioteki funkcję, która zwraca dwie wartości do podanych przez wskaźniki zmiennych umieszczonych w argumentach. Dwie pieczenie na jednym ogniu 🙂
Wypadałoby jeszcze przedstawić wyniki czasów konwersji różnych dokładności w postaci tabelarycznej. Tutaj BMP280 wprowadza dodatkowy stopień dokładności pomiaru do zużycia prądu. Mamy ich w sumie 5. Pomiarów dokonałem przy 16-bitowej rozdzielczości konwersji temperatury – tak, jak jest to w BMP180. Zwiększając rozdzielczość temperatury wydłuża się czas konwersji – wiadomo. Pominę te testy, bo 16-bitów na tą wielkość to i tak bardzo ładny wynik. A no i zrezygnowałem z mierzenia z chamskim delay’em. W poprzednim wpisie już stwierdziłem, że nie jest do niczego potrzebny. Oto wyniki:
100 kHz | 400 kHz | |
Ultra Low Power | 7,73 ms | 6,07 ms |
Low power | 9,7 ms | 8,1 ms |
Standard | 13,64 ms | 11,96 ms |
Highres | 21,53 ms | 19,89 ms |
Ultrahighres | 37,32 ms | 35,74 ms |
BME280
Ten Pan jest to rozbudowany o pomiar wilgotności BMP280. Nawet chińskie moduły potrafią być identyczne, a najczęstszą różnicą jest maźnięty markerem inny kwadracik oznaczający wersję zamontowanego czujnika(lub nie maźnięty jak u mnie). W porównaniu do BMP280 rozbudowany jest też trochę fizycznie, gdyż jego wymiary wynoszą 2,5 x 2,5 x 0,95 mm. 0.,5 mm na jednej długości to nie jest jednak wielka różnica. Powinien bez problemu pasować w footprint BMP280. Jednak najważniejszą zmianą jest dodanie pomiaru wilgotności powietrza, która dokonywana jest z dokładnością ±3 %RH oraz rozdzielczością 0.008 %RH. Zakres temperaturowy działania w pełnym zakresie 0÷100 %RH dostępny jest dla temperatur 0÷65 °C. W zakresie -40÷0 °C oraz 65÷85 °C jest nieco ograniczony od góry, co można znaleźć w dokumentacji. Zarówno jak dla pozostałych mierzonych wielkości, konwersja wilgotności pobiera bardzo mało prądu. Przy samplowaniu co sekundę jest to typowo 2,8 μA. Parametry pomiary temperatury i wilgotności są niemal identyczne jak w BMP280. Podobnie tryby dokonywania pomiarów i rozdzielczości. Pomiar temperatury i ciśnienia teoretycznie jest zawarty w takim samym czasie jak dla BMP280. Jak mocno więc wydłuża czas konwersji dodanie pomiaru wilgotności? Sprawdzam!
Konwersję wywołuję w trybie forced jednorazowo, zbieram dane i obliczam wyniki w jednej funkcji. Dla najniższego samplowania przebieg odczytu wygląda następująco:
100 kHz
400kHz
Dodatkowy pomiar wilgotności wydłuża całościowy czas konwersji o około 3 milisekundy w porównaniu do konwersji samej temperatury i ciśnienia przez BMP280. Jest to natomiast najniższa możliwa dokładność pomiaru wilgotności. Poniżej znajduje się tabela z wynikami dla wszytkich stopni oversamling’u. Temepatura ustawiona na 16-bit, ciśnienie na standard.
100 kHz | 400 kHz | |
Ultra Low Power | 16,49 ms | 14,65 ms |
Low power | 18,46 ms | 16,67 ms |
Standard | 22,41 ms | 20,64 ms |
Highres | 30,31 ms | 28,58 ms |
Ultrahighres | 46,45 ms | 44,39 ms |
W ramach ciekawostki jeszcze czas uzyskania wyników dla wszystkich najniższych opcji oraz najwyższych na czujniku BME280.
100 kHz | 400 kHz | |
All lowest | 10,58 ms | 8,736 ms |
All highest | 99,72 ms | 98,05 ms |
Rozpiętość jest ogromna i należy odpowiedzieć sobie na czym tak naprawdę zależy w projekcie. Przy urządzeniu bateryjnym pewnie będzie potrzeba pójścia w kierunku najniższych wartości oversampling’u i rozdzielczości. Dla zasilania sieciowego można pokusić się o najwyższe opcje. Należy wtedy pamiętać i zbudowaniu systemu tak, aby cały czas działał płynnie. 100 milisekund może dla człowieka nie jest dużo, ale taki czas oczekiwania np. między kolejnymi ramkami wyświetlacza przy prostym sterowaniu może być już niekomfortowy dla użytkownika urządzenia. Jest jeszcze inna możliwość niż ręczne wymuszanie konwersji.
Normal mode
Niewątpliwie wielką zmianą w porównaniu do BMP180 jest dodanie trybu periodic(normal). Co on daje? Automatyczną, cykliczną konwersję temperatury, ciśnienia oraz jeśli jest – wilgotności. Czujnik nie potrzebuje naszego sygnału do startu konwersji – pomiar dokonywany jest cyklicznie bez ingerencji MCU. Dzięki temu późniejszy odczyt jest zdecydowanie szybszy. Ale nic za darmo. Cykliczna konwersja oznacza również cykliczny zwiększony pobór prądu. Należy mieć to na uwadze projektując urządzenie bateryjne. Należy też wspomnieć, że BMP280 i BME280 default’owo są ustawione w tryb normal. W trybie tym można odczytać tylko jeden jak i wszystkie parametry na raz. Ile to trwa? Przykład dla BMP280:
100 kHz
400 kHz
W porównaniu do wymuszania konwersji i oczekiwania na jej zakończenie przy BMP180 oraz w trybie forced jest to czas piorunująco szybki. Czas poniżej 1 ms robi wrażenie. Moim zdaniem warto używać tego trybu przy zasilaniu sieciowym. Baterynie? Zależy od wymagań. Trzeba byłoby zrobić głębsze testy w dłuższej perspektywie czasu czy pomiar cykliczny ma duży wpływ na czas pracy z ogniwa. Przyjdzie na to odpowiedni czas 🙂
W rejestrze konfiguracyjnym podstawowym ustawieniem jest czas bezczynności(inaczej interwał), który znajduje się między kolejnymi konwersjami.
Myślę, że jest to dosyć proste do zrozumienia. Jeśli nie to dokumentacja ma do tego odpowiedni rysunek. Jest to czas t_standby.
Drugim parametrem jaki można ustawić to filtr IIR dla pomiaru ciśnienia. Jest to filtr o nieskończonej odpowiedzi impulsowej. Po co on tutaj? Ciśnienie jest parametrem, który może zmieniać się bardzo szybko w czasie(np. dmuchnięcie). Dlatego też BMP/BME280 posiadają wbudowany filtr, który zaburzenia takie niweluje. Standardowo jest on wyłączony i np. do budowy stacji pogodowej nie jest on szczególnie zalecany. Za to do budowy drona już jak najbardziej. Więcej informacji na temat jego działania znajdziesz w nocie czujnika.
To by było na tyle tego dwuwpisowego cyklu na temat popularnych czujników ciśnienia od firmy Bosch. Dziękuję Ci bardzo jeśli tutaj dotarłeś. Zachęcam do zajrzenia w inne moje posty.
Jeżeli czujniki Ci się spodobały, możesz nabyć je u mnie w sklepie: BMP280, BME280.
Kod źródłowy użyty w tym wpisie znajdziesz na GitHubie: link
Jeśli zauważyłeś jakiś błąd, nie zgadzasz się z czymś lub po prostu uważasz, że chciałbyś podystkutować w tym temacie, napisz komentarz. Pamiętaj, że dyskusja ma być kulturalna i zgodna z zasadami języka polskiego.
4 komentarze
Adrien · 20/06/2021 o 21:29
Cześć Mateuszu
Mam pytanie czy ten kod może działać w “stm32f1xx_hal.h”
Dzięki
Mateusz Salamon · 28/06/2021 o 12:08
A czemu chcesz wrzucać kod do nagłówka? 🙂 Z STM32F1xx będzie działał.
amilo_pa · 18/10/2020 o 00:03
Hej Mateusz,
Mam pewną zagwozdkę i chciałbym żebyś mi wyjaśnił jeden temat:)
W RM do F103, w rozdziale “3.2 Memory organization” jest napisane, że: The bytes are coded in memory in Little Endian format. Czy słowo 16 bitowe zapisywane jest w postaci LSB-MSB (jak się mylę to mnie popraw).
W datasheet do BMP280 w tabeli 17 jest informacja, że zmienne dig_Tx i dig_Rx są zapisane w rejestrech w postaci LSB/MSB (0x88 -> LSB / 0x89->MSB).
I teraz tak, na Twoim gitcie https://github.com/lamik/BMXX80_STM32_HAL/blob/master/Src/BMXX80.c masz takie takie dwie funkcje:
1.:
uint16_t BMP280_Read16(uint8_t addr)
{
#if(BMP_I2C == 1)
uint8_t tmp[2];
HAL_I2C_Mem_Read(i2c_h, BMP280_I2CADDR, addr, 1, tmp, 2, 10);
return ((tmp[0] < tmp[0] to LSB, przesówasz go o 8 bitów w lewo dodajesz MSB. Spoko dostajesz zapis Little Endian dla liczby 16bitowej.
a teraz do odczytu wyżej wspomnianych paramatrów używasz funkcji BMP280_Read16LE:
t1 = BMP280_Read16LE(BMP280_DIG_T1); -> rozumiem, że LE pochodzi od formatu Little Endian.
i teraz tak, ciało tej funkcji to
uint16_t BMP280_Read16LE(uint8_t addr)
{
uint16_t tmp;
tmp = BMP280_Read16(addr);
return (tmp >> 8) | (tmp < czyli zamieniasz LSB z MSB miejscami i dostajesz Big Endian.
}
Jeżeli się mylę to mnie popraw 🙂
Mateusz Salamon · 20/10/2020 o 08:07
Hej! To oznaczenie funkcji jako LE może być faktycznie trochę mylne. Chodzi o zamianę bajtów, ale czy koniecznie na LE… to już nie jest takie jasne 🙂 Zobacz, że funkcję Read16 przygotowałem pod czytanie rejestrów z pomiarami. One są właśnie zapisywane MSB-LSB, czyli BigEndian. W returnie zwracam tak, aby STM32 był w stanie je normalnie czytać, czyli przekształcam do LE. Teraz tej samej funkcji nie mogłem użyć do odczytu stałych kalibracyjnych, bo one z kolei są wpisane “odwrotnie LSB-MSB”. Stąd musiałem je odwrócić 🙂