Triple Axis Magnetometer HMC5883L interfacing with AVR ATmega16

Introduction

HMC5883l-1

HMC5883L Magnetometer Module

HMC5883L is a 3-axis magnetometer which is used for measuring the direction and magnitude of the Earth’s magnetic field. It is used for low cost compassing and magnetometry.

It measures the Earth’s magnetic field value along the X, Y and Z axes from milli-gauss to 8 gauss.

It can be used to find the direction of heading of the device.

It uses I2C protocol for communication with the microcontroller.

For more information about Magnetometer HMC5883L and how to use it, refer the topic HMC5883L Magnetometer Module in the sensors and modules section.

 

Programming for HMC5883L Magnetometer

Let’s interface triple axis magnetometer HMC5883L module with AVR ATmega16 and calculate its heading angle.

HMC5883L uses I2C protocol for communication. Here we are connecting AVR based ATmega16 as a master device and HMC5883L as a slave device. Its I2C device address is 0x3C. Its read and write operation addresses are:

Slave device write address (SLA+W): 0x3C

Slave device read address (SLA+R): 0x3D

 

Interfacing diagram

ATmega16-Interface-with-Magnetometer

Interfacing HMC5883L Magnetometer Module With ATmega 16 

 

Programming steps

First, we need to set configuration register A for average of 8-sample measurement with 15 Hz default data output rate

Set Gain using Configuration Register B i.e. here its 0xA0. (or we can choose any other desired gain)

Select Continuous measurement mode of operation in Mode Register. Hence Mode Register value will become 0x00.

After initialization, Write start location of output data registers X, Y and Z i.e. 0x03 and read all six registers raw values.

Calculate Heading value by using formula,

Magnetic Heading = atan2(\frac{y}{x})   (Radian)

True Heading = Magnetic Heading + declination Angle    (Radian)

Program

/*
 * ATmega16_Magnetometer.c
 * http://www.electronicwings.com
 * 
 */ 

#define F_CPU 8000000UL		/* Define CPU Frequency e.g. here its 8MHz */
#include <avr/io.h>		/* Include AVR std. library file */
#include <stdlib.h>		/* Include std. library file */
#include <math.h>		/* Include math header file */
#include "LCD_16x2_H_file.h"	/* Include LCD header file */
#include "I2C_Master_H_file.h"	/* Include I2C header file */
#define PI	3.14159265359	/* Define Pi value */
#define Declination	-0.00669/* Define declination of location from where measurement going to be done. e.g. here we have added declination from location Pune city, India. we can get it from http://www.magnetic-declination.com */

void Magneto_init()		/* Magneto initialize function */
{
	I2C_Start(0x3C);	/* Start and write SLA+W */
	I2C_Write(0x00);	/* Write memory location address */
	I2C_Write(0x70);	/* Configure register A as 8-average, 15 Hz default, normal measurement */
	I2C_Write(0xA0);	/* Configure register B for gain */
	I2C_Write(0x00);	/* Configure continuous measurement mode in mode register */
	I2C_Stop();		/* Stop I2C */
}

int Magneto_GetHeading()
{
	int x, y, z;
	double Heading;
	I2C_Start_Wait(0x3C);	/* Start and wait for acknowledgment */
	I2C_Write(0x03);	/* Write memory location address */
	I2C_Repeated_Start(0x3D);/* Generate repeat start condition with SLA+R */
	/* Read 16 bit x,y,z value (2's complement form) */
	x = (((int)I2C_Read_Ack()<<8) | (int)I2C_Read_Ack());
	z = (((int)I2C_Read_Ack()<<8) | (int)I2C_Read_Ack());
	y = (((int)I2C_Read_Ack()<<8) | (int)I2C_Read_Nack());
	I2C_Stop();		/* Stop I2C */
	Heading = atan2((double)y,(double)x) + Declination;
	if (Heading>2*PI)	/* Due to declination check for >360 degree */
		Heading = Heading - 2*PI;
	if (Heading<0)		/* Check for sign */
		Heading = Heading + 2*PI;
	return (Heading* 180 / PI);/* Convert into angle and return */

}


int main(void)
{
	char buffer[10];
	LCD_Init();		/* Initialize LCD */
	I2C_Init();		/* Initialize I2C */
	Magneto_init();		/* Initialize magneto */
	LCD_String("Magnetometer");/* Print title on LCD */
	while (1)
	{
		itoa (Magneto_GetHeading(),buffer,10);
		LCD_String_xy(2,0,"Heading = ");/* Print Heading on 2nd row of LCD */
		LCD_String(buffer);
		LCD_Char(0xDF);	/* ASCII of Degree symbol */
		LCD_String("   ");
	}
}

 

Note that heading also gets affected by device tilt and nearby magnetic devices effect. There are compensating methods provided in the attached document.

 

Video

 


Comments