The HMC5883L magnetometer communicates over an i2c bus, and will run off between 3 to 5 volts. So you’ll only need four wires to hook it up to an Arduino ProMicro. RAW is wired to 5V (assuming your input supply is 5 volts), pin 3 to SCL, pin 2 to SDA and GND goes to GND.

How to wire a HMC5883L magnetometer to an Arduino ProMicro.

One thing to keep in mind with wiring your magnetometer is that it has a fixed i2c address. This means you will ever only be able to wire one up to your Arduino at a time (and hopefully the address doesn’t collide with any other hardware you might be using). In terms of software, I use the library from Adafruit, it’s fairly straightforward to take magnetic measurements with the sensor:

#include "Adafruit_Sensor.h"
#include "Adafruit_HMC5883_U.h"

Adafruit_HMC5883_Unified mag = Adafruit_HMC5883_Unified(12345);

void setup() {
  mag.begin();
}

void loop() {
  sensors_event_t event;
  mag->getEvent(&event);

  // magnetic readings stored at: event.magnetic.x and event.magnetic.y
}

To work out your true heading from these magnetic measurements, we need to calibrate the magnetometer. Holding the sensor flat, slowly spin the magnetometer 360 degrees a couple of times and record the maximum and minimum values that are returned by the sensor.

float xMax, yMax, xMin, yMin = 0.0;

if (xMax == 0.0) {
  xMax = event.magnetic.x;
}

if (yMax == 0.0) {
  yMax = event.magnetic.y;
}

if (calibrate) {
  xMax = max(xMax, event.magnetic.x);
  yMax = max(yMax, event.magnetic.y);
  xMin = min(xMin, event.magnetic.x);
  yMin = min(yMin, event.magnetic.y);
}

NOTE: This calibration method wasn’t very accurate inside my workshop (it’s all steel construction), but was fine everywhere else I tried. So keep an eye out for things that might throw your magnetic readings out of whack.

The last step is to account for magnetic declination. Remember back to school and those pictures of a globe? You know, the ones with a magnetic north pole and a geographical north pole? We need to account for this difference or magnetic declination when working out our true heading. The only problem? Magnetic declination varies. A lot.

All that molten rock churning about deep down in the Earth’s mantle? Way below our feet? Variations in that flow cause the Earth’s magnetic poles to slowly wobble all over the place. It also creates a variation in declination depending on where you are standing. This is a map of magnetic declination and how it has changed over time:

A world isogonic map that shows how magnetic declination has changed between 1900 and 2010.

The good news? We can cruise over to http://www.magnetic-declination.com/ and use their map to find the magnetic declination for our current location. Convert this angle into radians and we can add that to our measurements and calculate our true heading.

sensors_event_t event;
mag->getEvent(&event);

float heading = atan2((event.magnetic.y - ((yMax + yMin) / 2.0)), (event.magnetic.x - ((xMax + xMin) / 2.0)));
float declinationAngle = -0.11; // Cairns magnetic declination. 6°41’ east.
heading += declinationAngle;

// Correct for when signs are reversed.
if (heading < 0) {
  heading += 2*PI;
}

// Check for wrap due to addition of declination.
if (heading > 2*PI) {
  heading -= 2*PI;
}

float headingDegrees = heading * 180/M_PI; // Convert radians to degrees.