Arduino Mini GPS in an Altoids Smalls Tin


Here’s the details on my first Arduino project I finished a few months ago.  It’s a functional GPS in an unmodified Altoids Smalls mint tin.  The GPS is built from an Ultimate GPS, 3V Pro Trinket, and 128×32 OLED from Adafruit. Demo/prototype video, build pictures, and source code below.

Demo/Prototype Video

The Build

The parts

Parts list:

Solder the wires onto the battery backpack

Normally it is easier to connect the battery backpack to the Pro Trinket with headers but it adds height. Not much room in the Altoids Smalls tin so had to connect with wire and put the Pro Trinket and battery backpackside by side.

Backpack connected to the Pro Trinket

Pro trinket and battery backpack connected.  Optional wires for on/off switch connected to the battery backpack.

Solder connecting wires to the OLED display

Get the wires soldered onto the OLED screen.  Leave them longer and cut down once you know the exact length.

Solder connecting wires to the GPS

Solder the connecting wires to the GPS.  For this project only connections are required for TX, RX, GND and VIN.

Getting everything connected

Ok, so here is where things start getting real.  I had put this circuit together so many times on a breadboard I could probably prototype it with my eyes closed.  Snipping, stripping, and soldering the wires is more permanent.  Especially because the wires had to be snipped short so they didn’t take much extra space.  I used 24 AWG wire.  Probably would have been easier to use something smaller.

All components connected.

Got everything connected.  Just need to connect the on/off switch.  Push the components together gently as to not break the solder joints and put it in the Altoids Smalls tin.

In the tin and connecting the on/off toggle switch

Stuffed it in the tin and connected the on/off toggle switch.  Still haven’t turned it on yet.

Powered on for the first time

It turned on when I flipped the switch. All of the components were new and had not been powered on before this.


Tin closes

Everything fits in the tin and the lid closes.  Watch the video above to see exactly how things are placed in the Altoids Smalls tin.  It will fit.

Getting Started

The best place to start is by getting an Ultimate GPS from Adafruit and follow this guide to get the libraries/samples installed and get it connected to an Arduino Uno.

Starting development with the Uno is recommended because deploying the code and using the serial window is easier.  When ready you can easily deploy the code you wrote for the Uno to the Pro Trinket using the Aduino IDE.  There’s a few things to know if developing on the Uno with plans to deploy to the 3V Trinket:

  • Pins #2 and #7 are not available on the Pro Trinket
  • The Uno has 32 KB of program space and the Pro Trinket has 28 KB.  Both have 2 KB RAM.
  • Use the 3.3V power output on the UNO because that is what you are getting from the 3V Pro Trinket.  There is also a 5V Pro Trinket but I’ve never worked with it.

After the GPS is hooked up, take a look at the “parsing” example in the GPS library example.  The source code below is based on that example.

Get the OLED working by following the information provided here.  The OLED libraries do a lot of graphics, but the code sample below only prints text.

If you’ve got the GPS and OLED examples running, then you should be able to use the paste the code below into new sketch and deploy it.

Source Code


Shawn Cruise
January 24, 2016

Sample code that can be used to create the Arduino Pocket GPS
found at

Based on the GPS Parser and SSD1306_128x32_SPI example code.  See original comments below.

PIN 3 - RX on GPS
PIN 4 - TX on GPS
PIN 10 - CLK on OLED
PIN 11 - DC on OLED
PIN 12 - CS on OLED
PIN 13 - RESET on OLED //don't use 13 if you want to use the LED for something
3V - VIN on OLED and GPS


Test code for Adafruit GPS modules using MTK3329/MTK3339 driver

This code shows how to listen to the GPS module in an interrupt
which allows the program to have more 'freedom' - just parse
when a new NMEA sentence is available! Then access data when

Tested and works great with the Adafruit Ultimate GPS module
using MTK33x9 chipset
Pick one up today at the Adafruit electronics shop
and help support open source hardware & software! -ada

This is an example for our Monochrome OLEDs based on SSD1306 drivers

Pick one up today in the adafruit shop!

This example is for a 128x32 size display using SPI to communicate
4 or 5 pins are required to interface

Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!

Written by Limor Fried/Ladyada  for Adafruit Industries.
BSD license, check license.txt for more information
All text above, and the splash screen must be included in any redistribution

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>

#define GPS_RX 3
#define GPS_TX 4
#define OLED_MOSI   9
#define OLED_CLK   10
#define OLED_DC    11
#define OLED_CS    12
#define OLED_RESET 13 //don't use 13 if you want to use the LED for something
#define GPSECHO  true

SoftwareSerial mySerial(GPS_TX, GPS_RX); // tx,rx
Adafruit_GPS GPS(&mySerial);
boolean usingInterrupt = false;
void useInterrupt(boolean); // Func prototype keeps Arduino 0023 happy
uint32_t timer = millis();
short tzOffset = 0; // setting to subtract from GMT for current time zome

void setup()

// Interrupt is called once a millisecond, looks for any new GPS data, and stores it
	char c =;
	// if you want to debug, this is a good time to do it!
#ifdef UDR0
		if (c) UDR0 = c;
	// writing direct to UDR0 is much much faster than Serial.print 
	// but only one character can be written at a time. 

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;

// prints the compass heading based on the angle reported by the GPS 
void printHeading()
	char dir[3];
	dir[0] = ' ';
	dir[1] = ' ';
	dir[2] = ' ';

	if (GPS.angle > 337.25)
		dir[0] = 'N';
	else if (GPS.angle <= 22.5)
		dir[0] = 'N';
	else if (GPS.angle <= 67.5)
		dir[0] = 'N';
		dir[1] = 'E';
	else if (GPS.angle <= 112.5)
		dir[0] = 'E';
	else if (GPS.angle <= 157.5)
		dir[0] = 'S';
		dir[1] = 'E';
	else if (GPS.angle <= 202.5)
		dir[0] = 'S';
	else if (GPS.angle <= 247.5)
		dir[0] = 'S';
		dir[1] = 'W';
	else if (GPS.angle <= 292.5)
		dir[0] = 'W';
	else if (GPS.angle <= 337.5)
		dir[0] = 'N';
		dir[1] = 'W';

void printDateTime()
	short hr = GPS.hour - tzOffset;
	// check if the hr is now less than 0 i.e. before midnight after TX adjustment
	// fine if GMT - offset, need to add code to handle GMT + offset 
	if (hr < 0)
		hr += 24;
	if (hr  < 10)
	display.print(hr, DEC);
	if ((short)GPS.minute < 10)
	display.print(GPS.minute, DEC);
	if ((short)GPS.seconds < 10)
	display.print(GPS.seconds, DEC);

void updateDisplay()
	display.setCursor(0, 0);
	// the GPS will output a time without a sat fix.  
	// it often gets the sat time long before the sat location fix
	display.setCursor(110, 0);  // num sats appear in small text to the right of time
	// display the location info only if there is a sat fix
	if (GPS.fix)
		display.setCursor(110, 8);
		display.print(GPS.HDOP, 1);  // HDOP appear in small text under num sats.
		// normally need a println here but the hdop value hits the end of the line and forces a new line 
		// coordinates  
		display.print(GPS.latitudeDegrees, 5); display.print(','); display.println(GPS.longitudeDegrees, 5);
		display.print(GPS.altitude, 0); display.print("m ");
		// only display the heading if moving otherwise it is bouncing around due to normal GPS error
		// must cast to int because speed is float value in knots and decimal values are changeing when not moving
		if ((int)GPS.speed>0)
			display.print("-- ");
		// speed is in knots, convert to km/h
		display.print((int)(GPS.speed*1.852)); display.println(" km/h");
	// refresh the display

void loop()
	// if a new sentence is received
	if (GPS.newNMEAreceived()) {
		//if the GPS object can't parse it, return and wait for the next one
		if (!GPS.parse(GPS.lastNMEA()))

	// if timer or mills wrap around, reset the timer
	if (timer > millis())  timer = millis();

	// update the display every second
	if (millis() - timer > 1000) {
		timer = millis(); // reset the timer