The ADXL345 accelerometer is a powerful and affordable sensor that provides detailed motion and tilt data in three axes. When combined with the Arduino Uno, it creates a versatile platform for developing IoT applications that require real-time motion tracking.
In this tutorial, we will explore the features of the ADXL345 accelerometer, connect it to the Arduino Uno, and write the code necessary to read the sensor data. By the end of this guide, you will be equipped to integrate motion sensing and IoT functionality into your projects.
Why Use the ADXL345 with Arduino Uno
By integrating the ADXL345 accelerometer on the Arduino Uno, you can create innovative solutions for applications like motion monitoring, tilt detection, and impact sensing.
The ADXL345 (Figure 1) is known for its ability to measure acceleration in three axes (X, Y, and Z), making it ideal for capturing detailed motion data.
With selectable measurement ranges (up to ±16g) and low-power operation, it fits perfectly into IoT applications that demand efficiency and precision. Possible use cases are:
- Motion Monitoring: Track vibrations or changes in position in industrial machinery, fitness equipment, or smart home devices.
- Tilt Detection: Build tilt-sensitive controls for interactive installations, robotics, or gaming applications.
- Impact Sensing: Detects sudden shocks, falls, or collisions, helpful in wearable safety systems or vehicle diagnostics.
Which library to use for ADXL345 on the Arduino Uno
While there are helper libraries like the Adafruit ADXL345 Unified Library that simplify interfacing with the ADXL345 accelerometer, this guide takes a different approach. Instead of relying on these abstractions, we will use the Wire.h library to communicate directly with the sensor via I2C. This approach helps give a deeper understanding of how the ADXL345 works, including its registers and configuration process. Using the Wire.h library allows us to interact directly with the ADXL345’s registers, giving you full control over its functionality. This method highlights the sensor’s inner workings and lets you configure parameters such as measurement range, data rate, and power settings manually. By programming the sensor at the register level, you’ll gain a better appreciation of the underlying protocol and hardware behavior.
Realize the ADXL345 project schematic
The first step of this project involves assembling and configuring the circuit schematic to ensure proper functionality. For this particular setup, I will use the Arduino Uno WiFi Rev 2, a versatile board that provides built-in WiFi capabilities and is well-suited for projects requiring robust connectivity and reliable performance. If you are interested in connecting this board to WiFi, you can refer to the following article: https://embeddedespresso.com/how-to-use-the-arduino-uno-wifi-for-iot-projects/
The circuit for this project is straightforward, requiring only the connection of the Arduino Uno board to the ADXL345 sensor. The sensor communicates with the Arduino over the I2C bus, which requires two wires for data transfer: SDA and SCL. Additionally, two more wires will supply power to the sensor. Below is the schematic for the setup:
The schematic shows the connections between an Arduino Uno WiFi Rev2 and an ADXL345 accelerometer module. The ADXL345 is powered by connecting the Arduino’s 3.3V pin to the module’s power input pin, while the Arduino’s GND pin is connected to the module’s ground pin. Communication between the Arduino and the ADXL345 is established through the I2C protocol, with the SDA pin on the Arduino connected to the SDA pin on the ADXL345 and the SCL pin on the Arduino connected to the SCL pin on the ADXL345. Pull-up resistors are required on the SDA and SCL lines to ensure proper I2C communication. These resistors may already be integrated into the ADXL345 module or may need to be added externally if not present.
More information on the ADXL345 accelerometer can be found here: https://www.analog.com/media/en/technical-documentation/data-sheets/adxl345.pdf
Configure the ADXL345 Arduino Uno project
To start working with the ADXL345 accelerometer and the Arduino Uno WiFi Rev 2, it is essential to configure the Arduino IDE properly. Begin by connecting the Arduino Uno WiFi Rev 2 to your computer using a USB cable. Open the Arduino IDE and navigate to Tools > Board, then select Arduino Uno WiFi Rev 2 from the list of available boards. Next, go to Tools > Port and choose the COM port corresponding to your connected Arduino board. Once the board and port are configured, create a new sketch to begin coding. Navigate to File > New to open a blank sketch. Save the sketch with a descriptive name to keep your project organized and easily identifiable. You are now ready to start coding and interfacing with the ADXL345 accelerometer.
Writing the ADXL345 Arduino Uno program
With the Arduino project configured and the ADXL345 properly connected, it is time to write the code to initialize the sensor and read its data. This program will retrieve acceleration values for the X, Y, and Z axes and display them on the Serial Monitor.
First, include the required library at the top of your sketch:
#include <Wire.h>
Next, the constants defining the ADXL345’s I2C address and the key registers used in communication are created.
// ADXL345 I2C address
#define ADXL345_ADDR 0x53
// ADXL345 Register Addresses
#define ADXL345_REG_POWER_CTL 0x2D
#define ADXL345_REG_DATAX0 0x32
#define ADXL345_REG_DATA_FORMAT 0x31
I then create some global variables representing the acceleration values:
int16_t accel_x, accel_y, accel_z;
In the setup() function, I initialize the serial communication and the accelerometer. The function initADXL345 will be explained later.
void setup() {
Serial.begin(9600); // Initialize Serial Monitor
Wire.begin(); // Initialize I2C
// Initialize ADXL345
initADXL345();
Serial.println("ADXL345 Accelerometer Initialized");
}
The loop() function is the core of the Arduino sketch, which runs repeatedly after the initial setup is complete. It continuously fetches and displays the acceleration data from the ADXL345 sensor, which is extrapolated through the readADXL345() function.
void loop() {
// Read data from ADXL345
readADXL345();
// Print accelerometer data
Serial.print("X: ");
Serial.print(accel_x);
Serial.print(" | Y: ");
Serial.print(accel_y);
Serial.print(" | Z: ");
Serial.println(accel_z);
delay(2000); // Update every 2000ms
}
The data is then stored in global variables: accel_x, accel_y, and accel_z, representing the acceleration values for the X, Y, and Z axes, respectively. The data is then printed through the Serial.print command.
The example uses three helper functions initADXL345(), readADXL345(), and writeRegister(). These functions simplify sensor configuration and register access, improving code clarity and maintainability.
Function writeRegister()
Purpose: Program a specific register on the ADXL345 sensor via I2C.
void writeRegister(uint8_t deviceAddr, uint8_t regAddr, uint8_t data) {
Wire.beginTransmission(deviceAddr);
Wire.write(regAddr);
Wire.write(data);
Wire.endTransmission();
}
Workflow:
- I2C communication with the device starts through the beginTransmission method.
- Specifies the target register (regAddr).
- Writes the data to the register.
- Ends the communication session through the endTransmission method.
Function initADXL345()
Purpose: Initializes the ADXL345 sensor by configuring its data format and enabling measurement mode.
void initADXL345() {
// Set data format to full resolution and +/-2g range
writeRegister(ADXL345_ADDR, ADXL345_REG_DATA_FORMAT, 0x08);
// Set the POWER_CTL register to wake up the device
writeRegister(ADXL345_ADDR, ADXL345_REG_POWER_CTL, 0x08);
}
The first line writes 0x08 to the DATA_FORMAT register to set full resolution and a ±2g range, while the second line writes 0x08 to the POWER_CTL register to activate the measurement mode. For the 2G range, full resolution will correspond to a 10-bit resolution.
Function readAdxl345()
The readADXL345() function retrieves the raw acceleration data for the X, Y, and Z axes from the ADXL345 sensor over the I2C bus. It processes the data from the sensor’s registers and stores the values in global variables for further use.
void readADXL345() {
Wire.beginTransmission(ADXL345_ADDR);
Wire.write(ADXL345_REG_DATAX0); // Set register pointer to data registers
Wire.endTransmission(false);
Wire.requestFrom((uint8_t)ADXL345_ADDR, (size_t)6, (bool)true);
// Combine bytes to form 16-bit values
accel_x = (int16_t)(Wire.read() | (Wire.read() << 8));
accel_y = (int16_t)(Wire.read() | (Wire.read() << 8));
accel_z = (int16_t)(Wire.read() | (Wire.read() << 8));
}
The function begins by initiating communication with the ADXL345 using beginTransmission, where ADXL345_ADDR is the I2C address of the sensor. This prepares the I2C bus to send commands. Next, Wire.write(ADXL345_REG_DATAX0) sets the register pointer to the DATAX0 register, the starting register for the X-axis acceleration data. This informs the sensor where the data request will begin. The Wire.endTransmission(false) command ends the transmission but keeps the I2C connection active for subsequent data reading.
Following this, the requestFrom method requests six bytes of data from the ADXL345 sensor. These bytes represent the raw acceleration data for the X, Y, and Z axes, with two bytes allocated to each axis. The function then reads the requested data from the I2C buffer using Wire.read() and combines two consecutive bytes for each axis into a 16-bit signed integer.
Here follows the whole example code:
#include <Wire.h>
// ADXL345 I2C address
#define ADXL345_ADDR 0x53
// ADXL345 Register Addresses
#define ADXL345_REG_POWER_CTL 0x2D
#define ADXL345_REG_DATAX0 0x32
#define ADXL345_REG_DATA_FORMAT 0x31
// Global variables for accelerometer data
int16_t accel_x, accel_y, accel_z;
void setup() {
Serial.begin(9600); // Initialize Serial Monitor
Wire.begin(); // Initialize I2C
// Initialize ADXL345
initADXL345();
Serial.println("ADXL345 Accelerometer Initialized");
}
void loop() {
// Read data from ADXL345
readADXL345();
// Print accelerometer data
Serial.print("X: ");
Serial.print(accel_x);
Serial.print(" | Y: ");
Serial.print(accel_y);
Serial.print(" | Z: ");
Serial.println(accel_z);
delay(2000); // Update every 2000ms
}
// Function to initialize ADXL345
void initADXL345() {
// Set data format to full resolution and +/-2g range
writeRegister(ADXL345_ADDR, ADXL345_REG_DATA_FORMAT, 0x08);
// Set the POWER_CTL register to wake up the device
writeRegister(ADXL345_ADDR, ADXL345_REG_POWER_CTL, 0x08);
}
// Function to read accelerometer data
void readADXL345() {
Wire.beginTransmission(ADXL345_ADDR);
Wire.write(ADXL345_REG_DATAX0); // Set register pointer to data registers
Wire.endTransmission(false);
Wire.requestFrom((uint8_t)ADXL345_ADDR, 6, true); // Request 6 bytes
// Combine bytes to form 16-bit values
accel_x = (int16_t)(Wire.read() | (Wire.read() << 8));
accel_y = (int16_t)(Wire.read() | (Wire.read() << 8));
accel_z = (int16_t)(Wire.read() | (Wire.read() << 8));
}
// Function to write data to a register
void writeRegister(uint8_t deviceAddr, uint8_t regAddr, uint8_t data) {
Wire.beginTransmission(deviceAddr);
Wire.write(regAddr);
Wire.write(data);
Wire.endTransmission();
}
Test the ADXL345 Arduino Uno project
To test the project, upload the sketch to the board by clicking the Upload button.
Once the code is successfully uploaded, open the Serial Monitor in the Arduino IDE, accessible through the Tools menu or by pressing Ctrl+Shift+M. Make sure the baud rate is set to 9600, matching the rate defined in the code using Serial.begin(9600). As the sketch runs, you should see acceleration data displayed in the Serial Monitor. The values will be in the format:
X: <value> | Y: <value> | Z: <value>
As shown in the following screenshot:
representing the raw acceleration readings from the ADXL345 for the X, Y, and Z axes.
Tilt the ADXL345 sensor along its axes and observe the changes in the values displayed in the Serial Monitor. For example, tilting the sensor forward or backward should cause the X-axis values to increase or decrease. Similarly, tilting the sensor side to side or up and down will affect the Y-axis and Z-axis readings. If you gently shake the sensor, you will notice rapid fluctuations in the values, indicating the sensor is capturing acceleration in real time.
Improving the ADXL345 project
While the current project demonstrates how to interface with the ADXL345 accelerometer and retrieve raw data, there is significant room for improvement by incorporating calibration and converting the raw readings into meaningful acceleration values.
Calibration
Calibration is a crucial step in ensuring the accuracy of the accelerometer’s readings. By calibrating the sensor, you can correct for any offsets or biases that might affect the measurements. For instance, when the sensor is stationary, the X and Y axes should ideally read zero, while the Z-axis should reflect the gravitational acceleration (approximately +1g). However, due to manufacturing variations and environmental factors, the raw data might deviate from these expected values.
By applying a calibration process, you can measure these offsets and subtract them from the raw data to ensure more precise and reliable readings. This step is particularly important in applications where accuracy is critical, such as motion tracking, angle measurement, or detecting small changes in movement.
Conversion to acceleration values
The ADXL345 outputs raw data in terms of digital counts, which correspond to acceleration values based on the selected measurement range. To make the data meaningful, it is necessary to convert these counts into physical acceleration values expressed in units of “g” (gravitational force). This conversion involves scaling the raw data using the sensor’s sensitivity, which is determined by the range setting. For example:
- In a ±2g range, each count corresponds to approximately 3.9 mg.
- In a ±16g range, each count corresponds to approximately 0.49 mg.
By performing this conversion, you can interpret the accelerometer’s output in real-world terms, enabling more sophisticated applications such as calculating velocity, detecting orientation, or analyzing motion patterns.
Troubleshooting
If your project is not working as expected, consider the following troubleshooting steps to identify and resolve common issues:
1. No Output on the Serial Monitor
If the Serial Monitor is not displaying any data, verify the following:
- Ensure the Arduino is correctly connected to your computer via USB.
- Double-check that the correct board (Arduino Uno WiFi Rev2) and port are selected in the Arduino IDE.
- Confirm that the Serial Monitor is set to the correct baud rate (9600). If it is not, adjust it using the dropdown menu in the Serial Monitor.
2. Unexpected or Incorrect Values
If the output values do not respond correctly to sensor movements, check the wiring between the ADXL345 and the Arduino. Ensure that the SDA and SCL pins are connected to the correct pins on the Arduino Uno WiFi Rev2. Confirm that the sensor is powered with 3.3V, as supplying 5V can cause malfunctions or permanent damage to the sensor. Additionally, ensure the I2C address in the code matches the ADXL345’s address (0x53 by default).
Conclusion
The ADXL345 accelerometer, paired with the Arduino Uno WiFi Rev 2, provides a powerful and versatile platform for exploring motion sensing and real-time data applications. This guide teaches you how to configure the hardware, install necessary libraries, write code to read acceleration data and test the project effectively.
With its ability to measure acceleration along three axes and high sensitivity, the ADXL345 is suitable for various applications, including motion tracking, tilt detection, and impact sensing. While this project focused on reading and displaying acceleration values on the Serial Monitor, it lays the foundation for more advanced developments, such as integrating with IoT platforms or performing real-time analysis.