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.

GY-271 compass (QMC5883L / HMC5883L) with Arduino Uno — heading and calibration

Wire a GY-271 compass to an Arduino Uno R3, detect whether it carries a QMC5883L (0x0D) or a real HMC5883L (0x1E), then read a calibrated heading.

Arduino C++Verified — core avr 1.8.8, QMC5883LCompass 1.2.3, 3 Nov 2026Compile-only

Community draft — report a mistake

The GY-271 board is the usual cheap compass module. The name says HMC5883L, but most boards sold now carry a QMC5883L, which sits at a different I2C address and needs a different library — the reason so many compass projects show nothing.

On the Uno the board is powered from 5V (it has a 3.3 V regulator) and wired to SDA/SCL. The sketch first checks which chip is fitted, then reads the QMC5883L’s raw X/Y/Z, the heading in degrees and the direction (N, NNE, …). Send c in the Serial Monitor to run the library’s calibration and get offsets you can paste back into the sketch.

Wiring

Arduino Uno R3Only the pins used are shown · 5 V logicHMC5883L / QMC5883L magnetometer (GY-271)5VGNDSDA · 18SCL · 19VCCGNDSCLSDADRDY (not connected)
Every connection
Arduino Uno R3HMC5883L / QMC5883L magnetometer (GY-271)WireNotes
5VVCCredInto the GY-271’s 3.3 V regulator.
GNDGNDblack
SCLSCLyellowSame signal as A5.
SDASDAblueSame signal as A4.

3.3–5 V on the GY-271 (chip itself 2.16–3.6 V) part, 5 V board. The GY-271 has a 3.3 V regulator and pull-ups to 3.3 V, so ESP32 and Pico connect directly and an Uno reads it fine. Power it from VCC, not straight into the chip.

Board quirks

  • Most “HMC5883L” boards sold today carry a QMC5883L (address 0x0D), a different chip with different registers. HMC5883L code then finds nothing. The sketch scans both addresses first and tells you which chip you have; it reads the QMC5883L with the QMC5883LCompass library. For a genuine HMC5883L at 0x1E use Adafruit HMC5883 Unified.
  • The GY-271’s pull-ups go to its own 3.3 V, so the Uno reads the bus directly. The chip is a 3.3 V part, though: if readings drop out on long wires or in a hot box, an I2C level shifter is the textbook fix.
  • Calibrate in place. Send c in the Serial Monitor and turn the module slowly through every direction (and upside down) for the few seconds the library asks. It prints a setCalibrationOffsets(…) line — paste it into setup() after init() so it applies every time.
  • Keep the compass flat and at least 10–15 cm from motors, speakers, relays and steel screws; recalibrate after mounting. Tilt adds a large error — a tilt-compensated heading needs an accelerometer too.
  • Magnetic declination across India is small (under about 2°), so the sketch leaves it at 0. Look up the value for your town if you need better than that.

Code

hmc5883l-uno.inoArduino C++Open in PlaygroundOpen in PlaygroundFlash
// GY-271 compass on an Arduino Uno R3 — detects QMC5883L (0x0D) vs HMC5883L (0x1E), then heading.
// VCC → 5V (board regulator), GND → GND, SDA → SDA (A4), SCL → SCL (A5). DRDY not used.
// Send 'c' in the Serial Monitor to calibrate: turn the module slowly through every direction.
#include <Wire.h>
#include <QMC5883LCompass.h>

QMC5883LCompass compass;

bool present(uint8_t addr) {
  Wire.beginTransmission(addr);
  return Wire.endTransmission() == 0;
}

void setup() {
  Serial.begin(9600);
  Wire.begin();
  if (present(0x1E)) {
    Serial.println(F("Genuine HMC5883L at 0x1E - this sketch is for the QMC5883L."));
    Serial.println(F("Use the Adafruit HMC5883 Unified library instead."));
    while (true) delay(1000);
  }
  if (!present(0x0D)) {
    Serial.println(F("No compass at 0x0D or 0x1E - check SDA/SCL and VCC"));
    while (true) delay(1000);
  }
  compass.init();
  // Magnetic declination is small across India (under about 2 degrees) — set yours if you need it.
  compass.setMagneticDeclination(0, 0);
  Serial.println(F("QMC5883L at 0x0D. Keep it flat and away from motors, speakers and steel."));
}

void loop() {
  if (Serial.read() == 'c') {
    Serial.println(F("Calibrating - rotate the module in all directions..."));
    compass.calibrate();
    Serial.print(F("compass.setCalibrationOffsets("));
    Serial.print(compass.getCalibrationOffset(0));
    Serial.print(F(", "));
    Serial.print(compass.getCalibrationOffset(1));
    Serial.print(F(", "));
    Serial.print(compass.getCalibrationOffset(2));
    Serial.println(F(");  <- paste into setup() to keep it"));
  }
  compass.read();
  int az = compass.getAzimuth();
  char dir[4] = {0};
  compass.getDirection(dir, az);
  Serial.print(F("X "));
  Serial.print(compass.getX());
  Serial.print(F("  Y "));
  Serial.print(compass.getY());
  Serial.print(F("  Z "));
  Serial.print(compass.getZ());
  Serial.print(F("  heading "));
  Serial.print(az);
  Serial.print(F(" deg "));
  Serial.println(dir);
  delay(500);
}

Library: QMC5883LCompass (MPrograms (for a genuine HMC5883L at 0x1E use Adafruit HMC5883 Unified)) — compiled with QMC5883LCompass 1.2.3.

Expected serial output

Serial Monitor · 9600Output
QMC5883L at 0x0D. Keep it flat and away from motors, speakers and steel.
X -812  Y 1043  Z -2210  heading 128 deg SE
X -905  Y 377  Z -2198  heading 157 deg SSE
Calibrating - rotate the module in all directions...
compass.setCalibrationOffsets(-418.00, 236.50, 512.00);  <- paste into setup() to keep it

Common errors

“No compass at 0x0D or 0x1E”

Check SDA/SCL and VCC/GND, then run the I2C scanner. Some GY-271 boards with a QMC5883P chip answer at 0x2C — they need a different library.

Heading only moves between a few values, or jumps

Not calibrated, or something magnetic is nearby. Calibrate away from the desk’s steel frame and keep the module flat.

North is off by a fixed amount

Mounting offset or declination. Add a fixed correction in code, or rotate the module until its X arrow points forward.

↑↓ to move · Enter to open