KursyPoradnikiInspirujące DIYForum

Kurs STM32 – #12 – I2C w praktyce, akcelerometr

Kurs STM32 – #12 – I2C w praktyce, akcelerometr

Na zakończenie kursu STM32 omówimy bardziej rozbudowany przykład. Na warsztat weźmiemy moduł z układem LSM303D, który zawiera w sobie akcelerometr, magnetometr oraz termometr.

Zobaczymy, jak można odczytywać z niego dane za pomocą I2C oraz jak zaprezentować wyniki na wyświetlaczu graficznym

Podstawowe informacje o LSM303D

Na początek musimy poznać nasz czujnik. Jest on nieco bardziej skomplikowany, niż omawiane wcześniej. Na szczęście dostępna jest do niego dobra dokumentacja. W naszym przykładzie nie omówimy wszystkich możliwości układu LSM303D. Skupimy się jednak na realizacji możliwie prostego i uniwersalnego mechanizmu odczytu danych z tego czujnika.

Gotowe zestawy do kursów Forbota

 Komplet elementów  Gwarancja pomocy  Wysyłka w 24h

Zestaw ponad 120 elementów do przeprowadzenia wszystkich ćwiczeń z kursu można nabyć u naszych dystrybutorów! Dostępne są wersje z płytką Nucleo lub bez niej!

Zamów w Botland.com.pl »

 Najważniejsze materiały to:

  • datasheet - w nim znajdziemy pełny opis możliwości układu, protokół komunikacji itd.
  • schemat modułu - jak zwykle obraz jest wart więcej niż tysiąc słów. Warto zwrócić uwagę na sposób podłączenia układu oraz obecne rezystory podciągające

Przy okazji ważna uwaga. Omawiamy czujnik LSM303D, jednak można się zetknąć z układami o podobnej nazwie, ale innym działaniu. Są to starsze modele LSM303DLM i LSM303DLHC - pomimo bardzo podobnej nazwy, ich sposób działania jest inny.

Moduł LSM303D wykorzystywany w tej części. Źródło: POLOLU - producent.

Moduł LSM303D wykorzystywany w tej części. Źródło: POLOLU - producent.

Układy nie są już produkowane i istnieje raczej mała szansa, że się na nie natkniemy, ale dostępnych sporo przykładów i bibliotek przeznaczonych dla starszych modeli, które mogę nie działać z nowym LSM303D.

LSM303D - komunikacja z modułem

W poprzedniej części kursu omówiliśmy sposób komunikacji poprzez I2C. Teraz możemy wykorzystać zdobytą wiedzę oraz napisany już program do rozpoczęcia pracy z nowym układem. Czytając datasheet zobaczymy, że komunikacja jest bardzo podobna do poznanej poprzednio.

Poprzednio używaliśmy układu 24AA01, który posiadał adres 0xa0. Nowy układ może mieć jeden z dwóch adresów 0x3c lub 0x3a, w zależności od stanu wyprowadzenia SA0. Oglądając schemat modułu zobaczymy, że na płytce znajduje się rezystor podciągający, co oznacza, że linia SA0 ma domyślnie stan wysoki, a adres układu to 0x3a. Na schemacie zobaczymy również, że linie SDA i SCL posiadają już rezystory podciągające. Możemy więc zrezygnować z podłączania własnych rezystorów podciągających.

Teraz możemy podłączyć moduł zgodnie z rysunkiem:

i2c-lsm303_bb

STM32 - schemat podłączenia modułu z LSM303D.

Gdy mamy podłączony układ, czas zająć się programem. Wykorzystamy kod napisany poprzednio, dostosowując go do nowego układu.

Po pierwsze musimy zmienić adres układu. Poprzednio było to 0xa0, teraz zdefiniujemy stałą, w której zapiszemy adres układu. Ułatwi to ewentualną modyfikację adresu w przyszłości:

Procedury, które napisaliśmy poprzednio nazywały się eeprom_write i eeprom_read. W nowym programie możemy je wykorzystać, ale dla czytelności kodu zmienimy im nazwy. Nazwiemy je lsm_write i lsm_read oraz zmienimy nazwę parametru - teraz zamiast adresu w pamięci przekazujemy numer rejestru w układzie LSM303D.

Kod z tymi zmianami wygląda następująco:

Pełna lista oraz opis dostępnych rejestrów znajduje się w dokumentacji LSM303D. Poniżej fragment dokumentacji:

LSM_01

Fragment dokumentacji układu LSM303D.

Zaczniemy od sprawdzenia, czy nasz układ w ogóle działa. Jak widzimy, dostępny jest rejestr WHO_AM_I (adres 0x0f). Jest to rejestr tylko do odczytu, który zawsze powinien zwracać wartość 01001001b, czyli 0x49.

Odczytamy jego zawartość, sprawdzimy czy jest poprawna i wyślemy przez UART odpowiedni komunikat. Program, który to realizuje wygląda następująco:

Komunikację przez UART oraz przekierowanie printf już znamy, więc program nie powinien być trudny do przeanalizowania:

W efekcie powinniśmy zobaczyć następujący komunikat w okienku terminala portu szeregowego:

LSM_02

Efekt programu sprawdzającego działanie modułu z LSM303D.

Natomiast układ na płytce stykowej wyglądał tak:

STM32 - pierwsze próby z modułem LSM303D.

STM32 - pierwsze próby z modułem LSM303D.

Odczyt temperatury

Zanim przejdziemy dalej, napiszemy kilka funkcji pomocniczych oraz uporządkujemy nieco program. Rejestry sterujące LSM303D są 8-bitowe, więc do zapisu i odczytu możemy napisać funkcje, które nieco ułatwią korzystanie z nich (unikniemy używania sizeof() za każdym razem):

Dodatkowo czytając dokumentację, zauważymy, że odczytywane wartości np. temperatury, przyspieszenia, czy strumienia magnetycznego są wartościami 16-bitowymi ze znakiem (zapisanymi w kodzie U2).

Możemy również napisać prostą funkcję, która będzie odczytywała taką wartość:

Teraz czas trochę posprzątać - podobnie jak w części dotyczącej wyświetlacza, przeniesiemy funkcje sterujące układem LSM303D do osobnych plików. Dodamy również stałe, definiujące rejestry układu. Będziemy mogli wykorzystywać je w programie zamiast "magiczych liczb".

Plik nagłówkowy lsm303d.h wygląda następująco:

Natomiast plik z kodem lsm303d.c:

Teraz możemy wrócić do programu głównego. Musimy odpowiednio skonfigurować LSM303D, czyli włączyć pomiar temperatury. W dokumentacji znajdujemy odpowiedni rejestr, czyli CTRL5.

LSM_03

Fragment dokumentacji LSM303D dotyczący pomiaru temperatury.

Jak widzimy, domyślnie pomiar temperatury jest wyłączony (pole TEMP_EN ma wartość 0). Zapiszemy więc do CTRL5 odpowiednią wartość

Przy okazji ustawiliśmy częstotliwość odczytów z magnetometru na 50Hz - nie wykorzystamy tego w tym momencie, ale skoro jest w tym samym rejestrze, to dlaczego nie ustawić jej "na zapas".

Po włączeniu pomiaru, musimy dać układowi trochę czasu. Jak pamiętamy, w części kursu o LCD utworzyliśmy moduł delay.h, zawierający funkcję delay_ms. Możemy z niego skorzystać po prostu kopiując pliki delay.h i delay.c do naszego projektu. Odczyt temperatury jest już bardzo prosty - wystarczy wczytywać wartość z rejestrów TEMP_OUT_L i TEMP_OUT_H.

Napisaliśmy funkcję lsm_read_value, więc oba rejestry odczytamy jednocześnie. Funkcja wykona za nas również konwersję na 16-bitową wartość ze znakiem. Kod wygląda następująco:

Pełny kod programu widzimy poniżej. Należy oczywiście pamiętać o dołączeniu plików delay.h, delay.c oraz lsm303d.h i lsm303d.c:

Rezultat działania widzimy w oknie terminala - powinna być to aktualna temperatura:

LSM_04

LSM303D - odczyt aktualnej temperatury.

Akcelerometr

Poznaliśmy już trochę układ LSM303D, czas przejść do głównego tematu tej części kursu, czyli odczytu danych z akcelerometru. W tym celu musimy nieco zmienić konfigurację układu (włączyć akcelerometr) oraz odczytać dane.

Opis konfiguracji jak zwykle znajdziemy w nocie katalogowej. Tym razem interesuje nas rejestr CTRL1. Trzy najwyższe bity określają prędkość odczytywania danych (ustawimy 25Hz jako przykład). Natomiast trzy najniższe bity odpowiadają za uruchomienie odczytów (z osi Z, Y i X):

LSM_05

Fragment dokumentacji LSM303D dotyczący akcelerometru.

Konfigurację wykonamy instrukcją:

Teraz możemy, podobnie jak w przypadku temperatury pobierać i wyświetlać dane:

W programie znajdziemy nieco więcej kodu, w tym zakomentowane instrukcje printf - omówimy je za chwilę. Cały program wygląda następująco:

Efekt działania powinien wyglądać mniej więcej jak na obrazku:

LSM_06

Efekt działania programu LSM303D - odczyt z akcelerometru.

Wyniki mogą być nieco zaskakujące, jeśli nie zajmowaliśmy się wcześniej akcelerometrami. Spróbujmy więc zrozumieć co oznaczają.

Odczyty są kodowane 16-bitowo ze znakiem. Więc ich zakres wynosi od -32768 do 32767. Czytając dokumentację, odkryjemy, że akcelerometr LSM303D może działać w kilku zakresach pomiarowych: 2 g, 4 g, 8 g i 12 g. Domyślna jest konfiguracja 2 g, do niej odnoszą się wyniki.

Ponieważ przyspieszenie 2 g, to pełny zakres, odpowiada mu odczyt 32767. Minimalna wartość wynosi -2 g, i daje wynik -32768. Możemy więc przeliczyć otrzymane wyniki na znane z fizyki wartości przyspieszenia:

W kodzie programu wystarczy odkomentować drugi printf (najlepiej zakomentowując pierwszy - inaczej wyniki będą nieco nieczytelne). Otrzymamy teraz następujący rezultat:

LSM_07

Przeliczone wartości odczytane z LSM303D.

Mając wyniki w takiej postaci, łatwiej jest zrozumieć ich znaczenie. Jak widzimy, wzdłuż osi X i Y mamy niewielkie odczyty, a na oś Z działa przyspieszenie prawie 1 g. Wynik może być pewnym zaskoczeniem - przecież nasza płytka leży spokojnie na biurku, nie przyspiesza w żadnym kierunku.

Mamy wiec poprawny wynik - na oś Z działa przyspieszenie ziemskie, a na X i Y - też trochę. Gdyby czujnik idealnie wypoziomować, powinniśmy otrzymać przyspieszenie zerowe na X i Y oraz 1 g dla osi Z. Niestety, nawet wtedy otrzymany wynik mógłby się zmienić np. po zmianie temperatury. Dlatego czujnik powinien być kalibrowany.

Co więcej chcąc obliczać np. przesunięcie robota, musimy pamiętać, że 1 g pochodzące od przyspieszenia ziemskiego i tak pojawi się w otrzymywanych wynikach.

STM32 i LSM303D - Projekt prostej poziomicy

Warto sprawdzić jak będą zmieniały się odczyty przechylając płytkę z czujnikiem. Na module z LSM303D znajdziemy nadruk z oznaczeniem kierunków osi X, Y oraz Z:

lsm303d-3-osiowy-cyfrowy-akcelerometr-magnetometr-i2cspi-modul-pololu

Wykorzystywany moduł, źródło zdjęcia: strona producenta Pololu.

Spróbujemy wykorzystać nasz czujnik do określania nachylenia czujnika - zbudujemy więc prostą, cyfrową poziomicę. Na początek uprościmy sobie trochę zadanie i zamiast w 3D, będziemy rozwiązywać problem w dwóch wymiarach.

Spróbujmy napisać program, który wyświetli kąt pod jakim nasz czujnik jest ułożony względem płaszczyzny ziemi. Z pomocą przychodzi nam trygonometria. Funkcja arcus tangens pozwala na przeliczenie uzyskanych wyników:

Ponieważ wyniki są w radianach, przeliczamy je na stopnie. Dodajemy też 90, aby uzyskać kąt między płytką, a płaszczyzną ziemi. Efekt wygląda jak na poniższym screenie:

LSM_08

LSM303D - odczyt kąta płytki względem płaszczyzny ziemi.

Do prezentowania wyników wykorzystamy wyświetlacz LCD, który omówiliśmy wcześniej. Mamy więc przygotowane odpowiednie procedury - wystarczy skopiować pliki omówione wcześniej.

Układ podłączamy zgodnie z rysunkiem:

i2c-lsm-lcd_bb

Kurs STM32 - schemat podłączenia modułu LSM303D i wyświetlacza graficznego.

Jednocześnie będziemy wykorzystywać komunikację przez SPI, I2C oraz UART. W tym celu kopiujemy następujące moduły z poprzednich przykładów (pliki .h oraz .c):

  • delay,
  • lsm303d,
  • lcd,
  • bitmap,
  • font.

Mając odpowiednie biblioteki, możemy przystąpić do pisania programu. W programie wyświetlimy poziomą linię - która będzie zachowywała kierunek nawet podczas obracania płytki z czujnikiem i wyświetlaczem.

Do poprzedniego programu dodajemy kod inicjalizujący wyświetlacz - był omówiony wcześniej. Teraz omówimy tylko pętlę główną programu:

Odczytujemy przyspieszenie działające wzdłuż osi X oraz Y (układ dużo lepiej działa w pionie, dlatego zamiast osi Z tym razem używana jest oś Y).

Mając wektor przyspieszenie ziemskiego, łatwo możemy obliczyć współrzędne odcinka do niego prostopadłego. W tym celu zamieniamy miejscami współrzędne x i y oraz przeliczamy zakres odczytów akcelerometru. Pełne wyprowadzenie matematyczne nie jest trudne - wystarczą podstawy geometrii, które pominiemy już w kursie.

Pełny kod programu:

Działanie programu w praktyce widoczne jest na poniższym filmie:

Podsumowanie

W tej części kursu poznaliśmy podstawy działania czujnika LSM303D. Sprawdziliśmy sposób komunikacji z układem. Wykorzystaliśmy wbudowany termometr oraz akcelerometr. Nie zajęliśmy się natomiast magnetometrem (kompasem cyfrowym). Zadanie to pozostawiam dla chętnych, jako zadanie domowe.

Nawigacja kursu

W kolejnym odcinku zajmiemy się małym podsumowaniem całego kursu. Przyjdzie również pora na QUIZ sprawdzający Waszą wiedzę! Jeśli nie chcesz przeoczyć kolejnego odcinka, to skorzystaj z poniższego formularza i zapisz się na powiadomienia o nowych publikacjach!

Autor kursu: Piotr (Elvis) Bugalski
Redakcja: Damian (Treker) Szymański

Załączniki

kurs, kursSTM32, programowanie, stm32

Trwa ładowanie komentarzy...