Tuesday 6 October 2015

stm32 - How to interpret the values sent by an MPU-9255?


Well, I am using this holiday in Brazil to improve my skills in C. I have learned how to use I2C and how to communicate with the MPU9255 (with help from this question). The last trouble I am facing is that the sensor is returning wrong values. The value returned is floating from 0 to 65000, but it is not linear.


I think that is because I am making some confusion on the data types or bytes merge on my code. Can someone help me revising my code?



    uint8_t Test[] = "\n AccelX: \n";
HAL_UART_Transmit(&huart1,Test,sizeof(Test),100);

//SET X_HIGH REGISTER ADDRESS
i2cData = 0x3B;
HAL_I2C_Master_Transmit(&hi2c1, adressMPU, &i2cData, 1, 100);

//REQUEST 6 BYTES OF DATA (ACCEL X, Y AND Z)
HAL_I2C_Master_Receive(&hi2c1, adressMPU, receive_buffer, 6, 100);


AccelX = (char)receive_buffer[0]<<8 | (char)receive_buffer[1];
AccelY = (char)receive_buffer[2]<<8 | (char)receive_buffer[3];
AccelZ = (char)receive_buffer[4]<<8 | (char)receive_buffer[5];

//PRINTA NA SERIAL 1
len = sprintf(buffer, " %i\r\n", AccelX); //sprintf will return the length of 'buffer'
HAL_UART_Transmit(&huart1, (uint8_t *)buffer, len, 1000);

HAL_Delay(500);




Update:


I just noted one thing: from 0 to 16768, the sensor measurements are right, but when I upside the axis, the sensor goes from 65536 to ~49000 when should be from 0 to -16768. Surely is a conversion error, but I still not can see where exactly is the error.



Answer



The MPU-9255 is giving you a 16-bit, signed integer. Your code is interpreting it as unsigned.


An unsigned, 16-bit number can represent values from 0 to 65535. A signed 16-bit number represents -32768 to +32767.


Here is an 8-bit example from Wikipedia:


SignedUnsigned


To make the conversion, first look at the high bit. If it is \$0\$, then no conversion is necessary. If it is \$1\$, then \$signed = (unsigned - 2^N)\$, where \$N\$ is the number of bits. Sixteen, in your case.


Here is a simple method for 16 bits:



uint16_t unsignedAccelX;
int16_t signedAccelX;

if (unsignedAccelX < 32768)
{
signedAccelX = unsignedAccelX;
}
else
{
signedAccelX = unsignedAccelX - 65536;

}

There are many more elegant and/or efficient ways of doing this. There is some discussion here.


Good luck!


No comments:

Post a Comment

arduino - Can I use TI&#39;s cc2541 BLE as micro controller to perform operations/ processing instead of ATmega328P AU to save cost?

I am using arduino pro mini (which contains Atmega328p AU ) along with cc2541(HM-10) to process and transfer data over BLE to smartphone. I...