/ RFout1MHzV1_04 / RFout1MHzV1_04.ino
RFout1MHzV1_04.ino
  1  //Software for Zachtek "GPS Referenced RF generator 1MHz Out" with a 8MHz Mini Pro Arduno
  2  //This will program an NEO-6 Gps module at startup to output an RF signal when locked.
  3  //The NEO-6 has an internal 48MHz PLL that can be diveded down to any freq below 10MHz. Divide to a frequency that is an integer fraction of 48MHz to get 
  4  //the lowest jitter
  5  //Examples on low jitter freqencies is 1, 2, 4 and 8 MHz  
  6  //To compile you need to install the Library "NeoGps by SlashDevin", you can download it using The Library manager in the Arduino IDE
  7  //ZachTec 2017-2018
  8  
  9  //The Version of this software is stored in the constant "softwareversion" and is displayed on the Serialport att startup
 10  //For Arduino Pro Mini.
 11  #include <NMEAGPS.h>  //NeoGps by SlashDEvin https://github.com/SlashDevin/NeoGPS
 12  #include <SoftwareSerial.h>  // SoftwareSerial by Arduino 
 13  SoftwareSerial gpsPort(2, 3); // RX, TX
 14  #define LEDIndicator1 5  //LED indicator for GPS Lock on pin A3
 15  #define FIXOut 4         //Pin Out at IDC. Indicator for GPS Lock on pin 4
 16  #define LDO_Enable A3    //GPS Voltage regulator Enable on pin A0
 17  boolean GPSOK;
 18  const char softwareversion[] = "1.04" ; //Version of this program, sent to serialport at startup
 19  NMEAGPS  gps; // This parses the GPS characters
 20  gps_fix  fix; // This holds on to the latest values
 21  
 22  
 23  
 24  //--------------------------  SETUP -----------------------
 25  
 26  void setup()
 27  {
 28    Serial.begin(9600);
 29    while (!Serial)
 30      ;
 31    
 32    Serial.println("");
 33    Serial.print(F("Zachtek GPS referenced RF, Software version: "));
 34    Serial.println(softwareversion);
 35     
 36     pinMode(LDO_Enable, OUTPUT); // Set Voltage Regulator Enable pin as output.
 37     digitalWrite(LDO_Enable, HIGH); //Turn on 3.1V Power supply for the Ublox GPS module
 38     Serial.println (F("Turning on Voltage Regulator for GPS module"));
 39     pinMode(LEDIndicator1, OUTPUT); // Set GPS Lock  LED pin as output.
 40     pinMode(FIXOut, OUTPUT);        // Set GPS Lock line as output.
 41     digitalWrite(LEDIndicator1, LOW); //Turn off Lock LED 
 42     digitalWrite(FIXOut, LOW);        //Go low on Lock line 
 43     delay(500);//Wait for GPSmodule to complete it's power on.
 44     gpsPort.begin(9600);
 45     GPSOK=true;
 46    
 47     //Program GPS to output RF
 48     if (setGPS_OutputFreq1MHz()) {
 49      Serial.println ("GPS Initialized to output RF at 1MHz");
 50      Serial.println ("Initialization is complete.");
 51      Serial.println ("");
 52      GPSOK=true; 
 53    }
 54    else
 55    {
 56      Serial.println ("Error! Could not program GPS!"); 
 57      GPSOK=false;  
 58    }
 59  }
 60  
 61  //--------------------------
 62  
 63  
 64  
 65  
 66  //--------------------------  Main loop -----------------------
 67  void loop()
 68  {
 69    while (gps.available( gpsPort )) {
 70      fix = gps.read();
 71      if (fix.valid.location && fix.valid.date && fix.valid.time) 
 72        {
 73        Serial.print( F("Fix - Location: ") );  
 74        digitalWrite(LEDIndicator1, HIGH);   // turn the LED on 
 75        digitalWrite(FIXOut, HIGH);          // Set Lock Line high  
 76        Serial.print( fix.latitude(), 6 );
 77        Serial.print( ',' );
 78        Serial.print( fix.longitude(), 6 );
 79        Serial.println();
 80    
 81      }
 82      else
 83      {
 84        if (GPSOK) { //If the GPS is connected but not locked then short blink
 85          digitalWrite(LEDIndicator1, HIGH);   // turn the LED on 
 86          digitalWrite(FIXOut, LOW);          // Set Lock Line low 
 87          delay(100); 
 88          digitalWrite(LEDIndicator1, LOW);    // turn the LED off   
 89          Serial.println(F("Waiting for GPS location fix")); 
 90        }  
 91      }
 92    }
 93  }
 94  
 95  
 96  //--------------------------
 97  
 98  bool setGPS_OutputFreq100kHz()
 99  {
100   int gps_set_sucess=0;
101   uint8_t setOutputFreq[] = {
102   0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00,
103   0x00, 0x00, 0xA0, 0x86, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
104   0x00, 0x00, 0xEF, 0x00, 0x00, 0x00, 0x20, 0x1B };
105  
106   sendUBX(setOutputFreq, sizeof(setOutputFreq)/sizeof(uint8_t));
107   gps_set_sucess=getUBX_ACK(setOutputFreq);
108   //Serial.println("Set output Freq Done");
109   return gps_set_sucess;
110  }
111  
112  bool setGPS_OutputFreq1MHz()
113  {
114   int gps_set_sucess=0;
115   uint8_t setOutputFreq[] = {
116   0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00,
117   0x00, 0x00, 0x40, 0x42, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
118   0x00, 0x00, 0xEF, 0x00, 0x00, 0x00, 0x8A, 0x8B };
119  
120   sendUBX(setOutputFreq, sizeof(setOutputFreq)/sizeof(uint8_t));
121   gps_set_sucess=getUBX_ACK(setOutputFreq);
122   //Serial.println("Set output Freq Done");
123   return gps_set_sucess;
124  }
125  
126  bool setGPS_OutputFreq2MHz()
127  {
128   int gps_set_sucess=0;
129   uint8_t setOutputFreq[] = {
130   0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00,
131   0x00, 0x00, 0x80, 0x84, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
132   0x00, 0x00, 0xEF, 0x00, 0x00, 0x00, 0x1B, 0x7F };
133  
134   sendUBX(setOutputFreq, sizeof(setOutputFreq)/sizeof(uint8_t));
135   gps_set_sucess=getUBX_ACK(setOutputFreq);
136   //Serial.println("Set output Freq Done");
137   return gps_set_sucess;
138  }
139  
140  
141  bool setGPS_OutputFreq4MHz()
142  {
143   int gps_set_sucess=0;
144   uint8_t setOutputFreq[] = {
145   0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00,
146   0x00, 0x00, 0x00, 0x09, 0x3D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
147   0x00, 0x00, 0xEF, 0x00, 0x00, 0x00, 0x3F, 0x8C };
148  
149   sendUBX(setOutputFreq, sizeof(setOutputFreq)/sizeof(uint8_t));
150   gps_set_sucess=getUBX_ACK(setOutputFreq);
151   //Serial.println("Set output Freq Done");
152   return gps_set_sucess;
153  }
154  
155  //8MHz is the highest low-jitter frequency possible
156  bool setGPS_OutputFreq8MHz()
157  {
158   int gps_set_sucess=0;
159   uint8_t setOutputFreq[] = {
160   0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
161   0x00, 0x00, 0x00, 0x12, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
162   0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0xD4, 0x28 };
163  
164   sendUBX(setOutputFreq, sizeof(setOutputFreq)/sizeof(uint8_t));
165   gps_set_sucess=getUBX_ACK(setOutputFreq);
166   //Serial.println("Set output Freq Done");
167   return gps_set_sucess;
168  }
169  
170  //10 MHz is very jittery. Numbers that can be done with an integer division from 48MHz will produce
171  //the lowest jitter so 16 ,12 ,8 ,6 ,4 ,2 and 1 MHz is low jitter but 10MHz is not
172  //If 10MHz low jitter is needed then one option is to output 2MHz and then filter out the 5th overtone arriving at 10MHz in that way.
173  bool setGPS_OutputFreq10MHz()
174  {
175   int gps_set_sucess=0;
176   uint8_t setOutputFreq[] = {
177   0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
178   0x00, 0x00, 0x80, 0x96, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
179   0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0xF6, 0x10 };
180  
181   sendUBX(setOutputFreq, sizeof(setOutputFreq)/sizeof(uint8_t));
182   gps_set_sucess=getUBX_ACK(setOutputFreq);
183   //Serial.println("Set output Freq Done");
184   return gps_set_sucess;
185  }
186  
187  //16MHz is above the specs for lUblox Neo-6, only included for experiments. 
188  //This will not produce as clean Square wave.
189  bool setGPS_OutputFreq16MHz()
190  {
191   int gps_set_sucess=0;
192   uint8_t setOutputFreq[] = {
193   0xB5, 0x62, 0x06, 0x31, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
194   0x00, 0x00, 0x00, 0x24, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
195   0x00, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x60, 0x12 };
196  
197   sendUBX(setOutputFreq, sizeof(setOutputFreq)/sizeof(uint8_t));
198   gps_set_sucess=getUBX_ACK(setOutputFreq);
199   //Serial.println("Set output Freq Done");
200   return gps_set_sucess;
201  }
202  
203  
204  void sendUBX(uint8_t *MSG, uint8_t len) {
205   gpsPort.flush();
206   gpsPort.write(0xFF);
207   _delay_ms(500);
208   for(int i=0; i<len; i++) {
209   gpsPort.write(MSG[i]);
210   }
211  }
212  
213  boolean getUBX_ACK(uint8_t *MSG) {
214   uint8_t b;
215   uint8_t ackByteID = 0;
216   uint8_t ackPacket[10];
217   unsigned long startTime = millis();
218   
219  // Construct the expected ACK packet
220   ackPacket[0] = 0xB5; // header
221   ackPacket[1] = 0x62; // header
222   ackPacket[2] = 0x05; // class
223   ackPacket[3] = 0x01; // id
224   ackPacket[4] = 0x02; // length
225   ackPacket[5] = 0x00;
226   ackPacket[6] = MSG[2]; // ACK class
227   ackPacket[7] = MSG[3]; // ACK id
228   ackPacket[8] = 0; // CK_A
229   ackPacket[9] = 0; // CK_B
230   
231  // Calculate the checksums
232   for (uint8_t ubxi=2; ubxi<8; ubxi++) {
233   ackPacket[8] = ackPacket[8] + ackPacket[ubxi];
234   ackPacket[9] = ackPacket[9] + ackPacket[8];
235   }
236   
237    while (1) {  // Test for success
238      if (ackByteID > 9) {
239        // All packets in order!
240        return true;
241      }
242   
243    // Timeout if no valid response in 3 seconds
244    if (millis() - startTime > 3000) {
245      return false;
246    }
247   
248    // Make sure data is available to read
249    if (gpsPort.available()) {
250      b = gpsPort.read();
251      // Check that bytes arrive in sequence as per expected ACK packet
252      if (b == ackPacket[ackByteID]) {
253        ackByteID++;
254      }
255      else {
256        ackByteID = 0; // Reset and look again, invalid order
257      }//else
258    }//If
259   }//While
260  }//getUBX_ACK