STM32 i GPS
Komunikacja z modułem GPS02 firmy HOPE realizowana jest przy wykorzystaniu protokołu NMEA-0183, polegającego na wysyłaniu odpowiednio uformowanych zdań. Moduł standardowo komunikuje się przez port UART z prędkością 9600 bps, 8 bitów danych, 1 bit stopu, brak bitu parzystości. Najbardziej przydatne sekwencje to RMC (Recommended Minimum Specific GNSS Data) oraz VTG (Course Over Ground and Ground Speed). Budowa zdania RMC jest następująca:
$GPRMC,170230.918,A,5413.2821,N,01610.4976,E,000.0,000.0,170611,,,A*68
Gdzie poszczególne elementy mają następujące znaczenie:
- $GPRMC, – nagłówek zdania RMC,
- 170230.918, – czas UTC (w postaci hhmmss.sss),
- A, – znacznik ważności danych (A – dane ważne, V – dane nieważne),
- 5413.2821,N, – szerokość geograficzna (w postaci ssmm.mmmm) wraz z określeniem półkuli,
- 01610.4976,E, – długość geograficzna (w postaci sssmm.mmmm) wraz z określeniem półkuli,
- 000.0, – prędkość przemieszczania podana w węzłach,
- 000.0, – kierunek przemieszczania podany w stopniach,
- 170611,,, – data czasu UTC (w postaci ddmmyy),
- A*68 – suma kontrolna.
Natomiast budowa zdania VTG wygląda jak poniżej:
$GPVTG,000.0,T,,M,000.0,N,000.0,K,A*0D
Gdzie poszczególne elementy mają następujące znaczenie:
- $GPVTG, – nagłówek zdania VTG,
- 000.0, T, – kierunek przemieszczania podany w stopniach (prawdziwy),
- , M, – kierunek przemieszczania podany w stopniach (magnetyczny),
- 000.0,N, – prędkość przemieszczania podana w węzłach,
- 000.0, K, – prędkość przemieszczania podana w km/h,
- A*0D – suma kontrolna.
Przesyłane zdania mają stałą długość, wobec czego najlepszym sposobem jest przechowywanie ich w postaci tablic, a do poszczególnych elementów odwoływać się poprzez odpowiedni indeks.
W projekcie zaimplementowano także sygnalizację stanu pracy, jest ona realizowana przy użyciu trzech diod LED:
- LED1 – zapalenie tej diody informuje iż moduł GPS do urządzenia wysyła poprawne dane o współrzędnych geograficznych,
- LED2 – dioda będzie świeciła w czasie generowania pliku .gpx,
- LED3 – podobnie jak dioda LED2, jest zapalana podczas generowania pliku .gpx, z tą różnicą iż w momencie zatrzymania generowania pliku dioda gaśnie.
Program dla mikrokontrolera
Na listingu poniżej przedstawiono część kodu głównego programu. Na początku realizowana jest konfiguracja: RCC, wykorzystywanych pinów, używanych peryferii UART, inicjalizacja obsługi przerwań oraz inicjalizacja wyświetlacza modułu KAmodLCD1. W przypadku konfiguracji RCC, GPIO, UART i przerwań mamy do czynienia z podstawowymi konfiguracjami.
int main(void) { //konfiguracja RCC Configuration_RCC(); //konfiguracja GPIO Configuration_GPIO(); //konfiguracja UART-ów Configuration_UART(); //konfiguracja obsługi przerwań Configuration_Interrupts(); //inicjalizacja wyświetlacza modułu KAmodLCD1 PCD8544_INIT(); PCD8544_LCDClear(); //nieskończona pętla while (1) { //kontrola dioda LED //uzyskiwane dane są ważne if(RxBufferRMC[18] == 'A') {LED_1_ON;} else {LED_1_OFF;} //włączone jest generowanie pliku .gpx if(OutputState != 0) {LED_2_ON;} else {LED_2_OFF;} //trwa wysyłanie nowych danych if((OutputState > 0) && (OutputState != 4)) {LED_3_ON;} else {LED_3_OFF;} //warunek sprawdzający czy odbiornik GPS przesyła poprawne dane //jeśli dane są poprawne to są one wyświetlane na wyświetlaczu if(RxBufferRMC[18] == 'A') { //wyczyszczenie zawartosci wyswietlacza PCD8544_LCDClear(); . . . //wyświetlenie aktualnej szerokości geograficznej PCD8544_LCDWriteSign(RxBufferRMC[20],12,2); PCD8544_LCDWriteSign(RxBufferRMC[21],18,2); PCD8544_LCDWriteSign(0x5C,24,2); PCD8544_LCDWriteSign(RxBufferRMC[22],30,2); PCD8544_LCDWriteSign(RxBufferRMC[23],36,2); PCD8544_LCDWriteSign('.',42,2); PCD8544_LCDWriteSign(RxBufferRMC[25],48,2); PCD8544_LCDWriteSign(RxBufferRMC[26],54,2); PCD8544_LCDWriteSign('\'',60,2); PCD8544_LCDWriteSign(RxBufferRMC[30],66,2); . . . } //w przypadku uzyskiwania danych, na wyświetlaczu pojawi się odpowiedni komunikat else { //wyczyszczenie zawartości wyświetlacza PCD8544_LCDClear(); //wyświetlenie odpowiednich informacji na wyświetlacz PCD8544_LCDWriteText("GPS",33,0); PCD8544_LCDWriteText("searching",15,3); } //zaktualizowanie informacji na wyświetlaczu PCD8544_LCDWrite(); //warunkowa aktualizacja informacji //realizowana gdy występuje różnica czasu w ciągach RxBufferRMC i OutputInner //sprawdzana jest wartość sekund if(RxBufferRMC[12] != OutputInner[73]) { //aktualizacja aktualnego czasu w ciągu OutputPre //rok OutputPre[306] = '2'; OutputPre[307] = '0'; OutputPre[308] = RxBufferRMC[61]; OutputPre[309] = RxBufferRMC[62]; //miesiac OutputPre[311] = RxBufferRMC[59]; OutputPre[312] = RxBufferRMC[60]; //dzien OutputPre[314] = RxBufferRMC[57]; OutputPre[315] = RxBufferRMC[58]; //godziny OutputPre[317] = RxBufferRMC[7]; OutputPre[318] = RxBufferRMC[8]; //minuty OutputPre[320] = RxBufferRMC[9]; OutputPre[321] = RxBufferRMC[10]; //sekundy OutputPre[323] = RxBufferRMC[11]; OutputPre[324] = RxBufferRMC[12]; //warunkowe wykonanie kodu w przypadku gdy program oczekuje //aktualizacji danych w ciągu OutputInner // if(OutputState == 3) { . . . //aktualizacja szerokości geograficznej w ciągu OutputInner OutputInner[15] = RxBufferRMC[20]; OutputInner[16] = RxBufferRMC[21]; //przeliczenie wartości minut na wartość ułamkowa stopnia temp = ((RxBufferRMC[22] - 0x30) * 100000); temp += ((RxBufferRMC[23] - 0x30) * 10000); temp += ((RxBufferRMC[25] - 0x30) * 1000); temp += ((RxBufferRMC[26] - 0x30) * 100); temp += ((RxBufferRMC[27] - 0x30) * 10); temp += ((RxBufferRMC[28] - 0x30) * 1); temp = temp / 60; //aktualizacja szerokości geograficznej w ciągu OutputInner cd. OutputInner[18] = temp / 1000 + 0x30; temp = temp % 1000; OutputInner[19] = temp / 100 + 0x30; temp = temp % 100; OutputInner[20] = temp / 10 + 0x30; temp = temp % 10; OutputInner[21] = temp % 10 + 0x30; OutputInner[22] = '0'; OutputInner[23] = '0'; . . . //ustawienie danych do wysyłani if(OutputState == 3) { OutputState = 2; //włączenie przerwania od TXE USART_ITConfig(USART1, USART_IT_TXE, ENABLE); } } } } }