Voting resources, early voting, and poll worker information - VOTE. ... Adafruit is open and shipping.
0

Adafruit Ultimate GPS Breakout
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Adafruit Ultimate GPS Breakout

by rbratton on Sun Jun 01, 2014 9:39 pm

I have A Adafruit Ultimate GPS Breakout and A Arduino UNO and I would like to build a clock that has 1 inch tall 7 segment displays. I would like for the clock to display hours, minutes and seconds. Do you know of a site that has a drawing to show how to do this and a site for the software? Also need a source for the 1 inch tall 7 segment LEDs? I am new to the Arduino but I have done a lot of board building in the past.
Thanks
rbratton
 
Posts: 2
Joined: Sun Jun 01, 2014 9:23 pm

Re: Adafruit Ultimate GPS Breakout

by adafruit_support_rick on Mon Jun 02, 2014 12:35 pm

We have lots of 7-segment displays in the store. We have individual RGB 7-segment digits at 1", and also several 1.2" clock displays. You can get the displays bundled with a driver board, or just the bare display.
https://www.adafruit.com/search?q=7%20segment

We also have lots of tutorials on interfacing and using 7-segment displays in the Learning System:
https://learn.adafruit.com/search?q=7%20segment

The Arduino Playground also has several articles and libraries devoted to 7-segment displays.

adafruit_support_rick
 
Posts: 35095
Joined: Tue Mar 15, 2011 11:42 am
Location: Buffalo, NY

Re: Adafruit Ultimate GPS Breakout

by rcomito on Mon Jun 09, 2014 3:49 pm

Hi rbratton,

I have a GPS clock that uses a 1.2" display for hours and minutes and a .56" display for seconds and the number of satellites in view.

It's built using an Arduino Micro. You're welcome to use it to get you started.

Code: Select all | TOGGLE FULL SIZE
// GPSClock                                                                   Rick Comito et al.
#define VERSION "Ver. 1.00.201400412 Rick Comito"
//
// Version history:
//     1.00 - add AM / PM indicator and call it done
//     0.90 - General code optimization and tweaking
//     0.80 - Display colon between HH and MM.  Add light sensor dimming.
//     0.70 - Display satellite count and fix status on display 1
//     0.60 - Display HHMM on display 0 and SS on display 1
//     0.50 - Incorporate standard / daylight time change
//     0.40 - Increase _SS_MAX_RX_BUFF to allow for faster polling.
//     0.30 - Incorporate timezone.h.  Adjust UTC to local standard time
//     0.20 - Move TX and RX pins to 8 and 9 to allow program upload without wireing changes
//     0.10 - Parse time and date from GPS data and send to serial monitor
//     0.00 - Just read the GPS module and send the data to the serial monitor
//
// This clock uses a GPS module to get the time and date.  We need the date so we know when to
// adjust for Standard Time/Daylight Saving Time.
//
// Thanks to the crews at http://www.adafruit.com and http://www.arduino.cc for all of the ideas,
// source code shared, and the great products and support.
//
// This clock uses two 4 x 7 segment displays on I2C backplanes to display hours, minutes, seconds,
// and number of satellites seen.  The first is addressed at 0x70 (default) and the second is addressed
// at 0x71 by shorting the address pads at A0.
//
// It uses an optional light sensor to adjust the display brightness based on ambient lighting.
//
// This code started with code written by Jay Doscher.  Turns out he used the same microcontroller and
// GPS module that I had decided on.  The slick interrupt stuff is his.  Thanks for the jumpstart Jay.
// http://www.polyideas.com/blog/2012/12/16/gps-clock-using-an-arduino-micro
//
//=========================================================================\\
// Parts list:                                                             \\
// Arduino Micro                     http://www.adafruit.com/products/1086 \\
// Adafruit Ultimate GPS module      http://www.adafruit.com/products/746  \\
// Two 4 x 7 segment displays with I2C backplanes:                         \\
//                            1.2"   http://www.adafruit.com/products/1270 \\
//                            .56"   http://www.adafruit.com/products/865  \\
//=========================================================================\\
// Optional parts:                                                         \\
// Light sensor                      http://www.adafruit.com/products/1384 \\
// GPS external antenna              http://www.adafruit.com/products/960  \\
// uFL to SMA adapter                http://www.adafruit.com/products/851  \\
//=========================================================================\\
// One stop shopping. Pick them up today at the Adafruit electronics shop
// and help support open source hardware & software!


#include <SoftwareSerial.h>        // Part of the Arduino standard library.
#include <Wire.h>                  // Part of the Arduino standard library.
#include <Time.h>                  //http://www.arduino.cc/playground/Code/Time
#include <Timezone.h>              //https://github.com/JChristensen/Timezone    Thanks to Jack Christensen (Nice work)
#include <Adafruit_GPS.h>          //https://github.com/adafruit/Adafruit-GPS-Library
#include <Adafruit_GFX.h>          //https://github.com/adafruit/Adafruit-GFX-Library
#include <Adafruit_LEDBackpack.h>  //https://github.com/adafruit/Adafruit-LED-Backpack-Library

// Increase _SS_MAX_RX_BUFF in SoftwareSerial.h from 64 to 128 in order to be able to pole the GPS
// faster than 1HZ.  Thanks to Wayne Holder over at SparkFun.com for this one.  He did it a little
// differently, but I got the idea from him.
#ifdef _SS_MAX_RX_BUF
#  undef _SS_MAX_RX_BUF
#  define _SS_MAX_RX_BUF 128
#endif

#define TIMETOUPDATE  10     // Milliseconds between clock updates.  Update frequently so there's no delay
                             // between second rollovers (ticks).
//#define LIGHTSENSOR          // Defined if this build has a light sensor
#define WAKEUP               // Run our "Teddy Ruxpin" boot-up routine

// Debugging flags - Allows for eight levels of debugging
#define DB       0b00000000  // Debugging off
#define DBGPS    0b00000001  // Show raw GPS sentences (also good for show and tell)
#define DBSATS   0b00000010  // Fix status and satellite count
#define DBUTC    0b00000100  // UTC time and date
#define DBLOCAL  0b00001000  // Local time and date
#define DBDISP   0b00010000  // Data to be sent to the displays
#define DBBRIGHT 0b00100000  // Display brightness settings

byte DEBUG = DB | DBGPS;     // OR in the levels that you need e.g: DEBUG = DB | DBGPS | DBSATS | DBCLOCK;

// Timezone rules.  Select yours from the following.  If you need space, comment out the rest.
// Atlantic
TimeChangeRule aDST = { "ADT", Second, Sun, Mar, 2, -180 };  // UTC - 3 hrs.
TimeChangeRule aSTD = { "AST", First, Sun, Nov, 2, -240 };   // UTC - 4 hrs.
// Eastern
TimeChangeRule eDST = { "EDT", Second, Sun, Mar, 2, -240 };  // UTC - 4 hrs.
TimeChangeRule eSTD = { "EST", First, Sun, Nov, 2, -300 };   // UTC - 5 hrs.
// Central
TimeChangeRule cDST = { "CDT", Second, Sun, Mar, 2, -300 };  // UTC - 5 hrs.
TimeChangeRule cSTD = { "CST", First, Sun, Nov, 2, -360 };   // UTC - 6 hrs.
// Mountain
TimeChangeRule mDST = { "MDT", Second, Sun, Mar, 2, -360 };  // UTC - 6 hrs.
TimeChangeRule mSTD = { "MST", First, Sun, Nov, 2, -420 };   // UTC - 7 hrs.
// Arizona - Does not observe daylight time
TimeChangeRule azDST = { "MST", Second, Sun, Mar, 2, -420 };  // UTC - 7 hrs.
TimeChangeRule azSTD = { "MST", First, Sun, Nov, 2, -420 };   // UTC - 7 hrs.
// Pacific
TimeChangeRule pDST = { "PDT", Second, Sun, Mar, 2, -420 };  // UTC - 7 hrs.
TimeChangeRule pSTD = { "PST", First, Sun, Nov, 2, -480 };   // UTC - 8 hrs.
// Alaska
TimeChangeRule akDST = { "AKDT", Second, Sun, Mar, 2, -480 }; // UTC - 8 hrs.
TimeChangeRule akSTD = { "AKST", First, Sun, Nov, 2, -540 };  // UTC - 9 hrs.
// Hawaii-Aleution
TimeChangeRule haDST = { "HADT", Second, Sun, Mar, 2, -540 }; // UTC - 9 hrs.
TimeChangeRule haSTD = { "HAST", First, Sun, Nov, 2, -600 };  // UTC - 10 hrs.
// Hawaii - Does not observe daylight time
TimeChangeRule hiDST = { "HDT", Second, Sun, Mar, 2, -600 };  // UTC - 10 hrs.
TimeChangeRule hiSTD = { "HST", First, Sun, Nov, 2, -600 };   // UTC - 10 hrs.

// Mine is US Eastern Time Zone (Boston, Detroit)
TimeChangeRule myDST = eDST;
TimeChangeRule mySTD = eSTD;
Timezone myTZ(myDST, mySTD);

TimeChangeRule *tcr;        //pointer to the time change rule, used to get TZ abbrev
time_t utc, local;          // Universal and local time in time_t format

// Connect the GPS Power pin to 5V
// Connect the GPS Ground pin to ground
// If using software serial (sketch example default):
//   Connect the GPS TX (transmit) pin to Digital 8
//   Connect the GPS RX (receive) pin to Digital 7
// If using hardware serial (e.g. Arduino Mega):
//   Connect the GPS TX (transmit) pin to Arduino RX1, RX2 or RX3
//   Connect the GPS RX (receive) pin to matching TX1, TX2 or TX3

#define TX 8
#define RX 7
SoftwareSerial mySerial(TX, RX);
Adafruit_GPS GPS(&mySerial);

// If using hardware serial (e.g. Arduino Mega), comment
// out the above four lines and enable this line instead:
//Adafruit_GPS GPS(&Serial1);

boolean firstFix = false;    // Clock has had it's first satellite fix and the GPS onboard RTC is set.

// The two 4 x 7 segment displays are at I2C addresses 0x70 and 0x71
Adafruit_7segment matrix0, matrix1 = Adafruit_7segment();
byte display0 = 0x70;
byte display1 = 0x71;

#ifdef LIGHTSENSOR
  // Light sensor pin
  uint8_t sensorPin = A0;    // Wire the sensor "OUT" pin to A0
#endif

// Set aside a small buffer to build sprintf() formatted debugging messages
char sbuffer[64] = "";

// This keeps track of whether we're using the interrupt.
// On by default!
boolean usingInterrupt = true;

// Stumbled across this in a thread on arduino.cc. Sets the fix interval.
// Match this with your PMTK_SET_NMEA_UPDATE_xxHZ.  Thanks Kas.
#define PMTK_SET_NMEA_FIX_1HZ  "$PMTK300,1000,0,0,0,0*1C"
#define PMTK_SET_NMEA_FIX_5HZ  "$PMTK300,200,0,0,0,0*2F"
#define PMTK_SET_NMEA_FIX_10HZ "$PMTK300,100,0,0,0,0*2"

void setup(void) 
{
  // 9600 NMEA is the default baud rate for Adafruit MTK GPS - some use 4800
  GPS.begin(9600);
  // Turn off all data output while we set our preferences.
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_OFF);
  delay(100);
  // Turn off antenna status
  GPS.sendCommand(PGCMD_NOANTENNA);
  // Set the GPS update rate
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_5HZ);
  // Set the GPS fix interval
  GPS.sendCommand(PMTK_SET_NMEA_FIX_5HZ);
  // Turn on GPS RMC (recommended minimum) and GGA (fix data) sentences
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);

  // Initialize, clear, and dim the displays. 
  // Note: my display0 is not quite as bright is display1, so set 0 to level 1, and 1 to level 0
  matrix0.begin(display0);
  matrix0.clear();
  matrix0.setBrightness(1);
  matrix1.begin(display1);
  matrix1.clear();
  matrix1.setBrightness(0);
  // Set the satellite count to 0
  matrix1.writeDigitNum(4, 0);
  matrix0.writeDisplay();
  matrix1.writeDisplay();
 
#ifdef LIGHTSENSOR
  // The light sensor needs a 3.3v reference.  Jumper 3.3v to AREF
  analogReference(EXTERNAL);
#endif

  // the nice thing about this code is you can have a timer0 interrupt go off
  // every 1 millisecond, and read data from the GPS for you. That makes the
  // loop code a heck of a lot easier!
  useInterrupt(true);
 
  // If we're debugging, connect the serial console at 115200 so we can read the GPS
  // fast enough and echo without dropping chars.
  if (DEBUG)
    Serial.begin(115200);

  delay(1500);
#ifdef WAKEUP
  wakeup();    // Just a little animation thing for fun.
#endif
} // setup

uint32_t timer = millis();

void loop(void) {
  uint8_t hh, mm, ss, dd, mo, yy;

  // if a sentence is received, we can verify the checksum, parse it ...
  if (GPS.newNMEAreceived()) {
    if (!GPS.parse(GPS.lastNMEA()))
      return;  // If we fail to parse a sentence, we should just wait for another
  }

  // if millis() timer wraps around, reset it
  if (timer > millis())
    timer = millis();

  // Update the clock approximately every TIMETOUPDATE milliseconds or so.
  // this should be often enough to ensure that we don't miss any seconds
  // rollover.
  if ((uint32_t)millis() - timer >= TIMETOUPDATE) {
    if (DEBUG & DBGPS)
      Serial.println(GPS.lastNMEA());

    timer = millis(); // reset the timer
    // If we have a GPS fix, the RTC on the GPS board has been set and is getting updated.
    if ((firstFix) || (GPS.fix > 0)) {
      if (DEBUG & DBSATS) {
        sprintf(sbuffer, "Fix: %d Satellites: %d\n", GPS.fix, GPS.satellites);
        Serial.print(sbuffer);
      }
      firstFix = true;
      hh = GPS.hour;
      mm = GPS.minute;
      ss = GPS.seconds;
      mo = GPS.month;
      dd = GPS.day;
      yy = GPS.year;
      // Set the Arduino software RTC
      setTime(hh, mm, ss, dd, mo, yy);
    }
    // Get the time from the software RTC in time_t format
    // so we can have the timezone tools do their magic.
    utc = now();
    if (DEBUG & DBUTC) {
      sprintf(sbuffer, "%02d:%02d:%02d ", hour(utc), minute(utc), second(utc));
      Serial.print(sbuffer);
      sprintf(sbuffer, "%s %02d %s %d\n", dayShortStr(weekday(utc)), day(utc), monthShortStr(month(utc)), year(utc));
      Serial.print(sbuffer);
    }
    local = myTZ.toLocal(utc, &tcr);
    if (DEBUG & DBLOCAL) {
      sprintf(sbuffer, "%02d:%02d:%02d ", hour(local), minute(local), second(local));
      Serial.print(sbuffer);
      sprintf(sbuffer, "%s %02d %s %d %s\n", dayShortStr(weekday(local)), day(local), monthShortStr(month(local)), year(local), tcr -> abbrev);
      Serial.print(sbuffer);
    }
    updateClock(local);
#ifdef LIGHTSENSOR
      setBrightness();
#endif
  }
} // loop


// Interrupt is called once a millisecond, looks for any new GPS data, and stores it
SIGNAL(TIMER0_COMPA_vect) {
  volatile char c = GPS.read();
}

void useInterrupt(boolean v) {
  if (v) {
    // Timer0 is already used for millis() - we'll just interrupt somewhere
    // in the middle and call the "Compare A" function above
    OCR0A = 0xAF;
    TIMSK0 |= _BV(OCIE0A);
    usingInterrupt = true;
  }
  else {
    // do not call the interrupt function COMPA anymore
    TIMSK0 &= ~_BV(OCIE0A);
    usingInterrupt = false;
  }
} // useInterrupt


// updateClock
//
// Update the clock displays.
// This function gets passed time_t localtime which is the current time adjusted for timezone and
// standard / daylight time with the great tools built by Jack Christensen.
//
// If you're building any kind of clock and you want to display local time, check out
// https://github.com/JChristensen/Timezone   Nice work Jack.  Thanks.
//
// The displays get cleared in setup().  We'll show the number of satellites we can see,
// but leave the time blank until we get our first satellite fix.  We can't count on the
// RTC if this is the first time the code has been run, or if it has had a recent battery
// change (or doesn't have one installed).  Besides, it adds a little drama to the clock
// when it's first plugged in.  You see the satellite count incrementing, then BAM, clock
// display.


#define PMDOT 0x08              // Leftmost lower dot for PM indicator
#define AMDOT 0x04              // Leftmost upper dot for AM indicator
#define COLON 0x02              // Colon between HH and MM

void updateClock(time_t localtime) {
  int hhmm;                     // Hours and minutes
  int secs;                     // Seconds
  uint8_t sats;                 // How many satellites we can see
  int ssss;                     // Second and satellites displayed as ss.ss
  static int lasthhmm = 0;      // Hour and minute last time we set the displays
  static int lastssss = 0;      // Second and satellites last time we set the displays
  byte ampmdot;                 // Code to present AM or PM dot indicator
  boolean showdot;              // Show the dot in ss.ss if we still have a fix

  sats = GPS.satellites;

  // If we haven't established our first satellite fix yet, leave the hours, minutes and
  // seconds blank, but display how many satellites (if any) we can see.
  if(!firstFix) {
    ssss = sats;
    if (ssss != lastssss) {
      matrix1.print(ssss);
      matrix1.writeDisplay();
    }
  }
  // We've had at least one satellite fix, so update the displays if they need it.
  else {
    // Display 12 hour time (My bride doesn't do military time)
    hhmm = ((hour(localtime) % 12) * 100) + minute(localtime);
    if (hhmm < 100)  // Midnight hour
      hhmm += 1200;

    ssss = (second(localtime) * 100) + sats;
    showdot = (GPS.fix > 0) ? true : false;
   
    // Update displays if something has changed.
    if (hhmm != lasthhmm) {
      matrix0.print(hhmm);
      ampmdot = (hour(localtime) < 12) ? AMDOT : PMDOT;
      matrix0.writeDigitRaw(2, COLON | ampmdot);
      matrix0.writeDisplay();
    }
    // Handle this display one digit at a time to preserve leading zeros.
    if (ssss != lastssss) {
      matrix1.writeDigitNum(0, (ssss / 1000));
      matrix1.writeDigitNum(1, (ssss / 100) % 10, showdot); // true turns on the dot in ss.ss
      matrix1.writeDigitNum(3, (ssss / 10) % 10);
      matrix1.writeDigitNum(4, ssss % 10);
      matrix1.writeDisplay();
    }
    if (DEBUG & DBDISP) {
      sprintf(sbuffer, "%4d %04d\n", hhmm, ssss);
      Serial.print(sbuffer);
    }
  }
  lasthhmm = hhmm;
  lastssss = ssss;
} // updateClock

#ifdef LIGHTSENSOR
  // setBrightness
  // Set the display brightness based on ambient light.
  // Sensor readings range from 1 to 1024
  // Display brightness ranges from 0 (dim) to 15 (bright).
  // The 1.2" and .56" displays have slightly different brightness
  // so we'll try to adjust accordingly.

#  define BRIGHT 15   // Maximum setting
#  define DIM 0       // Minimum display brightness setting
#  define HILIMIT 850 // Upper raw limit to set bright setting
#  define LOLIMIT 100 // Lower raw limit to set dim setting
#  define BIAS0  1    // Extra brightness to add to display 0
#  define BIAS1 -2    // Extra dimness to add to display 1

  void setBrightness()
  {
    static uint8_t lastsetting = 0; // Last display0 setting
    uint8_t bsetting0 = BIAS0;      // Brightness setting for display 0
    uint8_t bsetting1 = 0;          // Brightness setting for display 1

    // read the raw value from the sensor:
    uint8_t rawvalue = analogRead(sensorPin);
    // Set brightness accordingly
    if (rawvalue >= HILIMIT) {
      bsetting0 = BRIGHT;
      bsetting1 = BRIGHT + BIAS1;
    }
    else if (rawvalue <= LOLIMIT) {
      bsetting0 = DIM + BIAS0;
      bsetting1 = DIM;
    }

    if (bsetting0 != lastsetting) {
      matrix0.setBrightness(bsetting0);
      matrix1.setBrightness(bsetting1);
    }

    if (DEBUG & DBBRIGHT) {
      sprintf(sbuffer, "Raw %d Settings %d %d\n",  rawvalue, bsetting0, bsetting1);
      Serial.print(sbuffer);
    }
    lastsetting = bsetting0;
  } // setBrightness
#endif


#ifdef WAKEUP
  // wakeup
  //
  // A little "Teddy Ruxpin" inspired animation.

  void wakeup() {
    uint8_t i;
 
    for (i = 0; i < 2; i++) {
      closeeyes(500);
      openeyes(250);
    }
    while(!GPS.fix) {
      if (GPS.newNMEAreceived())
        GPS.parse(GPS.lastNMEA());
      lookaround();
      //matrix0.clear();
    }
  } // wakeup


  // Segment layout:
  //
  //The decimal point is mapped to 0x80.
  //
  //       0x01
  //       ----
  // 0x20 |    |0x02
  //      |    |
  //       ----
  // 0x10 |0x40|0x04
  //      |    |
  //       ----
  //       0x08

     
  void closeeyes(uint8_t dly) {
    matrix0.writeDigitRaw(1, 0x08);
    matrix0.writeDigitRaw(3, 0x08);
    matrix0.writeDisplay();
    delay(dly);
  } // closeeyes

  void openeyes(uint8_t dly) {
    matrix0.writeDigitRaw(1, 0x08 | 0x10 | 0x40 | 0x04);
    matrix0.writeDigitRaw(3, 0x08 | 0x10 | 0x40 | 0x04);
    matrix0.writeDisplay();
    delay(dly);
  } // openeyes
 

  void lookaround() {
    matrix0.clear();
    matrix0.writeDigitRaw(0, 0x40 | 0x20 | 0x01 | 0x02);
    matrix0.writeDigitRaw(1, 0x40 | 0x20 | 0x01 | 0x02);
    matrix0.writeDisplay();
    delay(1000);
    //matrix0.clear();
    //matrix0.writeDigitRaw(0, 0);
    //matrix0.writeDigitRaw(1, 0x40 | 0x20 | 0x01 | 0x02);
    //matrix0.writeDigitRaw(3, 0x40 | 0x20 | 0x01 | 0x02);
    //matrix0.writeDisplay();
    //delay(50);
    matrix0.clear();
    matrix0.writeDigitRaw(3, 0x40 | 0x20 | 0x01 | 0x02);
    matrix0.writeDigitRaw(4, 0x40 | 0x20 | 0x01 | 0x02);
    matrix0.writeDisplay();
    delay(1000);
  } // lookaround
#endif


Rick Comito

rcomito
 
Posts: 35
Joined: Tue Jan 28, 2014 9:03 am

Please be positive and constructive with your questions and comments.