Electronic Hobbyists Corner

Home
Site Information
Contact Details

Projects
Technical Articles
Reference Section
Component Tutorials

Site Map
Links
Firmware Code
Homebrew GPS Receiver Homebrew GPS Receiver
Tree Receiver Hardware - Overview of receiver design.
Tree Firmware Code - Explanation and download of firmware code.



Firmware Code
Download



Firmware Code:
For the curious the BASIC Stamp 2p40 program that runs the show. For those just wanting to use it, proceed directly to the download below.

This code is not thoroughly tested or debugged.

' Homebrew GPS Receiver
'=======================
'
' Jethro Donaldson
' 29/03/2007
'
' {$STAMP BS2p}
' {$PBASIC 2.5}
'
'
DATA      0, 0
' Configuration / Constants
DelayLCD  CON   5         ' 5ms delay for LCD bus
DelaySpl  CON   2000      ' How long to display the splash screen

LCDBus    CON   $20       ' Set bus mode (4 bit)
LCDClear  CON   $01       ' Clear display command
LCDFunc   CON   $28       ' Function set (2 line mode)
LCDDisp   CON   $0c       ' Display configuration (No cursors, display on)
LCDLeft   CON   $18       ' Scroll one character left
LCDPos    CON   $80       ' Position cursor (bitwise or new position)
LCDRight  CON   $1c       ' Scroll one character right
LCDShift  CON   $06       ' Display configuration (no auto-shift, no auto-increment)
LCDWakeUp CON   $30       ' Wakeup sequence

PinBtn    CON   8         ' Pin connected to display select button
PinLED    CON   0         ' Pin with blue LED attached for debug
PinRst    CON   9         ' Drive high to reset GPS mode
PinTxB    CON   12        ' GPS module UART A (NMEA text messages)
PinRxB    CON   13
PinTxA    CON   14        ' GPS module UART B (SiRF binary messages)
PinRxA    CON   15

SerTimOut CON   2500      ' Units of 400us until serial receive timeout

LogFreq   CON   30        ' Seconds between each log event

SymDegree CON   $df       ' Degrees symbol

DispLoc   CON   0         ' Values of Display variable
DispMisc  CON   1
DispCour  CON   2
DispTime  CON   3

B4800     CON   500       ' Baud rate constants
B4800N    CON   16884
B9600     CON   240
B9600N    CON   16624
B19200    CON   110
B19200N   CON   16494
B38400    CON   45
B38400N   CON   16429

GGA       CON   0         ' NMEA configuration, how often (in seconds to get each message)
GLL       CON   0
GSA       CON   0
GSV       CON   0
RMC       CON   0
VTG       CON   0
MSS       CON   0
ZDA       CON   0

' Variables
Display   VAR   Nib       ' Current display state
GPSStat   VAR   Nib       ' Fix available indicator
BtnSpace  VAR   Byte      ' Workspace for button command
LogInt    VAR   Byte      ' Counter to when to log
LogPoint  VAR   Word

LatDeg    VAR   Byte      ' Latitude information
LatMin    VAR   Byte
LatFrac   VAR   Word
LatDir    VAR   Byte

LonDeg    VAR   Byte      ' Longitude information
LonMin    VAR   Byte
LonFrac   VAR   Word
LonDir    VAR   Byte

Altitude  VAR   Word      ' Altitude, metres above see level
SatCount  VAR   Byte      ' Satellites in view

Speed     VAR   Byte      ' Speed in km/h
Heading   VAR   Word      ' Course over ground

UTCHour   VAR   Byte      ' UTC time from GPS
UTCMin    VAR   Byte
UTCSec    VAR   Byte
UTCDay    VAR   Byte
UTCMnth   VAR   Nib
UTCYear   VAR   Nib

' Configure I/O and initialize variables
  DIRS = $52ff            ' I/O directions: IOIO IIOI OOOO OOOO
  OUTS = $4200            ' Clear output latch, is this actually necessary?

' Initialization
  PAUSE   100             ' Allow LCD to self-initialize first
  LOW     PinRst          ' Release GPS module from reset
  GOSUB   LCD_INIT        ' Send required commands to initialize
  LCDOUT  1, LCDPos | 2,  ["Homebrew GPS"]
  LCDOUT  1, LCDPos | 68, [  "Receiver"  ]
  PAUSE   DelaySpl        ' Keep the splash screen up this long
  Display = 0             ' Initial state of Display

  LCDCMD  1, LCDClear

  SERIN   16, B19200, SerTimOut, MAIN, [WAIT("_DUMP")]
  GOSUB   LOG_DUMP

' Main program loop
MAIN:
  GOSUB   GET_DATA        ' Get data from Jupiter 30 GPS module

  IF GPSStat = 6 THEN
    LogInt = 0
    GOSUB LCD_DRAW_NO_FIX
    GOTO  MAIN
  ELSE
    GOSUB   LCD_DRAW_DATA

    IF LogInt = 0 THEN
      GOSUB   LOG_DATA
      LogInt = LogFreq
    ELSE
      LogInt = LogInt - 1
    ENDIF
  ENDIF

  BUTTON  PinBtn, 1, 1, 1, BtnSpace, 1, BUTTON_DOWN

  GOTO    MAIN            ' Loop back...

' Button pressed, increment Display variable and wrap around at 3
BUTTON_DOWN:
  Display = (Display + 1) // 4
  GOTO    MAIN

' LCD initialization code
LCD_INIT:
  LCDCMD  1, LCDWakeUP    ' Wakeup sequence with required delays
  PAUSE   DelayLCD
  LCDCMD  1, LCDWakeUP    ' Wakeup sequence with required delays
  PAUSE   DelayLCD
  LCDCMD  1, LCDWakeUP    ' Wakeup sequence with required delays
  PAUSE   DelayLCD
  LCDCMD  1, LCDBUs       ' Send bus size
  LCDCMD  1, LCDFunc      ' Send function set
  LCDCMD  1, LCDDisp      ' Send display settings
  LCDCMD  1, LCDShift
  LCDCMD  1, LCDClear     ' Clear display
  RETURN

' Draw data onto LCD
LCD_DRAW_DATA:
  SELECT Display          ' Update display in accordance with the Display variable
    CASE DispLoc
      LCDOUT  1, LCDPos | 0, ["Lt  ", DEC2 LatDeg, SymDegree, DEC2 LatMin, ".", DEC4 LatFrac, " ", LatDir]
      LCDOUT  1, LCDPos | 64, ["Ln ", DEC3 LonDeg, SymDegree, DEC2 LonMin, 
".", DEC4 LonFrac, " ", LonDir]
    CASE DispMisc
      LCDOUT  1, LCDPos | 0, ["Altitude: ", DEC5 Altitude, "m"]
      LCDOUT  1, LCDPos | 64, ["Sats in view: ", DEC2 SatCount]
    CASE DispCour
      LCDOUT  1, LCDPos | 0, ["Speed:   ", DEC3 Speed, "km/h"]
      LCDOUT  1, LCDPos | 64, ["Heading:  ", DEC3 Heading, SymDegree, " N"]
    CASE DispTime
      LCDOUT  1, LCDPos | 0, ["Time:   ", DEC2 UTCHour, ":", DEC2 UTCMin, 
":", DEC2 UTCSec]
      LCDOUT  1, LCDPos | 64, ["Date:   ", DEC2 UTCDay, "/", DEC2 UTCMnth, 
"/", DEC2 UTCYear]
  ENDSELECT
  RETURN

' Print message saying there is no data!
LCD_DRAW_NO_FIX:
  LCDCMD  1, LCDClear     ' Clear display
  LCDOUT  1, LCDPos | 1,  ["No signal from"]
  LCDOUT  1, LCDPos | 67, [  "satellites"  ]
  RETURN

' Read in data
GET_DATA:
  SERIN   PinRxA, B9600, [WAIT("$GPGGA")]
  SERIN   PinRxA, B9600, [WAIT(",")]                                         ' Ignore UTC time
  SERIN   PinRxA, B9600, [WAIT(",")]                                         ' Ignore latitude
  SERIN   PinRxA, B9600, [WAIT(",")]                                         ' Ignore latitude indicator
  SERIN   PinRxA, B9600, [WAIT(",")]                                         ' Ignore longitude
  SERIN   PinRxA, B9600, [WAIT(",")]                                         ' Ignore longitude indicator
  SERIN   PinRxA, B9600, [WAIT(",")]                                         ' Ignore quality indicator
  SERIN   PinRxA, B9600, [WAIT(","), DEC2 SatCount]                          ' Get satillites in view
  SERIN   PinRxA, B9600, [WAIT(",")]                                         ' Ignore horizontal dilution of precision
  SERIN   PinRxA, B9600, [WAIT(","), DEC Altitude]                           ' Get alititude (MSL)

  SERIN   PinRxA, B9600, [WAIT("$GPRMC")]
  SERIN   PinRxA, B9600, [WAIT(","), DEC2 UTCHour, DEC2 UTCMin, DEC2 UTCSec] ' Receive UTC time
  SERIN   PinRxA, B9600, [WAIT(","), GPSStat]                                ' Check status flag
  SERIN   PinRxA, B9600, [WAIT(","), DEC2 LatDeg, DEC2 LatMin]               ' Get degrees and minutes of latitude
  SERIN   PinRxA, B9600, [WAIT("."), DEC4 LatFrac]                           ' Get fractional part of minutes of latitude
  SERIN   PinRxA, B9600, [WAIT(","), LatDir]                                 ' Get direction indicator for latitude (N/S)
  SERIN   PinRxA, B9600, [WAIT(","), DEC3 LonDeg, DEC2 LonMin]               ' Repeat for longitude
  SERIN   PinRxA, B9600, [WAIT("."), DEC4 LonFrac]
  SERIN   PinRxA, B9600, [WAIT(","), LonDir]
  SERIN   PinRxA, B9600, [WAIT(",")]                                         ' Ignore speed field
  SERIN   PinRxA, B9600, [WAIT(",")]                                         ' Ignore heading field
  SERIN   PinRxA, B9600, [WAIT(","), DEC2 UTCDay, DEC2 UTCMnth, DEC2 UTCYear]' Get UTC date

  SERIN   PinRxA, B9600, [WAIT("$GPVTG")]
  SERIN   PinRxA, B9600, [WAIT(","), DEC Heading]                            ' Get true (non-magnetic) heading
  SERIN   PinRxA, B9600, [WAIT(",")]                                         ' Ignore heading reference
  SERIN   PinRxA, B9600, [WAIT(",")]                                         ' Ignore magnetic heading
  SERIN   PinRxA, B9600, [WAIT(",")]                                         ' Ignore heading reference
  SERIN   PinRxA, B9600, [WAIT(",")]                                         ' Ignore speed in knots
  SERIN   PinRxA, B9600, [WAIT(",")]                                         ' Ignore units
  SERIN   PinRxA, B9600, [WAIT(","), DEC Speed]                              ' Get speed in km/h

  UTCHour = (UTCHour + 12) // 24                                             ' Convert UTC to NZST (+12 hours)

  RETURN

LOG_DATA:
  HIGH    PinLED
                                                             ' Use LED to indicate log activity

  STORE   0                                                                  ' Select program slot 0 to get LogPoint
  READ    0, Word LogPoint                                                   ' Read LogPoint from the top of the program slot

  
STORE   (LogPoint / 2048) + 1                                              ' Change to the program slot the pointer is in

  WRITE   LogPoint // 2048, UTCHour, UTCMin, UTCSec, LatDeg, LatMin, Word LatFrac, LatDir, LonDeg, LonMin, Word LonFrac, LonDir, Word Altitude, Speed
  LogPoint = LogPoint + 16

  
STORE   0
  
WRITE   0, Word LogPoint

  LOW     PinLED
                                                             ' Log cycle complete
  RETURN

LOG_DUMP:
  STORE   0
                                                                  ' This stuff hacked in as an afterthought...
  READ    0, Word LogPoint
  Heading = 0

  IF LogPoint = 0 THEN
    RETURN
  ENDIF

  LCDOUT  1, LCDPos | 1, ["Dumping Log..."]
  SEROUT  16, B19200, ["_ACK", DEC3 LogPoint / 16]

  FOR Heading = 0 TO LogPoint - 16 STEP 16
    STORE   (Heading / 2048) + 1

    HIGH    PinLED
    READ    Heading // 2048, UTCHour, UTCMin, UTCSec, LatDeg, LatMin, Word LatFrac, LatDir, LonDeg, LonMin, Word LonFrac, LonDir, Word Altitude, Speed
    LOW     PinLED

    SEROUT  16, B19200, ["_LOG", DEC3 Heading, ":"]
    SEROUT  16, B19200, [DEC2 UTCHour, DEC2 UTCMin, DEC2 UTCSec]
    SEROUT  16, B19200, [DEC2 LatDeg, DEC2 LatMin, DEC4 LatFrac, LatDir]
    SEROUT  16, B19200, [DEC3 LonDeg, DEC2 LonMin, DEC4 LonFrac, LonDir]
    SEROUT  16, B19200, [DEC4 Altitude, DEC3 Speed]
  NEXT

  LCDCMD    1, LCDClear

  RETURN


Download:
The relevant software for editing and programming in PBASIC can be (hopefully) be found on the Parallax website. The above code can be downloaded in a ZIP archive or viewed in your browser, which may or may not recognize the .bsp file as text...

View in browser (text file)
Download - ZIP archive containing source code (.bsp)



If you have any comments or questions please don't hesitate to contact me.

Return To Top Last Updated: 02/08/2008 Home Page