[PRZYKŁAD] Odczyt danych z czujnika KAmodLPS25HB za pomocą Raspberry Pi Pico
Prezentujemy przykład implementacji komunikacji przez magistralę I2C na Raspberry Pi Pico. W tym celu użyjemy modułu z czujnikiem ciśnienia KAmodLPS25HB, z którego płytka pobiera dane dotyczące ciśnienia atmosferycznego. Dane zostaną wypisane na port szeregowy połączony z portem USB, co umożliwi ich odczyt na ekranie komputera.
Raspberry Pi Pico to płytka z mikrokontrolerem RP2040. Zarówno płytka, jak i sam mikrokontroler zaprojektowała i wprowadziła na rynek Fundacja Raspberry Pi odpowiedzialna także za popularne komputery Raspberry Pi. RP2040 to mikrokontroler z dwoma rdzeniami ARM Cortex-M0+ o taktowaniu do 133 MHz, pamięcią RAM o pojemności 264 kB oraz 30 portami GPIO. Sam układ nie jest wyposażony w pamięć flash, ale na płytce znajduje się zewnętrzna pamięć o pojemności 2 MB podłączona za pomocą interfejsu QSPI. Oprócz tego płytka zawiera również m.in. port microUSB oraz złącze do przylutowania portów goldpin, z wyprowadzonymi interfejsami mikrokontrolera. Platforma wspiera popularne języki programowania MicroPython oraz C/C++. Programy można wgrywać do pamięci za pomocą interfejsu USB w trybie pamięci masowej lub korzystając z zewnętrznego programatora obsługującego interfejs SWD.
Rys. 1. Płytka Raspberry Pi Pico
KAmodLPS25HB to moduł z czujnikiem ciśnienia bezwzględnego i temperatury LPS25HB firmy STMicroelectronics. Sensor cechuje się m.in. szerokim zakresem oraz wysoką rozdzielczością pomiaru. Komunikacja z modułem może odbywać się za pośrednictwem magistrali I2C lub SPI, zaś dzięki wbudowanemu stabilizatorowi i translatorowi napięć na liniach SDA oraz SCL, możliwa jest praca modułu przy różnych standardach napięć magistralowych.
Rys. 2. Moduł KAmodLPS25HB z czujnikiem LPS25HB
Podłączenie czujnika do Raspberry Pi Pico
W naszym programie będziemy korzystać z interfejsu I2C. Należy więc podłączyć czujnik do portu I2C0 płytki Pico. Domyślnie port jest wyprowadzony na piny GP4 i GP5. Do zasilania czujnika użyjemy napięcia 3,3 V, również dostępnego na złączu goldpin płytki.
Poniżej zaprezentowano sposób połączenia w postaci tabeli, a także fotografii:
Raspberry Pi Pico | KAmodLSP25HB |
GP4 | SDA |
GP5 | SCL |
3V3 | +3,3V |
GND | GND |
Rys. 3. Płytka Rapsberry Pi Pico połączona z modułem KAmodLPS25HB
Kod przykładu
Jak wspomniałem, kod ma za zadanie pobrać dane dotyczące zmierzonego ciśnienia, skonwertować na wartość w hektopaskalach, a następnie wypisać na port szeregowy. Na początku należy dodać wszystkie niezbędne biblioteki oraz zdefiniować zmienną addr, w której przechowywany jest adres czujnika.
#include <stdio.h> #include <string.h> #include "pico/stdlib.h" #include "pico/binary_info.h" #include "hardware/i2c.h" static int addr = 0x5d;
W dalszej kolejności definiujemy funkcję lps25hb_init, w której wpisujemy do rejestru CTRL_REG1 (0x20) wartość 0xB0. W ten sposób uruchomimy wykonywanie pomiarów i ustalimy częstotliwość poboru próbek przez sensor.
static void lps25hb_init() { uint8_t buf[] = {0x20, 0xB0}; i2c_write_blocking(i2c_default, addr, buf, 2, false); }
Kolejną funkcją jest lps25hb_read_raw. Jej zadaniem jest pobór wartości z rejestrów przechowujących zmierzoną wartość ciśnienia i zapisanie ich w tablicy bufferPress, Następnie za pomocą odpowiednich przesunięć bitowych, składa z nich tzw. wartość surową, która jest zapisywana w zmiennej pressure.
static void lps25hb_read_raw(int *pressure) { //odczyt danych o cisnieniu uint8_t bufferPress[3]; uint8_t pressOutXL = 0x28; uint8_t pressOutL = 0x29; uint8_t pressOutH = 0x2a; i2c_write_blocking(i2c_default, addr, &pressOutXL, 1, true); // true to keep master control of bus i2c_read_blocking(i2c_default, addr, bufferPress, 1, false); i2c_write_blocking(i2c_default, addr, &pressOutL, 1, true); i2c_read_blocking(i2c_default, addr, bufferPress+1, 1, false); i2c_write_blocking(i2c_default, addr,&pressOutH, 1, true); i2c_read_blocking(i2c_default, addr, bufferPress+2, 1, false); *pressure = (bufferPress[2] << 16 | bufferPress[1] << 8 | bufferPress[0]); }
W funkcji main inicjalizowany jest interfejs I2C, wraz z niezbędnymi rezystorami podciągającymi. Następnie uruchamiana jest funkcja lps25hb_init. W pętli głównej programu uruchamiana jest funkcja lps25hb_read_raw, a wartość zapisana w zmiennej pressure wypisywana jest na port USB. Wyskalowanie wartości w hektopaskalach jest uzyskiwane dzięki dzieleniu wartości surowej przez 4096, tuż przed wypisaniem na port szeregowy. Pomiędzy kolejnymi pomiarami następuje przerwa o długości 1,5 sekundy.
int main() { stdio_init_all(); #if !defined(i2c_default) || !defined(PICO_DEFAULT_I2C_SDA_PIN) || !defined(PICO_DEFAULT_I2C_SCL_PIN) #warning i2c/mpu6050_i2c example requires a board with I2C pins puts("Default I2C pins were not defined"); #else printf("Hello, LPS25HB! Reading raw data from registers...\n"); i2c_init(i2c_default, 400 * 1000); gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C); gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C); gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN); gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN); // Make the I2C pins available to picotool bi_decl(bi_2pins_with_func(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C)); lps25hb_init(); int pressure; while (1) { lps25hb_read_raw (&pressure); printf("Press. = %.2f hPa\n", (pressure/4096.0)); sleep_ms(1500); } #endif return 0; }
Pełen kod przykładu dostępny jest poniżej, w sekcji „Do pobrania”.
Kompilacja kodu i wgranie programu na płytkę
Aby wgrać kod na płytkę Raspberry Pi Pico, należy pobrać i skonfigurować toolchain. Instrukcja jak to zrobić znajduje się w artykule Raspberry Pi Pico – płytka z mikrokontrolerem zaprojektowanym przez Raspberry Pi.
W folderze, do którego uprzednio pobraliśmy pakiety pico-sdk oraz pico-examples, należy utworzyć folder z projektem, np. o nazwie lps25hb. Tam, oprócz pliku .c z kodem należy umieścić także plik CMakeLists.txt, w którym znajdują się informacje dla kompilatora, takie jak polecenie uruchomienia portu szeregowego na USB czy inicjalizacja SDK dla Pico. Ten plik dla naszego przykładu wygląda następująco:
cmake_minimum_required(VERSION 3.13) include(pico_sdk_import.cmake) project(test_project C CXX ASM) set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) pico_sdk_init() add_executable(lps25bh_i2c lps25hb_i2c.c ) pico_enable_stdio_usb(lps25bh_i2c 1) pico_enable_stdio_uart(lps25bh_i2c 1) pico_add_extra_outputs(lps25bh_i2c) target_link_libraries(lps25bh_i2c pico_stdlib hardware_i2c) }
W folderze należy także umieścić plik pico_sdk_import.cmake, który trzeba skopiować z folderu pico-sdk/external.
Następnie można skompilować projekt z poziomu terminala systemu Windows. Aby to zrobić, należy uruchomić komendę cmd, a następnie zdefiniować ścieżkę do pakietu pico SDK poleceniem
setx PICO_SDK_PATH "..\..\pico-sdk"
Po tym trzeba zrestartować konsolę. Po ponownym uruchomieniu zmienna środowiskowa zostanie zaktualizowana.
W kolejnym kroku należy przejść do folderu z kodem projektu za pomocą polecenia cd. W tym folderze należy utworzyć folder build.
mkdir build cd build
Po przejściu do tego katalogu można już uruchomić kompilację. Aby ją dokonać należy uruchomić polecenia:
cmake -G "NMake Makefiles" .. nmake
Aby wgrać kod na płytkę Raspberry Pi Pico należy podłączyć płytkę do komputera za pomocą przewodu USB, ale podczas włączania trzeba przytrzymać przycisk BOOTSEL. Płytka zainstaluje się jako pamięć masowa. Na tą wirtualną pamięć należy skopiować plik z rozszerzeniem .uf2, który pojawi się w folderze build po kompilacji. Po wgraniu pliku płytka sama zresetuje się i rozpocznie pracę.
Aby odczytać dane z czujnika należy połączyć się z portem szeregowym za pomocą programu takiego jak PuTTY. Port szeregowy pracuje z szybkością 115200 baud.
Program powinien wyświetlać dane o ciśnieniu w taki sposób jak na poniższym obrazku.