Pinout & Connection Guide
The GY-271 module features a 5-pin configuration, clearly labeled on the PCB.
Pin Definitions
Wiring Diagrams
For Arduino Uno / Nano:
For ESP32:
For ESP8266 (NodeMCU):
Theory of Operation
How a Magnetometer Works
The HMC5883L uses Anisotropic Magneto-Resistive (AMR) sensors – material that changes its electrical resistance in response to an external magnetic field. A bridge circuit measures these resistance changes, and the on-chip 12-bit ADC converts them to digital values . By measuring the magnetic field in three orthogonal axes (X, Y, Z), the Earth’s magnetic field vector can be determined, and the direction to magnetic north can be calculated.
Calculating Heading (Azimuth)
For a sensor held horizontally (parallel to the ground), the heading (azimuth) in degrees is calculated as:
heading = atan2(Y, X) × (180 / π)
Where:
If heading is negative, add 360° to get a result in the 0°–360° range.
Important: This formula gives magnetic north. To obtain true north, you must apply the magnetic declination (variation) for your geographic location, which can be found online or calculated.
When the Sensor is Not Horizontal
If your sensor is mounted vertically or at an angle, you must incorporate accelerometer data to perform tilt compensation using pitch and roll angles before calculating the heading.
Raw Data Interpretation
The 12-bit ADC outputs values ranging from -2048 to 2047. The measured magnetic field in Gauss is calculated as: field = raw_value × (gain / 2048), where gain is the selected sensitivity (e.g., 1090 LSB/Gauss for the ±1.3G range).
Usage Guide
Software Setup (Arduino IDE)
Step 1: Install Required Libraries
The easiest way to use the HMC5883L is with the Adafruit_HMC5883_Unified library .
-
Open Arduino IDE → Sketch → Include Library → Manage Libraries
-
Search for “Adafruit HMC5883”
-
Install the library by Adafruit (this will also install the Adafruit Sensor and BusIO libraries)
Step 2: Basic Test Sketch
GY-271 HMC5883L Compass Basic Read Example
*/
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_HMC5883_U.h>
Adafruit_HMC5883_Unified mag = Adafruit_HMC5883_Unified(12345);
void setup() {
Serial.begin(9600);
if (!mag.begin()) {
Serial.println("HMC5883L sensor not found! Check wiring.");
while (1);
}
mag.setRange(HMC5883L_RANGE_1_3GA);
mag.setMeasurementMode(HMC5883L_CONTINUOUS);
mag.setDataRate(HMC5883L_DATARATE_15_HZ);
Serial.println("GY-271 HMC5883L Ready");
Serial.println("-----------------------------");
}
void loop() {
sensors_event_t event;
mag.getEvent(&event);
float x = event.magnetic.x / 100.0;
float y = event.magnetic.y / 100.0;
float z = event.magnetic.z / 100.0;
float heading = atan2(y, x) * 180 / PI;
if (heading < 0) heading += 360;
Serial.print("X: "); Serial.print(x);
Serial.print(" G, Y: "); Serial.print(y);
Serial.print(" G, Z: "); Serial.print(z);
Serial.print(" G | Heading: ");
Serial.println(heading);
delay(100);
}
Step 3: Manual I2C Implementation (No Library)
If you prefer not to use the Adafruit library, you can control the HMC5883L directly using the Wire library.
GY-271 Manual I2C Read Example
*/
#include <Wire.h>
#define HMC5883L_ADDR 0x1E
#define CONFIG_A_REG 0x00
#define CONFIG_B_REG 0x01
#define MODE_REG 0x02
#define DATA_REG_BEGIN 0x03
void setup() {
Serial.begin(9600);
Wire.begin();
Wire.beginTransmission(HMC5883L_ADDR);
Wire.write(CONFIG_A_REG);
Wire.write(0x70);
Wire.endTransmission();
Wire.beginTransmission(HMC5883L_ADDR);
Wire.write(CONFIG_B_REG);
Wire.write(0xA0);
Wire.endTransmission();
Wire.beginTransmission(HMC5883L_ADDR);
Wire.write(MODE_REG);
Wire.write(0x00);
Wire.endTransmission();
Serial.println("GY-271 Manual Mode Ready");
}
void loop() {
Wire.beginTransmission(HMC5883L_ADDR);
Wire.write(DATA_REG_BEGIN);
Wire.endTransmission();
Wire.requestFrom(HMC5883L_ADDR, 6);
if (Wire.available() >= 6) {
int16_t x = Wire.read() << 8 | Wire.read();
int16_t z = Wire.read() << 8 | Wire.read();
int16_t y = Wire.read() << 8 | Wire.read();
float fx = x / 1090.0;
float fy = y / 1090.0;
float fz = z / 1090.0;
float heading = atan2(fy, fx) * 180 / PI;
if (heading < 0) heading += 360;
Serial.print("Heading: ");
Serial.println(heading);
}
delay(100);
}
Calibration for Accurate Heading
The magnetometer measures the Earth’s magnetic field, but nearby electronics (motors, wires, batteries) introduce hard-iron and soft-iron distortions. Calibration is essential for accurate heading.
Simple Hard-Iron Offset Calibration
-
Place the sensor in a fixed location.
-
Rotate the sensor 360° in the horizontal plane.
-
Record the minimum and maximum raw values for X and Y axes.
-
Calculate offsets:
X_offset = (X_max + X_min) / 2
Y_offset = (Y_max + Y_min) / 2
-
Apply offsets to all future readings:
X_cal = X_raw - X_offset
Y_cal = Y_raw - Y_offset
-
Recalculate heading using calibrated values.
Calibration Code Example
HMC5883L Hard-Iron Calibration Sketch
Rotate sensor 360° and record min/max values
*/
#include <Wire.h>
#include <Adafruit_HMC5883_U.h>
Adafruit_HMC5883_Unified mag = Adafruit_HMC5883_Unified(12345);
int16_t xMin = 32767, xMax = -32768, yMin = 32767, yMax = -32768;
void setup() {
Serial.begin(9600);
mag.begin();
mag.setRange(HMC5883L_RANGE_1_3GA);
mag.setMeasurementMode(HMC5883L_CONTINUOUS);
Serial.println("Rotate the sensor 360° in horizontal plane...");
delay(3000);
}
void loop() {
sensors_event_t event;
mag.getEvent(&event);
int16_t x = event.magnetic.x;
int16_t y = event.magnetic.y;
if (x < xMin) xMin = x;
if (x > xMax) xMax = x;
if (y < yMin) yMin = y;
if (y > yMax) yMax = y;
Serial.print("X: "); Serial.print(x);
Serial.print(" | Y: "); Serial.print(y);
Serial.print(" | Xmin: "); Serial.print(xMin);
Serial.print(" | Xmax: "); Serial.print(xMax);
Serial.print(" | Ymin: "); Serial.print(yMin);
Serial.print(" | Ymax: "); Serial.println(yMax);
delay(100);
}
Once offsets are determined, apply them in your main code:
float x = (event.magnetic.x - xOffset) / 1090.0;
float y = (event.magnetic.y - yOffset) / 1090.0;
float heading = atan2(y, x) * 180 / PI;
Using the DRDY Pin (Optional)
The DRDY pin pulses LOW for 250µs when new measurement data is ready . This can be used to trigger an interrupt in your microcontroller, allowing you to read data only when new values are available rather than continuously polling.
attachInterrupt(digitalPinToInterrupt(DRDY_PIN), dataReadyISR, FALLING);
Selecting the Measurement Range
The measurement range trades off between sensitivity and maximum field detection:
For most compass applications, the ±1.3 Gauss range (1090 LSB/G) provides the best sensitivity .