' ========================================================================= ' ' File...... Stamp_Dash.BSP ' Purpose... Digital Instrumentation for Moving Vehicle ' Author.... Jon Williams ' E-mail.... jwilliams@parallax.com ' Started... ' Updated... 21 SEP 2003 ' ' {$STAMP BS2p} ' {$PBASIC 2.5} ' ' ========================================================================= ' -----[ Program Description ]--------------------------------------------- ' ' This program accepts text data from a Garmin GPS receiver using the ' Garmin text output at 9600 baud. The advantage over NMEA 183 for this ' application is speed (2x) and fixed field positions and widths. ' ' String: ' ' @020202183142N3251129W09701159G008+00165E0000N0000D0001 <-- GPS data ' | ' | 1 2 3 4 5 ' 012345678901234567890123456789012345678901234567890123 <-- SPRAM addr ' ' ' @ header ' 020202 UTC date (yr [2], mo, dy) ' 183142 UTC time (hr, mn, sc) ' N lat hemisphere ' 32 lat degrees ' 51 lat minutes ' 129 lat frac minutes (1/1000) ' W long hemisphere ' 097 long degrees ' 01 long minutes ' 159 long frac minutes (1/1000) ' G position status ' 008 horizontal position error (meters) ' + altitude sign ' 00165 altitude above/below sea level (meters) ' E E/W velocity direction ' 0000 E/W velocity (meters per sec - tenths xxx.x) ' N N/S velocity direction ' 0000 N/S E/W velocity (meters per sec - tenths xxx.x) ' D vertical velocity direction (Up / Down) ' 0001 vertical velocity (meters per sec - hundredths xx.xx) ' ' ' For additional details see: http://www.garmin.com/support/text_out.html ' -----[ Revision History ]------------------------------------------------ ' -----[ I/O Definitions ]------------------------------------------------- LCD PIN 15 ' serial to 4x20 LCD GPS PIN 14 ' serial in from GPS FuncBtn PIN 0 ' function btn (active low) ' -----[ Constants ]------------------------------------------------------- N9600 CON $40F0 Null CON 0 ' null = 1 ms delay CrsrHm CON 1 ' cursor home BigOn CON 2 ' big characters BigOff CON 3 ' -- off NoCrsr CON 4 ' no cursor ULCrsr CON 5 ' underline cursor BlnkCrsr CON 6 ' blinking cursor ClrLcd CON 12 ' clear LCD BLOn CON 14 ' backlight on BLOff CON 15 ' -- off PosCmd CON 16 ' positioning command ClrCol CON 17 ' clear column RtAlign CON 18 ' right align Esc CON 27 DegSym CON 223 Pressed CON 0 ' button is active-low UtcAdj CON 24 - 5 ' adjust UTC for CDT ' -----[ Variables ]------------------------------------------------------- idx VAR Byte ' loop counter fldWidth VAR Nib ' width of data field workVal VAR Word ' temp value from parsing hr VAR Byte ' adjusted hours mn VAR Byte ' minutes sc VAR Byte ' seconds velEW VAR Word ' velocity E/W velNS VAR Word ' velocity E/W speed VAR Word vector VAR Word ' direction vector eePntr VAR Word ' eeprom pointer char VAR Byte ' display character mtr10 VAR Word ' meters x 0.1 mi10 VAR Word ' miles x 0.1 ' -----[ EEPROM Data ]----------------------------------------------------- CPoints DATA "-N-", "NNE", "N-E", "ENE" DATA "-E-", "ESE", "S-E", "SSE" DATA "-S-", "SSW", "S-W", "WSW" DATA "-W-", "WNW", "N-W", "NNW" ' -----[ Initialization ]-------------------------------------------------- Setup: PAUSE 500 ' let LCD initialize SEROUT LCD, N9600, [ClrLcd] ' clear screen IF (FuncBtn = Pressed) THEN SEROUT LCD, N9600, [BLOn] ' backlight on ENDIF ' -----[ Program Code ]---------------------------------------------------- Main: DO SERIN GPS, N9600, 3750, No_GPS, [WAIT("@"), SPSTR 50] GOSUB Parse_GPS GOSUB Calc_Speed GOSUB Show_Speed GOSUB Show_Time GOSUB Show_Vector GOSUB Show_Compass GOSUB Show_Miles_Acc LOOP END ' -----[ Subroutines ]----------------------------------------------------- ' Signal lost -- or receiver set to wrong output No_GPS: SEROUT LCD, N9600, [ClrLCD, CR, "- GPS SIGNAL ERROR -"] PAUSE 1000 SEROUT LCD, N9600, [ClrLcd] GOTO Main ' Grab fields from GPS string Parse_GPS: idx = 6 : fldWidth = 2 ' hours GOSUB Parse_Field hr = workVal + UtcAdj // 24 ' update for local position ' 12 hour mode hr = hr // 12 IF (hr = 0) THEN hr = 12 idx = 8 : fldWidth = 2 ' minutes GOSUB Parse_Field mn = workVal idx = 10 : fldWidth = 2 ' seconds GOSUB Parse_Field sc = workVal idx = 40 : fldWidth = 4 ' east/west velocity GOSUB Parse_Field velEW = workVal idx = 45 : fldWidth = 4 ' north/south velocity GOSUB Parse_Field velNS = workVal RETURN ' Parses numeric data field from GPS string in ScratchPad ' -- pass digits in field in "fldWidth" ' -- value returned in "workVal" Parse_Field: workVal = 0 ' clear return value IF (fldWidth < 6) THEN ' valid fldWidth? DO WHILE (fldWidth > 0) workVal = workVal * 10 ' shift result digits left GET idx, char ' get digit from field workVal = workVal + (char - "0") ' convert, add into value fldWidth = fldWidth - 1 ' decrement field width idx = idx + 1 ' point to next digit LOOP ENDIF RETURN ' Show time on LCD ' -- HH:MM:SS Show_Time: SEROUT LCD, N9600, [PosCmd, 12 + 64, DEC2 hr, ":", DEC2 mn, ":", DEC2 sc] RETURN ' Calculate speed from E/W and N/W velocities ' -- values are scaled to fit 0 - 127 range ' -- derived value scaled back ' -- saves direction vector ' -- accumulates meters traveled ' ' Note: This routine divides down the velocity values so that they ' will fit within the constraints of HYP and ATN fuctions. Calc_Speed: ' find biggest vector IF (velEW > velNS) THEN workVal = velEW ELSE workVal = velNS ENDIF ' create scaling factor (1 to 4) LOOKDOWN workVal, <[128,255,382,509], workVal workVal = workVal + 1 velEW = velEW / workVal ' scale to < 127 velNS = velNS / workVal speed = velEW HYP velNS ' calculate speed (mps) ' speed (mph) = meters/sec (tenths) * 0.223694 speed = speed * (workVal * 10) ** 14660 + 5 / 10 mtr10 = mtr10 + ((velEW HYP velNS) * workVal) ' accumulate meters moved RETURN Calc_Speed2: ' replaces HYP function speed = SQR((velNS * velNS) + (velEW * velEW)) ' accumulate meters traveled mtr10 = mtr10 + speed ' speed (mph) = meters/sec (tenths) * 0.223694 speed = speed ** 14660 + 5 / 10 RETURN ' Show current speed in "big digits" format ' -- code right justifies Show_Speed: SEROUT LCD, N9600, [CrsrHm] ' move to line 1, col 1 (Home) IF (speed < 10) THEN ' if 1 digit FOR idx = 0 TO 4 ' -- erase previous 10's SEROUT LCD, N9600, [ClrCol] NEXT ' print 1's SEROUT LCD, N9600, [BigOn, DEC1 speed, BigOff] ELSE ' print 2-digit speed SEROUT LCD, N9600, [BigOn, DEC2 speed, BigOff] ENDIF PAUSE 20 RETURN ' Show current direction in degrees ' -- 0º to 359º ' -- vector is converted to Brads, then Degrees ' -- value is rotated to match compass orientation ' ' Note that this routine counts on velEW and velNS being ' scaled to < 127 (done in Calc_Speed) Show_Vector: IF (speed > 0) THEN ' get EW direction GET 39, char IF (char = "W") THEN velEW = -velEW ' if W, change quadrant ' get NW direction GET 44, char IF (char = "S") THEN velNS = -velNS ' if S, change quadrant vector = velEW ATN velNS ' in Brads vector = vector */ 360 ' convert to degrees vector = 360 - vector + 90 // 360 ' orient to compass SEROUT LCD, N9600, [PosCmd, 35 + 64, RtAlign, "3", DEC vector, PosCmd, 35 + 64, DegSym] ELSE SEROUT LCD, N9600, [PosCmd, 32 + 64, "---"] ENDIF RETURN ' Show current direction as compass point ' -- 0º = "N" Show_Compass: SEROUT LCD, N9600, [PosCmd, 52 + 64] ' move to line 3, colum 13 IF (speed > 0) THEN eePntr = vector * 100 + 1125 / 2250 // 16 ' calc hextant (22.5°) eePntr = eePntr * 3 ' point to start of string FOR idx = 0 TO 2 ' print compass string READ eePntr + idx, char SEROUT LCD, N9600, [char] NEXT ELSE ' not moving SEROUT LCD, N9600, ["---"] ENDIF RETURN ' Show leg mileage accumulator ' -- 0.0 to 999.9 ' -- input on P0 will reset acc if low Show_Miles_Acc: IF (FuncBtn = Pressed) THEN ' reset on button press mtr10 = 0 mi10 = 0 ENDIF IF (mtr10 >= 1609) THEN ' gone 1/10 mile? mi10 = mi10 + 1 // 10000 mtr10 = mtr10 - 1609 ENDIF SEROUT LCD, N9600, [PosCmd, 75 + 64, RtAlign, "3", DEC (mi10 / 10), PosCmd, 75 + 64, ".", DEC1 mi10, " mi"] RETURN