2
\$\begingroup\$

Interpreting LSM303DLHC Accelerometer Output

Hi all, This is my first StackExchange question ever, so I will do my best to be specific and offer as much reference as possible. I'm currently working on a navigation module which uses a PIC16F873A microcontroller to read data from a GPS via the USART module and from a LSM303DLHC Magnetometer/Accelerometer using I2C. At this stage of the project, I'm only trying to use accelerometer data, which I currently do by running the PIC in master mode and reading from the appropriate registers. The way the accelerometer works is the X,Y and Z acceleration data are stored in six different consecutive registers inside of the linear accelerometer register area (i.e. OUT_X_L_A (28h), OUT_X_H_A (29h) ... OUT_Y_L_A (2Ah), OUT_Y_H_A (2Bh) ... OUT_Z_L_A (2Ch), OUT_Z_H_A (2Dh)). My I2C_Accelrometer_Data(unsigned char reg_address, unsigned char ack) function reads in one byte of data at a time so my code will read the low byte and then the high byte from the next register, store them in an array of unsigned chars and add them together. According to the datasheet: LSM303DLHC these bytes are expressed in two's complement form.


A section of my C code (XC8 compiler), which I've partly adapted from here on page #6 handles it as follows:

    unsigned char ACC_Data[6];

                                            ACC_Data[0] = I2C_Accelerometer_Data(0x28, 0);//X_Low Byte
                                            ACC_Data[1] = I2C_Accelerometer_Data(0x29, 0);//X_High_Byte

                                            ACC_Data[2] = I2C_Accelerometer_Data(0x2A, 0);//Y_Low_Byte
                                            ACC_Data[3] = I2C_Accelerometer_Data(0x2B, 0);//Y_High_Byte

                                            ACC_Data[4] = I2C_Accelerometer_Data(0x2C, 0);//Z_Low_Byte
                                            ACC_Data[5] = I2C_Accelerometer_Data(0x2D, 1);//Z_High_Byte

                                            int Ax = (int) (ACC_Data[1] << 8) + ACC_Data[0];
                                            int Ay = (int) (ACC_Data[3] << 8) + ACC_Data[2];
                                            int Az = (int) (ACC_Data[5] << 8) + ACC_Data[4];

                                            char Ax_str[];
                                            char Ay_str[];
                                            char Az_str[];
                                            itoa(Ax_str, Ax, 10);
                                            lcdcmd(0x94);//third row, first column position
                                            send_string(Ax_str);

                                            itoa(Ay_str, Ay, 10);
                                            lcdcmd(0x9E);//third row, 10th column position
                                            send_string(Ay_str);

                                            itoa(Az_str, Az, 10);
                                            lcdcmd(0xD4);//4th row, first column position
                                            send_string(Az_str);

My question is: because the numbers are in two's complement binary, won't that mess up the way they are added especially since the bytes are being stored as unsigned chars? Or can I do simply what I have done above to convert these two bytes to an int? Basically, the goal to get these numbers onto an LCD screen by then converting this integer into the appropriate string, I'm just not sure if I'm using the data correctly here. Thanks in advance for any insight.

\$\endgroup\$
1
\$\begingroup\$

You are sticking the bytes together in the wrong order. since ACC_Data[0] is the low byte, and ACC_Data[1] is the high byte, you need to shift ACC_Data[1] left by 8, and add it to ACC_Data[0] (unshifted) to get the correct int value.

\$\endgroup\$
  • \$\begingroup\$ Oh, I didn't see that! That's a silly mistake on my part. But after that correction I'm still wondering if this method will give me problems. \$\endgroup\$ – Alexander Villa Feb 9 '15 at 3:55
0
\$\begingroup\$

A further complication beyond the previously mentioned byte order of the LSM303DLHC accelerometer is that the accelerometer only have 12 value bits stored in two bytes, counted from MSB.

That means the values that you get have to be divided by 16, this is done in the STM32F3 demo code but is not explained in the LSM303DLHC datasheet. If you attach a debugger and display the received bytes in binary, you will see that the last 4 bits in the LSB are always zero.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.