2-Axis Accelerometer running I2c??

Hello all,

I was wondering if anyone had some knowledge of a library for running I2C on a 2-Axis Accelerometer. I have found many libraries for 3-axis gyroscopes and what-not, but nothing for 2-axis units. The only library that I did find for a dual-axis accelerometer was for the Memsic module which does not run I2C.

Usually I'd just buy a 3-axis module and replace the current one, however that is not an option for this particular project. I'm currently running a MXC6226XU 2 Axis accelerometer that is already hooked up to a custom PCB for I2C ONLY.

Any ideas? I'm currently attempting to write my own library using one for the ADXL345 as a base, but if there is one already available, or it anyone had any better suggestions, I'm all ears.

Thank you all in advance.

Regards,

Joe

Why write a library? The data sheet is pretty clear, all you need to do is read two registers using I2C. X and Y output are registers 0 and 1, respectively.

jremington:
Why write a library? The data sheet is pretty clear, all you need to do is read two registers using I2C. X and Y output are registers 0 and 1, respectively.

Quite write you are! I'm relatively new to I2C and the Wire library, so I was unaware that I could do that. I have it currently up and running. The only issue I have now is getting the correct data. I may be doing it right, however I feel I may be doing it slightly wrong.

My read lines are as follows:

  //Request one byte of data
  Wire.requestFrom(accelerometerAddress, 1);
  
  //wait for response
  while(Wire.available() == 0);
  
  //get data
  int x = Wire.read();
  
  //Request two bytes data
  Wire.requestFrom(accelerometerAddress, 2);
  
  //wait for response
  while(Wire.available() == 0);
  
  //get data
  int y = Wire.read();

Which receives data and later prints it to the serial line (values between 0 and 255). However the datasheet states that the values should be between -127 to 128. So I assume I am meant to receive both bytes together and then split them up. And suggestions on how to do this?

Thank you so much, you've already saved me countless hours of programming time.

-Joe

Good job!

What you are doing should work. An unsigned char has values 0 to 255, while a signed char or int has values -127 to 128. Post all your code, using code tags ("</>" button). However, I don't see where you are telling it to read register 0. Take a look at this tutorial: Tutorial: Arduino and the I2C bus – Part One | tronixstuff.com

You should either request 1 byte of data at a time from registers 0 and 1, or read 2 bytes beginning with register 0, using sequential Wire.read() operations.

Example of char/int conversion:

  void setup() {
  Serial.begin(9600);
  char a = 255;
  int x = a;
  Serial.print(a,HEX);
  Serial.print(" ");
  Serial.println(x);
  while(1);
}
void loop(){}

Thanks again.

Here's my entire program:

#include <Wire.h>

//default address B0010110 == 22
int accelerometerAddress = 22;

void setup()
{
  Serial.begin(9600);
  
  Wire.begin();
}

void loop()
{
  
  //Send request and start communication
  Wire.beginTransmission(accelerometerAddress);
  
  //Ask for register zero
  Wire.write(0);
  
  //Complete transmission
  Wire.endTransmission();
  
  //Request one byte of data
  Wire.requestFrom(accelerometerAddress, 1);
  
  //wait for response
  while(Wire.available() == 0);
  
  //get data
  int x = Wire.read();
  
  //Request two bytes data
  Wire.requestFrom(accelerometerAddress, 2);
  
  //wait for response
  while(Wire.available() == 0);
  
  //get data
  int y = Wire.read();
  
  //print data
  Serial.print("X Axis:  ");
  Serial.print(x);
  Serial.print("Y Axis:  ");
  Serial.print(y);

}

I saw two separate guides for I2C that were both pretty similar.

When I move around the module, it rolls over from 255 to 0 and from 0 to 255, instead of 128 to -127 and -127 to 128. Thoughts? Possibly related?

Next, I'm about to get the shake-event detection working. Hope to hear back from you regarding the matter above.

Regards,

Joe

After reading that link you posted, I learned that I can do this:

Wire.requestFrom(device_address, 3);

*a = Wire.read();
*b = Wire.read();
*c = Wire.read();

Very interesting that I have to use pointers, will try it out!

You are requesting one byte, then two more.
Try something like this:

#include <Wire.h>

//default address B0010110 == 22
int accelerometerAddress = 22;

char buf[4]; //extra bytes for safety


void setup()
{
  Serial.begin(9600);
 
  Wire.begin();
}

void loop()
{
 
  //Send request and start communication
  Wire.beginTransmission(accelerometerAddress);
 
  //Ask for register zero
  Wire.write(0);
 
  //Complete transmission
  Wire.endTransmission();
 
  //Request two bytes of data
  Wire.requestFrom(accelerometerAddress, 2);

  int i=0;
  while(Wire.available()) { //in abnormal case, ACC may send less than requested
    buf[i] = Wire.read(); // receive a byte
    i++; 
  }
 
 int x = buf[0];
 int y = buf[1];
 
  //print data
  Serial.print("X Axis:  ");
  Serial.print(x);
  Serial.print("Y Axis:  ");
  Serial.print(y);

}

joebro391:
Thanks again.

Here's my entire program:

There is one problem with your code,

  //Request one byte of data

Wire.requestFrom(accelerometerAddress, 1);

/* this while loop is un-necessary, and if the requestFrom() fails it will cause a perminent hang
 requestFrom() will not return until an error is detected or bytes are available.

//wait for response
 while(Wire.available() == 0);
*/
 
 //get data
 int x = Wire.read();
 
 //Request two bytes data
 Wire.requestFrom(accelerometerAddress, 2);  // requesting  2 more byte?

/* Delete,  see prior comment
 //wait for response
 while(Wire.available() == 0);

*/

/* if you want -128..127 values use a char */
 //get data
//  int y = Wire.read();
 char y = Wire.read();   // but only reading one byte?

//print data
 Serial.print("X Axis:  ");
 Serial.print(x);
 Serial.print("Y Axis:  ");
 Serial.print(y);

}




Joe, try this instead.



void readAxis(){
//Set internal register address pointer to 0
Wire.beginTransaction(accelerometerAddress);
Wire.write(0);
Wire.endTransaction();

char x=0,y=0;

// read 2 byte from sensor

Wire.requestFrom(accelerometerAddress,2);
if(Wire.available()){ // got data, requestFrom() will either return 0, or the number of requested bytes, nothing else.
 x=Wire.read();
 y=Wire.read();
 }
else{
 Serial.print("sensor Failed, No Response");
 }

Serial.print("X Axis:  ");
Serial.print(x);
Serial.print("Y Axis:  ");
Serial.print(y);
}




Chuck.

So I made some adjustments and this seems to work for the most part..

#include <Wire.h>

//default address B0010110 == 22
int accelerometerAddress = 22;

void setup()
{
  Serial.begin(9600);
  
  Wire.begin();
}

void loop()
{
  
  //Send request and start communication
  Wire.beginTransmission(accelerometerAddress);
  
  //Ask for register zero
  Wire.write(0);
  
  //Complete transmission
  Wire.endTransmission();
  
  //Request one byte of data
  Wire.requestFrom(accelerometerAddress, 3);
  
  //wait for response
  while(Wire.available() == 0);
  
  int x=0, y=0, shake=0;
  //get data
  x = Wire.read();
  y = Wire.read();
  shake = Wire.read();
  
  //print data
  Serial.print("X Axis:  ");
  Serial.print(x);
  Serial.print("\t");
  Serial.print("Y Axis:  ");
  Serial.print(y);
  Serial.print("\t");
  Serial.print("Shake:  ");
  Serial.print(shake);
  Serial.print("\n");
}

x and y still spit out values 0 - 255 and shake prints "23" ("31 if I completely flip it over) I think that value make need to be broken down further

I tried making all three variables char's and it print out some garbage instead of good values...thoughts? Shake was totally blank as a Char.

Thanks y'all

-Joe

The problem is still confusion between treating 0-255 as signed versus unsigned value.

Wire.read() seems to be returning an integer, rather than a character, but in a quick search I couldn't find the current source code. Try using Wire.receive() instead, which returns uint8_t values (equivalent to unsigned character).

jremington:
Try using Wire.receive() instead, which returns uint8_t values (equivalent to unsigned character).

I don't think there is a receive() function anymore. I believe it was dropped and re-written as the current read() function...

I tried making all three variables char's and it print out some garbage instead of good values...thoughts? Shake was totally blank as a Char.

Post the code that does this. This should work, and there MUST be a simple solution. Did you try what I suggested in reply #6 and if so, what happened?

jremington:
Post the code that does this. This should work, and there MUST be a simple solution. Did you try what I suggested in reply #6 and if so, what happened?

The code was exactly the same as what I previously posted, however when I declared x, y and shake, instead of declaring them of type int, I declared them of type char.

I Just tried what you suggested with the buffer and it actually helped a ton. But now, the values are -63 to 64. I'm not getting the last bit...Here's that code:

#include <Wire.h>

//default address B0010110 == 22
int accelerometerAddress = 22;

//to store read data
char buf[4];

void setup()
{
  Serial.begin(9600);
  
  Wire.begin();
}

void loop()
{
  
  //Send request and start communication
  Wire.beginTransmission(accelerometerAddress);
  
  //Ask for register zero
  Wire.write(0);
  
  //Complete transmission
  Wire.endTransmission();
  
  //Request one byte of data
  Wire.requestFrom(accelerometerAddress, 3);
  
  //wait for response
  //while(Wire.available() == 0);
  
  int x=0, y=0, shake=0, i=0;
  //get data
  while(Wire.available())
  {
    buf[i] = Wire.read();
    i++;
  }
  //print data
  Serial.print("X Axis:  ");
  Serial.print(x);
  Serial.print("\t");
  Serial.print("Y Axis:  ");
  Serial.print(y);
  Serial.print("\t");
  Serial.print("Shake:  ");
  Serial.print(shake);
  Serial.print("\n");
}

The code you just posted does not print out the values that are received. You don't do anything with the contents of the array buf[].

If the various accelerations aren't maxed out (to -128 or +127), smaller values is to be expected.

jremington:
The code you just posted does not print out the values that are received. You don't do anything with the contents of the array buf[].

What I'm posting is not the entire program because is it a small part of a much larger whole. I forgot to add that portion to arduino IDE where i'm testing code to make sure it compiles before adding it to the bigger project.

This should be complete:

#include <Wire.h>

//default address B0010110 == 22
int accelerometerAddress = 22;

//to store read data
char buf[4];

void setup()
{
  Serial.begin(9600);
  
  Wire.begin();
  

}

void loop()
{ 
  
  //Send request and start communication
  Wire.beginTransmission(accelerometerAddress);
  
  //Ask for register zero
  Wire.write(0);
  //int detection = 32; //0101001
  //Wire.write(32);
  
  //Complete transmission
  Wire.endTransmission();
  //Request one byte of data
  Wire.requestFrom(accelerometerAddress, 3);
  
  //wait for response
  //while(Wire.available() == 0);
  
  int x=0, y=0, shake=0, i=0;
  //get data
  while(Wire.available())
  {
    buf[i] = Wire.read();
    i++;
  }
  
  x = buf[0];
  y = buf[1];
  shake = buf[2];
  //print data
  Serial.print("X Axis:  ");
  Serial.print(x);
  Serial.print("\t");
  Serial.print("Y Axis:  ");
  Serial.print(y);
  Serial.print("\t");
  Serial.print("Shake:  ");
  Serial.print(shake);
  Serial.print("\n");
}

jremington:
If the various accelerations aren't maxed out (to -128 or +127), smaller values is to be expected.

I turn the module completely around. As I tilt one axis and cross the 90-degree plane (64 or -63), it starts to count back. The numbers are too perfect. There's a missing bit...

I'm actually quite satisfied with that portion, unless anyone has an theories regarding the missing bit. I'm now working on the shake detection which is just being annoying. I'm not really sure how to write to the detection register (register 4, as per the datasheet) to set the settings. None the less, I need to figure out how to just extract the 5th and 6th bit of the 3rd register (the status register) to get the data that pertains to shake events. Currently I just get the entire byte of data and put it in "shake".

I turn the module completely around. As I tilt one axis and cross the 90-degree plane (64 or -63), it starts to count back. The numbers are too perfect. There's a missing bit...

There is no missing bit. The accelerometer, as you describe using it, is working as expected.

You are measuring +/-1 g, and the maximum is +/- 2g, which would be -128 to 127.

jremington:
There is no missing bit. The accelerometer, as you describe using it, is working as expected.

You are measuring +/-1 g, and the maximum is +/- 2g, which would be -128 to 127.

Please explain that for me, I must be missing something

joebro391:
I turn the module completely around. As I tilt one axis and cross the 90-degree plane (64 or -63), it starts to count back. The numbers are too perfect. There's a missing bit...

You are just seeing the inaccuracy of the device. maybe it is less sensitive in the negative orientation. Also Where are you standing. Surface gravity on our Planet is not constant. I have a Weights and Measures license for my State. I calibrate scales. I use fixed Masses. if the scale is moved to a new location I have to re-calibrate for the new gravity field. Sea Level to 9,000ft can make a 1% difference. Let alone the Coriolis effect of difference Lattitudes.

Here is a good explaination Gravity by Lattitude

Chuck.

Please explain that for me, I must be missing something

What don't you understand? If 2g = 128, 1g = 64. On the Earth's surface, everything is subject to the force of gravity, 1g.

I guess I'm just over thinking it. this resolution should be just fine.

NOW...does anyone want to help me figure out the shake events? haha

Currently it spits out what I assume to be the integer value of the binary that is coming out of Register 3. Does anyone have any tips on how to extract 5th and 6th bit to get a reading?

Thanks again for everyone's input and feedback!

-Joe