Not reading a magnetic sensor

Hello,

I'm using an Arduino Uno and a GY-271 sensor board, which uses the HMC5883 magnetometer.

I've tried two libraries with this sensor, one from Adafruit and one from Robotpark/Electrodragon. The libraries use Wire.h and communicate with the sensor via I2C.

With either library I'm unable to get the sensor to record actual values. The Adafruit library and example code contains:

void loop(void) 
{
  /* Get a new sensor event */ 
  sensors_event_t event; 
  mag.getEvent(&event);
 
  /* Display the results (magnetic vector values are in micro-Tesla (uT)) */
  Serial.print("X: "); Serial.print(event.magnetic.x); Serial.print("  ");
  Serial.print("Y: "); Serial.print(event.magnetic.y); Serial.print("  ");
  Serial.print("Z: "); Serial.print(event.magnetic.z); Serial.print("  ");Serial.println("uT");

  // Hold the module so that Z is pointing 'up' and you can measure the heading with x&y
  // Calculate heading when the magnetometer is level, then correct for signs of axis.
  float heading = atan2(event.magnetic.y, event.magnetic.x);
  // Some adjustments for declination that I'm omitting here
  
     
  // Convert radians to degrees for readability.
  float headingDegrees = heading * 180/M_PI; 
  
  Serial.print("Heading (degrees): "); Serial.println(headingDegrees);
  
  delay(500);
}

I've determined that it gets stuck on the line mag.getEvent(&event);. The console will Serial.print("OK"); before this line but nothing gets printed after.

With the code from RobotPark, I get values printing out but the values never change when I move the sensor.

I've tried this with two sensors so far. I soldered the headers on myself but the solder joints look good to me. I'm not sure of any way to check my soldering other than to make sure the pins are not electrically connected to each other.

Can anyone advise on something I can try to troubleshoot? Maybe I just need to go buy another sensor from another vendor and see if that's the problem...

You left an important chunk of the code and have not shown how the sensor is connected to the Uno. If I had all of the code I could connect a HMC5883 to my Uno and test the code.

In the meantime, have you run an I2C scanner to verify that the I2C bus sees the HMC? What does the scanner report.

// I2C scanner by Nick Gammon.  Thanks Nick.

#include <Wire.h>

void setup() {
  Serial.begin (115200); //*****  make sure serial monitor baud matches *****

  // Leonardo: wait for serial port to connect
  while (!Serial) 
    {
    }

  Serial.println ();
  Serial.println ("I2C scanner. Scanning ...");
  byte count = 0;
  
  Wire.begin();
  for (byte i = 1; i < 120; i++)
  {
    Wire.beginTransmission (i);
    if (Wire.endTransmission () == 0)
      {
      Serial.print ("Found address: ");
      Serial.print (i, DEC);
      Serial.print (" (0x");
      Serial.print (i, HEX);
      Serial.println (")");
      count++;
      delay (1);  // maybe unneeded?
      } // end of good response
  } // end of for loop
  Serial.println ("Done.");
  Serial.print ("Found ");
  Serial.print (count, DEC);
  Serial.println (" device(s).");
}  // end of setup

void loop() {}

Thank you for the reply, I’ll test the I2C scanner when I get home. I’m connecting:
vcc -> 5V
gnd -> gnd
scl -> A5
sda -> A4

Here is the full code from adafruit:

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_HMC5883_U.h>

/* Assign a unique ID to this sensor at the same time */
Adafruit_HMC5883_Unified mag = Adafruit_HMC5883_Unified(12345);

void displaySensorDetails(void)
{
  sensor_t sensor;
  mag.getSensor(&sensor);
  Serial.println("------------------------------------");
  Serial.print  ("Sensor:       "); Serial.println(sensor.name);
  Serial.print  ("Driver Ver:   "); Serial.println(sensor.version);
  Serial.print  ("Unique ID:    "); Serial.println(sensor.sensor_id);
  Serial.print  ("Max Value:    "); Serial.print(sensor.max_value); Serial.println(" uT");
  Serial.print  ("Min Value:    "); Serial.print(sensor.min_value); Serial.println(" uT");
  Serial.print  ("Resolution:   "); Serial.print(sensor.resolution); Serial.println(" uT");  
  Serial.println("------------------------------------");
  Serial.println("");
  delay(500);
}

void setup(void) 
{
  Serial.begin(9600);
  Serial.println("HMC5883 Magnetometer Test"); Serial.println("");
  
  /* Initialise the sensor */
  if(!mag.begin())
  {
    /* There was a problem detecting the HMC5883 ... check your connections */
    Serial.println("Ooops, no HMC5883 detected ... Check your wiring!");
    while(1);
  }
  
  /* Display some basic information on this sensor */
  displaySensorDetails();
}

void loop(void) 
{
  /* Get a new sensor event */ 
  sensors_event_t event; 
  mag.getEvent(&event);
 
  /* Display the results (magnetic vector values are in micro-Tesla (uT)) */
  Serial.print("X: "); Serial.print(event.magnetic.x); Serial.print("  ");
  Serial.print("Y: "); Serial.print(event.magnetic.y); Serial.print("  ");
  Serial.print("Z: "); Serial.print(event.magnetic.z); Serial.print("  ");Serial.println("uT");

  // Hold the module so that Z is pointing 'up' and you can measure the heading with x&y
  // Calculate heading when the magnetometer is level, then correct for signs of axis.
  float heading = atan2(event.magnetic.y, event.magnetic.x);
  
  // Once you have your heading, you must then add your 'Declination Angle', which is the 'Error' of the magnetic field in your location.
  // Find yours here: http://www.magnetic-declination.com/
  // Mine is: -13* 2' W, which is ~13 Degrees, or (which we need) 0.22 radians
  // If you cannot find your Declination, comment out these two lines, your compass will be slightly off.
  float declinationAngle = 0.22;
  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;
   
  // Convert radians to degrees for readability.
  float headingDegrees = heading * 180/M_PI; 
  
  Serial.print("Heading (degrees): "); Serial.println(headingDegrees);
  
  delay(500);
}

I also just found this code from sparkfun http://sfecdn.s3.amazonaws.com/datasheets/Sensors/Magneto/HMC5883.pde which doesn’t use a hmc5833 library, I will also try this when I get home.

/*
An Arduino code example for interfacing with the HMC5883

by: Jordan McConnell
 SparkFun Electronics
 created on: 6/30/11
 license: OSHW 1.0, http://freedomdefined.org/OSHW

Analog input 4 I2C SDA
Analog input 5 I2C SCL
*/

#include <Wire.h> //I2C Arduino Library

#define address 0x1E //0011110b, I2C 7bit address of HMC5883

void setup(){
  //Initialize Serial and I2C communications
  Serial.begin(9600);
  Wire.begin();
  
  //Put the HMC5883 IC into the correct operating mode
  Wire.beginTransmission(address); //open communication with HMC5883
  Wire.send(0x02); //select mode register
  Wire.send(0x00); //continuous measurement mode
  Wire.endTransmission();
}

void loop(){
  
  int x,y,z; //triple axis data

  //Tell the HMC5883 where to begin reading data
  Wire.beginTransmission(address);
  Wire.send(0x03); //select register 3, X MSB register
  Wire.endTransmission();
  
 
 //Read data from each axis, 2 registers per axis
  Wire.requestFrom(address, 6);
  if(6<=Wire.available()){
    x = Wire.receive()<<8; //X msb
    x |= Wire.receive(); //X lsb
    z = Wire.receive()<<8; //Z msb
    z |= Wire.receive(); //Z lsb
    y = Wire.receive()<<8; //Y msb
    y |= Wire.receive(); //Y lsb
  }
  
  //Print out values of each axis
  Serial.print("x: ");
  Serial.print(x);
  Serial.print("  y: ");
  Serial.print(y);
  Serial.print("  z: ");
  Serial.println(z);
  
  delay(250);
}

I think that the first thing is run the I2C scanner. It does no good to try anything else until we know it is communicating.

I connected my HMC5883 (GY-271) to an Uno and tried the Adafruit code. Complies with a few warnings, uploads and is outputting reasonably accurate data. The code works. So my conclusion, at this point, is that there is a failure to communicate.

The second code will not even compile. It uses an old syntax for the Wire library (send vs. write, receive vs. read) and is not worth fixing.

vcc  -> 5V
gnd -> gnd 
scl -> A5
sda  -> A4

Any pull up resistors?

Any pull up resistors?

They are on the GY-271 breakout board, normally. Proably should check, though.

Many of those "GY-271" modules are mislabeled.

They do NOT have the HMC5883L compass chip. Instead, they have the similar QMC5883L, for which you need a different library.

See Interfacing HMC5883L / QMC5883 Digital compass with Arduino – SURTR TECHNOLOGY

groundFungus:
I think that the first thing is run the I2C scanner. It does no good to try anything else until we know it is communicating.

The scanner shows one device with address 0x0D.

As jremington writes, it turns out that I don't have the HMC5883L. Apparently I have a QMC5883L. There are a couple of libraries out there and some people report success with the library found in this post on reddit.

I tried this and it's now working. Well, it's giving values that change. I still have to work out what it's telling me :wink:

Thank you