Code:
; Filename : Maidenhead_10.pbp
; Compiler : PICBASIC PRO Compiler
; Target PIC : 16F1937, but will work with most any chip
; Oscillator : ANY
; Keywords : Maidenhead, Locator, GPS, Amateure Radio
; Description : PICBASIC PRO program to convert between
; : GPS Sexagesimal to Maidenhead coordinate systems
;-------------------------------------------------------------------------------
; Must use the 32-bit Floating Point routines
INCLUDE "FP2032.bas" ; 32-bit Floating Point for 14-bit cores with RAM at $20
DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
DEFINE HSER_TXSTA 20h ' Enable transmit, BRGH = 0
DEFINE HSER_SPBRG 25 ' 19200 Baud @ 32MHz, 0.16%
DEFINE HSER_CLROERR 1 ' Clear overflow automatically
HSEROUT [27,"[2J","Maidenhead Locator",13,10]
HSEROUT ["16F1937, 32-bit Floating Point",13,10,13,10]
MH VAR BYTE[10]
LonStr VAR BYTE[12]
LatStr VAR BYTE[12]
LonDeg VAR BYTE
LonMin VAR BYTE
LonMinDec VAR BYTE
LonDir VAR BYTE
LatDeg VAR BYTE
LatMin VAR BYTE
LatMinDec VAR BYTE
LatDir VAR BYTE
Idx VAR BYTE
AddChar VAR BYTE
Divisor VAR BYTE[4]
AARG_SAVE VAR BYTE[4]
;-------------------------------------------------------------------------------
ASM
MOVE?CF32 macro C, F ; put a Floating Point Constant in an FP variable
MOVE?CW (C & 0xFFFF), F
MOVE?CW (C >> 16), F + 2
endm
MOVE?FF32 macro Fin, Fout ; Copy an FP var to another FP var
MOVE?WW Fin, Fout
MOVE?WW Fin + 2, Fout + 2
endm
ENDASM
;-------------------------------------------------------------------------------
ARRAYWRITE LonStr,["00049.77,W",0] ; 0° 47.70' ;<-- enter GPS location here
ARRAYWRITE LatStr,["5325.83,N",0] ; 53° 26.20'
HSEROUT ["LonStr = ", STR LonStr,13,10] ; display manual input
HSEROUT ["LatStr = ", STR LatStr,13,10]
;----[parse strings as if they came from a GPS]---------------------------------
ARRAYREAD LonStr,[DEC3 LonDeg, DEC2 LonMin, Dec LonMinDec, LonDir]
ARRAYREAD LatStr,[DEC2 LatDeg, DEC2 LatMin, Dec LatMinDec, LatDir]
;----[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
@ MOVE?FF32 AARGB2, BARGB2 ; copy Float AARG to BARG
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]------------------------------------------
FOR Idx = 0 TO 8 STEP 2
SELECT CASE Idx
CASE 0 : AddChar = "A"
@ MOVE?CF32 0x83200000, _Divisor ; 20
CASE 2 : AddChar = "0"
@ MOVE?CF32 0x80000000, _Divisor ; 2
CASE 4 : AddChar = "a"
@ MOVE?CF32 0x7B2AAAAB, _Divisor ; 0.0833333
CASE 6 : AddChar = "0"
@ MOVE?CF32 0x78088889, _Divisor ; 0.00833333
CASE 8 : AddChar = "a"
@ MOVE?CF32 0x73360B61, _Divisor ; 0.000347222
END SELECT
GOSUB MH_Digit
NEXT Idx
;----[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
@ MOVE?FF32 AARGB2, BARGB2 ; copy Float AARG to BARG
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]------------------------------------------
FOR Idx = 1 TO 9 STEP 2
SELECT CASE Idx
CASE 1 : AddChar = "A"
@ MOVE?CF32 0x82200000, _Divisor ; 10
CASE 3 : AddChar = "0"
@ MOVE?CF32 0x7F000000, _Divisor ; 1
CASE 5 : AddChar = "a"
@ MOVE?CF32 0x7A2AAAAB, _Divisor ; 0.0416666
CASE 7 : AddChar = "0"
@ MOVE?CF32 0x770882F1, _Divisor ; 0.00416666
CASE 9 : AddChar = "a"
@ MOVE?CF32 0x723603EC, _Divisor ; 0.000173583
END SELECT
GOSUB MH_Digit
NEXT Idx
;----[Maidenhead conversion complete]-------------------------------------------
HSEROUT ["LOC ",STR MH\10,13,10,13,10] ; show final result
Main: ; blink an LED when done
HIGH PORTA.0
PAUSE 500
LOW PORTA.0
PAUSE 500
GOTO Main
;----[Calculate one digit of the Maidenhead Locator]----------------------------
MH_Digit:
@ MOVE?FF32 _Divisor, BARGB2 ; put divisor in BARG
GOSUB fpdiv ; do the divide
@ MOVE?FF32 AARGB2, _AARG_SAVE ; save AARG for modulus
GOSUB FtoIA ; get integer
MH(Idx) = Aint + AddChar ; The Character
Bint = Aint ; copy integer result to BARG
GOSUB ItoFB ; convert it to float
@ MOVE?FF32 _AARG_SAVE, AARGB2 ; restore previous AARG
GOSUB fpsub ; subtract integer
@ MOVE?FF32 _Divisor, BARGB2 ; multiply times original divisor
GOSUB fpmul ; AARG now contains the remainder
RETURN
The output of the program looks like this ...
Bookmarks