BMP180 – obsługa cyfrowego czujnika ciśnienia (moduł GY-68)

W poprzednim artykule przedstawiłem bibliotekę do obsługi czujnika ciśnienia HP02S. Natomiast tym razem prezentuję mój pomysł na obsługę czujnika ciśnienia i temperatury BMP180 firmy BOSCH. Czujnik ten został kupiony wraz z modułem GY-68, który posiada odpowiednie komponenty do prawidłowego (prawie – o tym można przeczytać dalej) działania całego układu – stabilizator, kondensatory, oraz rezystory.

Najważniejsze cechy czujnika:

  • zakres mierzonego ciśnienia – 300 do 1100hPa (pomiar ciśnienia bezwzględnego)
  • zakres mierzonej temperatury – -40 do +85°C
  • napięcie zasilania – 1,8 do 3,6V
  • pobór prądu w trybie standby – 0.1 μA
  • interfejs I2C
  • układ posiada 11 współczynników kompensujących – brak potrzeby kalibracji czujnika
  • czas konwersji zależny od rozdzielczości
  • rozdzielczość mierzonego ciśnienia (w zależności od rozdzielczości) – 16 do 19 bit.
  • maksymalna częstotliwość linii SCL – 3.4MHz

Więcej informacji dotyczących parametrów układu znajduje się w nocie katalogowej. – nie będę ich wszystkich tutaj przepisywał Jak można zauważyć jest to czujnik, który pobiera mało energii w stosunku do swoich parametrów – pobór mocy jest zależny od rozdzielczość mierzonego ciśnienia. W zależności od konfiguracji rejestrów, możliwy jest odczyt ciśnienia z bardzo dużą rozdzielczością do 19 bitów, z dokładnością do 0,03hPa. Producent układu BMP180 umożliwił użytkownikowi obliczenie oprócz ciśnienia również temperatury otoczenia w którym znajduje się ten układ – w przeciwieństwie do wcześniej przeze mnie omawianego czujnika HP02S.

Podział pamięci układu BMP180 - zaczerpnięte z noty katalogowej układu
Podział pamięci układu BMP180 – zaczerpnięte z noty katalogowej układu

Do obliczenia ciśnienia, oraz temperatury wymagane jest odczytanie 11 współczynników korygujących, które są zapisane w rejestrze układu – odczyt odbywa się od rejestru 0xAA do 0xBF. Dodatkowo w rejestrze konfigurujemy rozdzielczość dla pomiaru ciśnienia (2 najbardziej znaczące bity komórki o adresie 0xF4 ). Jednorazowo z rejestru można odczytać temperaturę bądź ciśnienie – aby można było tego dokonać w komórce o adresie 0xF4 należy umieścić wartość 0x0E dla pomiaru temperatury, bądź 0x14 dla pomiaru ciśnienia (dodatkowo należy skonfigurować oversampling – w skrócie ilość wykonywanych pomiarów dla uzyskania większej dokładności). Start pomiarów wykonuje się ustawiając bit 5 rejestru 0xF4 w stan '1′. Odczyt zmierzonych wartości temperatury odczytuje się z dwóch rejestrów (0xF6, 0xF7), a ciśnienia z trzech (0xF6, 0xF7, oraz 0xF8, przy czym pod ostatnim adresem znajdują się maksymalnie 3 bity – zależy od ustawionej wartości oversampling). Producent udostępnił użytkownikowi możliwość wykonania resetu układu (przynosi taki sam efekt jak reset zasilania) poprzez wpisania jedynek do pamięci pod adres 0xE0.

Dodatkowo można przeprowadzić test działania układu odczytując dane z rejestru 0xD0. Wartość tego rejestru powinna wynosić 0x55 – nie jest ona zmienna i powinna wynosić tyle samo dla każdego układu.

Krótki opis przedstawiający korzystanie z czujnika BMP180:

Algorytm przedstawiający sposób obsługi czujnika BMP180
Algorytm przedstawiający sposób obsługi czujnika BMP180 – zaczerpnięte z noty katalogowej
Tabela przedstawiające wartości określające typ pomiaru - zaczerpnięte z noty katalogowej
Tabela przedstawiające wartości określające typ pomiaru – zaczerpnięte z noty katalogowej

W nocie katalogowej znajduje się algorytm przedstawiający zasadę odczytu danych pomiarowych. Pierwszą czynnością jaką należy wykonać jest wysłanie do czujnika polecania startu pomiaru temperatury. Producent zaleca odczekanie przynajmniej 4.5ms – czas potrzebny na wykonanie pomiaru – przed odczytem danych z rejestru (z komórek o adresie 0xF6 oraz 0xF7). Po odczytaniu UT należy wysłać komendę rozpoczynającą pomiar ciśnienia o określonej dokładności. Czas jaki należy odczekać do uzyskania wyniku pomiaru ciśnienia, zależy od dokładności tego pomiaru i może zawierać się w przedziale od 4.5ms do 25.5ms – są to wartości graniczne dolne.Po odczekaniu tego okresu, można z rejestru odczytać dane dla UP i w następnym kroku wykonać obliczenia dla uzyskania temperatury, oraz ciśnienia. Podczas odczytywania danych dla ciśnienia należy pamiętać, że dla rozdzielczości większej od 16 bitów (czyli dla 17, 18 i 19 bitów), należy odczytać pozostałe dane pomiarowe (odpowiednio bity 1, 2 i 3 w zależności od rozdzielczości pomiaru) z adresu 0xF8 (XLSB).

Dodatkowo na samym początku programu – przed pętlą główną programu – należy wykonać odczyt współczynników kalibrujących, które są niezbędne do prawidłowego obliczenia ciśnienia i temperatury.

Komendy rozpoczynające określony pomiar są to wartości jakie należy wpisać w odpowiednią komórkę w pamięci czujnika BMP180. Adres tej komórki to 0xF4 a wartości określające dany pomiar zostały przedstawione na wcześniejszym obrazku – zaczerpniętym z noty katalogowej.

Układ BMP180 komunikuje się z mikrokontrolerem przy użyciu magistrali I2C. Aby więc do tej komunikacji mogło dojść potrzebny jest adres czujnika – adres ten jest na stałe zdefiniowany i każdy czujnik posiada taki sam. Dla zapisu danych adres ten wynosi 0xEE, natomiast dla odczytu 0xEF.

Moduł GY-68 – ciekawe rozwiązanie:

Parametry I2C - zaczerpnięte z noty katalogowej
Parametry I2C – zaczerpnięte z noty katalogowej

Do testowania, oraz dla celów rozwojowych kupiłem moduł GY-68 wraz z układem BMP180. Moduł ten zaciekawił mnie tym, że posiada w swojej konstrukcji stabilizator na 3.3V do zasilenia czujnika. Myślałem również, że jeżeli moduł posiada tylko stabilizator na 3.3V to nie potrzebna jest konwersja napięć dla linii sygnałowych SDA i SCL. Moduł zakupiłem i gdy przyszedł czas na zapoznanie się szczegółowo z notą katalogową okazało się, że napięcie na liniach magistrali I2C nie może być większe od napięcia zasilania (a dokładnie napięcie linie I/O które w tym module wynosi tyle samo co napięcie zasilania), które maksymalnie może wynieść 3.6V (w nocie można znaleźć również informację o tym, że maksymalne napięcie doprowadzone do wszystkich pinów nie może być większe od 4.25V co i tak dyskwalifikuje układy zasilanie z 5V). Więc po co producent tego układu zastosował stabilizator na napięcie 3.3V? Może dlatego, że przy testach układ działała, bo …. działał wbrew temu co producent umieścił w nocie katalogowej (możliwe też, że producent założył, że linie będą działały na 3.3V a zasilanie samego modułu będzie wynosiło 5V – trudno odgadnąć cel takiego rozwiązania). Ja zawsze zalecam aby ściśle stosować się do tego co dany producent danego układu pisze w nocie, a szczególnie brać pod uwagę parametry graniczne – w tedy jest się pewnym, że układ będzie działał poprawnie. Moduł GY-68 jest tani w porównaniu do samego układu BMP180, oraz do innych modułów z tym układem, dlatego jest tak popularny, a część schematów co znalazłem nie posiada translacji poziomów przy zasilaniu całego urządzenia z 5V.

Dla tego modułu polecam stosowanie konwersji napięć na liniach sygnałowych SCL i SDA. Można tego dokonać stosując dedykowane układy, bądź przy pomocy tranzystorów polowych. Przykład takiego podłączenia z wykorzystanie tranzystorów przedstawiam poniżej:

Zamiast zaprezentowanych tranzystorów MOSFET z kanałem typu N można zastosować inne tranzystory, np. BSS138 lub podobne. W powyższym schemacie nie umieściłem rezystorów podciągających do 3.3V z tego powodu, że na płytce modułu GY-68 takie rezystory już się znajdują. Do układu zostało dostarczone napięcie 5V (może być również mniejsze – zakres od 3.3V do 5V), gdyż jak już wcześniej wspomniałem, moduł posiada własny stabilizator na napięcie 3.3V.

Natomiast dedykowanym układem do konwersji napięć na liniach sygnałowych (translacji poziomów) jest układ MAXIM-DALLAS MAX3378EEUD. Zastosowanie tego układu dla hobbysty powoduje, że cena budowane urządzenia trochę wzrośnie. Więc do wyboru jest, albo zastosowanie dedykowane translatora poziomów, albo wykorzystanie tranzystorów polowych.

Budowa i działanie biblioteki:

Biblioteka składa się z dwóch plików:

  1. Nagłówkowego – ds_bmp180.h, oraz
  2. Źródłowego – ds_bmp180.c.

Obsługę czujnika starałem się tak wykonać, aby kod była jak najbardziej uniwersalny. Dodatkowym atutem tej biblioteki jest to, że funkcje są nie blokujące – jakiekolwiek opóźnienia występujące w programie, są wykonane na timerach programowych (które wykorzystują jeden timer sprzętowy). Użytkownikowi dałem do dyspozycji strukturę w której znajdują się obliczone wartości temperatury, oraz ciśnienia z podziałem na wartości po przecinku i całości (dla temperatury jest także zmienna określająca czy dana wartość jest ujemna czy dodatnia). W strukturze tej znajdują się także inne informacje odczytane z pamięci układu – opis znajduje się poniżej:

typedef struct{
	int32_t	bmp180_UT;					//wartosc UT odczytana z układu
	int32_t bmp180_UP;					//wartosc UP odczytana z układu
	uint8_t bmp180_temp_sign;			//temperatura - znak
	uint8_t bmp180_temp_cell;			//temperatura - calosc
	uint8_t bmp180_temp_frac;			//temperatura - wartosc po przecinku
	uint16_t bmp180_pressure_cell;		//cisnienie - calosc
	uint8_t bmp180_pressure_frac;		//cisnienie - wartosc po przecinku
	uint8_t chip_id;					//id chipu - 0x55
	uint8_t ver_regist;					//wersja rejestru
}DS_BMP180;

extern DS_BMP180	ds_bmp180;

Na początku programu, przed pętlą główną i uruchomieniem funkcji z biblioteki należy zarejestrować funkcje do obsługi magistrali I2C, wywołując następujące funkcje:

	//********** 	rejestracji funkcji i2c potrzebnych dla bmp180
	register_twi_start_bmp180(TWI_start);						//rejestracja funkcji start z i2c
	register_twi_stop_bmp180(TWI_stop);							//rejestracja funkcji stop z i2c
	register_twi_read_bmp180(TWI_read);							//rejestracja funkcji read z i2c
	register_twi_write_bmp180(TWI_write);						//rejestracja funkcji write z i2c

Dzięki tym funkcjom, biblioteka jest uniwersalna, tzn. współpracują z prawie każdą biblioteką do obsługi I2C. Wymagania jakie powinny spełniać rejestrowane funkcje do I2C to brak zwracanej wartości dla funkcji start, stop (dla tych dwóch również brak przekazywanych argumentów), oraz write. Dla funkcji read zwracana wartość powinna być typu uint8_t. Natomiast do funkcji read, oraz write powinny być przekazywane argumenty o typie uint8_t – dla read przekazywana jest informacja o wysyłanym potwierdzeniu (ACK), a dla write, adres bądź dane.

Po rejestracji funkcji, należy odczytać współczynniki, które są niezbędne do prawidłowego obliczenia ciśnienia i temperatury. Wykonuje się to raz na początku programu poprzez wywołanie funkcji:

	//**********	odczyt współczynników potrzebnych do poprawnego pomiaru
	ds_bmp180_coeff();

Do funkcji, która powoduje rozpoczęcie pomiarów, należy przesłać informację o ilości wykonanych próbek. Dzięki temu, jest możliwość zmiany dokładności w każdym miejscu tworzonego programu. Funkcję ta nie powinna być wywoływana za każdym razem w obiegu pętli – pomiar może być wykonywany na żądanie.

//Start pomiaru
	ds_bmp180_start(BMP180_OSS_8);


//wyrażenia do wpisania w funkcji ds_bmp180_start określające ilość próbek (oversampling)
BMP180_OSS_1
BMP180_OSS_2
BMP180_OSS_4
BMP180_OSS_8

Cała obsługa czujnika BMP180 znajduje się w funkcji wykonującej pomiary. Funkcja ta powinna znaleźć się w pętli głównej i nie powinna być przerywana żadnymi opóźnieniami typu _delay__, aby nie doszło do błędów podczas obsługi czujnika. Po zakończeniu pomiaru funkcja zwraca 1, ale tylko na czas jednego obiegu pętli głównej – później zwracana wartość wynosi 0.

ds_bmp180_measure();

Jedyny wymóg jaki jest postawiony użytkownikowi, to skonfigurowanie przerwania wykonywanego co 1ms i umieszczeniu wewnątrz tego przerwania następującego warunku:

if(bmp180_time_1ms--);

Zostały również utworzone dwie dodatkowe funkcje. Pierwsza funkcja powoduje zresetowanie układu, czego skutkiem jest taki sam efekt jak przy zresetowaniu układu (przywrócenie wartości domyślnych w rejestrach), oraz funkcja sprawdzająca czy dany czujnik jest aktywny (zwraca 1 lub 0 w zależności od tego czy podłączony układ działa czy nie).

ds_bmp180_restart();
ds_bmp180_active();

Przykładowy program:

//obsługa przerwania
ISR(TIMER0_COMP_vect){

	if(++time_1ms < 9){
		time_1ms=0;

		if(++time_10ms < 99){
			time_10ms=0;

			if(++time_1s < 59) time_1s=0;
		}
	}

	if(bmp180_time_1ms--);

}// /isr

int main(void){
	
	//inicjalizacja LCD
	lcd_init();

	//********** 	rejestracji funkcji i2c potrzebnych dla bmp180
	register_twi_start_bmp180(TWI_start);						//rejestracja funkcji start z i2c
	register_twi_stop_bmp180(TWI_stop);							//rejestracja funkcji stop z i2c
	register_twi_read_bmp180(TWI_read);							//rejestracja funkcji read z i2c
	register_twi_write_bmp180(TWI_write);						//rejestracja funkcji write z i2c

	//inicjalizacja przerwań
		//timer0 w trybie ctc
	TCCR0 |= (1<<WGM01);				//tryb CTC
	TCCR0 |= (1<<CS01) | (1<<CS00);			//preskaler 64
	OCR0 = 255;								//co 1ms dla preskalera 64 bity i kwarcu 16MHz
	TIMSK |= (1<OCIE0);				//aktywacja przerwania

	//aktywacja przerwań
	sei();
	
	//program własciwy
	lcd_cls();

	//**********	odczyt współczynników potrzebnych do poprawnego pomiaru
	ds_bmp180_coeff();

	ds_bmp180_start(BMP180_OSS_8);

	while(1){
		
		if( (time_1s != time_ls) && !(time_1s % 10) ){
			time_ls = time_1s;
			ds_bmp180_start(BMP180_OSS_8);
			lcd_locate(0,0);
			if(ds_bmp180.bmp180_temp_sign)
				lcd_char('-');

			lcd_int(ds_bmp180.bmp180_temp_cell);
			lcd_char(',');
			lcd_int(ds_bmp180.bmp180_temp_frac);

			lcd_locate(0,8);
			lcd_int(ds_bmp180.bmp180_pressure_cell);
			lcd_char(',');
			lcd_int(ds_bmp180.bmp180_pressure_frac);
		}
		ds_bmp180_measure();
	}
}

Pliki biblioteki:

Pobierz “DS_BMP180.zip”

DS_BMP180.zip – Pobrano 31319 razy – 4,57 KB

Zachęcam do pobierania, oraz zadawania pytań.

5 Komentarzy

  1. Anonim

    Przydatny czujnik, i dobra biblioteka. Dzieki

  2. Krzysiek

    Bardzo przydatna i klarownie napisana biblioteka. Co najważniejsze, można również liczyć na pomoc autora. Należy bardzo uważać na podłączenie czujnika (jeden spaliłem podając 5v na GND a SDA łącząc z masą zasilania – złe wpięcie na stykówce), pozdrawiam, Krzysiek

    1. danielos (Post autora)

      Ciesze się, że mogłem pomóc.Powodzenia z projektem;)

  3. Sławek

    Testuje taki czujnik w bascomie. Nie jestem autorem programu, działa niby poprawnie, ciśnienie spada ze wzrostem temperatury i odwrotnie. Ktos spotkał się z tym? Wzory do obliczeń zgadzają się z nota katalogowa producenta.

    1. danielos (Post autora)

      Witam.
      To trochę jak wróżenie z fusów. Jakbyś podał kod to może ktoś by mógł pewnie coś podpowiedzieć, a tak to można zgadywać.
      Może sam czujnik jest uszkodzony, może zła konwersja typów zmiennych, może jednak gdzieś we wzorach jest błąd, może …
      Jeżeli robiłeś testy suszarką, lub dmuchaniem na czujnik, to mogłeś na krótką chwilę oszukać go – przez to mógł wskazać inne ciśnienie. Opisz coś więcej na temat gdzie się ten czujnik znajduje i kiedy rośnie, kiedy malej, do ilu – więcej informacji.

      Pozdrawiam.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *