/*************************************************************************** * Version 1.1 * Alain fort F1CJN November, 11, 2016 / Patrick Coquerel F4HSP 30 décembre 2020 * * This program is made : * - first to program the Timepulse frequency of an UBLOX GPS NEO-8M module * - write on a 4 line LCD : latitude, longitude, Time, number of received satellites and the QRA Locator. * * The frequency can be changed near line 125. * The Timepulse is based on a master clock at 48 MHz * Only frequencies with even sub multiples integer numbers (ie, 2,4,6, 342 .....) have low jitter. For exemple :8MHz is ok(6) ,10Khz is * ok(4800). 10 MHz is not ok(divison factor of 4.8). The Timepulse frequency is programmed for 10 KHz and can be modified (on line of program). * * La fréquence peut être modifiée en ligne 125/ * The signal Timepulse est généré à partir d'une horloge à 48 MHz. * Seules les facteurs de divisions entiers pairs (2,4,6, 342, ....) présentent un très faible jitter. Par exemple 8MHz est ok, 10 KHz est ok * mais 10 MHz ne l'est pas (facteur de division de 4,8). La fréquence de Timepulse est programmé pour 10 KHz mais peut être modifiée à la ligne 125. * * Connections to the GPS board * GPS GND connects to Arduino Gnd * GPS RX connects to Software Serial pin 3 on the Arduino Nano, via voltage divider : 330 Ohms in serial to 680 Ohms to ground Pin 4--330--NEO RX--680--GND * GPS TX connects to Software Serial pin 4 on the Arduino Nano * GPS VCC connects to 5 volts * * Connections to the serial LCD 4x20 board * Arduino 5V to LCD 5V * Arduino GND to LCD GND * Arduino A4 to LCD SDA * Arduino A5 to CLD SCL * * Serial O/P at 9600 ( or 115200 ) is used for test purposes * * Dans la librairie TinyGPSPlus.cpp, il faut modifier : * #define _GPRMCterm "GNRMC" // remplace GPRMC le 31.12.20 * #define _GPGGAterm "GNGGA" // remplace GPGGA le 31.12.20 * **************************************************************************/ #include #include // Attention Librairie modifiée (voir texte ci-dessus) #include // Comes with Arduino IDE #include // set the LCD address to 0x20 for a 20 chars 4 line display // Set the pins on the I2C chip used for LCD connections: // addr, en,rw,rs,d4,d5,d6,d7,bl,blpol LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address boolean gpsStatus[] = {false, false, false, false, false, false, false, false, false}; unsigned long frequency; byte buf[4]; #define RXPIN 4 // vers GPS TX #define TXPIN 3 // vers GPS RX via pont diviseur 330/680 Ohms pour adapter en 3,3V #define GPSBAUD 9600 // SoftwareSerial gpsSerial(RXPIN,TXPIN); // 4,3 TinyGPSPlus gps; void getgps(TinyGPSPlus &gps); float latitude; float longitude; char locator[6]; float voltageA0; float tempA0; int analogValueA0; float r1A0=100000.0; //100 kOhm float r2A0=10000.0; //10 kOhm float voltageA1; float tempA1; int analogValueA1; void calcLocator(char *dst,float lat, float lng ) // Calcule le Locator ... { int lon1, lon2, lon3; int la1, la2, la3; float reste; // longitude reste = lng + 180.0; lon1 = int(reste / 20.0); reste = reste - float(lon1) * 20.0; lon2 = int(reste / 2.0); reste = reste - 2.0 * float(lon2); lon3 = int(12.0 * reste); // latitude reste = lat + 90.0; la1 = int(reste / 10.0); reste = reste - float(la1) * 10.0; la2 = int(reste); reste = reste - float(la2); la3 = int(24.0 * reste); dst[0] = (char)lon1 + 65; dst[1] = (char)la1 + 65; dst[2] = (char)lon2 + 48; dst[3] = (char)la2 + 48; dst[4] = (char)lon3 + 65; // dst[5] = (char)la3 + 65; // } void getgps(TinyGPSPlus &gps) { // Print latitude,longitude. Ligne 1 lcd.setCursor(0,0); lcd.print(""); lcd.print(gps.location.lat(),7);lcd.print("-"); lcd.print(""); lcd.print(gps.location.lng(),7);lcd.print(""); // Print voltage to LCD. Ligne 2 lcd.setCursor(0,1); lcd.print("VCC:"); lcd.print(voltageA0); lcd.print("V"); lcd.print(" "); lcd.print("VCO:"); lcd.print(voltageA1); lcd.print("V"); lcd.print(" "); // Print time. Ligne 3 lcd.setCursor(0,2); lcd.print("TIME UTC : "); lcd.print(gps.time.hour(), DEC); lcd.print(":"); lcd.print(gps.time.minute(), DEC); lcd.print(":"); lcd.print(gps.time.second(), DEC); lcd.print(""); // Print Sat + Locator. Ligne 4 lcd.setCursor(0,3); calcLocator(locator,gps.location.lat(),gps.location.lng()); lcd.print(" Sat:"); lcd.print(gps.satellites.value()); lcd.print(" "); lcd.print(locator[0]); lcd.print(locator[1]); lcd.print(locator[2]); lcd.print(locator[3]); lcd.print(locator[4]); lcd.print(locator[5]); lcd.print(" "); lcd.print("LOCK"); lcd.print("*"); // REMPLISSAGE LIGNE POUR UNE AUTRE FONCTION } static void smartDelay(unsigned long ms) { unsigned long start = millis(); do { while (gpsSerial.available()) gps.encode(gpsSerial.read()); } while (millis() - start < ms); } void setup() { gpsSerial.begin(9600); // GPS à 9600 Bauds Serial.begin(9600); // Serial monitor via USB at 9600 bauds ( au lieu de 115200 bauds ) frequency=100000; //100 KHz Timepulse Frequency in Hertz. The duty cycle is fixed at 50% // only frequencies with even sub multiples numbers (ie, 2,4,6, 342 .....) are not noisy for exemple :8MHz is ok, 10Khz is ok, //10 MHz is not ok configureUblox(); // Configure Timepulse lcd.begin(20,4); // initialize the lcd for 20 chars 4 lines and turn on backlight lcd.setCursor(0,0); //Start at position 0 at line 0 lcd.print(" GPSDO 10MHz "); lcd.setCursor(0,1); lcd.print(" Arduino and NEO-8M "); lcd.setCursor(0,2); lcd.print(" 10-2021 "); // efface la ligne 2 lcd.setCursor(0,3); lcd.print(" F1CJN-F4HSP-F1AZJ "); delay(5000); // délai maintien de l'écran de démarrage pendant 3s lcd.setCursor(0,3); lcd.print(" "); // efface la ligne 3 } void loop() { smartDelay(400); // 400 nearly 0.4s loop ( 1000 nearly 1 second loop , cette boucle était trop longue ) getgps(gps); // Get GPS parameters //Read value from A0 analog pin analogValueA0 = analogRead(A0); //Convert analog value from a range of 0-1203 to 0-5 //NOTE: Arduino analog maximum input voltage is 5V tempA0 = (analogValueA0* 5.0)/1024.0; // 1:10 (10kOhm:100kOhm) voltage divider used to increase voltage range //Voltage divider equation used to convert voltage received to input voltage voltageA0 = tempA0 / (r2A0/(r1A0+r2A0))-1; // Test -1V //Read value from A1 analog pin analogValueA1 = analogRead(A1); //Convert analog value from a range of 0-1203 to 0-5 //NOTE: Arduino analog maximum input voltage is 5V tempA1 = (analogValueA1* 5.0)/1024.0; //Voltage divider equation used to convert voltage received to input voltage voltageA1 = tempA1; } void configureUblox() { byte gpsSetSuccess = 0; buf[0]=(frequency&0x000000FF); // Preparation little endian buf[1]=(frequency&0x0000FF00)>>8; buf[2]=(frequency&0x00FF0000)>>16; buf[3]=(frequency&0xFF000000)>>24; //Generate the configuration string for TimePulse with frequency byte setTimePulse[] = {0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, buf[0], buf[1], buf[2], buf[3],buf[0], buf[1], buf[2], buf[3],0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,0x00,0xEF,0x00,0x00,0x00,0x91,0x22}; calcChecksum(&setTimePulse[2], sizeof(setTimePulse) - 4); delay(1000); while(gpsSetSuccess < 3) { Serial.println("Setting Timepulse... "); gpsSetSuccess = 0; while (gpsSetSuccess < 3) { Serial.println("configuration TimePulse"); sendUBX(&setTimePulse[0], sizeof(setTimePulse)); gpsSetSuccess += getUBX_ACK(&setTimePulse[2]); //Passes Class ID and Message ID to the ACK Receive function if (gpsSetSuccess == 10) gpsStatus[7] = true; if (gpsSetSuccess == 5 | gpsSetSuccess == 6) gpsSetSuccess -= 4; } if (gpsSetSuccess == 3) Serial.println("Timepulse non OK"); } } void calcChecksum(byte *checksumPayload, byte payloadSize) { byte CK_A = 0, CK_B = 0; for (int i = 0; i < payloadSize ;i++) { CK_A = CK_A + *checksumPayload; CK_B = CK_B + CK_A; checksumPayload++; } *checksumPayload = CK_A; checksumPayload++; *checksumPayload = CK_B; } void sendUBX(byte *UBXmsg, byte msgLength) { for(int i = 0; i < msgLength; i++) { gpsSerial.write(UBXmsg[i]); // send UBX msg gpsSerial.flush(); // Wait end of transmission } gpsSerial.println(); //send CR gpsSerial.flush(); // Wait end of transmission } byte getUBX_ACK(byte *msgID) { byte CK_A = 0, CK_B = 0; byte incoming_char; boolean headerReceived = false; unsigned long ackWait = millis(); byte ackPacket[10] = {0xB5, 0x62, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; int i = 0; while (1) { if (gpsSerial.available()) { incoming_char = gpsSerial.read(); if (incoming_char == ackPacket[i]) { i++; } else if (i > 2) {ackPacket[i] = incoming_char; i++; } } if (i > 9) break; if ((millis() - ackWait) > 1500) { Serial.println("ACK Timeout"); return 5; } if (i == 4 && ackPacket[3] == 0x00) { Serial.println("NAK Received"); return 1; } } for (i = 2; i < 8 ;i++) { CK_A = CK_A + ackPacket[i]; CK_B = CK_B + CK_A; } if (msgID[0] == ackPacket[6] && msgID[1] == ackPacket[7] && CK_A == ackPacket[8] && CK_B == ackPacket[9]) { Serial.println("Success!"); Serial.println("ACK Received! "); return 10; } else { Serial.println("ACK Checksum Failure: "); delay(1000); return 1; } }