Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Maidenhead grid calculator

Status
Not open for further replies.

SwingeyP

Member
Hello again,

I am trying to convert some code to OSHON pic basic but with no success.

The original code is this.

Code:
'#! / usr / bin / perl - W
'# (C) 2012 Chris Ruvolo.  Licensed under a 2-clause BSD license.
'If($ #argv < 1) {
'printf("Usage: $0 <lat> <long>\n");
'Exit(1);
'}

'my $lat = $ARGV[0];
'my $lon = $argv[1];
'my $grid = "";

'$lon = $lon + 180;
'$lat = $lat + 90;

'$grid .= chr(ord('A') + int($lon / 20));
'$grid .= chr(ord('A') + int($lat / 10));
'$grid .= chr(ord('0') + int(($lon % 20)/2));
'$grid .= chr(ord('0') + int(($lat % 10)/1));
'$grid .= chr(ord('a') + int(($lon - (int($lon/2)*2)) / (5/60)));
'$grid .= chr(ord('a') + int(($lat - (int($lat/1)*1)) / (2.5/60)));

'print "$grid\n";


I have this ....

Code:
'-------------------------------------------------
'Procedures
'-------------------------------------------------
Proc calc_loc(lat As Byte, lng As Byte)
If raw_data(30) = 0x57 Then  'in other words the value would be -1
    lng = 179  'so -1 + 180 = 179
Else
    lng = lng + 180
Endif

lat = lat + 90


loc(0) = 65 + (lng / 20)  '65 = ascii A

loc(1) = 65 + (lat / 10)

loc(2) = 48 + ((lng Mod 20) / 2)  '48 = Ascii zero

loc(3) = 48 + ((lat Mod 10) / 1)

'temp1 = lng / 2  '179/2=89
'temp2 = temp1 * 2  '89*2=178
'temp3 = lng - temp2  '179 - 178 = 1
'temp4 = (temp3 / (5 / 60)) + 97  '= 1/0.084 = 98 = b
'loc(4) = temp4
loc(4) = 97 + ((lng - ((lng / 2) * 2)) / (5 / 60)))
'$grid.= chr(ord(  'a') + int(($lat - (int($lat/1)*1)) / (2.5/60)));

End Proc

I hope this makes sense. I tried to break down the equation into parts but even that didn't work and I ended up with a value for loc(4) of 96. Which is less than the 97 being added to it. think this might be something to do with divide by zero as the equation works out to 97+(1/0) or 0.084 to be exactish.

Can anyone help me with this please?

Regards - Paul
 
temp3 / (5/60)
is same as:
temp3*12

loc(4) = 97 + ((lng - ((lng / 2) * 2)) / (5 / 60)))
That is messy.. I think you are missing parenthesis there. Because (lng - ((lng / 2) * 2)) becomes (lng-lng)
EDIT: Ok, it seems to be consistent with the original equation. I don't know what is purpose of that.. extract decimal parts of the numbers?

And, every time you divide by (5/60), that is the same as multiplying by 12.. and is much more accurate and efficient. Same goes with dividing with (2.5/60). That is the same as multiplying by 24.
 
Last edited:
I'm not very good at maths but surely 5/60 is not the same as multiplying by 12. 60/5 would make sense.

I said that dividing by (5/60) is the same as multiplying by 12.
 
But, I would like to know is there any significance in a code like this: (int($lat/1)*1)
If there is, then it might be more complicated to convert the code. If there is not, then the original wikipedia code is strange.. stupid even.

I can look into Perl later.. I don't remember much about it.
 
Ok.. I know this much:
The purpose of this code (int($lon/2)*2) is to return the integer part of the number. The division and multiplication by 2 makes also differense. For example numbers through 2 to 3.999 all result in 2.

This code: (int($lat/1)*1) is just an ordinary truncation, I think.
 
I don't know Basic well enough, but if I try to convert the math into C, would that help?

Edit: Actually all I would have to do is to change all int() calls to floor() :) so, I won't do that.
The ord() function just returns the ascii value of the character.
 
I think the problem is that you are making floating point calculations on byte variables.
You should use single variables ( floats ) which uses a lot of program space or make the calculations on integer constants as misterT said.
For example /(5/60) is divide by zero but multiply by 12 is ok.
 
I'm lost with this 5/60 being the same as multiply by 12 but here is the code I have so far. Everything is working except the last two digits. I'm sure it's because I don't understand how the equation works for the last two digits. Can someone see what's wrong or just explain what the equation is doing. I always seem to get the first part to a 1 or 0 which divided by 0 i'm sure isn't what it's supposed to do. I understand that it takes the ascii character 'a' and adds the calculated value to it. Thus giving a letter a but how does the equation increment? LOST :-(

You should be able to just compile and load this with OSHON and see the results on the virtual LCD.

Code:
'- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
'Maidenhead locator - Written by Paul Swingewood
'13/10/2013  - PIC 16F628A
'--------------------------------------------------------------------------

Define SIMULATION_WAITMS_VALUE = 1


Define CONF_WORD = 0x3f50  'Internal Oscillator'
Define CLOCK_FREQUENCY = 4
AllDigital

'Define the comms for the LCD display.
Define LCD_LINES = 4
Define LCD_CHARS = 16
Define LCD_BITS = 4
Define LCD_DREG = PORTB
Define LCD_DBIT = 4  'Use the high order bits'
Define LCD_RSREG = PORTA
Define LCD_RSBIT = 2
Define LCD_EREG = PORTA
Define LCD_EBIT = 0
Define LCD_RWREG = PORTA
Define LCD_RWBIT = 1
Define LCD_READ_BUSY_FLAG = 1


Define LCD_COMMANDUS = 5000  'delay after LCDCMDOUT, default value is 5000
Define LCD_DATAUS = 100  'delay after LCDOUT, default value is 100
Define LCD_INITMS = 20


'--------------------------------------------------
'variables
'----------------------------------------------------
Dim lng As Byte
Dim lat As Byte
Dim i As Byte  'used as array element loop
Dim pos As Byte

Dim temp1 As Byte
Dim temp2 As Byte
Dim temp3 As Byte
Dim temp4 As Byte
Dim temp5 As Byte
Dim temp6 As Byte


Dim loc(5) As Byte


startup:
Lcdinit LcdCurBlink
Lcdcmdout LcdClear
WaitMs 2000  'Give everything time to power up 2 seconds?




start:



'calcualte the locator
Call calc_loc(44, 1, 0)

'Display the locator
pos = 5
For i = 0 To 5
Lcdcmdout LcdLine4Pos(pos)
Lcdout loc(i)
pos = pos + 1
Next i

Goto start
End                                             


'-------------------------------------------------
'Procedures
'-------------------------------------------------
Proc calc_loc(arglat As Byte, arglng As Byte, argew As Byte)
If argew = 0 Then
    If arglng <= 0 Then
        lng = 178
    Else  'west
        lng = 180 - arglng
    Endif
Else
    lng = arglng + 180
Endif

lat = arglat + 90


loc(0) = (lng / 20) + 65  '65 = ascii A

loc(1) = 65 + (lat / 10)

loc(2) = 48 + ((lng Mod 20) / 2)  '48 = Ascii zero

loc(3) = 48 + ((lat Mod 10) / 1)

temp1 = lng / 2  '179/2=89
temp2 = temp1 * 2  '89*2=178
temp3 = lng - temp2  '179 - 178 = 1

temp4 = temp3 / (5 / 60)
loc(4) = temp4
'loc(4) = 97 + ((lng - ((lng / 2) * 2)) / (5 / 60)))
'$grid .= chr(ord('a') + int(($lon - (int($lon/2)*2)) / (5/60)));
'$grid.= chr(ord(  'a') + int(($lat - (int($lat/1)*1)) / (2.5/60)));

End Proc                                         

'--------------------------- O R I G I N A L   C O D E -----------------------------------
'#! / usr / bin / perl - W
'# (C) 2012 Chris Ruvolo.  Licensed under a 2-clause BSD license.
'If($ #argv < 1) {
'printf("Usage: $0 <lat> <long>\n");
'Exit(1);
'}

'my $lat = $ARGV[0];
'my $lon = $argv[1];
'my $grid = "";

'$lon = $lon + 180;
'$lat = $lat + 90;

'$grid .= chr(ord('A') + int($lon / 20));
'$grid .= chr(ord('A') + int($lat / 10));
'$grid .= chr(ord('0') + int(($lon % 20)/2));
'$grid .= chr(ord('0') + int(($lat % 10)/1));
'$grid .= chr(ord('a') + int(($lon - (int($lon/2)*2)) / (5/60)));
'$grid .= chr(ord('a') + int(($lat - (int($lat/1)*1)) / (2.5/60)));

'print "$grid\n";
 
Oops should point out the 3 arguments for call calc_loc (lng, lat, and 1 or 0) 0 means west 1 or anything else means east. Greenwich and all that :)
this **broken link removed** will give you some idea of what the locators should be.

Thanks - Paul
 
The last two digits come from the decimal part of the lat and long.
They will be zero ( aa ) when using integer ( byte ) variables. So you should use floating point variables.

About this 5/60 thing: 5/60 is zero in integer math.
x/zero is infinity which is in Oshon Basic 255 :)
If you add 255 to byte variable z you get z-1 when z is>0

5/60 = 0.0833... x/0.08333... = 12*x which is ok in integer math.
 
If you have floating point support:
Dim lat As Single

It can be done also with byte variables if you put integer and decimal parts in two bytes, but then the calculation is different.
btw. from where do you get the coordinates ?
 
I have just purchased the floating point and 32bit add ons. I thought I already had. Now waiting for licences. I see now how the equation works having gone through it bit by bit on paper.

Will the floating point allow me to store the coordinates as 1.89698 and 52.56216 ( maybe a little shorter accuracy)? This would be really helpful :)

The co-ordinates come from a GPS receiver (Lassen SK8) I have all that bit of the code working fine having used it on another project. The maidenhead project serves no real purpose other than knowing how to do it.

The idea is to take the project outdoors with me when I operate my Ham Radio station portable and know the maidenhead square I am operating from. You can do it with a mobile phone app but where's the fun in that?

I'll let you know how I get on when I have the new licence(s).

I do have a further question but i'll start a new thread for that one.
 
Ok next silly question is there an INT function or similar in OSHON? I can do it another way but it would be easier if this was there.
 
I have just purchased the floating point and 32bit add ons. I thought I already had. Now waiting for licences. I see now how the equation works having gone through it bit by bit on paper.

Will the floating point allow me to store the coordinates as 1.89698 and 52.56216 ( maybe a little shorter accuracy)? This would be really helpful :)

The co-ordinates come from a GPS receiver (Lassen SK8) I have all that bit of the code working fine having used it on another project. The maidenhead project serves no real purpose other than knowing how to do it.

The idea is to take the project outdoors with me when I operate my Ham Radio station portable and know the maidenhead square I am operating from. You can do it with a mobile phone app but where's the fun in that?

I'll let you know how I get on when I have the new licence(s).

I do have a further question but i'll start a new thread for that one.

You can store the coordinates as 1.8969.. , I think with 6 digit accuracy.

I got your code working with floating point variables.
Floating point math is missing the mod function so I wrote a Basic function for it.

Compiled code takes 1726 program words.
PIC16F628 may be too small depending of your other code.

Code:
'- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
'Maidenhead locator - Written by Paul Swingewood
'13/10/2013  - PIC 16F628A
'--------------------------------------------------------------------------

Define SIMULATION_WAITMS_VALUE = 1


Define CONF_WORD = 0x3f50  'Internal Oscillator'
Define CLOCK_FREQUENCY = 4
AllDigital

'Define the comms for the LCD display.
Define LCD_LINES = 4
Define LCD_CHARS = 16
Define LCD_BITS = 4
Define LCD_DREG = PORTB
Define LCD_DBIT = 4  'Use the high order bits'
Define LCD_RSREG = PORTA
Define LCD_RSBIT = 2
Define LCD_EREG = PORTA
Define LCD_EBIT = 0
Define LCD_RWREG = PORTA
Define LCD_RWBIT = 1
Define LCD_READ_BUSY_FLAG = 1


Define LCD_COMMANDUS = 5000  'delay after LCDCMDOUT, default value is 5000
Define LCD_DATAUS = 100  'delay after LCDOUT, default value is 100
Define LCD_INITMS = 20


'--------------------------------------------------
'variables
'----------------------------------------------------
Dim lng As Single
Dim lat As Single
Dim i As Byte  'used as array element loop
Dim pos As Byte
Dim tmp As Byte
Dim tmp2 As Single
Dim loc(5) As Byte

startup:
Lcdinit LcdCurBlink
Lcdcmdout LcdClear
WaitMs 2000  'Give everything time to power up 2 seconds?

start:

'calcualte the locator
Call calc_loc(60.17, 24.94, 1)  'Helsinki KP20le

'Display the locator
pos = 5
For i = 0 To 5
Lcdcmdout LcdLine4Pos(pos)
Lcdout loc(i)
pos = pos + 1
Next i
Break
'Goto start
End                                            


'-------------------------------------------------
'Procedures
'-------------------------------------------------
Proc calc_loc(arglat As Single, arglng As Single, argew As Byte)
If argew = 0 Then
If arglng <= 0 Then
lng = 178
Else  'west
lng = 180 - arglng
Endif
Else
lng = arglng + 180
Endif

lat = arglat + 90

loc(0) = 65 + lng / 20  '65 = ascii A

loc(1) = 65 + lat / 10

loc(2) = 48 + modulus(lng, 20) / 2  '48 = Ascii zero

loc(3) = 48 + modulus(lat, 10) / 1

tmp = lng / 2
tmp = tmp * 2
tmp2 = lng - tmp
loc(4) = 97 + tmp2 * 12

tmp = lat / 1
tmp = tmp * 1
tmp2 = lat - tmp

loc(5) = 97 + tmp2 * 24

End Proc                                        

Function modulus(arg1 As Single, arg2 As Single) As Single
Dim x As Byte
Dim y As Single
y = arg1 / arg2
x = y
modulus = (y - x) * arg2 + 0.001  '0.001 is for small errors in floating point math
End Function                                    



'--------------------------- O R I G I N A L  C O D E -----------------------------------
'#! / usr / bin / perl - W
'# (C) 2012 Chris Ruvolo.  Licensed under a 2-clause BSD license.
'If($ #argv < 1) {
'printf("Usage: $0 <lat> <long>\n");
'Exit(1);
'}

'my $lat = $ARGV[0];
'my $lon = $argv[1];
'my $grid = "";

'$lon = $lon + 180;
'$lat = $lat + 90;

'$grid .= chr(ord('A') + int($lon / 20));
'$grid .= chr(ord('A') + int($lat / 10));
'$grid .= chr(ord('0') + int(($lon % 20)/2));
'$grid .= chr(ord('0') + int(($lat % 10)/1));
'$grid .= chr(ord('a') + int(($lon - (int($lon/2)*2)) / (5/60)));
'$grid .= chr(ord('a') + int(($lat - (int($lat/1)*1)) / (2.5/60)));

'print "$grid\n";
 
Last edited:
Hi. Original code author here. I wrote this Maidenhead grid code to maximize readability and consistency as a teaching aid. Indeed the code:

Code:
int($lat/1)*1

can be replaced by:

Code:
int($lat)

Likewise, many of the dividing operations could be replaced by multiply operations for embedded systems where dividing is expensive.

Let me know if you have any questions I can help with.

Glad to see the code used and translated.

Cheers.
-Chris
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top