Preview build — page text is a draft awaiting human review. Code badges come from real compiles. The flasher is real but not yet hardware-tested; the Playground is still a preview.

ADXL345 with Arduino Uno — level-shifted I2C and a tilt alarm

Connect a GY-291 ADXL345 to an Arduino Uno R3 through an I2C level shifter (CS to 3.3V, SDO to GND = 0x53) and light the LED when it tilts past 20°.

Arduino C++Verified — core avr 1.8.8, Adafruit ADXL345 1.3.4, 3 Nov 2026Compile-only

Community draft — report a mistake

The ADXL345 is a 3-axis accelerometer with tap, double-tap and free-fall detection built in. The GY-291 board is a common, cheap way to use it.

The board has a 3.3 V regulator, so it is powered from the Uno’s 5V, but the chip’s I2C pins stay at 3.3 V — so SDA and SCL go through a BSS138 level shifter. Two more wires are often skipped and cause most problems: CS to 3.3V for I2C mode and SDO to GND for address 0x53. The sketch prints acceleration in m/s² and the tilt angle, and lights the on-board LED when the module tilts past 20°.

Wiring

Arduino Uno R3Only the pins used are shown · 5 V logicADXL345 3-axis accelerometer (GY-291)LV⇄HVLV⇄HV3.3V5VGNDSDA · 18SCL · 19GNDVCCCSINT1 (not connected)INT2 (not connected)SDOSDASCL
Also needed: 2-channel (or 4-channel) BSS138 I2C level shifter.
Every connection
Arduino Uno R3ADXL345 3-axis accelerometer (GY-291)WireNotes
5VVCCredInto the GY-291’s 3.3 V regulator.
GNDGNDblack
SDASDAblueVia level shifter — Shifter LV = 3.3V, HV = 5V, GND shared.
SCLSCLyellowVia level shifter
3.3VCSredCS HIGH locks the chip in I2C mode.
GNDSDOblackSDO LOW = address 0x53 (HIGH = 0x1D).

3.3–5 V on the GY-291 (chip itself 2.0–3.6 V) part, 5 V board. The GY-291 has a 3.3 V regulator and pulls SDA/SCL up to 3.3 V, so ESP32 and Pico connect directly. The chip’s pins are not 5 V tolerant: on an Uno it usually works because I2C lines are only pulled low, but a level shifter is the correct fix.

Board quirks

  • The ADXL345 chip is rated to 3.6 V and its pins are not 5 V tolerant. The Wire library turns on the Uno’s internal pull-ups to 5 V, which would push the bus above the chip’s limit, and the board’s 3.3 V pull-ups only just reach the Uno’s HIGH threshold (0.7 × 5 V = 3.5 V). A BSS138 shifter solves both.
  • CS and SDO are tied on purpose. CS to 3.3V keeps the chip in I2C mode, SDO to GND fixes the address at 0x53. Left floating, both can change from board to board.
  • Use the Uno’s 3.3V pin for CS, not 5V — CS is a direct chip input with no level shifting on the GY-291.
  • The tilt angle is measured between the sensor’s Z axis and gravity, so it is 0° flat and 90° on edge, whatever the direction. That is all a “has it fallen over?” alarm needs, for a ladder, a cupboard or an LPG cylinder trolley.
  • Accelerometer tilt is only valid while the sensor is still: any shake adds to gravity. For a moving vehicle combine it with a gyro (MPU6050).

Code

adxl345-uno.inoArduino C++Open in PlaygroundOpen in PlaygroundFlash
// ADXL345 (GY-291) on an Arduino Uno R3 — tilt alarm with level-shifted I2C.
// VCC → 5V (board regulator), GND → GND, SDA/SCL → level shifter → SDA/SCL (A4/A5),
// CS → 3.3V (I2C mode), SDO → GND (address 0x53). Shifter: LV = 3.3V, HV = 5V, GND shared.
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_ADXL345_U.h>

Adafruit_ADXL345_Unified accel(12345);
const float TILT_ALARM_DEG = 20;  // e.g. a cupboard, ladder or gas cylinder that should stay upright

void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  if (!accel.begin(0x53)) {
    Serial.println(F("No ADXL345 at 0x53 - check the level shifter, CS on 3.3V and SDO on GND"));
    while (true) delay(1000);
  }
  accel.setRange(ADXL345_RANGE_2_G);  // finest steps for slow tilt
  Serial.println(F("ADXL345 ready (+-2 g)"));
}

void loop() {
  sensors_event_t e;
  accel.getEvent(&e);
  float x = e.acceleration.x, y = e.acceleration.y, z = e.acceleration.z;
  // Angle between the sensor's Z axis and straight down: 0° when flat.
  float tilt = degrees(acos(constrain(z / sqrt(x * x + y * y + z * z), -1.0, 1.0)));
  bool alarm = tilt > TILT_ALARM_DEG;
  digitalWrite(LED_BUILTIN, alarm);
  Serial.print(F("X "));
  Serial.print(x, 2);
  Serial.print(F("  Y "));
  Serial.print(y, 2);
  Serial.print(F("  Z "));
  Serial.print(z, 2);
  Serial.print(F(" m/s2  tilt "));
  Serial.print(tilt, 1);
  Serial.println(alarm ? F(" deg  TILTED") : F(" deg"));
  delay(250);
}

Library: Adafruit ADXL345 (Adafruit (also install Adafruit Unified Sensor)) — compiled with Adafruit ADXL345 1.3.4.

Expected serial output

Serial Monitor · 9600Output
ADXL345 ready (+-2 g)
X 0.12  Y -0.08  Z 9.81 m/s2  tilt 0.8 deg
X 4.93  Y -0.10  Z 8.47 m/s2  tilt 30.2 deg  TILTED

Common errors

“No ADXL345 at 0x53”

Check the shifter’s LV (3.3V), HV (5V) and GND, then SDO on GND (or try 0x1D) and CS on 3.3V. Run the I2C scanner.

All axes read 0

CS floating — the chip dropped into SPI mode. Tie CS to 3.3V and reset.

It worked without a shifter, why add one?

It often does work, out of spec. The shifter keeps 5 V off a 3.6 V chip and gives clean HIGH levels, so it keeps working in a hot enclosure or on a long cable.

↑↓ to move · Enter to open