//=========================================== // Simulator GPS modulu z Arduina NANO //=========================================== // verze: 2024-12-11 // Tx vystup z Arduina generuje kazdou sekundu 2 vety (GPRMC a GPGGA). // V Arduinu jsou nektere vety prednastavene - zapinaji se odeslanim dvojice znaku z PC pres USB: // "NE" - souradnice v CR (severni sirka a vychodni delka) // "NW" - souradnice v USA (severni sirka a zapadni delka) // "SE" - souradnice v Australii (jizni sirka a vychodni delka) // "SW" - souradnice v Brazilii (jizni sirka a zapadni delka) // Dvojici znaku "AA" je mozne zadat vlastni generovane souradnice. // Zadavaji se postupne stupne a minuty zemepisne sirky (s minusem pro jih a bez mezer) a stupne a minuty zemepisne delky (s minusem pro zapad a bez mezer). // Desetiny minut se pak automaticky nastavuji na ".00000". // Mezi znaky "AA", sirkou a delkou jsou mezery. // Format zadavani souraddnic je nasledujici: "dddmm". 'ddd' jsou cele stupne a 'mm' jsou cele minuty. Neni mezi nimi zadny oddelovac. // priklady: "AA 5000 1500" nastavi souradnice na 50 stupnu severni sirky a 15 stupnu vychodni delky. // "AA 2515 -14038" nastavi souradnice na 25 stupnu a 15 minut severni sirky a 140 stupnu a 38 minut zapadni delky. // "AA -106 55" nastavi souradnice na 1 stupen a 6 minut jizni sirky a 0 stupnu a 55 minut vychodni delky. // Dvojice znaku "BB" zacne odesilat souradnice 50 stupnu severni sirky a nahodne souradnice kolem 180 stupne zapadni / vychodni delky. // Presne je to interval 179 stupnu a 10 minut zapadni nebo vychodni delky az 180 stupnu vychodni (zapadni) delky. // Funkce slouzila k testovani spravneho prumerovani souradnic kolem prechodu polokouli. // Dvojice znaku "CC" vezme znakova pole 'nmeaRMC[]' a 'nmeaGGA[]' a vypocte k nim spravne kontrolni soucty. // Pak zacne vety se pravnym CRC odesilat, jako pri zadani souradnic pres kody "AA". // Editaci techto znakovych poli je mozne nastavit libovolne souradnice a nadmorskou vysku. // Pokud by bylo treba zmenit delku vet, musi se upravit pozice koncovych hvezdicek ve vetach: promenna "CRC_end" v podprogramu "vypocet_CRC()". // Pro prednastavene vety to je 63 pro vetu GPRMC a 70 pro vetu GPGGA. // Cas je nastaven na pevno (odesila se porad stejny). // unsigned long posledni_vysilani; // pozice hvezdicek: * * // 1111111111222222222233333333334444444444555555555566666666667777777777 // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 char nmeaRMC[] = "$GPRMC,110109.00,A,4926.00000,N,01421.00000,E,0.521,,301124,,,A*72\r\n\0"; char nmeaGGA[] = "$GPGGA,110109.00,4926.00000,N,01421.00000,E,1,05,5.01,500.8,M,44.3,M,,*5C\r\n\0"; char znak1, znak2; //---------------------------------------------- void setup(void) { Serial.begin(9600); } //---------------------------------------------- void loop(void) { if (Serial.available()) { delay(20); znak1 = Serial.read(); znak2 = Serial.read(); Serial.println(znak1); Serial.println(znak2); if (znak1 == 'A' and znak2 == 'A') // rezim primeho zadavani souradnic (stupne a minuty) { delay(100); // cas na prijem celeho retezce int latit = Serial.parseInt(); // zemepisna sirka se zadava jako int cislo ve formatu "[-]ssmm" int longit = Serial.parseInt(); // zemepisna delka se zadava jako int cislo ve formatu "[-]sssmm" nastav_vety(latit, longit); // nastaveni souradnic na presne pozice ve vetach a vypocet CRC } if (znak1 == 'C' and znak2 == 'C') // prepocet CRC { vypocet_CRC(1); // vypocet CRC pro vetu GPRMC vypocet_CRC(2); // vypocet CRC pro vetu GPGGA znak1 = 'A'; // pak se to zacne chovat, jako by byly rucne zadane souradnice funkci "AA" znak2 = 'A'; } while (Serial.available()) Serial.read(); } if (millis() - posledni_vysilani > 1000) // interval odesilani je 1 sekunda (1000 ms) { posledni_vysilani = millis(); if (znak1 == 'N' and znak2 == 'E') { Serial.print(F("$GPRMC,110219.00,A,4933.67227,N,01425.99590,E,0.710,171.45,050724,,,A*65\r\n")); Serial.print(F("$GPGGA,110219.00,4933.67227,N,01425.99590,E,1,05,5.01,489.8,M,44.3,M,,*5C\r\n")); } if (znak1 == 'N' and znak2 == 'W') { Serial.print(F("$GPRMC,110519.00,A,5131.67227,N,01521.99590,W,0.710,171.45,050724,,,A*7E\r\n")); Serial.print(F("$GPGGA,110519.00,5131.67227,N,01521.99590,W,1,05,5.01,502.8,M,44.3,M,,*45\r\n")); } if (znak1 == 'S' and znak2 == 'W') { Serial.print(F("$GPRMC,110845.00,A,4730.67227,S,01125.09590,W,0.710,171.45,050724,,,A*68\r\n")); Serial.print(F("$GPGGA,110845.00,4730.67227,S,01125.09590,W,1,05,5.01,470.0,M,44.3,M,,*5F\r\n")); } if (znak1 == 'S' and znak2 == 'E') { Serial.print(F("$GPRMC,110630.00,A,4730.67227,S,01325.09590,E,0.710,171.45,050724,,,A*74\r\n")); Serial.print(F("$GPGGA,110630.00,4730.67227,S,01325.09590,E,1,05,5.01,488.1,M,44.3,M,,*45\r\n")); } if (znak1 == 'A' and znak2 == 'A') { Serial.print (nmeaRMC); Serial.print (nmeaGGA); } if (znak1 == 'B' and znak2 == 'B') // rezim automatickeho kolsani kolem 180 stupnu { // souradnice se meni pri kazdem pruchodu (kazdou sekundu) int latit = 5000; int longit; int smer = random(0,100); // nahodna volba polokoule (vychod / zapad) if (smer < 50) longit = 17910 + random(0, 50); // nahodna delka pro vychod else longit = -17910 - random(0, 50); // nahodna delka pro zapad nastav_vety(latit, longit); Serial.print (nmeaRMC); Serial.print (nmeaGGA); } } } //========================================================================================================================== //========================================================================================================================== // Zadane souradnice ulozi na presna mista do vet a vypocte kontrolni soucet upravenych vet. void nastav_vety(int vstup_lat, int vstup_lon) { char znak_lat, znak_lon; if (vstup_lat < 0) znak_lat = 'S'; // zaporna cisla pro jih else znak_lat = 'N'; if (vstup_lon < 0) znak_lon = 'W'; // zaporna cisla pro zapad else znak_lon = 'E'; vstup_lat=abs(vstup_lat); // souradnice jsou ve vetach vzdycky jako kladna cisla, vstup_lon=abs(vstup_lon); // urceni N/S/E/W se provadi promennymi "znak_lon" a "znak_lat" nmeaRMC[19] = 48 + ((vstup_lat % 10000L) / 1000L ); // rad desitek stupnu nmeaRMC[20] = 48 + ((vstup_lat % 1000L) / 100L ); // rad jednotek stupnu nmeaRMC[21] = 48 + ((vstup_lat % 100L) / 10L ); // rad desitek minut nmeaRMC[22] = 48 + ((vstup_lat % 10L) ); // rad jednotek minut nmeaRMC[30] = znak_lat; nmeaRMC[32] = 48 + ((vstup_lon % 100000L) / 10000L ); // rad stovek stupnu nmeaRMC[33] = 48 + ((vstup_lon % 10000L) / 1000L ); // rad desitek stupnu nmeaRMC[34] = 48 + ((vstup_lon % 1000L) / 100L ); // rad jednotek stupnu nmeaRMC[35] = 48 + ((vstup_lon % 100L) / 10L ); // rad desitek minut nmeaRMC[36] = 48 + ((vstup_lon % 10L) ); // rad jednotek minut nmeaRMC[44] = znak_lon; vypocet_CRC(1); nmeaGGA[17] = 48 + ((vstup_lat % 10000L) / 1000L ); // rad desitek stupnu nmeaGGA[18] = 48 + ((vstup_lat % 1000L) / 100L ); // rad jednotek stupnu nmeaGGA[19] = 48 + ((vstup_lat % 100L) / 10L ); // rad desitek minut nmeaGGA[20] = 48 + ((vstup_lat % 10L) ); // rad jednotek minut nmeaGGA[28] = znak_lat; nmeaGGA[30] = 48 + ((vstup_lon % 100000L) / 10000L ); // rad stovek stupnu nmeaGGA[31] = 48 + ((vstup_lon % 10000L) / 1000L ); // rad desitek stupnu nmeaGGA[32] = 48 + ((vstup_lon % 1000L) / 100L ); // rad jednotek stupnu nmeaGGA[33] = 48 + ((vstup_lon % 100L) / 10L ); // rad desitek minut nmeaGGA[34] = 48 + ((vstup_lon % 10L) ); // rad jednotek minut nmeaGGA[42] = znak_lon; vypocet_CRC(2); } //========================================================================================================================== //========================================================================================================================== // podle typu vety (1 = GPRMC; 2 = GPGGA) na konci prislusneho retezce za znak '*' prida kontrolni soucet (2 znaky) void vypocet_CRC(byte typ) { char Hnib, Lnib; // horni a dolni pulbajt (nibble) CRC byte CRC_end = 0; if (typ == 1) CRC_end = 63; // pozice hvezdicky v RMC vete if (typ == 2) CRC_end = 70; // pozice hvezdicky v GGA vete byte CRC=0; // vypocet CRC z prijatych dat for (byte i = 1 ; i <= CRC_end -1 ; i++) // prochazi se od prvnho znaku ZA uvodnim '$' az do posledniho znaku PRED hvezdickou { if (typ == 1) CRC = CRC xor nmeaRMC[i]; if (typ == 2) CRC = CRC xor nmeaGGA[i]; } byte pomprom = (CRC >> 4); if (pomprom < 10) Hnib = pomprom + 48; // pod 10 se pricita ASCII kod znaku '0' else Hnib = pomprom + 55; // od 10 se pricita 55, protoze pricteni 10 nastavi ASCII na 65 = 'A' pomprom = (CRC & 0b1111); if (pomprom < 10) Lnib = pomprom + 48; // pod 10 se pricita ASCII kod znaku '0' else Lnib = pomprom + 55; // od 10 se pricita 55, protoze pricteni 10 nastavi ASCII na 65 = 'A' if (typ == 1) { nmeaRMC[CRC_end+1] = Hnib; // ZA hvezdicku zapise dva vypoctene kontrolni znaky nmeaRMC[CRC_end+2] = Lnib; } if (typ == 2) { nmeaGGA[CRC_end+1] = Hnib; // ZA hvezdicku zapise dva vypoctene kontrolni znaky nmeaGGA[CRC_end+2] = Lnib; } } //==========================================================================================================================