In the previous tutorial, we covered the I2C bus in Arduino. We also learned about using the wire library to communicate with the Inter-integrated circuit or I2C devices using Arduino boards.
The I2C bus is commonly used by digital sensors. When using this interface, hundreds of slave devices can be connected over just two wires. Each device — whether it be an I2C master or slave — requires only two channels to connect with the bus.
Although this is a slow-data communication protocol, its simplicity makes the I2C bus one of the most popular interfaces among digital sensors. Typically, sensors only use other communication interfaces (such as the UART or SPI) when full-duplex communication is strictly required. Otherwise, the I2C is the de facto serial interface for all digital sensors.
Some examples of sensors that use an I2C/TWI bus include: ADXL345 accelerometer, L3G4200D gyroscope, MC5883L magnetometer, BMP180 pressure sensor, and DS1307 RTC.
In this tutorial, we will learn how to interface an ADXL345 accelerometer sensor with Arduino using the I2C/TWI bus.
The ADXL345 accelerometer
ADXL345 is a three-axis, MEMS accelerometer sensor. It’s also a digital inertial sensor that uses a capacitive accelerometer design.
Features include:
- A user-selectable range of up to +/-16g
- A maximum output resolution of 13 bits
- A sensitivity of 3.9 mg/LSB
- A maximum output data rate of 3200 Hz
The sensor has both I2C and SPI interfaces to communicate with controllers or computers.
The ADXL345 measures static acceleration due to gravity and dynamic acceleration, resulting from motion or shock. It can be used to sense linear acceleration in three axes, detecting the tilt and free-fall of an object.
There are two interrupt pins along with the I2C and SPI interfaces on the sensor. This is where various, built-in sensing functions such as free-fall, single-tap, and double-tap, can be mapped. The ADXL345 can also detect the presence or lack of relative motion by comparing acceleration values to user-defined thresholds.
As a digital sensor, the ADXL345 has built-in registers that can be read and written to configure settings and read acceleration values. It offers four measurement ranges: +/-2g, +/-4g, +/-8g, and +/-16g.
The default measurement range is +/-2g, which can be used to sense acceleration of up to 19.6 m/s2 in either direction along each axis.
The maximum resolutions are:
- 10-bit for +/-2g
- 11-bit for +/-4g
- 12-bit for +/-8g
- 13-bit for +/-16g range
The default resolution is 10-bit. For the +/-2g (default) range, it allows a sensitivity of 3.9mg/LSB. The default data rate is 100 Hz. All these configurations can be changed or set by writing data to built-in registers of the ADXL345. A controller/computer can read the acceleration simply by reading values from the registers 0x32 to 0x37.
Interfacing ADXL345 with Arduino
The ADXL345 sensor has both I2C and SPI interfaces to communicate with any controller or computer. The sensor supports three and four-wire SPI. Apart from these serial interfaces, the interrupt pins of the sensor can be directly interfaced with digital I/O channels of the controller/computer.
As Arduino also supports the I2C and the SPI bus, ADXL345 can be interfaced to Arduino using either one. In this tutorial, we’ll use the I2C bus.
The I2C pins of Arduino are not internally pulled HIGH. However, the ADXL345 sensor is typically available as a module, wherein the I2C pins of the sensor are already pulled HIGH on-board. Therefore, we can directly connect the I2C pins of the ADXL345 sensor with the I2C port of the Arduino board.
The ADXL345 can be supplied power from the 5V power output of Arduino. This circuit diagram shows ADXL345 interfacing with Arduino.
The I2C in Arduino
Most Arduino boards have at least one I2C module, which is accessible through one or more ports. An Arduino board can serve as the I2C master and slave. To read data from a digital sensor such as ADXL345, however, Arduino needs to be programmed as the I2C master. It can also be programmed to talk with the I2C/TWI devices by using the wire library.
- Configure Arduino as an I2C master by calling the Wire.begin() without arguments.
- The master Arduino can set the I2C clock frequency using the Wire.setClock() method if the clock speed needs to be modified.
- Arduino can transmit data to a slave (such as ADXL345 for setting configurations) by calling the Wire.beginTransmission(), Wire.write(), and Wire.endTransmission() methods.
- Arduino can also request data from a slave using the requestFrom() method and retrieve the requested data using the Wire.available() and Wire.read() methods.
Talking with the ADXL345 using Arduino
Each I2C slave device needs to have a unique I2C address. The ADXL345 has an ALT address pin that can be hardwired to set the I2C address of this digital sensor. If the ALT ADDRESS pin is pulled HIGH in a module, the 7-bit I2C address for the device is 0x1D — followed by the R/W bit.
This translates to 0x3A for a write and 0x3B for a read. If the ALT ADDRESS pin is connected to the ground, the 7-bit I2C address for the device is 0x53 (followed by the R/W bit). This translates to 0xA6 for a write and 0xA7 for a read.
In a module, the ALT ADDRESS pin is already pulled HIGH or LOW. The I2C address of the ADXL345 sensor used in this tutorial is 0x53. When using this address, Arduino can access the sensor on the I2C bus.
Arduino needs to read and write the data to the registers of the ADXL345 for setting configurations (including the setting-measurement range, data-transfer rate, sensitivity, and resolution) and for reading the acceleration values.
Here’s a table of these registers:
When writing data to the ADXL345, the sensor can be addressed using the Wire.beginTransmission() method. The first byte indicating the ADXL345 register (where the data is to be written) must be sent followed by the data byte by using the Wire.write() method. The transmission completes only when the Wire.endTransmission() method is called.
When reading data from the ADXL345, the sensor must be addressed using the Wire.beginTransmission() method. The first byte indicating the ADXL345 register (where the data is to be read) must be written by the Arduino master on the I2C bus by using the Wire.write() method.
This transmission is only complete when the Wire.endTransmission() method is called. Zero data is sent along with the register address when it has to be read from the ADXL345 register. And immediately after addressing the register to be read, the Arduino master must make a call to the Wire.requestFrom() method to read the selected register’s value.
Configuring the ADXL345 sensor
Below are a few simple steps to configure the ADXL345 sensor for serial communication.
1. Set the power mode and data transfer rate by writing to the 0x2C register. This register has these bits:
If the LOW_POWER bit is set to 0, the ADXL345 works in normal mode. If it’s set to 1, ADXL345 works in reduced power modes, where there’s a higher noise.
The bits D3 to D0 select the data-transfer rate according to this table:
2. Set the data format by writing to the 0x31 register. It has these bits:
If the SELF-TEST bit is set to 1, a self-test force is applied to the sensor, causing a shift in the output data. If it is set to 0, the self-test force is disabled.
If the SPI bit is set to 1, the ADXL345 uses the three-wire SPI mode. If it’s set to 0, it uses the four-wire SPI mode.
If the INT_INVERT bit is set to 0, it sets the interrupts to active HIGH and if it’s set to 1, it sets the interrupts to active LOW.
If the FULL_RES bit is set to 1, the sensor outputs a full-resolution value (10-bit for +/- 2g; 11-bit for +/-4g; 12-bit for +/- 8g; 13-bit for +/- 16g). Otherwise, if it’s set to 0, the default 10-bit is used.
If the justify bit is set to 1, the acceleration values in the registers 0x32 to 0x37 are left-justified. If it’s set to 0, these values are right-justified.
The following image shows the format of data-value registers with the left and right justifications and positions of the LSB or MSB for different measurement ranges.
The range bits D1 and D0 selects the measurement range according to this table:
3. Set the power-saving features by writing to the 0x2D register, which has these bits:
If the link bit is set to 1, the activity and inactivity functions are serially linked (meaning the activity function is delayed until the inactivity function is detected). If it’s set to 0, both functions are concurrent. The inactivity function refers to a situation when the acceleration is below the THRESH_INACT value (or the 0x25 register) for at least the time indicated by the TIME_INACT (the 0x26 register).
If the link bit is set and the AUTO_SLEEP bit is set to 1, it enables the auto-sleep functionality. In this mode, the ADXL345 automatically switches to sleep mode if the inactivity function is enabled and inactivity is detected. If the activity is also enabled, the ADXL345 automatically wakes up from sleep after detecting it and returns to operation at the output data-rate set in the BW_RATE register.
If the AUTO_SLEEP bit is set to 0, it disables the automatic switching to sleep mode. If the link bit is not set, the AUTO_SLEEP feature is disabled and setting the AUTO_SLEEP bit has zero impact on the device operation.
If the Measure bit is set to 1, the ADXL345 operates in measurement mode. If it’s set to 0, the ADXL345 operates in standby mode.
If the Sleep bit is set to 1, the ADXL345 operates in sleep mode. If it’s set to 0, the ADXL345 operates in normal mode. The sleep mode suppresses the DATA_READY, stops the transmission of data to FIFO, and switches the sampling rate to one specified by the wakeup bits.
In sleep mode, only the activity function can be used. The wake-up bits control the frequency of the reading in the sleep mode according to this table:
Reading the acceleration from the ADXL345
The acceleration along the:
- X-axis is read from registers 0x32 and 0x33
- Y-axis is read from registers 0x34 and 0x35
- Z-axis is read from registers 0x36 and 0x37
The raw values are 16-bit in two’s to compliment the form. The resolution, the left/right justification of the values, and the measurement range is set as per the value written to the 0x31 register of the ADXL345.
In any measurement range, the 10-bit resolution can be selected. The 10-bit acceleration value can be adjusted left or right. If the value is right-adjusted, the 10-bit acceleration values can be obtained by masking the second byte (which is read from 0x33 for the x-axis, 0x35 for the y-axis, and 0x37 for the z-axis) — with 0x03, right-shifting it eight times. Then, the two bytes are combined (0x32 and 0x33; 0x34 and 0x35; 0x36 and 0x37) to a 16-bit integer.
If the value is adjusted left, the 10-bit acceleration values can be obtained by right-shifting the first byte (which is read from 0x32 for the x-axis, 0x34 for the y-axis, and 0x36 for the z-axis) six times, masking the second byte (which is read from 0x33 for the x-axis, 0x35 for the y-axis, and 0x37 for the z-axis) with 0x3F to a temporary byte. Its temporary byte is left-shifted two times, adding the temporary byte to the first byte. Then, left-shift the first byte six times and combine the two bytes (0x32 and 0x33; 0x34 and 0x35; 0x36; and 0x37) for a 16-bit integer.
This 10-bit value will range from 0 to 1024. The acceleration is measured in both directions along the axis. So, if the value is greater than 511, subtract 1024 from it to get a negative value which indicates the other direction of the axis.
For a 10-bit resolution, the value of the acceleration in a gravity unit can be derived by multiplying this value with 4 mg (0.004) for +/- 2g range, 7.8 mg (0.0078) for +/- 4g range, 15.6 mg (0.0156) for +/- 8g, or 31.25 mg (0.03125) for +/- 16g range.
If the selected resolution is 11-bit for the +/- 4g range and the acceleration values are adjusted right, the 11-bit acceleration values can be obtained by masking the second byte (read from 0x33 for the x-axis, 0x35 for the y-axis, and 0x37 for the z-axis) — with 0x07, right-shifting it eight times, and combining the two bytes (0x32 and 0x33; 0x34 and 0x35; 0x36; and 0x37) for a 16-bit integer.
If the selected resolution is 11-bit for the +/- 4g range and the acceleration values are adjusted left, the 11-bit acceleration values can be obtained by right-shifting the first byte (read from 0x32 for the x-axis, 0x34 for the y-axis, and 0x36 for the z-axis) five times, masking second byte (read from 0x33 for the x-axis, 0x35 for the y-axis, and 0x37 for the z-axis) with 0x1F to a temporary byte. Then, left-shift the temporary byte three times, add the temporary byte to the second byte, left-shift the second byte five times, and finally combine the two bytes (0x32 and 0x33; 0x34 and 0x35; 0x36; and 0x37) for a 16-bit integer.
This 11-bit value will range from 0 to 2048. The acceleration is measured in both directions along the axis. So, if the value is greater than 1023, subtract 2048 from it to get a negative value, which indicates the other direction of the axis.
For an 11-bit resolution for the +/- 4g range, the value of the acceleration in the gravity unit can be derived by multiplying this value with 3.9 mg (0.0039).
If the selected resolution is 12-bit for the +/- 8g range and the acceleration values are adjusted right, the 12-bit acceleration values can be obtained by masking the second byte (read from 0x33 for the x-axis, 0x35 for the y-axis, and 0x37 for the z-axis) — with 0x0F, right-shifting it eight times, and combining the two bytes (0x32 and 0x33; 0x34 and 0x35; 0x36; and 0x37) for a 16-bit integer.
If the selected resolution is 12-bit for the +/- 8g range and the acceleration values are adjusted left, the 12-bit acceleration values can be obtained by right-shifting the first byte (read from 0x32 for the x-axis, 0x34 for the y-axis, and 0x36 for the z-axis) four times, masking the second byte (read from 0x33 for the x-axis, 0x35 for the y-axis, and 0x37 for the z-axis) with 0x0F to a temporary byte. Then, left shift the temporary byte four times, add a temporary byte to the first byte, left-shift second byte four times, and combine the two bytes (0x32 and 0x33; 0x34 and 0x35; 0x36; and 0x37) for a 16-bit integer.
This 12-bit value will range from 0 to 4096. The acceleration is measured in both directions along the axis. So, if the value is greater than 2047, subtract 4096 from it to get a negative value, which indicates the other direction of the axis.
For the 12-bit resolution for the +/- 8g range, the value of the acceleration in the gravity unit can be derived by multiplying this value with 3.9 mg (0.0039).
If the selected resolution is 13-bit for the +/- 16g range and the acceleration values are adjusted right, the 13-bit acceleration values can be obtained by masking the second byte (read from 0x33 for the x-axis, 0x35 for the y-axis, and 0x37 for the z-axis) — with 0x1F, right-shifting it eight times, and combining the two bytes (0x32 and 0x33; 0x34 and 0x35; 0x36; and 0x37) for a 16-bit integer.
If the selected resolution is 13-bit for the +/- 16g range and the acceleration values are adjusted left, the 13-bit acceleration values can be obtained by right-shifting the first byte (read from 0x32 for the x-axis, 0x34 for the y-axis, and 0x36 for the z-axis) three times, masking the second byte (read from 0x33 for the x-axis, 0x35 for the y-axis, and 0x37 for the z-axis) — with 0x03 to a temporary byte, left shift the temporary byte five times, add a temporary byte to the first byte, left-shift second byte three times, and combine the two bytes (0x32 and 0x33; 0x34 and 0x35; 0x36; and 0x37) for a 16-bit integer.
This 13-bit value will range from 0 to 8192. The acceleration is measured in both directions along an axis. So, if the value is greater than 4095, subtract 8192 from it to get a negative value, which indicates the other direction of the axis.
For the 12-bit resolution for the +/- 16g range, the value of acceleration in the gravity unit can be derived by multiplying this value with 3.9 mg (0.0039).
Detecting tilt from the ADXL345
The value of the acceleration obtained in the gravity units can range from +2 g to -2g, or +4g to -4g, or +8g to -8g, or +16g to -16g — depending on the selected measurement range.
The value of the acceleration includes both the static acceleration due to gravity and the dynamic acceleration due to motion or shock.
This image shows the acceleration values in gravity units due to gravity:
The tilt of the sensor can be detected by the sign and value of the acceleration in the x, y, and z- axes. When only the static acceleration is working on the ADXL345 sensor, the value of the acceleration along a given axis will be approximately +1g or -1g.
By examining the sign and value of the acceleration in all axes, the exact orientation of the ADXL345 sensor in a three-axis frame can be determined. How the orientation of the sensor is expressed (such as the degree tangent with respect to the axial planes) and how the orientation is used for some electronic control application (such as for pointing the device or controlling the three-dimensional motion of a system) depends on the user program.
Configuring the ADXL345 to +/- 2g, 10-bit resolution and reading acceleration using Arduino
The following Arduino sketch configures the ADXL345 sensor to a +/- 2g measurement range and uses a 10-bit resolution. The script reads the acceleration data of each of the axes and converts it to gravity units.
The values of acceleration in the x, y, and z-axes are 10-bit and right-justified. Accordingly, the values are derived from 16-bit registers. At the 10-bit resolution, the value of acceleration in the gravity unit is obtained by multiplying by 4 mg i.e. multiplying by 0.004.
Results
The value of the acceleration along different axes with respect to different orientations of the ADXL345 sensor can be observed in this video:
In the next tutorial, we will learn how to use the SPI interface in Arduino.
You may also like:
Filed Under: Arduino, Tutorials
Questions related to this article?
👉Ask and discuss on Electro-Tech-Online.com and EDAboard.com forums.
Tell Us What You Think!!
You must be logged in to post a comment.