Code:
;
;
; PIC16F876a
; __________
; !MCLR |1 28| RB7------D7
; PLL Volt--AN0---RA0 |2 27| RB6------D6
; Temp--AN1---RA1 |3 26| RB5------D5
; AN2---RA2 |4 25| RB4------D4
; AN3---RA3 |5 24| RB3------LCD E
; NMEA data---RA4 |6 23| RB2------LCD RS
; AN4---RA5 |7 22| RB1------
; Ground---Vss |8 21| RB0------
; OSC1---XTAL |9 20| VDD------ +5 V
; OSC2---XTAL |10 19| Vss------Ground
; ---RC0 |11 18| RC7------
; ---RC1 |12 17| RC6------
; ---RC2 |13 16| RC5------
; pbutton---RC3 |14 15| RC4------
; ----------
;
; Serial data out Not used Not used
;====================================================================='
' Program to display returned value of a GPS on RA4
' LCD in 4-BIT mode PIC16F876a controller 4Mhz clock Fuse PWRT BODEN
'
'GPS sentence: $GPRMC,192144.62,A,5041.6058,N,00412.6124,E,0.45,3 57.74,081205,,*0B
@__config_HS_OSC
@__config_BOD_OFF
@__config_PWRT_ON
@__config_WDT_ON
@__config_PROTECT_OFF
@__config_LVP_OFF
;-- Place a copy of these variables in your Main program -------------------
;-- The compiler will tell you which lines to un-comment --
;-- Do Not un-comment these lines --
;---------------------------------------------------------------------------
;wsave VAR BYTE $20 SYSTEM ' location for W if in bank0
wsave VAR BYTE $70 SYSTEM ' alternate save location for W
' if using $70, comment wsave1-3
' --- IF any of these three lines cause an error ?? ------------------------
' Comment them out to fix the problem ----
' -- Which variables are needed, depends on the Chip you are using --
wsave1 VAR BYTE $A0 SYSTEM ' location for W if in bank1
wsave2 VAR BYTE $120 SYSTEM ' location for W if in bank2
;wsave3 VAR BYTE $1A0 SYSTEM ' location for W if in bank3
' --------------------------------------------------------------------------
INCLUDE "FP20.bas" ; 24-bit Floating Point for 14-bit cores with RAM at $20
Define LCD_DREG PORTB ' Port for LCD Data
Define LCD_DBIT 4 ' Set LCD starting data bit
Define LCD_RSREG PORTB ' Port for RegisterSelect (RS) bit
Define LCD_RSBIT 2 ' Port Pin for RS bit (pin9)
Define LCD_EREG PORTB ' Port for Enable (E) bit
Define LCD_EBIT 3 ' Port Pin for E bit (pin7)
Define LCB_BITS 4 ' Using 4-bit bus
Define LCD_COMMANDUS 1500 ' Command Delay (uS)
define LCD_DATAUS 50 ' Data Delay (uS)
DEFINE OSC 4
OPTION_REG.7=0 ' Enable Pull-Up's
GPSin VAR PORTA.4
Pbutton VAR PORTC.3
' Initialise ADC
ADCON1 = %10000100 ' Set PORTA analog and RIGHT justify result
ADCON0 = %01000001 ' Configure and turn on A/D Module channel 0 Fosc 8
PAUSE 500
'Declare variables
val VAR WORD ' final calculated adc valuesWORD' final calculated adc values
volt VAR WORD ' scaled value real part
voltd1 VAR WORD ' scaled value first decimal place
voltd2 VAR WORD ' scaled value second decimal place
i var byte ' counter
'Allocate Variables for GPS:
TimeOut CON 2000
hh VAR BYTE 'hours
mm VAR BYTE 'minutes
ss VAR BYTE 'seconds
knots VAR WORD 'speed in knots (units)
knotsten VAR BYTE 'speed in knots (tens)
course VAR WORD 'heading
latdeg VAR BYTE 'degrees latitude
latmin VAR BYTE 'minutes latitude
latsecs VAR BYTE 'seconds latitude
NS VAR BYTE 'north or south
londeg VAR BYTE 'degrees longitude
lonmin VAR BYTE 'minutes longitude
lonsecs VAR BYTE 'seconds longtitude
EW VAR BYTE 'east or west
d VAR BYTE 'day
m VAR BYTE 'month
y VAR BYTE 'year
MH VAR BYTE[6]
LonMinDec VAR BYTE
LonDir VAR BYTE
LatMinDec VAR BYTE
LatDir VAR BYTE
nPos var byte
nDig var byte
'Set up the digits (http://www.darreltaylor.com/files/CustChar.htm)
LCDOUT $FE,$40,$03,$03,$03,$03,$03,$03,$03,$03 ' Cust Char #0
'LCDOUT $FE,$40,$02,$02,$02,$02,$02,$02,$02,$02 ' Cust Char #0
LCDOUT $FE,$48,$1F,$1F,$1B,$1B,$1B,$1B,$1B,$1B ' Cust Char #1
LCDOUT $FE,$50,$1F,$1F,$18,$18,$18,$18,$1F,$1F ' Cust Char #2
LCDOUT $FE,$58,$03,$03,$03,$03,$03,$03,$1F,$1F ' Cust Char #3
LCDOUT $FE,$60,$1F,$1F,$1B,$1B,$1B,$1B,$1F,$1F ' Cust Char #4
LCDOUT $FE,$68,$1B,$1B,$1B,$1B,$1B,$1B,$1F,$1F ' Cust Char #5
LCDOUT $FE,$70,$1F,$1F,$03,$03,$03,$03,$1F,$1F ' Cust Char #6
LCDOUT $FE,$78,$1F,$1F,$03,$03,$03,$03,$03,$03 ' Cust Char #7
LCDOUT $FE,$40,$03,$03,$03,$03,$03,$03,$03,$03 ' Cust Char #8
fix VAR WORD 'GPS fix
LCDOut $fe,$80," GPS Decoder "
LCDOut $FE,$c0," G8VLQ March 2014 "
Pause 3000
LCDOut $FE, 1 'Clear Screen
GPS: 'read GPS
SerIn2 GPSin,188,Timeout,Clock,[wait("$GPRMC"),wait(","),DEC2 hh,DEC2 mm,DEC2 ss,wait(","),fix,wait(",")_
,DEC2 latdeg,DEC2 latmin,wait("."),DEC2 latsecs,wait(","),NS,wait(","),DEC3 londeg,DEC2 lonmin,wait("."),DEC2 lonsecs,_
wait(","),EW,wait(","),knots,wait("."),DEC2 knotsten,wait(","),DEC3 course,wait(","),DEC2 d,DEC2 m,DEC2 y]
LonMinDec = lonmin
LatMinDec = latmin
LonDir = EW
LatDir = NS
gosub PLL ;pll control voltage
GOSUB Locator ;maidenhead locator
GOSUB Clock ; Large digit clock
goto GPS
If m = 01 then gosub January ; show month
If m = 02 then gosub February
If m = 03 then gosub March
If m = 04 then gosub April
If m = 05 then gosub May
If m = 06 then gosub June
If m = 07 then gosub July
If m = 08 then gosub August
If m = 09 then gosub September
If m = 10 then gosub October
If m = 11 then gosub November
If m = 12 then gosub December
;-------------------------------------------------------------
PLL:
Val = 0 ' Value returned is the average of 5 conversions
For i = 0 TO 4
ADCON0.2 = 1 ' Start conversion
NotDone:
pause 1
IF ADCON0.2 = 1 Then NotDone
val = val + ((ADRESH * 256)+(ADRESL))
nEXT I
VAL = VAL/5
' Calculate Voltage to 2 decimal places
volt = val * 5/1024
voltd1 = ( val * 5//1024) * 10/1024
Voltd2 = ((val *5 //1024) * 10//1024) * 10/1024
RETURN
;---------------------------------------------
Locator:
;----[convert Longitude Sexagesimal to Decimal Degrees]-------------------------
Aint = LonMinDec : GOSUB ItoFA ; decimal portion of Minutes
Bint = 100 : GOSUB ItoFB ; divided by 100
GOSUB fpdiv
Bint = LonMin : GOSUB ItoFB ; add whole portion of Minutes
GOSUB fpadd
Bint = 60 : GOSUB ItoFB ; divide by 60
GOSUB fpdiv
Bint = LonDeg : GOSUB ItoFB ; add degrees
GOSUB fpadd
IF LonDir = "W" THEN ; if west of Prime Meridian
GOSUB AtoB
Aint = 0 : GOSUB ItoFA ; subtract from 0 to negate
GOSUB fpsub
ENDIF
Bint = 180 : GOSUB ItoFB ; add 180
GOSUB fpadd
;----[Have Longitude in AARG as Float]------------------------------------------
GOSUB SaveLon ; save Longitude for later
Bint = 20 : GOSUB ItoFB ; Lon / 20
GOSUB fpdiv
GOSUB SaveAARG ; save AARG for modulus
GOSUB FtoIA ; get integer
MH(0) = "A" + Aint ; + "A" = First character
; -- do Lon // 20 --- (modulus)
Bint = Aint ; copy integer result to BARG
GOSUB ItoFB ; convert it to float
GOSUB RestoreAARG ; restore Lon / 20 to AARG
GOSUB fpsub ; subtract integer
Bint = 20 ; multiply times original divisor (20)
GOSUB ItoFB
GOSUB fpmul ; AARG now contains the modulus
Bint = 2 : GOSUB ItoFB ; divide modulus by 2
GOSUB fpdiv
GOSUB FtoIA ; get integer
MH(2) = "0" + Aint ; + "0" = Third character
GOSUB RestoreLon ; restore Longitude
Bint = 2 : GOSUB ItoFB
GOSUB fpdiv ; divide by 2
GOSUB FtoIA ; get integer
Bint = Aint * 2 : GOSUB ItoFB ; put int * 2 in BARG, change back to float
GOSUB RestoreLon ; restore original Longitude
GOSUB fpsub ; subtract A - B
Bint = 12 : GOSUB ItoFB ; Multiply * 12
GOSUB fpmul
GOSUB FtoIA ; get integer
MH(4) = "a" + Aint ; + "a" = Fifth Character
;----[convert Latitude Sexagesimal to Decimal Degrees]--------------------------
Aint = LatMinDec : GOSUB ItoFA ; decimal portion of Minutes
Bint = 100 : GOSUB ItoFB ; divided by 100
GOSUB fpdiv
Bint = LatMin : GOSUB ItoFB ; add whole portion of Minutes
GOSUB fpadd
Bint = 60 : GOSUB ItoFB ; divide by 60
GOSUB fpdiv
Bint = LatDeg : GOSUB ItoFB ; add degrees
GOSUB fpadd
IF LatDir = "S" THEN ; if south of equator
GOSUB AtoB
Aint = 0 : GOSUB ItoFA ; subtract from 0 to negate
GOSUB fpsub
ENDIF
Bint = 90 : GOSUB ItoFB ; add 90
GOSUB fpadd
;----[Have Latitude in AARG as Float]------------------------------------------
GOSUB SaveLon ; save Latitude for later
Bint = 10 : GOSUB ItoFB ; Lat / 10
GOSUB fpdiv
GOSUB SaveAARG ; save AARG for modulus
GOSUB FtoIA
MH(1) = "A" + Aint ; + "A" = Second character
; -- do Lat // 10 --- (modulus)
Bint = Aint ; copy integer result to BARG
GOSUB ItoFB ; convert it to float
GOSUB RestoreAARG ; restore Lat / 10 to AARG
GOSUB fpsub ; subtract integer
Bint = 10 ; multiply times original divisor (10)
GOSUB ItoFB
GOSUB fpmul ; AARG now contains the modulus
GOSUB FtoIA
MH(3) = "0" + Aint ; + "0" = Fourth character
GOSUB RestoreLon ; restore original Latitude
GOSUB FtoIA ; get integer
Bint = Aint : GOSUB ItoFB ; put int in BARG, change back to float
GOSUB RestoreLon ; restore original Latitude
GOSUB fpsub ; subtract A - B
Bint = 24 : GOSUB ItoFB ; Multiply * 24
GOSUB fpmul
GOSUB FtoIA ; get integer
MH(5) = "a" + Aint ; + "a" = Sixth character
;----[Maidenhead conversion complete]-------------------------------------------
RETURN
;-------------------------------------------------------------------------------
Aexp_Copy VAR BYTE
AARGB0_Copy VAR BYTE
AARGB1_Copy VAR BYTE
AARGB2_Copy VAR BYTE
Aexp_Lon VAR BYTE
AARGB0_Lon VAR BYTE
AARGB1_Lon VAR BYTE
AARGB2_Lon VAR BYTE
SaveAARG:
Aexp_Copy = Aexp
AARGB0_Copy = AARGB0
AARGB1_Copy = AARGB1
AARGB2_Copy = AARGB2
RETURN
RestoreAARG:
Aexp = Aexp_Copy
AARGB0 = AARGB0_Copy
AARGB1 = AARGB1_Copy
AARGB2 = AARGB2_Copy
RETURN
AtoB:
Bexp = Aexp
BARGB0 = AARGB0
BARGB1 = AARGB1
BARGB2 = AARGB2
RETURN
SaveLon:
Aexp_Lon = Aexp
AARGB0_Lon = AARGB0
AARGB1_Lon = AARGB1
AARGB2_Lon = AARGB2
RETURN
RestoreLon:
Aexp = Aexp_Lon
AARGB0 = AARGB0_Lon
AARGB1 = AARGB1_Lon
AARGB2 = AARGB2_Lon
RETURN
;---------------------------------------
January:
LCDOut $fe,$80,DEC2 d," Jan ",DEC2 y," ",DEC2 hh,":",DEC2 mm,":",DEC2 ss
RETURN
February:
LCDOut $fe,$80,DEC2 d," Feb ",DEC2 y," ",DEC2 hh,":",DEC2 mm,":",DEC2 ss
RETURN
March:
LCDOut $fe,$80,DEC2 d," Mar ",DEC2 y," ",DEC2 hh,":",DEC2 mm,":",DEC2 ss
RETURN
April:
LCDOut $fe,$80,DEC2 d," Apr ",DEC2 y," ",DEC2 hh,":",DEC2 mm,":",DEC2 ss
RETURN
May:
LCDOut $fe,$80,DEC2 d," May ",DEC2 y," ",DEC2 hh,":",DEC2 mm,":",DEC2 ss
RETURN
June:
LCDOut $fe,$80,DEC2 d," Jun ",DEC2 y," ",DEC2 hh,":",DEC2 mm,":",DEC2 ss
RETURN
July:
LCDOut $fe,$80,DEC2 d," Jul ",DEC2 y," ",DEC2 hh,":",DEC2 mm,":",DEC2 ss
RETURN
August:
LCDOut $fe,$80,DEC2 d," Aug ",DEC2 y," ",DEC2 hh,":",DEC2 mm,":",DEC2 ss
RETURN
September:
LCDOut $fe,$80,DEC2 d," Sep ",DEC2 y," ",DEC2 hh,":",DEC2 mm,":",DEC2 ss
RETURN
October:
LCDOut $fe,$80,DEC2 d," Oct ",DEC2 y," ",DEC2 hh,":",DEC2 mm,":",DEC2 ss
RETURN
November:
LCDOut $fe,$80,DEC2 d," Nov ",DEC2 y," ",DEC2 hh,":",DEC2 mm,":",DEC2 ss
RETURN
December:
LCDOut $fe,$80,DEC2 d," Dec ",DEC2 y," ",DEC2 hh,":",DEC2 mm,":",DEC2 ss
RETURN
;--------------------------------------------------------------------------
Clock: ;Display time
nDig=hh dig 1 : nPos=1 : gosub displaydigit
nDig=hh dig 0 : nPos=2 : gosub displaydigit
npos=3 : gosub colon
ndig=mm dig 1 : npos=4 : gosub displaydigit
ndig=mm dig 0 : npos=5 : gosub displaydigit
npos=6 : gosub colon
ndig=ss dig 1 : npos=7 : gosub displaydigit
ndig=ss dig 0 : npos=8 : gosub displaydigit
LCDOut $fe,$80+9," ",DEC2 d,"-",DEC2 m,"-",DEC2 y
LCDOut $fe,$c0+9," ",#volt, ".", # voltd1,# voltd2,"v"
LCDOUT $fe,$94," G8VLQ ",STR MH\6
LCDOut $fe,$d4,DEC2 latdeg,$DF,DEC2 latmin,"'",DEC2 latsecs,NS," ",DEC2 londeg,$DF,DEC2 lonmin,"'",DEC2 lonsecs,EW ; ,#volt, ".", # voltd1,# voltd2,"v" ; d4 4th line
displaydigit:
if ndig=0 then gosub zero
if ndig=1 then gosub one
if ndig=2 then gosub two
if ndig=3 then gosub three
if ndig=4 then gosub four
if ndig=5 then gosub five
if ndig=6 then gosub six
if ndig=7 then gosub seven
if ndig=8 then gosub eight
if ndig=9 then gosub nine
return
Zero:
LCDOUT $FE,$80+nPos,1
LCDOUT $FE,$C0+nPos,5
return
One:
LCDOUT $FE,$80+nPos,0
LCDOUT $FE,$C0+nPos,0
return
Two:
LCDOUT $FE,$80+nPos,7
LCDOUT $FE,$C0+nPos,2
return
Three:
LCDOUT $FE,$80+nPos,6
LCDOUT $FE,$C0+nPos,3
return
Four:
LCDOUT $FE,$80+nPos,5
LCDOUT $FE,$C0+nPos,0
return
Five:
LCDOUT $FE,$80+nPos,2
LCDOUT $FE,$C0+nPos,3
return
Six:
LCDOUT $FE,$80+nPos,2
LCDOUT $FE,$C0+nPos,5
return
Seven:
LCDOUT $FE,$80+nPos,7
LCDOUT $FE,$C0+nPos,0
return
Eight:
LCDOUT $FE,$80+nPos,4
LCDOUT $FE,$C0+nPos,5
return
Nine:
LCDOUT $FE,$80+nPos,4
LCDOUT $FE,$C0+nPos,3
return
colon:
lcdout $fe,$80+nPos,$A5
lcdout $FE,$C0+nPos,$2E
return
Bookmarks