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 R3 | HMC5883L / QMC5883L magnetometer (GY-271) | Wire | Notes |
|---|---|---|---|
| 5V | VCC | red | Into the GY-271’s 3.3 V regulator. |
| GND | GND | black | |
| SCL | SCL | yellow | Same signal as A5. |
| SDA | SDA | blue | Same 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
cin the Serial Monitor and turn the module slowly through every direction (and upside down) for the few seconds the library asks. It prints asetCalibrationOffsets(…)line — paste it intosetup()afterinit()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
// 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);
}// 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
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 itQMC5883L 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.