Floating Point problem using PIC18F4550

cfloating pointmicrocontrollerpic

I'm making an obstacle avoiding robot and using the mentioned PIC controller. I'm currently not at the obstacle avoiding part so what i'm doing is writing code to control the movement, e.g. making it go in a rectangular loop. The way it works is that I have made functions for going straight, turning left/right and one for a small 2 second halt on both wheels called pause. In the straight function I pass an RPM value and a Distance, the function then has to figure out how long this velocity has to be maintained to travel the specified distance. It does this by passing the data to a counts_cal function which returns the value of the counts to be used and then the wheel speeds are set and the counts are sent to a timer function to produce the desired timing. Now the problem is that the counts_cal function isn't working and I think its because of the floats I have used and somehow the conversion from float to long isn't producing what its supposed to. The timer function and the rest works since when I directly passed the counts from straight to timer and bypassed the counts_cal, it all worked fine. But bypassing it is not really an option and I need help because I'm out of my depth with this floating point stuff in micro controllers. When i try this code as it is shown here, what happens is that it acts as if there is no delay on the straight and turn left functions but works fine for the pause since I have passed the counts manually there.

I'm showing code for only the straight function and ignoring the turn_right/left and pause because they are exactly similar in their function.

Here is the relevant code part :

//----------FUNCTION DECLARATIONS-----------//

void send_pos_right (int data);              //Transmit sequence to right wheel(forward)
void send_pos_left (int data);               //Transmit sequence to left wheel(forward)
void straight(int rpm, float dist);         //go straight at certain rpms for certain dist
void turn_left(void);                       //make 90 degree left
void turn_right(void);                      //make 90 degree right
void pause(void);                           //halt both wheels for a brief time (2sec)

void timer(unsigned long counts);                 //produces required time delay based on counts
unsigned long counts_cal (int rpm, float dist);   //calculates number of counts required for travel

//..........GLOBAL VARIABLES...........//

float circum = 0.3989823;           //circumference of wheels
float mc = 0.0000512;               //timer period with 256 prescaler
int turning_rpm = 30;               //standard turning velocity
float turning_dist = 0.44;          //distance to make a 90 degree turn

//............MAIN CODE.............//

void main(void)
{

while(1)
{
    straight(60,4);
    pause();
    turn_left();
    pause();

   }
}

void straight(int rpm, float dist)
{
    unsigned long counts = counts_cal(rpm,dist);
    send_pos_right(rpm);
    send_pos_left(rpm);
    timer(counts);
}

void timer(unsigned long counts)
{
    unsigned char loader_H, loader_L;
    int reps = counts/65536;                        //calculates number of complete reloads required
    unsigned long sub_reps = counts-(reps*65536);   //calculates number of counts required after the complete reloads (semi relaod)
    long value = 65536 - sub_reps;                  //calculates value to load into TMR0H & TMR0L for the semi reload
    T0CON = 0x07;                                   //timer off, 256 prescaler

    while(reps>0)                   //performs the number of complete 16bit timer reloads
    {
        TMR0H = 0x00;
        TMR0L = 0x00;
        T0CONbits.TMR0ON=1;
        while(INTCONbits.TMR0IF==0);
        T0CONbits.TMR0ON=0;
        INTCONbits.TMR0IF=0;
        reps-=1;
    }

    if ((reps==0) && (sub_reps>0))  //performs the semi 16bit timer reload
    {
        loader_H = (value&0xFF00)>>8;
        loader_L = (value&0x00FF);
        TMR0H = loader_H;
        TMR0L = loader_L;

        T0CONbits.TMR0ON=1;
        while(INTCONbits.TMR0IF==0);
        T0CONbits.TMR0ON=0;
        INTCONbits.TMR0IF=0;
    }

}

unsigned long counts_cal (int rpm, float dist)
{
    float rps = rpm/60.0;
    float v = circum * rps;
    float t = dist/v;
    float temp = t/mc;
    unsigned long counts = (unsigned long)(temp);
    return(counts);                                 //returns counts which are required to produce desired time delay
}

Best Answer

So I sort of figured out how to get this running myself. What I had done previously was this;

unsigned long counts_cal (int rpm, float dist)
{
    float rps = rpm/60.0;
    float v = circum * rps;
    float t = dist/v;
    float temp = t/mc;
    unsigned long counts = (unsigned long)(temp);
    return(counts);                                 //returns counts which are required to produce desired time delay

}

But then I noticed that floats were causing problems when I equated the floats to ints and I thought it might be due to errors of truncation when converting to int or long, so I tried something a little different and boiled down the first 5 lines into 1 line after some algebraic manipulation and it worked.I think this worked because now all the multiplications are happening before the division and then when the division + conversion does take place, the truncated value has a very forgivable error (off by less than 100 ms from what I've observed).The PWMs are being maintained for the required timing and all is well. The working method was this;

unsigned long counts_cal (int rpm, float dist)
{
    unsigned long counts = (dist*60*78125)/(4*circum*rpm);
    return(counts);

}