CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Data conversion problem [Solved]

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
erhane



Joined: 01 Jul 2014
Posts: 41

View user's profile Send private message Send e-mail

Data conversion problem [Solved]
PostPosted: Mon Jul 07, 2014 2:24 am     Reply with quote

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: 19506

View user's profile Send private message

PostPosted: Mon Jul 07, 2014 2:52 am     Reply with quote

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

View user's profile Send private message Send e-mail

PostPosted: Mon Jul 07, 2014 3:10 am     Reply with quote

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: 19506

View user's profile Send private message

PostPosted: Mon Jul 07, 2014 3:28 am     Reply with quote

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

View user's profile Send private message Send e-mail

PostPosted: Mon Jul 07, 2014 4:33 am     Reply with quote

I changed some types of my variables and used your loop and solved it. Thank you Smile
Ttelmah



Joined: 11 Mar 2010
Posts: 19506

View user's profile Send private message

PostPosted: Mon Jul 07, 2014 1:24 pm     Reply with quote

Good. Smile

Flag the thread as 'solved' please.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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