LinkedIn YouTube Facebook
Szukaj

Wstecz
Artykuły

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);
				}
			}
		}
	}
}