Mając przygotowany i połączony sprzęt możemy można przejść do oprogramowania Arduino (pełny kod źródłowy znajduje się w sekcji „Do pobrania”). W pierwszym kroku dołączamy biblioteki sterujące wyświetlaczem LCD oraz czujnikiem LSM303. Następnie deklarujemy wszystkie niezbędne zmienne oraz funkcje. Krótkie omówienie ich roli znajduje się w komentarzach do kodu.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <LiquidCrystal.h> #include <Wire.h> #include "LSM303.h" LSM303 akcelerometr; LiquidCrystal lcd(8, 9, 4, 5, 6, 7); float acc_x, acc_y, acc_z, mag_x, mag_y, mag_z, kat; //zmienne w których przechowywane będą wyskalowane odczyty czujnika float ax_offset = 0, ay_offset = 0, az_offset = 0; //zmienne kalibrujące odczyty akcelerometru void wyswieltPrzyspieszenie(void); //deklaracja funkcji odczytującej i wyświetlającej wskazania akcelerometru void wyswietlKompas(void); //deklaracja funkcji odczytującej i wyświetlającej wskazania kompasu void wyswietlMagnetometr (void); //deklaracja funkcji odczytującej i wyświetlającej wskazania magnetometru void (*wskaznikFunkcji) (void); //wskaźnik na funkcję która ma zostać wykonana w danej iteracji pętli void (*tablicaFunkcji[3])(void) = {wyswieltPrzyspieszenie, wyswietlMagnetometr, wyswietlKompas}; //tablica wskaźników do funkcji odczytujacych i wyswietlajacych dane unsigned short int f=0; //numer aktualnie używanej funkcji int stat; //odczyt z linii A0, podłączonej do klawiatury |
Funkcja klawiatura() umożliwia odczyt stanów przycisków na nakładce. Warto zauważyć, że wszystkie przyciski są połączone z jedną linią analogową mikrokontrolera. W związku z tym napięcie na tej linii informuje nas o tym, który przycisk został naciśnięty. Zalecane wartości dla poszczególnych przycisków zostały podane m.in. w przykładzie producenta. W naszym przykładzie, przyciski UP i DOWN zmieniają rodzaj wyświetlanych wartości, zaś przyciskiem SELECT włączamy procedurę kalibracji odczytów akcelerometru. Wartości wskazujące na naciśnięcie któregoś z tych przycisków limitowane są zarówno od góry, jak i od dołu tak, aby przyciski nieużywane w przykładzie (tj. LEFT i RIGHT) nie powodowały żadnej reakcji przyrządu. Obsługa zmiany wyświetlanych wartości polega na odwoływaniu się do bufora kołowego wskaźników do funkcji. W przypadku naciśnięcia przycisku UP do wskaźnika wskaznikFunkcji wpisywany jest wskaźnik na następną funkcję, w przypadku naciśnięcia przycisku DOWN – na poprzednią. W funkcji loop() aktualna funkcja wywoływana jest już przez wskaźnik. Takie rozwiązanie pozwala na szybkie i niezawodne przejście przez procedurę wyboru aktualnie wyświetlanej funkcji, zwłaszcza dla przypadku, gdy żaden przycisk nie jest wciśnięty.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
void klawiatura (void) //Odczyt klawiatury i wybór funkcji { stat = analogRead(A0); if (stat > 1000) return; if (stat < 250 && stat > 50) // naciśnięcie przycisku UP { wskaznikFunkcji = tablicaFunkcji[(++f)%=3]; delay(100); return; } if (stat < 450 && stat > 250 ) // naciśnięcie przycisku DOWN { wskaznikFunkcji = tablicaFunkcji[f=(f+2)%3]; delay(100); return; } if (stat < 850 && stat > 650) //naciśnięcie przycisku SELECT { kalibracja(); return; } } |
W funkcji kalibracja() odbywa się kalibracja odczytów akcelerometru. Funkcja jest wywoływana raz na początku każdego użycia przyrządu. Można ją wywołać w każdej chwili przez naciśnięcie przycisku SELECT. Funkcja wypisuje na wyświetlaczu komunikat o ustawieniu w pozycji płaskiej. Pozycja płaska to taka pozycja, gdy płytka jest równolegle do ziemi, a czujnik znajduje się na górnej powierzchni płytki. Wtedy oś Z akcelerometru skierowana jest pionowo do ziemi. Tak ułożony jest czujnik na zdjęciu ukazującym podłączenie przyrządów. Funkcja informuje o rozpoczęciu procedury kalibracji, a także o jej zakończeniu. Wartości offset wyznaczone w tej procedurze pozwalają na dokładniejszy odczyt z akcelerometru.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
void kalibracja(void) //kalibracja akcelerometru { const int liczbaProbek = 1024; acc_x=0; acc_y=0; acc_z=0; lcd.clear(); lcd.setCursor(0,0); lcd.println("Ustaw czujnik w "); lcd.setCursor(0,1); lcd.println("pozycji plaskiej"); delay(5000); lcd.clear(); lcd.setCursor(0,0); lcd.println("Kalibracja "); for (int i=0; i<=liczbaProbek; ++i) { akcelerometr.read(); acc_x+=(2.0/32768.0)*akcelerometr.a.x; acc_y+=(2.0/32768.0)*akcelerometr.a.y; acc_z+=(2.0/32768.0)*akcelerometr.a.z; } ax_offset = acc_x / liczbaProbek; ay_offset = acc_y / liczbaProbek; az_offset = (acc_z / liczbaProbek)-1; lcd.clear(); lcd.setCursor(0,0); lcd.println("Kalibracja "); lcd.setCursor(0,1); lcd.println("Zakonczona "); delay(1500); return; } |
Funkcja wyswietlPrzyspieszenie() odczytuje oraz wyświetla na ekranie wskazania akcelerometru w trzech kierunkach: X, Y i Z. Wyświetlane wartości są skalowane w zakresie ±2G (dwukrotność przyspieszenia ziemskiego), który jest domyślnie ustawiany w bibliotece. Wartości przyspieszenia są ułożone na ekranie w sposób intuicyjny: na górze od lewej X i Y, na dole od lewej Z i napis przypominający jakie wartości są obserwowane.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
void wyswietlPrzyspieszenie(void) //definicja funkcji odczytującej i wyświetlającej wskazania akcelerometru { akcelerometr.readAcc(); acc_x=((2.0/32768.0)*akcelerometr.a.x)-ax_offset; acc_y=((2.0/32768.0)*akcelerometr.a.y)-ay_offset; acc_z=((2.0/32768.0)*akcelerometr.a.z)-az_offset; lcd.clear(); lcd.setCursor(0,0); lcd.print(acc_x); lcd.print(" G"); lcd.setCursor(8,0); lcd.print(acc_y); lcd.print(" G"); lcd.setCursor(0,1); lcd.print(acc_z); lcd.print(" G"); lcd.setCursor(10,1); lcd.print("ACC"); delay(100); } |
Funkcja wyswietlMagnetometr() działa podobnie jak funkcja poprzednia z tą różnicą, że wyświetla wskazania magnetometru. Warto zauważyć, że wskazania magnetometru nie są w tym przyrządzie kalibrowane. Domyślnym zakresem pomiarowym przy korzystaniu z biblioteki Pololu jest ±4 Gausy i do tej wartości skalowane są wyniki.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
void wyswietlMagnetometr(void) //definicja funkcji odczytującej i wyświatlającej wskazania magnetometru { akcelerometr.readMag(); mag_x=(4.0/32768.0)*akcelerometr.m.x; mag_y=(4.0/32768.0)*akcelerometr.m.y; mag_z=(4.0/32768.0)*akcelerometr.m.z; lcd.clear(); lcd.setCursor(0,0); lcd.print(mag_x); lcd.setCursor(8,0); lcd.print(mag_y); lcd.setCursor(0,1); lcd.print(mag_z); lcd.setCursor(10,1); lcd.print("MAG"); delay(100); } |
Funkcja wyswietlKompas() wyświetla odchylenie wektora X od bieguna N w stopniach, czyli działa jak prosty kompas. Wykorzystywana jest tu funkcja biblioteczna heading(). Kompas najlepiej sprawuje się, gdy leży równolegle do ziemi. Wszelkie odchylenia od tej pozycji znacznie zakłamują jego odczyt.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
void wyswietlKompas(void) //definicja funkcji odczytującej i wyświatlającej wskazania kompasu { akcelerometr.read(); acc_x = akcelerometr.heading(); lcd.clear(); lcd.setCursor(0,0); lcd.print("WYCHYLENIE"); lcd.setCursor(0,1); lcd.print(acc_x); lcd.print(" st."); delay(100); } |
W funkcji setup() inicjalizowane są: ekran LCD, czujnik LSM303 oraz transmisja I2C. Wywoływana jest także procedura kalibracja(), aby skalibrować odczyty akcelerometru jeszcze przed jakimikolwiek pomiarami.
1 2 3 4 5 6 7 8 9 10 |
void setup() { Wire.begin(); //inicjalizacja połączenia I2C lcd.begin(16,2); //inicjalizacja ekranu lcd.setCursor(0,0); akcelerometr.init(); //inicjalizacja czujnika akcelerometr.enableDefault(); kalibracja(); //wywołanie procedury kalibracyjnej wskaznikFunkcji = tablicaFunkcji[f]; } |
W funkcji loop() wywoływana jest procedura obsługi klawiatury, a następnie przez wskaźnik funkcja wyświetlająca odczyty zgodnie z aktualnymi potrzebami.
1 2 3 4 5 |
void loop() { klawiatura(); wskaznikFunkcji(); } |
Działanie projektu przedstawione jest na poniższym filmie: