' 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, will get most of this stuff from $GPRMC 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 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 RETURN LOG_DUMP: STORE 0 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