An afterthought, before the fact.
I went through this trying to make sure it didn't require PBP3 since Rob doesn't have it. But now that I've posted it, I realized it requires PBP 2.60 or later. DOH!
At least you can download the free PBP3 trial version and compile it with that, or you can change the arrayread/arraywrite statements, so I'm not changing it.
---------------------------------- -------------------------------- ----------------------------------
Ok, here goes ...
It's not as ugly as it was, but without PBP3 there's only so much you can do.
This code is based on the Perl script on the Wikipedia site for Maidenhead Locator System by Chris Ruvolo.
Although I had to do things quite differently for the Microchip Floating-Point routines.
The Microchip Floating-Point routines for PBP are available from http://melabs.com/resources/fp.htm
Extract the .zip file to the same folder as your source code, or this code.
To try to make things easy, the routines start out with a String in the same format as the Lat/Lon data of the $GPRMC sentence.
For instance, an approximation of the IO93ok square is 0 degrees, 47.70 minutes West Longitude by 53 degrees, 26.20 minutes North latitude.
$GPRMC will present the data as .... 5326.20,N and 00047.70,W.
These can be parsed from the GPS data, or entered manually with the following two statements ... Note that they are null terminated.
I am entering them manually for this sample.Code:ARRAYWRITE LonStr,["00047.70,W",0] ; -0° 47.70' ARRAYWRITE LatStr,["5326.20,N",0] ; 53° 26.20
I'm using the 24-bit Floating-Point routines, since it gave the same results as the 32-bit FP, but you can use either one by simply changing the include file.
I imagine the 32-bit routines will be better around the edges of each square, but I haven't confirmed that.
I'm using a 16F1937, so if you are using an 18F ... you'll need to use the 18F FP includes.
Obviously, you need to initialize your hardware configs first.
The output from the program in a terminal looks like this ...Code:; Filename : Maidenhead.pbp ; Compiler : PICBASIC PRO Compiler ; Target PIC : 16F1937, but will work with most any chip ; Oscillator : ANY ; Keywords : Maidenhead, Locator, GPS, Amateur Radio ; Description : PICBASIC PRO program to convert between ; : GPS Sexagesimal to Maidenhead coordinate systems ;------------------------------------------------------------------------------- ; use only one of the FP includes INCLUDE "FP20.bas" ; 24-bit Floating Point for 14-bit cores with RAM at $20 ;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, 32Mhz, PBP3 not required",13,10,13,10] MH VAR BYTE[6] 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 ARRAYWRITE LonStr,["00047.70,W",0] ; -0° 47.70' <-- Enter location here ARRAYWRITE LatStr,["5326.20,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 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]------------------------------------------- HSEROUT ["LOC ",STR MH\6,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 ;------------------------------------------------------------------------------- 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
If you are using an Enhanced 14-bit core like the 16F1937 that I'm using ... you'll need to add the processor to the DEV_FAM.INC file from the FP.zipCode:Maidenhead Locator 16F1937, 32Mhz, PBP3 not required LonStr = 00047.70,W LatStr = 5326.20,N LOC IO93ok
For the 16F1937 add this towards the bottom of the file (before the if statement).
References:Code:IFDEF __16F1937 ; Generic Processor Type P16CXX SET TRUE ; If P16CXX, use INHX8M file format. P16_MAP2 SET TRUE ; ENDIF
- Maidenhead_Locator_System - Wikipedia - http://en.wikipedia.org/wiki/Maidenhead_Locator_System
- Find your QTH locator (or your grid square) with GoogleMaps - http://qthlocator.free.fr/index.php <-- Too Cool!
- $GPRMC sentence format - http://aprs.gids.nl/nmea/#rmc
Bookmarks