HMC5883L是霍尼韦尔采用各向异性磁阻技术开发的磁力计模块。它是一个多芯片模块,充当数字罗盘(电子罗盘模块),用于确定方向并测量沿X、Y和Z轴的磁场的大小和方向。HMC5883L模块将磁场转换为3轴引脚上的差分电压输出。
与人类不同,机器人和无人机等无人机器无法感知向哪个方向移动,所以它们需要一个传感器来识别方向,这就是磁力计发挥的功能。它们感知磁场并基于该磁场,告诉集成该磁力计设备的方向。因此,可以使用HMC5883L来确定物体的方向。
HMC5883L磁力计模块由XC6206P332MR IC等元器件组成,首先来看看该IC的引脚配置,然后看看该模块的引脚排列。
引脚配置说明:
Pin3、5、6、7和14是NC引脚,它们没有任何功能,这就是未连接的原因。
Pin1和Pin16是I2C接口的通信引脚,具体为:
SCL是主/从时钟输入,它从主设备接收时钟信号。当我们将磁力计IC与微控制器连接时,它充当从属设备。因此,微控制器向IC提供时钟信号。SDA是串行数据引脚。
Pin2为电源引脚。传感器工作需要2.16V至3.6V范围内的电压,它为内部操作提供动力。Pin9和Pin11为接地引脚。
如下图所示,XC6206P332MR IC有很多管脚,我们需要使用外部元件来使其工作。幸运的是,市场上可以买到包含所有必需组件的模块。此图显示了磁力计模块的引出线。
从这个引脚图可以看出,该模块易于使用且引脚数较少。所有管脚的功能都是一样的。SCL和SDA引脚用于连接微控制器以接收来自磁力计的3轴数据。
下图显示了HMC5883L传感器模块的两个参考设计,以了解其工作原理。在单电源设计中,在引脚VDD和VDDIO上应用相同的电源电压。在双电源模式下,在两个引脚上应用了单独的电源。VDD为IC的内部操作提供电源,而VDDIO为I2C接口提供电源以实现通信。两个电路中的所有其它连接都相同。它有两种操作模式标准和快速模式。因此,连接上拉电阻来支持这些模式。
1、单电源设计电路
2、双电源设计电路
以下是开始初始化和读取指南针模块值的基本步骤。该模块配备4.7 kΩ SDA线上的上拉电阻器和SCL线上的2.2K电阻器,不需要任何外部硬件进行操作。电路示意图如下所示:
HMC5883L有一个分线板,其中包含额外的电路,使其与其它微控制器兼容。你可以直接将此分线板与Arduino Uno连接,无需额外的组件。连接很简单,将Vcc连接到+5V并接地到Arduino的接地引脚。将通信引脚SCL和SDA连接到模拟引脚5和4或Arduino。
HMC5883 Arduino库
使用James Sleeman的HMC5883L库可以非常轻松地对该HMC5883模块进行编程。首先,转到此链接并下载库。
之后转到Arduino库管理器并添加HMC5883库。或者可以提取下载的文件夹并将此文件粘贴到Arduino库文件夹中。
与Arduino的连接图
按照下面所示连接磁力计模块和Arduino Uno。
Arduino代码
此代码显示HMC5883L模块Arduino库的功能。
#include <Arduino.h>
// PLEASE NOTE!
// The Arduino IDE is a bit braindead, even though we include Wire.h here, it does nothing
// you must include Wire.h in your main sketch, the Arduino IDE will not include Wire
// in the build process otherwise.
#include <Wire.h>
#include "HMC5883L_Simple.h"
HMC5883L_Simple::HMC5883L_Simple()
{
declination_offset_radians = 0;
mode = COMPASS_SINGLE | COMPASS_SCALE_130 | COMPASS_HORIZONTAL_X_NORTH;
i2c_address = COMPASS_I2C_ADDRESS; // NB: The HMC5883L does not appear to be able to have any different address.
// so this is a bit moot.
}
/** Set declination in degrees, minutes and direction (E/W)
* See http://www.magnetic-declination.com/
*/
void HMC5883L_Simple::SetDeclination( int declination_degs , int declination_mins, char declination_dir )
{
// Convert declination to decimal degrees
switch(declination_dir)
{
// North and East are positive
case 'E':
declination_offset_radians = ( declination_degs + (1/60 * declination_mins)) * (M_PI / 180);
break;
// South and West are negative
case 'W':
declination_offset_radians = 0 - (( declination_degs + (1/60 * declination_mins) ) * (M_PI / 180));
break;
}
}
/** Set the sampling mode to one of COMPASS_CONTINUOUS or COMPASS_SINGLE
*/
void HMC5883L_Simple::SetSamplingMode( uint16_t sampling_mode )
{
// Mode is the bits marked M in mode
// xxxxxxxxxxxSSSMM
mode = (mode & ~0x03) | (sampling_mode & 0x03);
Write(COMPASS_MODE_REGISTER, mode & 0x03);
}
/** Set the scale to one of COMPASS_SCALE_088 through COMPASS_SCALE_810
* Higher scales are less sensitive and less noisy
* Lower scales are more sensitive and more noisy
*/
void HMC5883L_Simple::SetScale( uint16_t scale )
{
// Scale is the bits marked S in mode
// xxxxxxxxxxxSSSMM
mode = (mode & ~0x1C) | (scale & 0x1C);
Write(COMPASS_CONFIG_REGISTER_B, (( mode >> 2 ) & 0x07) << 5);
}
/** Set the orientation to one of COMPASS_HORIZONTAL_X_NORTH
* through COMPASS_VERTICAL_Y_WEST
*
*/
void HMC5883L_Simple::SetOrientation( uint16_t orientation )
{
// Orientation is the bits marked XXXYYYZZZ in mode
// xxXXXYYYZZZxxxxx
mode = (mode & ~0x3FE0) | (orientation & 0x3FE0);
}
/** Get the heading of the compass in degrees. */
float HMC5883L_Simple::GetHeadingDegrees()
{
// Obtain a sample of the magnetic axes
MagnetometerSample sample = ReadAxes();
float heading;
// Determine which of the Axes to use for North and West (when compass is "pointing" north)
float mag_north, mag_west;
// Z = bits 0-2
switch((mode >> 5) & 0x07 )
{
case COMPASS_NORTH: mag_north = sample.Z; break;
case COMPASS_SOUTH: mag_north = 0-sample.Z; break;
case COMPASS_WEST: mag_west = sample.Z; break;
case COMPASS_EAST: mag_west = 0-sample.Z; break;
// Don't care
case COMPASS_UP:
case COMPASS_DOWN:
break;
}
// Y = bits 3 - 5
switch(((mode >> 5) >> 3) & 0x07 )
{
case COMPASS_NORTH: mag_north = sample.Y; break;
case COMPASS_SOUTH: mag_north = 0-sample.Y; ; break;
case COMPASS_WEST: mag_west = sample.Y; break;
case COMPASS_EAST: mag_west = 0-sample.Y; break;
// Don't care
case COMPASS_UP:
case COMPASS_DOWN:
break;
}
// X = bits 6 - 8
switch(((mode >> 5) >> 6) & 0x07 )
{
case COMPASS_NORTH: mag_north = sample.X; break;
case COMPASS_SOUTH: mag_north = 0-sample.X; break;
case COMPASS_WEST: mag_west = sample.X; break;
case COMPASS_EAST: mag_west = 0-sample.X; break;
// Don't care
case COMPASS_UP:
case COMPASS_DOWN:
break;
}
// calculate heading from the north and west magnetic axes
heading = atan2(mag_west, mag_north);
// Adjust the heading by the declination
heading += declination_offset_radians;
// Correct for when signs are reversed.
if(heading < 0)
heading += 2*M_PI;
// Check for wrap due to addition of declination.
if(heading > 2*M_PI)
heading -= 2*M_PI;
// Convert radians to degrees for readability.
return heading * 180/M_PI;
}
/** Read the axes from the magnetometer.
* In SINGLE mode we take a sample. In CONTINUOUS mode we
* just grab the most recent result in the registers.
*/
HMC5883L_Simple::MagnetometerSample HMC5883L_Simple::ReadAxes()
{
if(mode & COMPASS_SINGLE)
{
Write(COMPASS_MODE_REGISTER, (uint8_t)( mode & 0x03 ));
delay(66); // We could listen to the data ready pin instead of waiting.
}
uint8_t buffer[6];
Read(COMPASS_DATA_REGISTER, buffer, 6);
MagnetometerSample sample;
// NOTE:
// The registers are in the order X Z Y (page 11 of datasheet)
// the datasheet when it describes the registers details then in order X Y Z (page 15)
// stupid datasheet writers
sample.X = (buffer[0] << 8) | buffer[1];
sample.Z = (buffer[2] << 8) | buffer[3];
sample.Y = (buffer[4] << 8) | buffer[5];
return sample;
}
/** Write data to the compass by I2C */
void HMC5883L_Simple::Write(uint8_t register_address, uint8_t data)
{
Wire.beginTransmission(i2c_address);
Wire.write(register_address);
Wire.write(data);
Wire.endTransmission();
}
/** Read data from the compass by I2C
*/
uint8_t HMC5883L_Simple::Read(uint8_t register_address, uint8_t buffer[], uint8_t length)
{
// Write the register address that we will begin the read from, this
// has the effect of "seeking" to that register
Wire.beginTransmission(i2c_address);
Wire.write(register_address);
Wire.endTransmission();
// Read the data starting at that register we seeked
Wire.requestFrom(i2c_address, length);
if(Wire.available() == length)
{
for(uint8_t i = 0; i < length; i++)
{
buffer[i] = Wire.read();
}
return length;
}
return 0;
}
示例代码
此示例草图显示了Arduino串行监视器上HMC5883L三轴磁力计的航向读数。
#include <Arduino.h>
#include <Wire.h>
#include <HMC5883L_Simple.h>
// Create a compass
HMC5883L_Simple Compass;
void setup()
{
Serial.begin(9600);
Wire.begin();
// Magnetic Declination is the correction applied according to your present location
// in order to get True North from Magnetic North, it varies from place to place.
//
// The declination for your area can be obtained from http://www.magnetic-declination.com/
// Take the "Magnetic Declination" line that it gives you in the information,
//
// Examples:
// Christchurch, 23° 35' EAST
// Wellington , 22° 14' EAST
// Dunedin , 25° 8' EAST
// Auckland , 19° 30' EAST
//
Compass.SetDeclination(23, 35, 'E');
// The device can operate in SINGLE (default) or CONTINUOUS mode
// SINGLE simply means that it takes a reading when you request one
// CONTINUOUS means that it is always taking readings
// for most purposes, SINGLE is what you want.
Compass.SetSamplingMode(COMPASS_SINGLE);
// The scale can be adjusted to one of several levels, you can probably leave it at the default.
// Essentially this controls how sensitive the device is.
// Options are 088, 130 (default), 190, 250, 400, 470, 560, 810
// Specify the option as COMPASS_SCALE_xxx
// Lower values are more sensitive, higher values are less sensitive.
// The default is probably just fine, it works for me. If it seems very noisy
// (jumping around), incrase the scale to a higher one.
Compass.SetScale(COMPASS_SCALE_130);
// The compass has 3 axes, but two of them must be close to parallel to the earth's surface to read it,
// (we do not compensate for tilt, that's a complicated thing) - just like a real compass has a floating
// needle you can imagine the digital compass does too.
//
// To allow you to mount the compass in different ways you can specify the orientation:
// COMPASS_HORIZONTAL_X_NORTH (default), the compass is oriented horizontally, top-side up. when pointing North the X silkscreen arrow will point North
// COMPASS_HORIZONTAL_Y_NORTH, top-side up, Y is the needle,when pointing North the Y silkscreen arrow will point North
// COMPASS_VERTICAL_X_EAST, vertically mounted (tall) looking at the top side, when facing North the X silkscreen arrow will point East
// COMPASS_VERTICAL_Y_WEST, vertically mounted (wide) looking at the top side, when facing North the Y silkscreen arrow will point West
Compass.SetOrientation(COMPASS_HORIZONTAL_X_NORTH);
}
// Our main program loop.
void loop()
{
float heading = Compass.GetHeadingDegrees();
Serial.print("Heading: \t");
Serial.println( heading );
delay(1000);
}
HMC5883L是一款价格低廉且易于获得的小型传感器,它的数字接口允许它与其它微控制器一起使用。甚至可以将它与普通IC连接。与业内其它磁力计相比,这些传感器是最可靠、最灵敏的传感器。
当然,你可以在应用中使用此传感器来测量磁场的强度和大小,还可以测量材料的磁化强度。如果正在寻找可以通过提供精确测量来执行上述功能的磁力计,那么此传感器最适合此目的。一些比较常见的应用如下:
HMC5883L是霍尔磁敏感元件,用于测量磁场强度和方向。它是一种数字式三轴磁力计,通过霍尔效应测量磁场强度和方向,具有可调的分辨率和量程,并通过I2C接口与其它设备通信。HMC5883L在导航、定位和姿态测量等领域具有广泛应用。