Electronic – dspic MPU6050 calibration problem

imupic

I use dspic33fj128gp802 and MPU6050 for my project. Microcontroller succesfully takes the data from sensors 6 channel and sends the data pc via UART. When i want to add "float 2.0" or "int 2" to accelerometer data for calibration it stops to send data to uart. I've tried all of data type combinations but it always fails. I only add one line of code to my source code but when i add, the code doesn't send data to PC. I use MikroC pro for dspic. The newly added line can be seen in source code as bold in function of Extract_Readings. This newly added line does not generate any compiling or debugging error.

accel_z = (float) accel_z + 2.0;

As a solution when i change the last line to accel_z = (float) accel_z / 2.0;

it succesfully divides the result to 2. As a summary, dividing operator works well but addition operator does not work.

I cannot find any solution. I am waiting for your considerations.

Thank you.

The source code is below:

 #include "MPU_IMU_Register_Map.h"

unsigned int raw_data[7];

sbit INT at RB7_bit;
sbit INT_Direction at TRISB7_bit;

int gyro_x_temp, gyro_y_temp, gyro_z_temp, accel_x_temp, accel_y_temp, accel_z_temp, temp_raw;
char i, buff, gyro_x_out[15], gyro_y_out[15], gyro_z_out[15], accel_x_out[15], accel_y_out[15], accel_z_out[15], temp_out[15];
float temp, gyro_x, gyro_y, gyro_z, accel_x, accel_y, accel_z;

void MCU_Init(){
  ADPCFG = 0xffff;

  TRISBbits.TRISB10 = 1;
  TRISBbits.TRISB11 = 0;
  Delay_ms(100);

  RPINR18bits.U1RXR = 10;
  RPOR5bits.RP11R   = 3;

  INT_Direction = 1;
  I2C1_Init(400000);
  Delay_ms(100);

  Delay_ms(100);
  UART1_Init_Advanced(19200, 1, 1, 1);
  Delay_ms(600);

  UART1_Write_Text("MCU Ready\n");
  Delay_ms(100);
}
void MPU_I2C_Write(unsigned char s_addr, unsigned char r_addr, unsigned char len, unsigned char *dat) {
 unsigned int i;
 I2C1_Start();                         // issue I2C start signal
 I2C1_Write(s_addr & 0xFE);            // send byte via I2C  (device address + W(&0xFE))
 I2C1_Write(r_addr);                   // send byte (address of EEPROM location)
 for (i = 0 ; i < len ; i++){
  I2C1_Write(*dat++);                 // send data (data to be written)
 }
 I2C1_Stop();                          // issue I2C stop signal

}

void MPU_I2C_Read(unsigned char s_addr, unsigned char r_addr, unsigned char len, unsigned char *dat) {
 unsigned int i;
 I2C1_Start();                         // issue I2C start signal
 I2C1_Write(s_addr & 0xFE);            // send byte via I2C  (device address + W(&0xFE))
 I2C1_Write(r_addr);                   // send byte (data address)
 I2C1_Restart();                       // issue I2C signal repeated start
 I2C1_Write(s_addr | 0x01);            // send byte (device address + R(|0x01))
 for (i = 0; i < (len-1); i++){
  *dat++ = I2C1_Read(_I2C_ACK);       // Read the data (acknowledge)
  }
  *dat = I2C1_Read(_I2C_NACK);          // Read the data (NO acknowledge)
 I2C1_Stop();                          // issue I2C stop signal
 }

void MPU_I2C_Read_Int(unsigned char s_addr, unsigned char r_addr, unsigned char len, unsigned char *dat) {
  unsigned int i;
  unsigned short *pt;
  I2C1_Start();                         // issue I2C start signal
  I2C1_Write(s_addr & 0xFE);            // send byte via I2C  (device address + W(&0xFE))
  I2C1_Write(r_addr);                   // send byte (data address)
  I2C1_Restart();                       // issue I2C signal repeated start
  I2C1_Write(s_addr | 0x01);            // send byte (device address + R(|0x01))
  for (i = 0 ; i < ((len << 1)-1) ; i++){
   if (i%2) {
     pt = pt - 1;
   }
   else {
     pt = dat + i + 1;
   }
    *pt = I2C1_Read(_I2C_ACK);          // Read the data (acknowledge)
  }
  *(pt - 1) = I2C1_Read(_I2C_NACK);     // Read the data (NO acknowledge)
  I2C1_Stop();                          // issue I2C stop signal
}


void MPU_Init(){
 MPU_I2C_Write(mpu_I2C_ADDR, mpu_rm_PWR_MGMT_1 , 1, 0x80);
 Delay_ms(100);
 MPU_I2C_Write(mpu_I2C_ADDR, mpu_rm_PWR_MGMT_1 , 1, 0x00);
 Delay_ms(100);

 MPU_I2C_Write(mpu_I2C_ADDR, mpu_rm_FIFO_EN , 1, 0x78);
 Delay_ms(100);

 MPU_I2C_Write(mpu_I2C_ADDR, mpu_rm_INT_ENABLE , 1, 0x10);
 Delay_ms(100);

 MPU_I2C_Read (mpu_I2C_ADDR, mpu_rm_ACCEL_CONFIG, 1, &raw_data);
 Delay_ms(100);


 MPU_I2C_Read (mpu_I2C_ADDR, mpu_rm_INT_ENABLE, 1, &raw_data);
 Delay_ms(100);

 raw_data[0] |= 0x11;
 MPU_I2C_Write(mpu_I2C_ADDR, mpu_rm_INT_ENABLE, 1, &raw_data[0]);
 Delay_ms(100);
 UART1_Write_Text("MPU6050 Hazir\n");

}
void Extract_Readings() {

 accel_x_temp = raw_data[0];
 accel_x = (float)accel_x_temp / 2048.0;
 accel_y_temp = raw_data[1];
 accel_y = (float)accel_y_temp / 2048.0;
 accel_z_temp = raw_data[2];
 accel_z = (float)accel_z_temp / 2048.0;
 **accel_z = (float) accel_z + 2.0;** //When this line deleted or changed to accel_z = (float) accel_z /2.0, code works well

 temp_raw = raw_data[3];

 temp = (float)temp_raw / 325.0;

 gyro_x_temp = raw_data[4];
 gyro_x = (float)gyro_x_temp / 131.0;
 gyro_y_temp = raw_data[5];
 gyro_y = (float)gyro_y_temp / 131.0;

 gyro_z_temp = raw_data[6];
 gyro_z = (float)gyro_z_temp / 131.0;

}
void Convert_Readings_To_String() {

FloatToStr(accel_x, accel_x_out);
FloatToStr(accel_y, accel_y_out);
FloatToStr(accel_z, accel_z_out);


FloatToStr(temp, temp_out);


FloatToStr(gyro_x, gyro_x_out);
FloatToStr(gyro_y, gyro_y_out);
FloatToStr(gyro_z, gyro_z_out);

}


void Print_Readings() {

 Delay_ms(500);
 UART1_Write_Text("\nGyro readings:\n");
 UART1_Write(0x0D);
 UART1_Write_Text("\nx = \n");
 UART1_Write_Text(gyro_x_out);
 UART1_Write(0x0D);
 UART1_Write_Text("\ny = \n");
 UART1_Write_Text(gyro_y_out);
 UART1_Write(0x0D);
 UART1_Write_Text("\nz = \n");
 UART1_Write_Text(gyro_z_out);
 UART1_Write(0x0D);
 UART1_Write(0x0D);
 UART1_Write(0x0D);


 UART1_Write_Text("\nAccel readings:\n");
 UART1_Write(0x0D);
 UART1_Write_Text("\nx = \n");
 UART1_Write_Text(accel_x_out);
 UART1_Write(0x0D);
 UART1_Write_Text("\ny = \n");
 UART1_Write_Text(accel_y_out);
 UART1_Write(0x0D);
 UART1_Write_Text("\nz = \n");
 UART1_Write_Text(accel_z_out);
 UART1_Write(0x0D);
 UART1_Write(0x0D);
 UART1_Write(0x0D);


 UART1_Write_Text("\nTemperature readings (Celsius) = ");
 UART1_Write_Text(temp_out);
 UART1_Write(0x0D);
 UART1_Write(0x0D);
 UART1_Write(0x0D);
 Delay_ms(1000);


}
void main() {

 MCU_Init();
 MPU_Init();
 while(1) {
 while(INT != 1)
  ;
 MPU_I2C_Read_Int(mpu_I2C_ADDR, mpu_rm_ACCEL_XOUT_H, 7, &raw_data);
 Extract_Readings();
 Convert_Readings_To_String();
 Print_Readings();
}


}   

Best Answer

The problem you are having is floating point precision. As a rule of thumb, DON'T use floating points if you can avoid it.

Plenty has been written about why not to use them, so I won't go into too much detail. See link.

What you are probably getting is rounding errors and most likely running out of stack and heap. For example 0.1, the simplest decimal number you can think of, looks like this in 32bit binary:

0.1 (Most accurate representation) = 1.00000001490116119384765625E-1e
Exponent        Mantessa
01111011        10011001100110011001101

In reality this number continues rounding to infinity.

Simple solution, DON'T use floats, just simply multiply all your sensor reading by 1000 to get rid of the decimal and read them in Milli precision.