Accelerometers can detect the magnitude and direction of acceleration experienced by the sensor. One common use for an accelerometer is to wake up a device by tapping it. Many smartphones use accelerometers to detect when the phone is picked up or tapped. They are also used to detect when a device has been dropped. Most laptops have internal accelerometers that are able to detect when the device is falling, in order to turn off the hard drive before it hits the floor.

In this article, we will use an Arduino to get raw sensor data from an accelerometer and convert it into an acceleration value in g’s.

Introduction to the ADXL345 Accelerometer

The accelerometer we will use in this tutorial is the ADXL345. There are a variety of different ADXL345 boards available, but the one we are using is a breakout module from Adafruit:

ADXL345 Accelerometer Pin Diagram.jpg

The directional arrows indicate the direction of each sensor axis (x, y, and z) in relation to the physical board. The z axis extends up and down, perpendicular to the x and y axes.

The ADXL345 can communicate with the Arduino over SPI and I2C. In this article we will use I2C, but SPI is an option if you want to use it.

Description of the ADXL345 pins:

  • Vin – Connects to a 5 volt power source.
  • 3V3 – The ADXL345 can be powered with 3.3 volts or 5 volts. This pin is where the 3.3 volt power source would connect.
  • GND – Connects to ground.
  • CS – Chip select pin for SPI communication.
  • INT1 – Hardware interrupt pin 1.
  • INT2 – Hardware interrupt pin 2.
  • SDO – Serial data output pin. Doubles as the MISO pin for SPI communication.
  • SDA – SDA pin for I2C communication. Doubles as the MOSI pin for SPI communication.
  • SCL – SCL pin for I2C communication. Doubles as the SCLK pin for SPI.

How the ADXL345 Accelerometer Works

Acceleration is the rate of increase or decrease of velocity:

Acceleration Formula.png

If you drive in a car and step on the gas, the car has a positive acceleration. If you step on the brakes, the car has a negative acceleration.

Static acceleration is caused by forces like gravity. Dynamic acceleration is caused by forces of motion like the acceleration from a car speeding up or slowing down. Accelerometers measure both static acceleration and dynamic acceleration.

Two common units of acceleration are meters per second squared (m/s2) and g’s. One g is defined as the rate of acceleration of gravity, which is 9.8 m/s2.

The ADXL345 outputs separate acceleration measurements for each axis, x, y, and z:

XYZ Axes Double.png

The ADXL345 measures acceleration by detecting changes in capacitance. Along each axis there is a tiny plate suspended between two micro-springs that can move back and forth:

How to Setup Accelerometers on the Arduino - How it Works 1

The mobile plate and the fixed plate are charged, so an electric field is formed between them:

How to Setup Accelerometers on the Arduino - How it Works 2

When the accelerometer is at rest, the electric field between the plates is constant. When the sensor accelerates, the mobile plate moves, and the distance between the plates changes.

7 Springs with Capacitive Plates with Car plus bottom car and springs and field lines.png

Capacitance is a function of the distance between two charged plates, so when the distance between the plates changes, the electric field between the plates also changes. The sensor measures this change in capacitance and calculates an acceleration value.

How to Connect the ADXL345 Accelerometer to the Arduino

Now let’s connect the accelerometer to the Arduino and take a look at the raw values it provides. We’re going to connect the accelerometer with I2C, so the wiring is pretty simple:

ADXL345 Wiring Diagram.png

How to Program the ADXL345 Accelerometer

To program the ADXL345 accelerometer we will use the Sparkfun ADXL345 library. Download and install the library here.

Once you get the library installed, upload the code below to the Arduino. The sketch will output the raw accelerometer readings to the serial monitor.

#include <SparkFun_ADXL345.h>

ADXL345 adxl = ADXL345();

int range = 2; // Range: 2g, 4g, 8g, 16g

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

  adxl.powerOn();
  adxl.setRangeSetting(range);
}

void loop() {
  int x, y, z;
  adxl.readAccel(&x, &y, &z);

  Serial.print("X: ");
  Serial.print(x);

  Serial.print("    Y: ");
  Serial.print(y);

  Serial.print("    Z: ");
  Serial.println(z);

  delay(250);
}

Explanation of the Code

The first thing we do is include the Sparkfun ADXL345 library. Next we create an object called adxl, which is a member of the ADXL345 class. We set the adxl object equal to the function ADXL345(). The ADXL345() function configures the communication mode that the sensor will use to talk to the Arduino. When there are no arguments passed to the function, as in this case, the sensor will use I2C to communicate with the Arduino. To use SPI, use ADXL345(10) instead.

Next we declare a variable called range, which will store the sensitivity range we want the ADXL345 to have. It can be either 2, 4, 8, or 16 g’s.

In the setup() section we initialize the serial monitor. Then we initialize the ADXL345 with the powerOn() function. This function is called through the adxl object we created earlier. Next, we call the setRangeSetting() function to set the sensitivity range of the sensor. We pass it the range variable, which stores the range setting we defined when we declared it.

In the loop() section, the first thing we do is declare variables to hold the sensor readings. The ADXL345 outputs separate acceleration measurements for each axis, so we need a unique variable for each axis. Therefore we declare three int variables – x, y, and z.

Next, we get the sensor readings from the accelerometer with the readAccel() function. The arguments of the readAccel() function are the variables that will hold the sensor readings from each axis. The sensor’s x axis measurement will be stored in the variable that is placed in the first parameter. The y axis measurements will be stored in the variable in the second parameter, and the z axis measurements will be stored in the variable placed in the third parameter.

Next we have a series of Serial.print() functions to print the values stored in the x, y, and z variables to the serial monitor. Then we delay for 250 milliseconds to slow down the output a bit.

Once you connect the ADXL345 to your Arduino and upload the code, open up the serial monitor. You should see values like this being printed out:

ADXL345 Accelerometer Raw Output on Arudino Serial Monitor.png

Notice how the X and Y values are close to zero, but the Z axis has a value around 230. The sensor was resting flat on a table when this screenshot was taken, so it wasn’t moving. But it was accelerating. The higher Z axis reading is caused by acceleration from gravity. Try moving the sensor around and see what happens to the values of the x, y, and z axes.

The raw values output by the accelerometer are not the typical Arduino ADC values between 0 and 1023. The numbers you see in the serial monitor are in “two’s complement” format. Two’s complement is a way to represent signed (positive and negative) numbers in binary.

We can convert the accelerometer’s two’s complement values to g’s with some conversion factors from the ADXL345 datasheet.

How to Convert Two’s Complement Values to G’s

In the specifications table on page 4 of the ADXL345 datasheet there is a section called sensitivity. This section has the scale factors for each sensitivity range::

ADXL345 Scale Factors for Conversion to G_s.png

To get the acceleration readings in g’s, we need to multiply the sensor’s two’s complement output by one of these scale factors. Each sensitivity range has a different scale factor, indicated by the red box in the image above.

ADXL345 Accelerometer Output in G’s

Now let’s look at a sketch that will output the accelerometer readings in g’s. This sketch will actually output the sensor readings in milli g’s, but if you want the output in g’s, just divide the milli g’s reading by 1,000.

#include <SparkFun_ADXL345.h>

ADXL345 adxl = ADXL345();

int range = 2; // Range: 2g, 4g, 8g, 16g

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

  adxl.powerOn();
  adxl.setRangeSetting(range);
}

void loop() {

  int x, y, z;
  adxl.readAccel(&x, &y, &z);

  switch (range) {
    case 2:
      x = x * 3.9;
      y = y * 3.9;
      z = z * 3.9;
      break;
    case 4:
      x = x * 7.8;
      y = y * 7.8;
      z = z * 7.8;
      break;
    case 8:
      x = x * 15.6;
      y = y * 15.6;
      z = z * 15.6;
      break;
    case 16:
      x = x * 31.2;
      y = y * 31.2;
      z = z * 31.2;
      break;
    default:
      Serial.println("Please specify a range of 2, 4, 8, or 16 g");
  }

  Serial.print("X: ");
  Serial.print(x);

  Serial.print("    Y: ");
  Serial.print(y);

  Serial.print("    Z: ");
  Serial.println(z);

  delay(250);
}

Explanation of the Code

The top of the sketch and the setup() section are identical to the raw data sketch explained earlier.

In the loop() section, we declare x, y, and z variables to store the sensor readings from each axis. Then we get readings for each axis with the readAccel() function.

Next we convert the raw sensor readings to g’s by multiplying the raw sensor readings by the scale factor. The scale factor is different depending on which range setting we choose. This is a perfect application for a switch case statement. So we use a switch statement with the range variable as the condition. Each case statement will define what happens when the range is set to 2, 4, 8, or 16 g’s. When the range variable is equal to 2, the code in the first case statement will be executed. The scale factor for 2 g sensitivity is 3.9, so we multiply the output from each axis by 3.9. Then we have a break command so that the program exits the case statement.

Then we have case statements for all the other possible values of the range variable. When the range is set to 4 g’s, the scale factor is 7.8, so we multiply each axis output by 7.8. When the range is set to 8 g’s, the scale factor is 15.6, so we multiply all three axis variables by 15.6. And when the range is set to 16 g’s, the scale factor is 31.2, so we have to multiply everything by 31.2.

Then we have a default statement at the end of the switch case statement. The default statement will only be executed if the range variable was set equal to something different than 2, 4, 8, or 16. The code inside the default statement will print a line on the serial monitor that says: “Please specify a range of 2, 4, 8, or 16 g’s”.

Now we print the x, y, and z variables to the serial monitor with a series of Serial.print() functions. Finally we use a delay of 250 milliseconds to slow down the output to make it easier to read on the serial monitor.

After uploading the sketch, open up the serial monitor and you should see the acceleration readings being output in milli g’s:

ADXL345 Accelerometer Output in g_s on Arduino Serial Monitor.png

Notice that the Z axis values are around 910 milli g’s. That is pretty close to one g, which is the acceleration due to gravity.