Problems with a i2c accelerometer...

Hey guys,
I' ve a problem with an accelerometer, really it' s a magneto with a built-in accelerometer for tilt-compensated output but the two devices work in two different i2c address so I think it' s fine... I' m working with this device LSM303DLH, and I wrote this code to get the accelerometer output...

#include <Wire.h>
#define AXEL 0x18
//Funzione di setup
// Accelerometer address: 0011000b  0x18
// Magnetometer address:  0011110b  0x1E
// Registi di setup acceletometro:
// CTRL_REG1_A address:   0x20  parameters:  0x27
// CTRL_REG4_A address:   0x23  parameters:  0x40
//
// Registri di setup magnetometro:
// CRA_REG_M  address:   0x00  parameters:  0x14
// MR_REG_M   address:   0x02  parameters:  0x00
void lsmsetup(byte address, byte reg, byte setting);
void lsmsetup(byte address, byte reg, byte setting){
  Wire.beginTransmission(address);
  Wire.send(reg);
  Wire.send(setting);
  Wire.endTransmission();
}

//Funzione di lettura dei dati da un registro
int reading(int address, byte reg);
int reading(int address, byte reg){
  byte value;
  Wire.beginTransmission(address);
  Wire.send(reg);
  Wire.endTransmission();
  Wire.requestFrom(address, 1);
  while(Wire.available()){
    value=Wire.receive();
  }return value;
}

byte xlow, ylow, zlow, xhigh, yhigh, zhigh;
int X, Y, Z;
void setup(){
  Serial.begin(9600);
  Wire.begin();
  lsmsetup(AXEL, 0x20, 0x27);
  lsmsetup(AXEL, 0x23, 0x40);
  lsmsetup(0x1E, 0x00, 0x14);
  lsmsetup(0x1E, 0x02, 0x00);
}

void loop(){
  xhigh= reading(AXEL, 0x28);
  xlow= reading(AXEL, 0x29);
  X = (xhigh << 8) + xlow;
  
  yhigh= reading(AXEL, 0x2A);
  ylow= reading(AXEL, 0x2B);
  Y = ((yhigh << 8) | ylow);
   
  zhigh= reading(AXEL, 0x2C);
  zlow= reading(AXEL, 0x2D);
  Z = ((zhigh << 8) | zlow);
  
  Serial.print(X);
  Serial.print('\t');
  Serial.print(Y);
  Serial.print('\t');
  Serial.print(Z);
  Serial.print('\n');
  delay(100);
}




/* //Funzione di lettura multipla dei dati da un registro
int multireading(byte address, byte register);
int multireading(byte address, byte register){
  int value;
  int temp[1];
  Wire.beginTransmission(address);
  Wire.send(register);
  Wire.send(register + 1);
  Wire.endTransmission();
  Wire.requestFrom(address, 2);
  while(Wire.available()){
    temp[0]=Wire.receive();
    temp[1]=Wire.receive();
  }
  temp[0] << 8;
  temp[0] += temp[1];
  value= temp[0];
  return value;
} */

I really don' t understand why the values I get are something which doesn' t match with real forces: these are some examples...

1136 368 49040
1136 384 49008
2176 1984 48256
5936 65280 51984

Respectly x, y and z axis; I don' t understand why it doesn' t give me negative numbers: I tried to join the two byte of z axis and it gives me "-something" but the "print" function says something like "51512". It' s strange, isn' t?
Here a quick start guide I followed to setup correctly the accelerometer http://www.sparkfun.com/datasheets/Sensors/Magneto/Tilt%20Compensated%20Compass.pdf
And here the datasheet:
http://www.sparkfun.com/products/10703

It' s my first time approaching with Arduino, but I' ve programmed some stuffs with C, I checked multiple times the code and I can' t find the error, someone can help me? :frowning: Thank you,
Pentium

Looking at the data sheet you seem to have your high and low registers mixed up.
For example the X has the low at address 0x28 and high at 0x29, this does not match your code.

Well, you' re right: my high is actually the low; I' ve done the correction but I' ve always a problem:

61475 16386 32971
22 12288 53441
32782 4097 4288
4107 16385 45247
24582 57344 61630
53252 32768 41150

This doesn' t sound promising at all, what' s the matter? I really don' t understand :frowning:

I don't see how you get an int with a value of 61475 because as http://www.arduino.cc/en/Reference/Int says

Integers are your primary datatype for number storage, and store a 2 byte value. This yields a range of -32,768 to 32,767 (minimum value of -2^15 and a maximum value of (2^15) - 1).

So you are not making the int correctly.

I am not sure why this is but I would try:-
Y = ((int(yhigh) << 8) | int(ylow));

Nope, it doesn' t work :frowning: :frowning:
The code is the simplest ever wrote, it' s divided just in few phases:
-Read data from register MSB X
-Store in xhigh

-Read data from register LSB X
-Store in xlow

-X= (Bitshift xhigh of 8 and merge with OR to xlow)
I really can' t understand why it gives values over the maximum int value D:

Is what you had above your current sketch? What operating system and version of Arduino are you using?

I tried to reproduce with a simple test:

void setup ()
{
  volatile byte xhigh, xlow;

  xhigh = 0xBC;
  xlow = 0x10;
  int x = (xhigh << 8) | xlow;
  Serial.begin (115200);

  Serial.print (x);
}

void loop () {}

But that printed:

-17392

As you would expect.

I really can' t understand why it gives values over the maximum int value D:

It's not your fault, you can blame the technical writers! That IC claims to give 16 bit data but what they fail to mention is that the accelerometer data is only 12 bits so you have to shift it by 4 to the right.

Try this instead, it should work.

  yhigh= reading(AXEL, 0x2A);
  ylow= reading(AXEL, 0x2B);
  Y = ((yhigh << 12) | ylow << 4) >> 4;

wayneft:
Try this instead, it should work.

  yhigh= reading(AXEL, 0x2A);

ylow= reading(AXEL, 0x2B);
  Y = ((yhigh << 12) | ylow << 4) >> 4;

Hey, thank you a lot!!!By the way, I think you meant:

  yhigh= reading(AXEL, 0x2A);
  ylow= reading(AXEL, 0x2B);
  Y = ((yhigh << 8) | ylow ) >> 4;

I tried this code:

  xhigh= reading(AXEL, 0x29);
  xlow= reading(AXEL, 0x28);
  X = ((xhigh << 8) + xlow) >> 4;

Now, I get smaller values but I' ve still a problem: at first I know that if the first bit is equal to 1 then the number should be negative( for example B11111111 is negative!), now, this doesn' t work with my variable; don' t know why...

By the way, I think you meant:

Whoops, your right.

now, this doesn' t work with my variable; don' t know why...

It's because you have the high byte and low byte backwards. Using the default configuration would put the LSB at the lower address but you have the Control Register4A (0x23) set to 0x40 which swaps the LSB to the upper address and MSB to the lower address.

ok, now it works!!!Thank you really, I would never thought of that setting, how stupid I' ve been! :smiley:
That' s my final code, to solve the negative numbers problem...

  xhigh= reading(AXEL, 0x29);
  xlow= reading(AXEL, 0x28);
  X = ((xhigh << 8) + xlow) >> 4;
  if(X>2048){
    X -= 4096;
  }

Instead of working with the xhigh binary argument I' ve just written that if the joint value of X is over 2048( the xhigh has the first bit on!), then substract the amount of 2^12, because my final value is 12 bit composed, but it' s like a word...
:slight_smile: