' 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
|