To set up the time, simply send the command TIME=hh:mm:ss, where "hh", "mm", "ss" are the hours, the minutes and the seconds, respectively.
Setting up multiple clocks is a tedious process: pair your Android tablet with one at a time, then (from BlueTerm) send the command that includes the correct time. Then repeat for each clock.
What if you could broadcast the TIME=... command? And that command to include the most accurate time, acquired from GPS? This is what this post is about. Now you have the "method".
Next, to the "apparatus". It consists essentially of 3 parts: GPS receiver, microcontroller and Bluetooth master module. Putting them together is trivial, since both GPS receiver and Bluetooth module communicate through serial ports.
I used an old (now discontinued at the major online stores, but still available on ebay) Fastrax UP-501 GPS module I already had laying around. But any GPS receiver should work as well, including the Adafruit Ultimate GPS Breakout.
The "Bluetooth master module" is a re-programmed HC-05 (see the datasheet) as master, with CMODE=1 (for broadcasting).
The sketch, presented below, uses SoftwareSerial library to communicate with the GPS module (Rx on D3, Tx on D4) and TinyGPS library to extract the time from the NMEA sentence. The BTBee module is connected to the hardware serial port (D0, D1).
#include "TinyGPS.h"
#include "SoftwareSerial.h"
SoftwareSerial GPSSerial(4, 3);
// GPS Fatrax UP501, connected as follows:
// - power pin to 3.3V
// - ground pin to ground
// - VBAT pin to 3.3V if no battery is used
// - TX pin to D4
// - RX pin to D3 through a voltage divider (2 resistors, 10k + 4k7)
#define _DEBUG_ true
// commands for GPS module;
#define PMTK_SET_NMEA_UPDATE_1HZ "$PMTK220,1000*1F"
#define PMTK_SET_NMEA_UPDATE_5HZ "$PMTK220,200*2C"
#define PMTK_SET_NMEA_UPDATE_10HZ "$PMTK220,100*2F"
// turn on only the second sentence (GPRMC)
#define PMTK_SET_NMEA_OUTPUT_RMCONLY "$PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29"
// turn on ALL THE DATA
#define PMTK_SET_NMEA_OUTPUT_ALLDATA "$PMTK314,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0*28"
// MTK command datasheet at http://www.hhhh.org/wiml/proj/nmeaxor.html
TinyGPS gps;
void setup()
{
// default baud rate for BTBee (on hardware serial);
Serial.begin(9600);
// default baud rate for UT501 (on software serial);
GPSSerial.begin(9600);
// turn on all the available data (for 9600 baud you'll want 1Hz rate);
GPSSerial.println(PMTK_SET_NMEA_OUTPUT_ALLDATA);
// set update rate to 1Hz
GPSSerial.println(PMTK_SET_NMEA_UPDATE_1HZ);
#ifdef _DEBUG_
Serial.println("ready for reading GPS...");
#endif
}
void loop()
{
acquireTimeFromGPS();
delay(5000);
}
void acquireTimeFromGPS()
{
unsigned long age;
int Year;
byte Month, Day, Hour, Minute, Second, Hundredths;
if (feedgps())
{
#ifdef _DEBUG_
Serial.println("GPS feed acquired...");
#endif
gps.crack_datetime(&Year, &Month, &Day, &Hour, &Minute, &Second, &Hundredths, &age);
char buf[20] = {0};
sprintf(buf, "TIME=%02d:%02d:%02d", Hour, Minute, Second+1);
Serial.println(buf);
}
}
bool feedgps()
{
while (GPSSerial.available())
{
char c = GPSSerial.read();
#ifdef _DEBUG_
Serial.print(c);
#endif
if (gps.encode(c))
return true;
}
return false;
}
As protoboard I used the XBee Shield from seeedstudio because it had a socket for my BTBee (plus 3V3 regulator) and also ample space for processor and GPS. (It could even fit in a Altoids tin if the GPS receiver is soldered directly to the board, without headers.)
Future improvements should include a couple of status LEDs, one to show that the data was being acquired from GPS, another to indicate that the "TIME" command was successfully built and broadcast. Similarly but more expensively, a small OLED screen could be used to display the activity.
On the software side, the time, which comes as UTC in the NMEA sentence, should be adjusted to the current time zone, probably based on the longitude.