View previous topic :: View next topic |
Author |
Message |
eng.alamin
Joined: 08 Sep 2008 Posts: 17
|
problem with pic18f4550 in mathematics {solved} |
Posted: Mon Sep 08, 2008 11:59 am |
|
|
hello
I am trying to develop gps data logger.
So i have to receive data serially from gps module and store longitude and latitude each in Double variables to allow me to make mathematical operators.
GPS module transmit this package
($GPGLL,2447.2073,N,12100.5022.E)
What i want to do is load
Double lon = 2447.2073 ;
and
Double lat = 12100.5022 ;
But i felt to catch these two variables direct from rs232 receiving pin.
So i did some magic and load all data in array.
int buffer[31] ;
By this code all incoming serial data will store in buffers array.
Code: |
for (x = 0 ; x ==31 ; x++)
{
buffer[x] = getc() ;
} |
Then i found that buffer array is content the ASCII code of incoming data :(
So i did some trick to convert ASCII code to correct integers
by using switch.
Code: |
for(x = 0 ; x ==31 ; x++)
{
switch(buffer[x])
case 48 : buffer[x] == 0 ;
break;
...
...
...
case 57 : buffer[x] == 9 ;
break;
}
|
and finally to load data in lon and lat variable in correct way i did this
Code: | lon = buffer[7]* 1000 + buffer[8]*100 + buffer[9]*10 + buffer[10] |
The outcome
It suppose to be = 2447
But its came weird strange number :(
But when i check buffers they are all right all contents of corrects integer.
Please tell me what is problem.
regards
Last edited by eng.alamin on Wed Sep 10, 2008 5:39 am; edited 1 time in total |
|
|
meereck
Joined: 09 Nov 2006 Posts: 173
|
|
Posted: Mon Sep 08, 2008 12:51 pm |
|
|
what about using function atoi()
however your for loop is wrong:
for (x = 0 ; x ==31 ; x++)
it should be:
for (x = 0 ; x <31 ; x++)
you also dont need switch()
just subtract the value of 48 (which is 0x30 in hex) from the character
e.g. buffer[i]-=0x30 |
|
|
Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
|
Posted: Mon Sep 08, 2008 12:54 pm |
|
|
Our brains only comprehend numbers through notation. For example lat = 12100.5022 is 121 degrees in base 180 notation 00 minutes in base 60 notation and .5022 fractions of a minute in base 10 decimal notation. The digits are further encoded in ascii. Now to put a mixed base into PIC internal binary floating point notation requires an idea of the precision that may be lost in changing notations. PIC Floating point binary is exact in terms of base two mathematics. However, it is only able to contain certain values of decimal notated numbers exactly ( this is not an error just a fact of mathematics). Further due to finite 4 byte storage truncation will also occur. This truncation will occur at about 6 to 7 decimal digits but even 0.1 will never be able to be represented in binary notation exactly. 12100.5022 has nine digits neglecting the mixed bases in its representation of navigational position so serious truncation must occur often.
Suggestion:
Bring the number into binary integer notation. An byte integer for degrees and a byte integer for minutes and a two byte integer for fractions of a minute. These internal binary integers will be exact. Converting from ascii encoding to binary values can take advantage of the fact that digits 0 to 9 are ascii values 48 to 57
so binval=asciival-48 can be an alternative to a messy case statement. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Sep 08, 2008 1:11 pm |
|
|
There are many previous posts on this topic, with lots of sample code.
Do a search for:
Set it to: "Search for all words"
or do a search for:
Link to the forum's search page:
http://www.ccsinfo.com/forum/search.php |
|
|
Guest
|
|
Posted: Mon Sep 08, 2008 3:26 pm |
|
|
meereck wrote: | what about using function atoi()
however your for loop is wrong:
for (x = 0 ; x ==31 ; x++)
it should be:
for (x = 0 ; x <31 ; x++)
you also dont need switch()
just subtract the value of 48 (which is 0x30 in hex) from the character
e.g. buffer[i]-=0x30 |
atoi is not working .
ya it's wrong i guess i used (=<) .
thanks for this method (buffer[i]-=0x30) i'll use it .
by the way my problem is not load incoming data into buffers
i load it successfully and i chick it , each number is in correct buffer
to load digits from buffers to (lat) which is double variable
i used this method
example: 2447 = ( 2 * 100) +( 4 * 100) + (4 * 10) + 7
this type of operation never done successful by pic c and pic18f4550
but when i used pic16f877a it worked perfect.
most of exampls expane how to read gps data and display it wither on lcd or to pc but i have to load longitude and latitude into double variable to do some mathematical calculation (distance - pearing .... etc ) |
|
|
Guest
|
|
Posted: Mon Sep 08, 2008 3:42 pm |
|
|
Douglas Kennedy wrote: | Our brains only comprehend numbers through notation. For example lat = 12100.5022 is 121 degrees in base 180 notation 00 minutes in base 60 notation and .5022 fractions of a minute in base 10 decimal notation. The digits are further encoded in ascii. Now to put a mixed base into PIC internal binary floating point notation requires an idea of the precision that may be lost in changing notations. PIC Floating point binary is exact in terms of base two mathematics. However, it is only able to contain certain values of decimal notated numbers exactly ( this is not an error just a fact of mathematics). Further due to finite 4 byte storage truncation will also occur. This truncation will occur at about 6 to 7 decimal digits but even 0.1 will never be able to be represented in binary notation exactly. 12100.5022 has nine digits neglecting the mixed bases in its representation of navigational position so serious truncation must occur often.
Suggestion:
Bring the number into binary integer notation. An byte integer for degrees and a byte integer for minutes and a two byte integer for fractions of a minute. These internal binary integers will be exact. Converting from ascii encoding to binary values can take advantage of the fact that digits 0 to 9 are ascii values 48 to 57
so binval=asciival-48 can be an alternative to a messy case statement. |
what is killing me this .. look at this operation:
if Y is defined as integer
int y ;
y = 2 * 1000 + 4 * 100 + 4 * 10 ;
printf("%U", y) ;
answer will be 2440 and it's a correct answer
but if Y is defined as Double
double y ;
the outcome is really weird -784
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Sep 08, 2008 3:54 pm |
|
|
Quote: | if Y is defined as integer
int y ;
y = 2 * 1000 + 4 * 100 + 4 * 10 ;
printf("%U", y) ;
answer will be 2440 and it's a correct answer
|
Not true. Not in CCS. In CCS, an 'int' is an 8-bit unsigned integer.
Your program above will compile and execute, but it gives me a
result of 13. I don't think you are really running the code listed above.
To actually get 2440, you need to declare 'y' as 'int16'. Also, to display
an int16 value with printf, you need to use "%LU". Note the 'L'. |
|
|
Guest
|
|
Posted: Mon Sep 08, 2008 4:03 pm |
|
|
PCM programmer wrote: | Quote: | if Y is defined as integer
int y ;
y = 2 * 1000 + 4 * 100 + 4 * 10 ;
printf("%U", y) ;
answer will be 2440 and it's a correct answer
|
Not true. Not in CCS. In CCS, an 'int' is an 8-bit unsigned integer.
Your program above will compile and execute, but it gives me a
result of 13. I don't think you are really running the code listed above.
To actually get 2440, you need to declare 'y' as 'int16'. Also, to display
an int16 value with printf, you need to use "%LU". Note the 'L'. |
ya ya your right
what i ment is y = 2 * 100 + 4 * 10 + 4 ;
result is 244
also iused %f when ichange (y ) from int to duoble
sorry for that
regards |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Sep 08, 2008 4:37 pm |
|
|
Is it working now, or do you still have a problem ? |
|
|
Guest
|
|
Posted: Mon Sep 08, 2008 4:54 pm |
|
|
it works in case of y is int only
but it never work when y is double
i still don't know why
if you have any idea to load longitude and latitude as double
please help me ! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Sep 08, 2008 4:58 pm |
|
|
When you have a problem, you need to post a small but complete test
program that demonstrates the problem. Example:
The program below uses your code, and uses %f as you said.
This was tested with vs. 4.069 in the MPLAB simulator.
It displays the following output:
Code: | #include <18F4550.h>
#fuses HS,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
//===============================
void main()
{
double y;
y = 2 * 100 + 4 * 10 + 4;
printf("%f \n\r", y);
while(1);
} |
|
|
|
eng.alamin
Joined: 08 Sep 2008 Posts: 17
|
|
Posted: Mon Sep 08, 2008 5:37 pm |
|
|
this is my code iused Proteus simulator
Code: | #include <18f4550.h>
#include <stdlib.h>
#include <MATH.H>
#fuses HS,NOWDT,NOPROTECT
#use delay(clock=12000000)
#use rs232(baud=4800, xmit=PIN_b4,rcv=PIN_b0,stream=GPS)
void main()
{
int string[31];
int buff[8] ;
byte sync;
double lon ;
double lat ;
char value1;
char value;
int x ;
float des ;
amin:
lon = 0 ;
lat = 0 ;
while(TRUE) {
loop :
sync = getc() ;
if (sync == '$' )
{
for (x = 1 ; x <= 6 ; x++)
{
string[x] = getc() ;
}}else{goto loop ;}
if ( string[3] == 'G' && string[4] == 76 && string[5] == 76 )
{
for (x = 7 ; x <= 30 ; x++)
{
string[x] = getc() ;
}
}
else {goto loop ; }
for(x = 7 ; x <= 30 ; x ++)
{
switch(string[x])
{
case 48 : string[x] = 0;
break;
case 49 : string[x] = 1 ;
break;
case 50 : string[x] = 2;
break;
case 51 : string[x] = 3;
break;
case 52 : string[x] = 4;
break;
case 53 : string[x] = 5;
break;
case 54 : string[x] = 6;
break;
case 55 : string[x] = 7 ;
break;
case 56 : string[x] = 8;
break;
case 57 : string[x] = 9;
break;
}
}
//strcpy(string,"123456789");
//lat = atod(string);
lat = (string[7] * 1000 )+ (string[8] *100) + (string[9] * 10) + (string[10] )+(string[12] *0.1) +(string[13] * 0.01) +(string[14] * 0.001)+(string[15] * 0.0001) ;
lon= (string[19] *10000) +(string[20] *1000) + (string[21] * 100) + (string[22] *10) +(string[23] )+(string[25] *0.1) +(string[26] * 0.01) +(string[27] * 0.001)+(string[28] * 0.0001) ;
printf("%f %C %f %C ", lon ,string[30], lat , string[17] );
}
goto amin; }
|
am using pcw c compiler
idid some quick modification and ididn't compile it you may find some erorr
anyway please tell me what is wrong with it |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Sep 08, 2008 5:46 pm |
|
|
I confess that I don't want to look at it. Reasons:
1. It has goto's in it.
2. It has a switch-case statement to convert ascii to binary integers.
The code is over 20 lines. It could be replaced by 1 line.
Why not just tell us what your purpose is ?
Show the input ASCII, and show the desired output.
I suspect that you are simply trying to parse an incoming NMEA-0183
stream from a GPS. There is tons of sample code on the forum to do that. |
|
|
eng.alamin
Joined: 08 Sep 2008 Posts: 17
|
|
Posted: Mon Sep 08, 2008 6:15 pm |
|
|
will thanks for your words i guess it's hard to learn something this days without get some humiliation .
i just moved from picbasic pro to pic c without any proper education
that why i have those stupid mistake.
any way i saw these (( tons of example )) they all about get data from GPS module and display it or send it
what i need is get data from gps and store longitude and latitude in (variables ) type (double)
i used printf just to be able to see what is store in (lon , lat ) variable
that's all
if you can make it in one line it will be cool
-----------------------
this is the input
$GPGLL,2447.2073,N,12100.5022,E,104548.04,A,A*65
no output need
just store
lon = 2447.2073,
lat = 12100.5022,
lon and lat are double
------------------- |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Mon Sep 08, 2008 6:39 pm |
|
|
eng.alamin wrote: | if you can make it in one line it will be cool |
eng.alamin wrote: | thanks for this method (buffer[i]-=0x30) i'll use it . | You didn't use it or the switch statement would have been replaced by one line... |
|
|
|