|
|
View previous topic :: View next topic |
Author |
Message |
erhane
Joined: 01 Jul 2014 Posts: 41
|
Data conversion problem [Solved] |
Posted: Mon Jul 07, 2014 2:24 am |
|
|
I am using dspic30f6015.
I am taking position in micrometers byte by byte and covert it to distance then send it to step integer for microstepping value and read step integer via rs232.
The problem is if data_position_got[1] greater than 3 there is a calculation problem occurs.
For example:
if i give 949999 in decimal = it is converted to 0x38 0x38 0x75 0xC9 0x33 0x35
if i give 999999 in decimal = it is converted to 934463
if i give 939999 in decimal = it is converted to 939999
if i give 929999 in decimal = it is converted to 929999
if i give 919999 in decimal = it is converted to 919999
Another time:
if i first give 100000 = it is converted to 100000
then if i give 040000 = it is also converted to 100000. no change.
too weird :S
There is a logic error or variable mismatch i think but couldn't find it.
There is my code:
Code: |
char data_position_got[6] = {0,0,0,0,0,0};
char data_set[11] = {0,0,0,0,0,0,0,0,0,0,0};
char data_go[11] = {1,1,1,1,1,1,1,1,1,1,1};
char reg_rs485_message=0;
unsigned int32 x_current_position= 0;
unsigned int32 y_current_position= 0;
char data_got=0;
char go_setted=0;
unsigned int32 step=0;
unsigned int32 backup_step=0;
unsigned int32 distance_um=0;
unsigned int step_for_10um;
char data_x_setted=0;
char data_y_setted=0;
void configure_data()
{
distance_um=(data_position_got[0]*100000)+(data_position_got[1]*10000)+(data_position_got[2]*1000)+(data_position_got[3]*100)+(data_position_got[4]*10)+(data_position_got[5]);
step=(distance_um);
if(distance_um<=3000000)
{
backup_step=step;
data_set[3]=(backup_step/100000);
step=step-(data_set[3]*100000);
backup_step=step;
data_set[4]=(backup_step/10000);
step=step-(data_set[4]*10000);
backup_step=step;
data_set[5]=(backup_step/1000);
step=step-(data_set[5]*1000);;
backup_step=step;
data_set[6]=(backup_step/100);
step=step-(data_set[6]*100);
backup_step=step;
data_set[7]=(backup_step/10);
step=step-(data_set[7]*10);
backup_step=step;
data_set[8]=step;
}
void send_data()
{
for (int i=0;i<11;i++)
{
delay_ms(10);
fputc(data_set[i]+48,RS232);
}
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19516
|
|
Posted: Mon Jul 07, 2014 2:52 am |
|
|
Haven't looked in detail, but I'd suspect the problem is a partial overflow:
distance_um=(data_position_got[0]*100000)+(data_position_got[1]*10000)+(data_position_got[2]*1000)+(data_position_got[3]*100)+(data_position_got[4]*10)+(data_position_got[5]);
Now each part of this maths, is a sub-component. Executed separately.
(data_position_got[2]*1000)
Will execute correctly. 1000 is a 'long' integer, and data_position_got[2] is a char, so the latter will get promoted to be a long integer and the sum performed correctly. Same applies with the 100000, and 10000 sections (though see below..).
But:
(data_position_got[3]*100)
has a problem. 100, is an int8. data_position_got[3] is a char (also int8), so this sum will be done using int8 arithmetic. It'll overflow when this character is greater than 2. Result, problem....
(data_position_got[3]*100L)
Note the 'L'. This now again uses long integer arithmetic, and will work correctly.
The problem won't appear for the 10, or 1 factors, since these give results less than 255, so will function OK with int8 arithmetic.
The problem 'recurs' with the 10000 factor, since this is an int16 long, and in int16 arithmetic this can overflow.
Consider doing the sum as a single loop.
So:
Code: |
int8 ctr;
distance_um=0;
for (ctr=0;ctr<6;ctr++)
{
distance_um*=10;
distance_um+=data_position_got[ctr];
}
|
This ensures the multiplication is all done 'in' the int32 value, and avoids the problem.
You do realise you can output the number with printf?. No need for all the 'step' calculations.
Code: |
if(distance_um<=3000000)
fprintf(RS232,"%011Lu",distance_um);
|
Last edited by Ttelmah on Mon Jul 07, 2014 3:14 am; edited 1 time in total |
|
|
erhane
Joined: 01 Jul 2014 Posts: 41
|
|
Posted: Mon Jul 07, 2014 3:10 am |
|
|
Thank you for printf suggestion i will change it.
I think problem is not in sum part. Because i did it as you told me in loop.
Is there any algorithm example which converts an integer in to an array?
Code: |
backup_step=step;
data_set[4]=(backup_step/10000);
step=backup_step-(data_set[4]*10000);
|
at this part i have problem i think. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19516
|
|
Posted: Mon Jul 07, 2014 3:28 am |
|
|
The same problem appears with the way you are doing this conversion. The data_set array entries are characters, so when you do:
step=step-(data_set[6]*100);
It'll use int8 arithmetic for the multiplication, and
step=step-(data_set[4]*10000);
It'll use int16 arithmetic.
Again the result will overflow, and the function will go wrong....
For the output, you do need the array?.
Otherwise the printf version is much easier.
You could sprintf, and just subtract '0' (ASCII) from the digits to get what you want in the array. Remember the target array for sprintf, will need to be one character larger to allow for the terminator.
Annoyingly, the compile has a function 'div', and 'ldiv' for long integers (int16), which will return both the quotient, and remainder of a division, which makes this type of conversion much easier, but doesn't offer a 32bit version of this.
You do realise that data_set[3] could end up containing 29 with your code as posted?. You also don't initialise data_set[0] or 1. |
|
|
erhane
Joined: 01 Jul 2014 Posts: 41
|
|
Posted: Mon Jul 07, 2014 4:33 am |
|
|
I changed some types of my variables and used your loop and solved it. Thank you |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19516
|
|
Posted: Mon Jul 07, 2014 1:24 pm |
|
|
Good.
Flag the thread as 'solved' please. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|