GPS Clock using ArduPilot and EM-406
So we got tired of not being able to see what time it was when we were watching movies/shows on Netflix. We could have just bought a clock, but where’s the fun in that? I had an EM-406 GPS module and an ArduPilot lying around, and I heard about Sparkfun’s 12ft GPS Wall Clock so I figured I would give it a try.
I had built a clock before just using an Arduino board, but the clock would get out of sync after a couple of days because of the little bit of processing time that was taken by the Arduino. So I put that aside and was planning on getting a Real Time Clock DS3234 IC from Sparkfun, but the chip is a bit expensive, hard to solder, and the breakout board is even more expensive. Not that I couldn’t afford to spend $20 on this, I just had more exciting projects on my mind so it went to the back burner.
When I heard that you could use a GPS module to get very accurate UTC, I was like “Allllllrighty then!” and I started working. I had a little trouble programming the ArduPilot until I realized that you have to connect a power supply other than the FTDI cable to power the MCU. Once I did that, I got a simple blinky sketch running, and then I started working with the EM-406 module. When the EM-406 module has a signal, it’s LED blinks. Once it’s blinking you can get UTC time from it using an NMEA library, do some funky magic and “badda bing, badda boom” you’ve got a clock. See my code below:
#include <wprogram.h>
#include <nmea.h>
#include <SoftwareSerial.h>
#define txPin 6 //to the RX pin
#define rxPin 12 //not used
SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin);
NMEA gps(GPRMC); // GPS data connection to GPRMC sentence type
float gpsTime;
void setup() {
Serial.begin(4800);
pinMode(txPin, OUTPUT);
mySerial.begin(9600);
mySerial.print(0x76,BYTE); // Reset Command
mySerial.print(0x7A,BYTE); // Command byte
mySerial.print(0x05,BYTE); // bright display
//display the colon
mySerial.print(0x77,BYTE); // Command byte
mySerial.print(0x10,BYTE); // colon
demo();
}
void loop() {
if (Serial.available() > 0 ) {
// read incoming character from GPS
char c = Serial.read();
// check if the character completes a valid GPS sentence
if (gps.decode(c)) {
// check if GPS positioning was active
if (gps.gprmc_status() == 'A') {
gpsTime = int(gps.gprmc_utc() / 100) - 600;
if (gpsTime < 0) { gpsTime = 2400 + gpsTime; } if (gpsTime >= 1300) {
gpsTime = gpsTime - 1200;
}
if (getPlace(1000, gpsTime) == 0) {
mySerial.print(0x78,BYTE);
mySerial.print(getPlace(100, gpsTime),BYTE);
mySerial.print(getPlace(10, gpsTime),BYTE);
mySerial.print(getPlace(1, gpsTime),BYTE);
}
else {
mySerial.print(getPlace(1000, gpsTime),BYTE);
mySerial.print(getPlace(100, gpsTime),BYTE);
mySerial.print(getPlace(10, gpsTime),BYTE);
mySerial.print(getPlace(1, gpsTime),BYTE);
}
}
}
}
}
int getPlace(int place, int startingValue) {
startingValue = startingValue - (startingValue % place);
startingValue = startingValue / place;
int placeValue = startingValue % 10;
return placeValue;
}
void demo() {
delay(80);
mySerial.print(8,BYTE);
mySerial.print(0x78,BYTE);
mySerial.print(0x78,BYTE);
mySerial.print(0x78,BYTE);
delay(80);
mySerial.print(0x78,BYTE);
mySerial.print(8,BYTE);
mySerial.print(0x78,BYTE);
mySerial.print(0x78,BYTE);
delay(80);
mySerial.print(0x78,BYTE);
mySerial.print(0x78,BYTE);
mySerial.print(8,BYTE);
mySerial.print(0x78,BYTE);
delay(80);
mySerial.print(0x78,BYTE);
mySerial.print(0x78,BYTE);
mySerial.print(0x78,BYTE);
mySerial.print(8,BYTE);
}
Pictures!