In this 4th part of this project we upgrade the software to give satellite data and frequency lock display. Plus the current frequency on the display is improved to give reading in MHz, KHz or Hz.
The new software version can be downloaded from the link below:
http://www.scullcom.com/GPS_Ref_Version6.zip
PLEASE NOTE TO COMPILE THIS CODE YOU NEED TO BE RUNNING THE LATEST VERSION OF ARDUINO IDE (version 1.6.7)
Below is a link to download a user guide on this project which includes circuit detail, PCB detailed layouts, schematics and software details. The file is a zip file which contains a PDF document:
http://www.scullcom.com/Scullcom_GPS_Ref_manual.zip
Reading the GPS module data to extract the number of Satellites detected
When the GPS module starts receiving satellite data it provides a constant stream of data sentences which are know as NMEA sentences. Within this data stream the most important NMEA sentences include the GGA which provides the current Fix data, the RMC which provides the minimum GPS sentences information, and the GSA which provides the Satellite status data. In our project we will use the GGA data stream to extract the number of satellites detected and locked on to.
Below is an example of a typical GGA data sentence:
$GPGGA,123519.00,4807.03830,N,01131.00000,E,1,08,0.9,545.4,M,46.9,M,,*47
Where:
- GGA Global Positioning System Fix Data
- 123519.00 Fix taken at 12:35:19 UTC (current time)
- 4807.03830,N Latitude 48 deg 07.038′ N
- 01131.00000,E Longitude 11 deg 31.000′ E
- 1 Fix quality: 0 = invalid, 1 = GPS fix (SPS), 2 = DGPS fix, 3 = PPS fix, 4 = Real Time Kinematic,
5 = Float RTK, 6 = estimated (dead reckoning) (2.3 feature), 7 = Manual input mode,
8 = Simulation mode - 08 Number of satellites being tracked
- 0.9 Horizontal dilution of position
- 545.4,M Altitude, Meters, above mean sea level
- 46.9,M Height of geoid (mean sea level) above WGS84 ellipsoid
- (empty field) time in seconds since last DGPS update
- (empty field) DGPS station ID number
- *47 the checksum data, always begins with *
We will be using the data highlighted above to show the number of satellite on our LCD. In order to extract this information we will set up a second Software Serial port.
First we need to identify the NMEA data we need to capture and we do this with the flowing code:
char gpsin[8] = “$GPGGA,”; //define a character string “$GPGGA,”
if (GPSreceiver.find(gpsin)) { //if serial data starts with the characters “$GPGGA,”
GPGGAdata = GPSreceiver.readStringUntil(‘\n’); //read data until carriage return
When the characters “$GPGGA,” are detected it starts reading the remainder of the string data in to the buffer. So the captured data starts from the first digit of the ‘time’ data (and not from the $ character). The captured data then looks as follows:
123519.00,4807.03830,N,01131.00000,E,1,08,0.9,545.4,M,46.9,M,,*47
With in the main loop we will use the substring command to extract the number of satellites from the GGA data sentence. This is a simply and easy way of extracting the data you wish to use. The substring command is defined as follows:
substring(index, to) – this returns a string with the characters starting from index and ending at the character location before the to
So to extract the number of satellites (highlighted in read) from the GGA data sentence below
We use the following code:
sats = GPGGAdata.substring(39,41);
The string “sats” now is equal to “08”
If you wanted to extract other data you simply need to change the “index, to” numbers in the substring. For example to extract the current time to a string labeled time then you would use:
time = GPGGAdata.substring(7,13); //the string “time” now is equal to “123519”
Details of Code used in program loop to extract number of satellites and display on LCD
//new variables added at start of program
String sats; //number of satellites detected
String GPGGAdata; //satellite data string from GPS module
String FreqStatus; //used to print Frequency locked if applicable
int satNum; //number of satellites detected as an integer
//set up a Software Serial port called GPSreceiver
SoftwareSerial GPSreceiver (14,255); //14(A0) is RX on Arduino connected to GPS TX pin.
//255 a nonexistent pin number used to free up a pin
//in void setup() include serial monitor command and set to 57600 baud.
Serial.begin(57600); //this is simply used for testing
//The # key used to tell the unit to display the number of satellites on LCD.
// below is the software code used in the main loop to show number of satellites when //“#” key pressed:
case '#'://# pressed Show number of satellites detected and frequency status
lcd.clear(); //clear LCD
lcd.print("Satellites ="); //print the word 'Satellites =' on the top line of LCD
do { //now loop
GPSreceiver.flush(); //clear any data which may be in the Serial Buffer
if (GPSreceiver.available()) //if any GPS data is available
{
GPSreceiver.read(); //read GPS serial data streams if available
}
char gpsin[8] = "$GPGGA,"; //define a character string “$GPGGA,”
if (GPSreceiver.find(gpsin)) { //if serial data starts with the characters “$GPGGA,”
GPGGAdata = GPSreceiver.readStringUntil('\n'); //read data until a carriage return
sats = GPGGAdata.substring(39,41); //extract number of satellites from data string
}
satNum = sats.toInt(); //convert sats string to an integer so as to remove leading zero
if (satNum >0){
FreqStatus = "Frequency Locked"; //if satellites detected the status string
//= “Frequency Locked”
}else{
FreqStatus = " "; //16 spaces to clear line if no lock
}
Serial.print(GPGGAdata); //These serial print lines are for testing using
//Serial Monitor
Serial.println(); //full GPGGA data sentence printed and then carriage return
Serial.print("Satellite = ");
Serial.print(satNum);
Serial.println();
Serial.print(FreqStatus);
Serial.println();
lcd.setCursor(13,0); //set cursor position to column 13 of row 0 (first line on LCD)
lcd.print(" "); //clears number if no satellites detected (3 spaces used)
lcd.setCursor(13,0); //set cursor position to column 13 of row 0 (first line on LCD)
lcd.print(satNum); //print number of satellites to LCD
lcd.setCursor(0,1); //set cursor position to column 0 of row 1 (second line on LCD)
lcd.print(FreqStatus); //print Frequency Locked status
}
while (customKeypad.getKey()!= '#'); //if # key pressed again break out of loop
displayCurrentFrequency(); //and display current frequency subroutine
break; //break and return to main program loop
The software for this project is made up of three parts all of which are include in a download zip file.
Once the file is unzipped you will have a folder as above. In this folder you will find the following files shown below:
Please ensure that you are running the latest version of the Arduino IDE which is “Arduino 1.6.7” (older versions may not work). Run the “GPS_Ref_Version6” file and you should find the software opens up in the Arduino IDE as shown below:
Now compile and upload the software to the Arduino nano on the main PCB.
GPS Locked Frequency Standard Project
This project will use a small GPS module which has the u-blox Neo-7 GPS receiver. These modules are readily available on sites like eBay for around £12, they tend to be advertised for use with flight controllers on model aircraft.
The u-blox receiver is normally fitted in the centre of a small PCB. Additional components on the PCB include a 3.3 volt Low Drop Voltage Regulator, timepulse and power on LED’s and EEPROM. There is also some short term back-up supply for the DRAM of the Neo-7 receiver by use of a 0.08F super capacitor (Seiko XH414HG). These capacitors normally only provide power off back-up for around a day or so if you are lucky.
These GPS modules are usually configured by default to provide a 1Hz timing pulse output which is normally used to flash a green LED to indicate when the unit has a fix on satellites and the local oscillator is locked to the GPS signal. By default this timing pulse provides a 100mSec pulse every 1000mSec, as shown below.
This timing pulse can be configured to provide different frequencies and different duty cycle and we will be using this option in this project to change the frequency and fix the duty cycle to 50%.
GPS satellites are primarily used as a navigation system; this global positioning system can also used to disseminate precise time, time intervals, and frequency. The GPS carrier signals originate from an on-board atomic clock (oscillator) which is also monitored and controlled by ground stations in the United States to ensure it agrees with the Coordinated Universal Time (UTC). UTC is the primary time standard by which the world regulates clocks and time.
Atomic clocks are based on the natural atomic oscillations of gases in resonant cavities. When isolated from magnetic fields, rubidium and cesium gases will resonate at specific frequencies under controlled conditions. These frequencies are so accurate that since 1967 the length of the second has been defined as the frequency of a specific resonant mode of the cesium atom, producing 9,192,631,770 oscillations in one second.
The u-blox receiver uses a built-in 48MHz oscillator.
There are various versions of the u-blox receiver available, some of which can be configured to provide a frequency pulse output in the range 0.25Hz to 10MHz. Those which are suitable for this project are listed in the table below:
u-blox Receiver Type | Type of Memory fitted | Type of Oscillator used |
Neo-6T | ROM | TCXO |
Neo-7M | ROM | Crystal |
Neo-7N | FLASH | TCXO |
Neo-7P | FLASH | Crystal |
Neo-M8M | ROM | Crystal |
Neo-M8N | FLASH | TCXO |
Neo-M8Q | ROM | Crystal |
In this project we will use the Neo-7M. As this uses a ROM, the option to use a 3 volt backup battery on the PCB will help to speed up satellite lock after switch-on (this is optional). If the back-up battery is not used it may take a few minutes before the unit locks on to satellites. If the Neo-7N version is used then as it uses a FLASH memory there is no need for a back-up supply.
Read my comments on youtube. The conclusion is that the mcu won’t output a clean clock without a PLL. It can only output a signal synchronized with the 48 MHz clock and will add extra cycles from time to time to generate the right number of cycles ON AVERAGE but not on a single period. With frequencies that are low enough the problem is reduced (because changing the half period by +- 1/48000000 s is negligeable if the half cycle is 1/48000s) but will never disappear.
I have found if you select any random frequency up to about 2 MHz the output always gives a nice clean square wave with no phase jitter. The output waveform of any frequency between 3 MHz to 4 MHz also stays fairly clean. Once you go higher than these frequencies the square wave has some phase noise but the frequency is still accurate when monitored on a frequency counter or spectrum analyser. Choosing frequencies which have a factor of 48 MHz like 4, 6, 8 or 12 MHz does show some slight improvement but the phase jitter on the waveform is still there. To remove this phase jitter altogether a Phase Locked Loop circuit could be used, but I will leave this for future project as it involves a second PCB with a Voltage Controlled Oscillator and a Programmable Frequency Divider in the feedback loop. The project as it stands at the moment does give out an accurate frequency reference signal so is still quite useful for the hobbyist and a good source of reference to check the accuracy of frequency counter.
Thanks for all your helpful work on this project.
Do you think you could give some advice on how to do the PLL circuit you suggested? It has been nearly a year and a half, and the PLL circuit is for me the most useful part of the project.
Hello,
I rebuilt the device, had the board manufactured (in China) and fully equipped. Unfortunately the LCD is not initialized correctly, I have black rectangles in the first line.
I measured everything, ok. The sketch is loaded into the Arduino without errors, only the display shows rectangles. I tried several with the original Hitchi chipset, nothing works!
Any tips?
hi
I would like to find out were in china and what’s the name co where you got the circuit board made?
and a copy of the art work. would you e-mail back (pierron.allan@yahoo.com) i would like to order a circuit board from you or the manufactured in china.
thank’s Allan Pierron
pierron.allan@yahoo.com
6/23/2024
Hi Louis,
do you have a working link that would allow me to download the Arduino code for this project?
Best
Wolfgang Daum WY2S
Mr. Scully. You spoke of the strange FFT display as causing the jitter on the 10 MHz display. It is actually the other way around. The jitter causes the strange FFT. The state of the 10 MHz output can change from low to high or high to low only on ticks of the GPS internal 48 MHz clock which come every 20.833 ns. The device is trying to change its output state from low to high or high to low every 50 ns in order to produce a square wave at 10 MHz. Lets assume for discussion that it switches output as soon as possible after every 50 ns. Ticks of
the internal clock will come at 20.83, 41.66, 62.5, 83.33, 104.16, 125, 145.83 166.67, 187.5, and 208.33 ns. Output transitions will happen at 62.5 ns instead of 50. Then 104.16 instead of 100, then 166.67 instead of 150 and finally 208.33 ns instead of 200. I have a plot I can send via email if you would like. There will be exactly 10 million pulses in one second which is why your frequency counter got that result. To say that is the frequency of the wave is obviously wrong. Those pulses are bouncing back and forth between 2 and three of the 48 MHz clock in width. If you slow your scope down by 2x and take a single shot trigger. You will see this. Measure the period of any wave. Take the reciprocal of the period. That is the frequency of that particular period. You will find some are 12 MHz and some are 9.6 MHz. This is phase modulation. The effect on an FFT will be subject to the Bessel functions and very different from what you expect from amplitude modulation. I suggest this 10 MHz output is unsuitable for most uses as a frequency reference. The phase noise is awful, making It harder to filter to get a sine wave. If used in work on radio receivers it will produce many frequencies which you do not want when you need 10 MHz. I have a suggestion. You may be able to find a duty cycle around 41 % that will minimize but not eliminate the jitter. At frequencies below about 1 MHz you can use the Arduino Nano itself by feeding a reference clock (up to 24 MHz into the Nano. Using timers, interrupts and software almost any frequency and duty cycle below about 1 MHz can be produced. You might even be able to get extremely low jitter. The frequencies of 12 MHz and 9.6 MHz from the GPS device should have nearly zero Jitter if you can use them. They are 48/4 and 48/5 respectively. The number of frequencies below 1 MHz that can be produced by dividing the 48 MHz clock by an integer and have nearly zero jitter grows dramatically as you decrease frequency. The jitter is caused because some frequencies require the device to make one period by dividing by n and some periods by dividing by n+1. The jitter on even the worst examples expressed as a percentage becomes vanishingly small as output frequency goes down. That is the nature of using counters to synthesize frequencies. I found your software and module selection information quite useful. I will likely try to phase lock an actual 10 MHz crystal oscillator to a 1 MHz (no jitter) output from the GPS. You probably have all the parts except the oscillator to do it. I’ll be glad to share my results.
I believe the issues you are seeing with “phase distortion” are rather due to the pulse dropping method that ublox uses for synthesis of frequencies that are not integer multiples of the 48 MHz crystal frequency. This means that 12,8,6,4,2,1 MHz etc. will be clean but 10 MHz etc. will not.
Over an averaging period such as that used by a frequency counter the frequency will look spot on, but as you’ve demonstrated a spectrum analyzer and oscilloscope will notice the difference.
Louis,
What is the accuracy of the GPS reference ?
Thank you for your videos and your excellent teaching skills !!
Phil,
I have compared it with my rubidium standard which would mean to within a few parts in 10 to the power 11.
Hi Louis,
Where did you get your NEO module from ?
Would you trust Ali-very-fast for those modules at very very low price ?
Thanks for your projects and videos.
Hi David, I purchased mine on eBay and had no problems.
OK, thanks for your reply. I’ll give it a chance.
I hope to see new projects and new videos
Hi Louis,
Such a reference std has been on my to-do list for a couple of years. I happened upon your excellent video presentations and am encouraged to do something about it!
Is it possible to send me a 1:1 image of the final PCB? Ideally a reversed image would be excellent since I routinely use the ‘iron-on’ method for producing my PCBs.
Thanks,
Steve.
Hello Louis,
I got it working, and I am very impressed. My previous reference was a 100KHz signal derived from Droitwich. It is interesting to compare the two (with your design producing 100KHz of course). There appear locked of course, but after several hours there was a relative phase shift of about a quarter of a cycle. Probably of no practical consequence but mildly interesting.
If I might be cheeky enough to suggest two software changes:
It would be useful if the numeric keys were ignored until the “A” key is pushed. I have a habit of pushing a numeric button, and then remembering that I should have done an A first! Then, when the brain rights itself, using the A does not clear the junk already entered. So a nonsense frequency has to be sent before the process can be done properly.
Secondly, and related to that, a possible use for the * key would be to erase anything previously entered, to fix a misstype!
Nice project Louis. Thank you for it.
Tony
(G3PTD)
Louis
I have finally got down to building the frequency standard, but when I try to Arduino: 1.8.5 (Windows 10), Board: “Arduino/Genuino Uno” verify the program I get the following error message :
C:\Users\Robert\Documents\Arduino\GPS_Ref_Version6\GPS_Ref_Version6.ino:19:112: fatal error: Keypad.h: No such file or directory
#include //dowmload and add this library from http://playground.arduino.cc/uploads/Code/Keypad.zip
^
compilation terminated.
exit status 1
Error compiling for board Arduino/Genuino Uno.
This report would have more information with
“Show verbose output during compilation”
option enabled in File -> Preferences.
I can see the Keyboard.H program but as I am not familiar with the Adruino I am not sure in which file it should be residing . can you help?
Whilst I wa checking what I had done I noticed that you showed the original download as GPS_Ref_version5,
I could not find version 5 so used version6.
I can be contacted on 07974204219 or rileyr103nun@sky.com if you want any further details.
regards
bob riley
Hi Bob,
Sorry for delay only just seen your message.
You need to download the Keypad.h libary from the link I gave, namely;
http://playground.arduino.cc/uploads/Code/Keypad.zip
This will be a zip file which will be saved in your download folder.
You then need to install that library in your Arduino IDE.
There are basically two ways of doing this.
Below is a link to a You Tube video which describes both these methods. I would recommend you use the second method he explains as it is the simplest – it starts at 2.00 mins in to the video but I recommend you view the whole video first before doing it.
https://www.youtube.com/watch?v=d5LU1ig4BQQ
Once the library is installed you should be able to compile and upload the code. If you still have any issues then shut down the Arduino IDE software and then start the Arduino IDE again so it is reset – sometimes it needs to reset before the library is recognized.
Regards,
Louis
Regards,
Louis
Hi Louis
Please ignore my question about where the Keypad file had to go, having put it in manually I found out the correct (very simple) way to install it, so on to finishing the population of my board. Many thank for all yhe time and effort that it must take. It really is appreciated.
Regards
Bob R
Hi bob
how did you get the software to install on your arduino nano board .when i try to install the software i get a error (keypad.h no such file) could you please write back.
Allan pierron
Allan
Sorry for the delay but have only just seen your request
I cannot remember the exact procedure, but I went to the Arduino site.
https://www.arduino.cc/en/guide/homepage.
Learn Arduino
– libraries
How to install a library.
Got rid of all the rubbish that I had tried to enter, followed the instructions and it went in without any problems.
Good Luck it is well worth the effort.
Bob
Hi
I build your frequency standard .but I’m having a problem with the software.it will not let me install the gps_ref_version 6 on to the arduous nano .I on zipped gps_ref_version6 all three files are there gps_ref_version6 8k and ublox 3k and ublox.h 1k but when I try to up load it to the nano board I get a error saying (keypad.h no such file)?? and yes I’m running the latest version of Android 1.8.3
but it will let me up load arduous blink from the arduous library and it works I can make changes to the blink rate slower or faster no problem just can’t upload your software. plese write back.
Allan pierron
Hello Louis,
Thank you again for all the time and effort that you put into these fine projects
I have got my Frequency Standard working, and I am very impressed, It worked first time, (ignoring the slight problem when loading the Arduino Nano {refused to accept the keyboard.h file}.)
Looking forward to the next project.
Regards
Bob
Hi Bob,
Glad to hear you got it working. Sometimes installing Arduino libraries can be an issue.
All the best,
Louis
Can you advise the part number of the keypad you use and the source; most of the membrane keypads I’ve seen on eBay are the stick-on type and I would prefer to mount via screws to a front-panel.
Hi Nigel,
You should be able to get one from Farnells. There order code for the 4×4 Button Keypad is 1182239. Direct link below:
http://uk.farnell.com/multicomp/mcak1604nbwb/keypad-4×4-array-0-02a-24vdc-plastic/dp/1182239?st=matrix%20keypad
They are also available on eBay much cheaper – one example is the link below:
https://www.ebay.co.uk/itm/4×4-Matrix-Keyboard-Keypad-Module-Use-Key-PIC-AVR-Stamp-Plastic-Keys-Switch-UK/253005966171?hash=item3ae854ab5b:g:pKwAAOSwvjdZS9tW
Regards,
Louis
The project is a bit slow-going here (too many actually !) but I did buy a keypad similar to your design but just as an aside; what exactly is the difference between a “keypad” and a “membrane keypad”? I naively imagined they would have the same pin-out….. but of course not !!
I’ve decided that since the physics of my design are going to be substantially different to your layout that I might just as well use veroboard and do it the hard way.
Hello Louis,
I have been following your excellent projects for some time now, and am in the process of building the DC Voltage Calibrator and the GPS locked Frequency Reference. Do you have available the Gerber production files for the GPS Freq Ref. project ? I downloaded them for the DC Calibrator and had the pcb commercially manufactured, but it has been some time since I made my own boards photographically. Maybe you could email them to me if available, or post them as a link.
Keep up the fantastic projects and support videos. All the best – Kevin Pearce.
Hi Kevin,
I sent you an email with the gerber files and also the KiCad files for the latest double sided PCB (with no wire links required). I have alos made them available as downloads from the links below:
http://www.scullcom.com/GPS_Disciplined_Oscillator_Gerber_Files.zip
The PCB size is 100mm x 160mm
http://www.scullcom.com/GPS_Disciplined_Oscillator_KiCad_Files.zip
regards,
Louis
Thanks heaps Louis.
I never received your email (you may have left out the “g” in the middle), but I have successfully downloaded the files from your links.
I have ordered the PCB’s to be manufactured.
Still needing enough time to assemble your DC voltage calibrator, but will get to that shortly.
Thanks again for your very fast response, and my very best wishes for the future.
I will remain “glued” to your channel for as long as it exists.
Kindest regards, Kevin.
Hi Kevin,
I double check my email to you. I did use the correct email address, may be it is in your spam mail due to the fact that I added 2 zip files.
Anyway as long as you have the files you wanted from my download links here.
Regards,
Louis
Hi, Louis,
I am starting the process of building this project. I will be attempting to make a few changes, to accommodate my skill sets:
– Use of a PIC18F4550 microcontroller. Google “PIC 18F Pinquino”
– Use of the chips PLL, to calm jitters
– Use the chip’s memory, instead of a separate EEPROM
– Use of C Code
– Use of all 3.3 volt components, to reduce power usage and give better battery life.
3.3 volt, 1602 character displays are available on Ebay. You need to specify the voltage, in the search terms and read the description, carefully. I have had good experiences, with this seller:
https://www.ebay.com/itm/DC-3-3V-HD44780-1602-LCD-Display-Module-16×2-Character-LCM-Blue-Blacklight-NEW/191563253688?ssPageName=STRK%3AMEBIDX%3AIT&_trksid=p2057872.m2749.l2649
I have ordered some of the larger components. The GPS module has arrived. At 3.3 volts, I was able to configure it (thanks to your great tutorial, in Episode #1) and fully acquire a signal lock. I used this USB to TTL Converter:
https://www.banggood.com/3_3V-5V-USB-to-TTL-Converter-CH340G-UART-Serial-Adapter-Module-STC-p-1232728.html?rmmds=myorder&cur_warehouse=CN
Care must be taken, when using this converter. The converter is not intended to power the DUT, from the limited laptop USB supply. DMM testing of the open positive pin (See Jumper) shows that it is the inverse voltage of the programming logic level… 5 volts on unused jumper/power pin, at 3.3v logic… 3.3 volts on unused jumper/power pin, at 5v logic. Meaning the use of the jumper is not intended to make power available, from the unused jumper pin. Therefore, the DUT/GPS needs its own power supply.
I believe that, regardless of the DUT’s/GPS’s power source, the grounds need to be tied, to enable programming. The converter is tied to earth, through the laptop. I used my bench PSU and configured to it leave the ground floating. This setup worked well and I did not toast anything.
This is the proper RP-SMA (The “RP” designation is important) connector, to attach the powered antenna directly to the PCB:
https://www.ebay.com/itm/10pcs-RP-SMA-Female-Plug-Bulkhead-Solder-Edge-PCB-Clip-Mount-RF-Connector-zg/232697419551?ssPageName=STRK%3AMEBIDX%3AIT&_trksid=p2057872.m2749.l2649
This is the powered antenna I purchased:
https://www.amazon.com/gp/product/B00LHKKJY4/ref=oh_aui_detailpage_o01_s00?ie=UTF8&psc=1
This is my GPS unit:
https://www.amazon.com/gp/product/B06Y2P5NST/ref=oh_aui_detailpage_o02_s00?ie=UTF8&psc=1
If I were to do it again, I would order the bare receiver, without a passive antenna, as you need to order a powered antenna, anyway. That will save you a couple of dollars.
Anyway, I listed the parts, because they all worked together, correctly, at the desired 3.3 volts.
I know that this will be a very long-term project, for me. But, I will post updates and the final project, when completed.
If anyone would like to work on this, with me, please reply. Maybe we can get Louis to forward our contact information, to each other, without posting it publicly.
Thanks, so much!
I seem to have lost the plot on what all the jumpers were intended for in this project; I can’t seem to find any past reference to the purpose of each one. For my application It looks like I can simply remove all the jumpers (ie short them all out)?
Not entirely sure what JP4/5/6 are doing (i’m using a std keypad, not a membrane)?
Good evening Louis,
I am going to built this GPS frequency standard and I would like to avoid to use a back-up battery.
as you said that “if a NEO-7N is purchased you do not need a back-up battery” I would like to use a NEO-7N (or a M8N) module.
but looking at the pictures of the boards which use the 7N (and also M8N) I can see that the high value capacitor is still there! so what is its purpose?
and what is the difference between a NEO-7N and a NEO-M8N?
best regards
i2NDT Claudio
Hi mr scully,
Recently i found this youtube channel an enjoy your way if explaning the projects.
so is start with the GPS frequency standard.
The GPS and arduio are bought recently.
Question, do yoy sell the PCB ?
I do not have the opportunity to make the PCB myself.
thanks
regards,
William (PE1BZF)
Dear Louis,
first of all let me thank you for your excellent contributions on YouTube. – I realised the “10 MHz Generator”
with an ublox 7n Module. It worked perfectly. After I had replaced the 7n by an 8 n it didn’t any more ( the display shows always “No Signal, 10 MHz unlocked” although the GPS Module receives at least 4 sats = 3D fix).
Do I have to change anything in the program-code for the Arduino Nano? Is the Output (TX-signal) of the Ublox 8n different of that of a 7n? – Or is it just a question of correct configuration of the GPS unit?
Thanks and best regards
Wolfgang Matti (DL5TP)
Modifications to use a 4×20 LCD – Only input keys needed are ‘A’ to begin frequency entry and ‘B’ to terminate it. The display now includes operating frequency, battery voltage, number of satellites, and lock status.
/**************************************************************************
10MHz GPS linked Frequency Standard – 4X20 LCD Version
version 10.0
July 2020
Keypad frequency entry and Satellite data
Original authors: Louis Scully and Andre Eisenbach
Modified for 4X20 character display by Dick Jugel
Special thanks to Andre for the hard work with coding the UBLOX library.
In order for the 4X20 display to fit on the circuit board, the NANO and
UBLOX are not mounted in sockets but fitted with SIP .01 spaced pins and
soldered directly to the board. This will provide the necessary clearance
necessary to mount the larger 4 line display.
Press the ‘A’ key to enter a new frequency via the numeric key pad.
Press the ‘B’ key to end the frequency entry and send it to the UBLOX.
The ‘C’ ‘D’ ‘#’ and ‘*’ keys are reserved for possible future functions.
NOTE: The battery voltage will be rechecked and redisplayed every time
a new output frequency is entered.
**************************************************************************/
// LCD RS pin to digital pin 7
// LCD Enable pin to digital pin 8
// LCD D4 pin to digital pin 9
// LCD D5 pin to digital pin 10
// LCD D6 pin to digital pin 11
// LCD D7 pin to digital pin 12
// LCD R/W pin connect to ground
#include “ublox.h” // UBLOX library
#include //LCD library
#include //download and add this library from
// http://playground.arduino.cc/uploads/Code/Keypad.zip
#define PIN_GPS_RX 255 //was 14 changed to 255, a nonexsistent pin
// to free up a regular pin
#define PIN_GPS_TX 15 //connected to GPS module RX pin
UBloxGPS gps(PIN_GPS_RX, PIN_GPS_TX); //PIN_GPS_TX is connected to
// the RX pin on the GPS module.
SoftwareSerial GPSreceiver (14,255); //14 (A0) is RX pin on Arduino
// connected to GPS TX pin. 255 is a
// nonexsistent pin number used to
// free up an Arduino pin
LiquidCrystal lcd(7, 8, 9, 10, 11, 12); // (RS, E, D4, D5, D6, D7)
long SetFreq = 0;
float NewFreq = 0;
float CurrentFrequency = 0;
const float R11 = 100000; //Resistor values in ohms for the
//voltmeter divider
const float R12 = 47000;
const float RefVolt = 5; //use default reference of 5 volt on Arduino
float ResistorDivideFactor = 0;
float voltage_reading = 0;
float battery_voltage = 0;
unsigned long StartTime = 0; // Timer variables used to limit
unsigned long CurrentTime = 0; // UBLOX read calls ….
unsigned long ElapsedTime = 0;
char gpsin[8] = “$GPGGA,”; //define a character string “$GPGGA,”
String sats; //number of satellites detected
String GPGGAdata; //satellte data string from GPS module (See UBLOX documentation)
String FreqStatus; //used to print Frequency lock/unlock indication
int satNum; //number of satellites detected as an interger
int LastSatNum = 99; // Last (current) number of sats detected
String range; //frequency range for displayed frequency – MHz, KHz or Hz
int decimalPlaces; //number of decimal places used dependant on range
char customKey; //key pressed input from keyboard
const byte ROWS = 4; // keybad row/column matrix
const byte COLS = 4; // to decode keys
char keys[ROWS][COLS] = { // Keyboard decoding matrix
{‘1′,’2′,’3′,’A’},
{‘4′,’5′,’6′,’B’},
{‘7′,’8′,’9′,’C’},
{‘*’,’0′,’#’,’D’}
};
byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {16, 17, 18, 19}; //connect to the column pinouts of the keypad
boolean A_up = false; //frequency entry active indicator
boolean Debugging = false; // debugging indicator
//initialize an instance of class NewKeypad
Keypad customKeypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
//
// Setup code – executed only once when sketch is started ….
//
void setup() {
if (Debugging) Serial.begin(57600); // Open serial port only if in debugging mode
GPSreceiver.begin(9600); // Start up the UBLOX GPS receiver
// display splach screen for five seconds
lcd.begin(20, 4);
lcd.print(“GPS Locked Freq Gen”);
if (Debugging) Serial.println(“GPS Locked Frequency Standard”);
lcd.setCursor(0,1);
lcd.print(” Frequency Standard”);
lcd.setCursor(0,2);
lcd.print(” Version 11.0″);
lcd.setCursor(0,3);
lcd.print(” June, 2020″);
delay(5000); // pause for five seconds
// clear and format the runtime LCD display
lcd.clear();
lcd.setCursor(0,3);
lcd.print(“Satellites =”); // Display the caption “Satellites =”
// on the last line of the LCD
// Initialize elapsed timer and set up the initial starting
// output frequency
StartTime = millis();
NewFreq = 1000000; // Set starting frequency to 1 mHZ
displayCurrentFrequency();
}
void loop() {
customKey = customKeypad.getKey();
if (Debugging) Serial.print(customKey);
switch(customKey)
{
case ‘0’ … ‘9’: // routine to process a single frequency digit
if (Debugging) Serial.print(customKey);
if (A_up) // if A_up is false we’re not processing digits so
// simply skip erroneous keyboard entry …
{
SetFreq = SetFreq * 10 + (customKey – ‘0’); // else add digit to
lcd.setCursor(0,1); // frequency string
lcd.print(SetFreq); // and display on LCD
}
break;
case ‘A’: //enter new frequency in Hertz
if (Debugging) Serial.print(customKey);
A_up = true; // indicate we are going to process digits now
SetFreq = 0; // zero the frequence compiliation cell
lcd.setCursor(0,0);
lcd.print(“Enter New Frequency:”); // indicate we’re ready for digits
lcd.setCursor(0,1);
lcd.print(” “); // blank LCD frequence entry line
lcd.setCursor(0,1); // set LCD cursor up for frequency digit entry
break;
case ‘B’: //send new frequency to GPS module
if (Debugging) Serial.print(customKey);
A_up = false; // indicate frequency diget entry is finished
NewFreq=SetFreq; // set up the new frequency
gps.writeFrequency(NewFreq); // and send it to the UBLOX
displayCurrentFrequency(); // then go display the new frequency
SetFreq = 0; // reset the frequency entry cell
break;
case ‘C’: // for possible future use
if (Debugging) Serial.print(customKey);
break;
case ‘D’: // for possible use
if (Debugging) Serial.print(customKey);
break;
case ‘*’: //For possible future use
if (Debugging) Serial.print(customKey);
break;
case ‘#’: //For possible future use
if (Debugging) Serial.print(customKey);
break;
}
//
// if we’re not entering frequency digits, check timers to see
// if it’s time to read the UBLOX data stream
//
if (!A_up) {
CurrentTime = millis();
if ((CurrentTime – StartTime) >= 1000) { // read the UBLOX every second (1000 ms)
StartTime = CurrentTime; // reset elapsed timer
GPSreceiver.flush(); //clear any data which may be in the UBLOX Buffer
if (GPSreceiver.available()) //if any GPS data is available
{
GPSreceiver.read(); //read GPS serial data streams if available
}
if (GPSreceiver.find(gpsin)) { //if serial data starts with the characters “$GPGGA,”
GPGGAdata = GPSreceiver.readStringUntil(‘\n’); //read data until a carriage return
sats = GPGGAdata.substring(39,41); //extract number of satellites data
}
satNum = sats.toInt(); //convert sats string to an integeter so as to remove leading zero
// if number of satellites has changed then update the LCD display fields
// and display them on the LCD
if (satNum != LastSatNum) {
LastSatNum = satNum;
if (satNum >0){
FreqStatus = ” LOCK”; //if satellites detected the status string = LOCK
}else{
FreqStatus = ” UNLK”; //otherwise status string = UNLK
}
if (Debugging) {
Serial.print(GPGGAdata); //These serial print lines are for testing using Serial Monitor
Serial.println(); //full GPGGA data sentence and then carriage return
Serial.print(“Satellite = “);
Serial.print(satNum);
Serial.print(” “);
Serial.println(FreqStatus);
}
lcd.setCursor(13,3); //set cusor position to column 13 of row 0 (first line on LCD)
lcd.print(” “); //clears satellite number, lock status fields
lcd.setCursor(13,3); //set cusor position to column 13 of row 3 (last line on LCD)
lcd.print(satNum); //display number of satellites on LCD
lcd.print(FreqStatus); //display Frequency Lock status
}
}
}
}
void displayCurrentFrequency(){ //subroutine to display current frequency
displayBatteryVoltage(); // display the current battery voltage
// display specified frequency on the LCD
CurrentFrequency = NewFreq; //current frequency is set to new frequency entered
if (CurrentFrequency >=1000000)
{
CurrentFrequency = CurrentFrequency / 1000000;
range = “MHz”;
decimalPlaces = 6; //sets number of decimal places to 6 if MHz range used
}
else if (CurrentFrequency >=1000)
{
CurrentFrequency = CurrentFrequency /1000;
range = “KHz”;
decimalPlaces = 3; //sets number of decimal places to 3 if KHz range used
}
else
{
range = “Hz”;
decimalPlaces =0; //sets number of decimal places to 0 if Hz range used
}
lcd.setCursor(0,0);
lcd.print(“Current Frequency: “);
lcd.setCursor(0,1);
lcd.print(CurrentFrequency,decimalPlaces);
lcd.setCursor(13,1);
lcd.print(range);
}
// calculate and display the current battery voltage
void displayBatteryVoltage() {
lcd.setCursor(0,2);
lcd.print(” “);
lcd.setCursor(0,2);
lcd.print(“Battery: “);
voltage_reading = analogRead(A6);
ResistorDivideFactor = 1023 * (R12/(R11+R12));
battery_voltage = (voltage_reading * RefVolt)/ResistorDivideFactor;
lcd.print(battery_voltage,2);
lcd.print(” Volts”);
}
Updated Sketch – Version 12 – 4×20 LCD Display:
/**************************************************************************
10MHz GPS linked Frequency Standard – 4X20 LCD Version
version 12.0
July 2020
Keypad frequency entry and Satellite data
Original authors: Louis Scully and Andre Eisenbach
Modified for 4X20 character display by Dick Jugel
Special thanks to Andre for the hard work with coding the UBLOX library.
In order for the 4X20 display to fit on the circuit board, the NANO and
UBLOX are not mounted in sockets but fitted with SIP .01 spaced pins and
soldered directly to the board. This will provide the necessary clearance
necessary to mount the larger 4 line display.
Press the ‘A’ key to enter a new frequency via the numeric key pad.
Press the ‘B’ key to end the frequency entry and send it to the UBLOX.
The ‘C’ ‘D’ ‘#’ and ‘*’ keys are reserved for possible future functions.
**************************************************************************/
// LCD RS pin to digital pin 7
// LCD Enable pin to digital pin 8
// LCD D4 pin to digital pin 9
// LCD D5 pin to digital pin 10
// LCD D6 pin to digital pin 11
// LCD D7 pin to digital pin 12
// LCD R/W pin connect to ground
#include “ublox.h” // UBLOX library
#include //LCD library
#include //download and add this library from
// http://playground.arduino.cc/uploads/Code/Keypad.zip
#define PIN_GPS_RX 255 //was 14 changed to 255, a nonexsistent pin
// to free up a regular pin
#define PIN_GPS_TX 15 //connected to GPS module RX pin
UBloxGPS gps(PIN_GPS_RX, PIN_GPS_TX); //PIN_GPS_TX is connected to
// the RX pin on the GPS module.
SoftwareSerial GPSreceiver (14,255); //14 (A0) is RX pin on Arduino
// connected to GPS TX pin. 255 is a
// nonexsistent pin number used to
// free up an Arduino pin
LiquidCrystal lcd(7, 8, 9, 10, 11, 12); // (RS, E, D4, D5, D6, D7)
long SetFreq = 0;
long dFreq = 0;
float NewFreq = 0;
float CurrentFrequency = 0;
const float R11 = 100000; //Resistor values in ohms for the
//voltmeter divider
const float R12 = 47000;
const float RefVolt = 5; //use default reference of 5 volt on Arduino
float ResistorDivideFactor = 0;
float voltage_reading = 0;
float Lvoltage_reading = 1023;
float battery_voltage = 0;
unsigned long StartTime = 0; // Timer variables used to limit
unsigned long CurrentTime = 0; // UBLOX read calls ….
unsigned long ElapsedTime = 0;
unsigned long etStart = 0;
unsigned long etDuration = 0;
char gpsin[8] = “$GPGGA,”; //define a character string “$GPGGA,”
String sats; //number of satellites detected
String GPGGAdata; //satellte data string from GPS module (See UBLOX documentation)
String FreqStatus; //used to print Frequency lock/unlock indication
int satNum; //number of satellites detected as an interger
int LastSatNum = 99; // Last (current) number of sats detected
String range; //frequency range for displayed frequency – MHz, KHz or Hz
int decimalPlaces; //number of decimal places used dependant on range
char customKey; //key pressed input from keyboard
const byte ROWS = 4; // keybad row/column matrix
const byte COLS = 4; // to decode keys
char keys[ROWS][COLS] = { // Keyboard decoding matrix
{‘1′,’2′,’3′,’A’},
{‘4′,’5′,’6′,’B’},
{‘7′,’8′,’9′,’C’},
{‘*’,’0′,’#’,’D’}
};
byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {16, 17, 18, 19}; //connect to the column pinouts of the keypad
boolean A_up = false; //frequency entry active indicator
boolean Debugging = true; // debugging indicator
//initialize an instance of class NewKeypad
Keypad customKeypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
//
// Setup code – executed only once when sketch is started ….
//
void setup() {
if (Debugging) Serial.begin(57600); // Open serial port only if in debugging mode
GPSreceiver.begin(9600); // Start up the UBLOX GPS receiver
// display splach screen for five seconds
lcd.begin(20, 4);
lcd.print(“GPS Locked Freq Gen”);
if (Debugging) Serial.println(“GPS Locked Frequency Standard”);
lcd.setCursor(0,1);
lcd.print(” Frequency Standard”);
lcd.setCursor(0,2);
lcd.print(” Version 12.0″);
lcd.setCursor(0,3);
lcd.print(” June, 2020″);
delay(5000); // pause for five seconds
// clear and format the runtime LCD display
lcd.clear();
lcd.setCursor(0,2);
lcd.print(“Battery:”);
lcd.setCursor(0,3);
lcd.print(“Satellites =”); // Display the caption “Satellites =”
// on the last line of the LCD
// Initialize output frequency
NewFreq = 1000000; // Set starting frequency to 1 mHZ
displayCurrentFrequency();
}
void loop() {
customKey = customKeypad.getKey();
switch(customKey)
{
case ‘0’ … ‘9’: // routine to process a single frequency digit
if (A_up) // if A_up is false we’re not processing digits so
// simply skip erroneous keyboard entry …
{
SetFreq = SetFreq * 10 + (customKey – ‘0’); // else add digit to
lcd.setCursor(0,1); // frequency string
lcd.print(SetFreq); // and display on LCD
}
break;
case ‘A’: //enter new frequency in Hertz
if (!A_up) {
A_up = true; // indicate we are going to process digits now
SetFreq = 0; // zero the frequence compiliation cell
lcd.setCursor(0,0);
lcd.print(“Enter New Frequency:”); // indicate we’re ready for digits
lcd.setCursor(0,1);
lcd.print(” “); // blank LCD frequence entry line
lcd.setCursor(0,1); // set LCD cursor up for frequency digit entry
}
break;
case ‘B’: //send new frequency to GPS module
if (A_up) {
A_up = false; // indicate frequency diget entry is finished
NewFreq=SetFreq; // set up the new frequency
displayCurrentFrequency(); // then go display the new frequency
}
break;
case ‘C’: // for possible future use
break;
case ‘D’: // for possible use
break;
case ‘*’: //For possible future use
break;
case ‘#’: //For possible future use
break;
}
//
// if we’re not entering frequency digits, check timers to see
// if it’s time to read the UBLOX data stream
//
if (!A_up) {
CurrentTime = millis();
if ((CurrentTime – StartTime) >= 5000) { // read the UBLOX every 5 seconds (5000 ms)
StartTime = CurrentTime; // reset elapsed timer
etStart = millis();
GPSreceiver.flush(); //clear any data which may be in the UBLOX Buffer
if (GPSreceiver.available()) //if any GPS data is available
{
GPSreceiver.read(); //read GPS serial data streams if available
}
if (GPSreceiver.find(gpsin)) { //if serial data starts with the characters “$GPGGA,”
GPGGAdata = GPSreceiver.readStringUntil(‘\n’); //read data until a carriage return
sats = GPGGAdata.substring(39,41); //extract number of satellites data
}
etDuration = (millis() – etStart);
if (Debugging) {
Serial.print(“GPS Read Time=”);
Serial.print(etDuration);
Serial.println(” ms”);
}
satNum = sats.toInt(); //convert sats string to an integeter so as to remove leading zero
// if number of satellites has changed then update the LCD display fields
// and display them on the LCD
if (satNum != LastSatNum) {
LastSatNum = satNum;
if (satNum >0){
FreqStatus = ” LOCK”; //if satellites detected the status string = LOCK
}else {
FreqStatus = ” UNLK”; //otherwise status string = UNLK
}
if (Debugging) {
Serial.print(GPGGAdata); //These serial print lines are for testing using Serial Monitor
Serial.println(); //full GPGGA data sentence and then carriage return
Serial.print(“Satellite = “);
Serial.print(satNum);
Serial.print(” “);
Serial.println(FreqStatus);
}
lcd.setCursor(13,3); //set cusor position to column 13 of row 0 (first line on LCD)
lcd.print(” “); //clears satellite number, lock status fields
lcd.setCursor(13,3); //set cusor position to column 13 of row 3 (last line on LCD)
lcd.print(satNum); //display number of satellites on LCD
lcd.print(FreqStatus); //display Frequency Lock status
}
displayBatteryVoltage(); // display the current battery voltage
}
}
}
void displayCurrentFrequency(){ //subroutine to display current frequency
// display specified frequency on the LCD
etStart = millis();
gps.writeFrequency(NewFreq); // and send it to the UBLOX
etDuration = (millis() – etStart);
if (Debugging) {
Serial.print(“New Frequency=”);
dFreq = NewFreq;
Serial.print(dFreq);
Serial.print(“, Write GPS elapsed time=”);
Serial.print(etDuration);
Serial.println(” ms”);
}
CurrentFrequency = NewFreq;
if (CurrentFrequency >=1000000)
{
CurrentFrequency = CurrentFrequency / 1000000;
range = “MHz”;
decimalPlaces = 6; //sets number of decimal places to 6 if MHz range used
}
else if (CurrentFrequency >=1000)
{
CurrentFrequency = CurrentFrequency /1000;
range = “KHz”;
decimalPlaces = 3; //sets number of decimal places to 3 if KHz range used
}
else
{
range = “Hz”;
decimalPlaces =0; //sets number of decimal places to 0 if Hz range used
}
lcd.setCursor(0,0);
lcd.print(“Current Frequency: “);
lcd.setCursor(0,1);
lcd.print(CurrentFrequency,decimalPlaces);
lcd.setCursor(13,1);
lcd.print(range);
}
// calculate and display the current battery voltage
void displayBatteryVoltage() {
voltage_reading = analogRead(A6);
if (voltage_reading != Lvoltage_reading) {
Lvoltage_reading = voltage_reading;
ResistorDivideFactor = 1023 * (R12/(R11+R12));
battery_voltage = (voltage_reading * RefVolt)/ResistorDivideFactor;
lcd.setCursor(9,2);
lcd.print(battery_voltage,2);
lcd.print(” Volts”);
}
}
Hello Louis,
Could you please provide the gerber file for the last PCB for this project.
Regards,
G Harding
Dear Louis,
I like your work very much !
Just wanted to let you know.
I think about doing something similar using also such a module.
Unfortunately those modules so not seem to be available in 20MHz, 40MHz, 50MHz or so.
Then no jitter with 10MHz would be there I assume.
I also like your idea to show how to build something easy to calibrate volt meters or so.
Those Fluke or Valhalla calibrators are fine, but huge, expensive, and not so easy to repair when defective. Also may be building an ac voltage and current calibrator for 100V may be interesting somehow. Jim Williams also had ideas for such stuff.
May be you are interested in discussing this a bit.
Dear Louis,
Inspired by your GPS locked signal source and your technical explanationsI bought a NEO-M8N with a view to re-configuring the 1PPS output to 6MHz to replace the 6MHz microprocessor clock in my 2.4GHz frequency counter.
However.
Having downloaded the U-Centre software, bought the Neo-M8N module (chinese) iff ebay, I now find that:-
1 My version of U-centre looks nothing like the one you are demonstrating.
2 My GPS module talks to the u-centre as Ican see lots of satellites and my location on the map, but the ‘configuration menu’ doesn’t seem to have a TP5 ( I can only see TP1, 2, and 3)
3 When I click on any item in the configuration menu, a momentary pop-up window appears on the PC saying “Configuration data cannot be retrieved”.
4 I can’t decide whether most of the items in the configuration menu are ‘greyed out’.
Where is the item that allows the re-config of the 1PPS please?
This was only going to be a 5 minute job as it looked so easy on your Youtube video…lol!
Dave
HI,
HI, I tried to compile a sketch but i found this error ::
sketch\ublox.cpp: In constructor ‘UBloxGPS::UBloxGPS(uint8_t, uint8_t)’:
ublox.cpp:58:39: error: use of deleted function ‘SoftwareSerial::SoftwareSerial(const SoftwareSerial&)’
: ss_(SoftwareSerial(pin_rx, pin_tx))
^
In file included from sketch\ublox.h:9:0,
from sketch\ublox.cpp:6:
C:\Users\ufqual1\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\libraries\SoftwareSerial\src/SoftwareSerial.h:94:5: error: declared here
SoftwareSerial(const SoftwareSerial&) = delete;
^
C:\Users\ufqual1\Documents\Arduino\GPSDO\GPSDO.ino: In function ‘void loop()’:
GPSDO:122:34: error: ‘A6’ was not declared in this scope
voltage_reading = analogRead(A6);
^
exit status 1
use of deleted function ‘SoftwareSerial::SoftwareSerial(const SoftwareSerial&)’
can you help me?
thank you
Hi all
I have build this 10MHz GPS linked Frequency Standard
It works almost, but dont update the satelite it say 0 satelite found
in the display maybe i missed som library in Arduino IDE?
Any one have the same problem. I have Ublox 7M from Aliexpress
It works fine in U-center. If anyone have a clue what it could be
You can send me an e-mail peter@boren.se
Regards//Peter