[PRZYKŁAD] KAmodMMA7361LC – akcelerometr analogowy i KA-NUCLEO-F411CE
Po wykonaniu powyższych czynności, należy wygenerować kod i otworzyć ulubione środowisko programistyczne w celu uzupełnienia programu.
Na początek należy załączyć bibliotekę odpowiedzialną za obsługę wyświetlacza LCD. Biblioteka została oparta o kod z książki Marka Galewskiego STM32. Aplikacje i ćwiczenia w języku C. Przy czym kod użyty w programie jest kompatybilny z biblioteką HAL i można go używać na wszystkich płytkach kompatybilnych z HAL pod warunkiem ustawienia odpowiednich etykiet pinom w programie STM32Cube. Biblioteka znajduje się w sekcji „Do pobrania”.
#include "LIB_LCD1602/lcd_hd44780_lib.h"
Kolejnym krokiem jest deklaracja wszystkich niezbędnych zmiennych. Poniżej kod z komentarzami wyjaśniającymi co do czego służy:
uint16_t ACC_Raw[3]; // miejsce w pamieci na surowe odczyty z przetwornika int x_min = 2048, y_min = 2048, z_min = 2048, x_max = 2048, y_max = 2048, z_max = 2048; // zmienne uzupelniane w procesie kalibracji uint16_t x_b, y_b, z_b, x_a, y_a, z_a; // zmienne konieczne podczas skalowania float x_val, y_val, z_val; // wyskalowane wartosci przyspieszenia char odczytx[8], odczyty[8], odczytz[8]; // odczyty do wyswietlenia na lcd
Kolejnym krokiem jest deklaracja własnych funkcji, które omówię za chwile:
void konwertujNaString (char * tekst, float wartosc); void kalibracjaMMA7361LC (void);
Funkcja konwertujNaString pozwala na przedstawienie obliczonego wyniku w formie, którą można wyświetlić na ekranie LCD, tj. łańcucha znaków. Polega na podziale na części całkowitą i ułamkową, a następnie doklejeniu do łańcucha znaków.
void konwertujNaString (char * tekst, float wartosc){ int t; char temp[2]; //for (int i = 0; i<8; ++i) // tekst[i] = '\0'; itoa (abs((int)wartosc), temp, 10); if (wartosc < 0) // znak liczby strcpy (tekst, "-"); else strcpy(tekst,"+"); strcat(tekst, temp); // czesc calkowita strcat(tekst, "."); // kropka t = abs((int)((wartosc - (int)wartosc)*100)); itoa (t, temp, 10); if (t< 10) strcat(tekst, "0"); // "0" po kropce gdy czesc ulamkowa jest mniejsza niz 0.1 // Funkcja "itoa" go nie wstawia strcat(tekst, temp); //czesc ulamkowa
Funkcja kalibracjaMMA77361LC dokonuje prostej kalibracji akcelerometru. Aby skalibrować akcelerometr należy znać minimalną i maksymalną wartość wysyłaną przez czujnik dla każdej z osi w momencie, gdy reaguje on tylko na przyspieszenie ziemskie (a więc jednostkę, w której wyskalowany jest przyrząd). Podczas kalibracji należy obracać akcelerometr tak, aby wyświetliła się minimalna lub maksymalna możliwa do uzyskania liczba, gdy czujnik nie porusza się. Ta liczba oznacza reakcję na przyspieszenie ziemskie działające dokładnie wzdłuż określonej osi, w kierunku „+” lub „-„. Po ustabilizowaniu się odczytu należy przycisnąć przycisk znajdujący się na płytce KA-NUCLEO. Po dokonaniu odczytów – program oblicza parametry potrzebne do wyskalowania odczytu w wielokrotnościach przyspieszenia ziemskiego. Część procesu kalibracji przedstawię na filmie obrazującym działanie przykładu.
void kalibracjaMMA7361LC (void){ char bufor[4]; int n = 8; LCD_WriteTextXY("Kalibracja", 0, 0); //kalibracja osi x LCD_WriteTextXY("Xmax", 0, 1); while(1) { x_max = ((n-1)*x_max + ACC_Raw[0])/n; itoa(x_max, bufor, 10); LCD_WriteTextXY(bufor, 8,1); if (HAL_GPIO_ReadPin(Przycisk_GPIO_Port, Przycisk_Pin)==0){ HAL_Delay(200); break; } } LCD_WriteTextXY("Xmin", 0, 1); while(1) { x_min = ((n-1)*x_min + ACC_Raw[0])/n; itoa(x_min, bufor, 10); LCD_WriteTextXY(bufor, 8,1); HAL_Delay(100); if (HAL_GPIO_ReadPin(Przycisk_GPIO_Port, Przycisk_Pin)==0){ HAL_Delay(200); break; } } // kalibracja osi y LCD_WriteTextXY("Ymax", 0, 1); while(1) { y_max = ((n-1)*y_max + ACC_Raw[1])/n; itoa(y_max, bufor, 10); LCD_WriteTextXY(bufor, 8,1); if (HAL_GPIO_ReadPin(Przycisk_GPIO_Port, Przycisk_Pin)==0){ HAL_Delay(200); break; } } LCD_WriteTextXY("Ymin", 0, 1); while(1) { y_min = ((n-1)*y_min + ACC_Raw[1])/n; itoa(y_min, bufor, 10); LCD_WriteTextXY(bufor, 8,1); if (HAL_GPIO_ReadPin(Przycisk_GPIO_Port, Przycisk_Pin)==0){ HAL_Delay(200); break; } } // Kalibracja osi z LCD_WriteTextXY("Zmax", 0, 1); while(1){ z_max = ((n-1)*z_max + ACC_Raw[2])/n; itoa(z_max, bufor, 10); LCD_WriteTextXY(bufor, 8,1); if (HAL_GPIO_ReadPin(Przycisk_GPIO_Port, Przycisk_Pin)==0){ HAL_Delay(200); break; } } LCD_WriteTextXY("Zmin", 0, 1); while(1) { z_min = ((n-1)*z_min + ACC_Raw[2])/n; itoa(z_min, bufor, 10); LCD_WriteTextXY(bufor, 8,1); HAL_Delay(50); if (HAL_GPIO_ReadPin(Przycisk_GPIO_Port, Przycisk_Pin)==0){ HAL_Delay(200); break; } } // Przeliczenie na wartosci potrzebne do skalowania x_a = (x_max-x_min)/2; x_b = (x_min+x_max)/2; y_a = (y_max-y_min)/2; y_b = (y_min+y_max)/2; z_a = (z_max-z_min)/2; z_b = (z_min+z_max)/2; }
W funkcji main najpierw inicjalizowany jest ekran LCD, następnie transmisja przez DMA. Wartości odczytane z przetwornika będą na bieżąco wpisywane do trzech elementów tablicy ACC_Raw przez cały czas trwania programu. Również przed pętlą główną uruchomiona zostaje omówiona powyżej procedura kalibracji akcelerometru.
LCD_Initialize(); HAL_ADC_Start_DMA(&hadc1, ACC_Raw, 3); kalibracjaMMA7361LC();
W pętli głównej programu wartości znajdujące się w tablicy ACC_Raw zostają przeliczone na wielokrotności przyspieszenia grawitacyjnego. Następnie, po konwersji na łańcuch znaków, odczyty zostają wyświetlone na ekranie LCD.
while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ x_val = (15*x_val + (ACC_Raw[0]-x_b)/(float)x_a)/16; y_val = (15*y_val + (ACC_Raw[1]-y_b)/(float)y_a)/16; z_val = (15*z_val + (ACC_Raw[2]-z_b)/(float)z_a)/16; konwertujNaString (&odczytx, x_val); konwertujNaString (&odczyty, y_val); konwertujNaString (&odczytz, z_val); LCD_WriteCommand (0x01); // czyszczenie ekranu LCD_WriteTextXY("X:", 0, 0); LCD_WriteTextXY(odczytx, 2, 0); LCD_WriteTextXY("Y:", 8, 0); LCD_WriteTextXY(odczyty, 10, 0); LCD_WriteTextXY("Z:", 0, 1); LCD_WriteTextXY(odczytz, 2, 1); HAL_Delay(50); } /* USER CODE END 3 */
Działanie przykładu zaprezentowano na poniższym materiale wideo: