電子指南針也稱爲電子羅盤,是一種重要的導航工具,能實時提供移動物體的航向和姿態。隨着半導體工藝的進步和手機操作系統的發展,集成了越來越多傳感器的智能手機變得功能強大,很多手機上都實現了電子羅盤的功能。而基於電子羅盤的應用(如Android的Skymap)在各個軟件平臺上也流行起來。
霍尼韋爾 HMC5883L是一種表面貼裝的高集成模塊,並帶有數字接口的弱磁傳感器芯片,應用於低成本羅盤和磁場檢測領域。HMC5883L 包括最先進的高分辨率HMC118X系列磁阻傳感器,並附帶霍尼韋爾專利的集成電路包括放大器、自動消磁驅動器、偏差校準、能使羅盤精度控制在1°~2°的12 位模數轉換器.簡易的I2C 系列總線接口。HMC5883L 是採用無鉛表面封裝技術,帶有16 引腳,尺寸爲3.0X3.0X0.9mm。HMC5883L 的所應用領域有手機、筆記本電腦、消費類電子、汽車導航系統和個人導航系統。
HMC5883L 採用霍尼韋爾各向異性磁阻(AMR)技術,該技術的優點是其他磁傳感器技術所無法企及。這些各向異性傳感器具有在軸向高靈敏度和線性高精度的特點.傳感器帶有的對於正交軸低敏感行的固相結構能用於測量地球磁場的方向和大小,其測量範圍從毫高斯到 8 高斯(gauss)。 霍尼韋爾的磁傳感器在低磁場傳感器行業中是靈敏度最高和可靠性最好的傳感器。
我們採用CC2540作爲單片機,通過模擬I2C與HMC5883L通信,代碼如下#include<ioCC2540.h>
#include <math.h>
#include <stdio.h>
#include "hmc5883l.h"
#define uchar unsigned char
#define uint unsigned int
#define SCL P1_0 //IIC時鐘引腳定義
#define SDA P1_1 //IIC數據引腳定義
#define SlaveAddress 0x3C //定義器件在IIC總線中的從地址
typedef unsigned char BYTE;
typedef unsigned short WORD;
void delay(unsigned int k);
void Init_HMC5883(void); //初始化5883
void WriteDataLCM(uchar dataW);
void WriteCommandLCM(uchar CMD,uchar Attribc);
void DisplayOneChar(uchar X,uchar Y,uchar DData);
void conversion(uint temp_data);
void Single_Write_HMC5883(uchar REG_Address,uchar REG_data); //單個寫入數據
uchar Single_Read_HMC5883(uchar REG_Address); //單個讀取內部寄存器數據
void Multiple_Read_HMC5883(); //連續的讀取內部寄存器數據
//以下是模擬iic使用函數-------------
void Delay5us();
void Delay5ms();
void HMC5883_Start();
void HMC5883_Stop();
void HMC5883_SendACK(unsigned char ack);
unsigned char HMC5883_RecvACK();
void HMC5883_SendByte(BYTE dat);
BYTE HMC5883_RecvByte();
void HMC5883_ReadPage();
void HMC5883_WritePage();
//-----------------------------------
/*******************************/
void delay(unsigned int k)
{
unsigned int i,j;
for(i=0;i<k;i++)
{
for(j=0;j<1210;j++)
{;}}
}
/**************************************
延時5微秒(STC90C52RC@12M)
不同的工作環境,需要調整此函數,注意時鐘過快時需要修改
當改用1T的MCU時,請調整此延時函數
**************************************/
void Delay5us()
{
unsigned char count_i;
for(count_i=0; count_i<30; count_i++);
}
/**************************************
延時5毫秒(STC90C52RC@12M)
不同的工作環境,需要調整此函數
當改用1T的MCU時,請調整此延時函數
**************************************/
void Delay5ms()
{
WORD n = 5600;
while (n--);
}
/**************************************
起始信號
**************************************/
void HMC5883_Start()
{
P1DIR |= 0x02;
SDA = 1; //拉高數據線
SCL = 1; //拉高時鐘線
Delay5us(); //延時
SDA = 0; //產生下降沿
Delay5us(); //延時
SCL = 0; //拉低時鐘線
}
/**************************************
停止信號
**************************************/
void HMC5883_Stop()
{
P1DIR |= 0x02;
SDA = 0; //拉低數據線
SCL = 1; //拉高時鐘線
Delay5us(); //延時
SDA = 1; //產生上升沿
Delay5us(); //延時
}
/**************************************
發送應答信號
入口參數:ack (0:ACK 1:NAK)
**************************************/
void HMC5883_SendACK(unsigned char ack)
{
P1DIR |= 0x02;
SDA = ack; //寫應答信號
SCL = 1; //拉高時鐘線
Delay5us(); //延時
SCL = 0; //拉低時鐘線
Delay5us(); //延時
}
/**************************************
接收應答信號
**************************************/
unsigned char HMC5883_RecvACK()
{
P1DIR &= 0xfd;
SCL = 1; //拉高時鐘線
Delay5us(); //延時
CY = SDA; //讀應答信號
SCL = 0; //拉低時鐘線
Delay5us(); //延時
return CY;
}
/**************************************
向IIC總線發送一個字節數據
**************************************/
void HMC5883_SendByte(BYTE dat)
{
BYTE i;
P1DIR |= 0x02;
for (i=0; i<8; i++) //8位計數器
{
dat <<= 1; //移出數據的最高位
SDA = CY; //送數據口
SCL = 1; //拉高時鐘線
Delay5us(); //延時
SCL = 0; //拉低時鐘線
Delay5us(); //延時
}
HMC5883_RecvACK();
}
/**************************************
從IIC總線接收一個字節數據
**************************************/
BYTE HMC5883_RecvByte()
{
BYTE i;
BYTE dat = 0;
P1DIR |= 0x02;
SDA = 1;//使能內部上拉,準備讀取數據,
P1DIR &= 0xfd;
for (i=0; i<8; i++) //8位計數器
{
dat <<= 1;
SCL = 1; //拉高時鐘線
Delay5us(); //延時
dat |= SDA; //讀數據
SCL = 0; //拉低時鐘線
Delay5us(); //延時
}
return dat;
}
//***************************************************
void Single_Write_HMC5883(uchar REG_Address,uchar REG_data)
{
HMC5883_Start(); //起始信號
HMC5883_SendByte(SlaveAddress); //發送設備地址+寫信號
HMC5883_SendByte(REG_Address); //內部寄存器地址,請參考中文pdf
HMC5883_SendByte(REG_data); //內部寄存器數據,請參考中文pdf
HMC5883_Stop(); //發送停止信號
}
//********單字節讀取內部寄存器*************************
uchar Single_Read_HMC5883(uchar REG_Address)
{ uchar REG_data;
HMC5883_Start(); //起始信號
HMC5883_SendByte(SlaveAddress); //發送設備地址+寫信號
HMC5883_SendByte(REG_Address); //發送存儲單元地址,從0開始
HMC5883_Start(); //起始信號
HMC5883_SendByte(SlaveAddress+1); //發送設備地址+讀信號
REG_data=HMC5883_RecvByte(); //讀出寄存器數據
HMC5883_SendACK(1);
HMC5883_Stop(); //停止信號
return REG_data;
}
//******************************************************
//
//連續讀出HMC5883內部角度數據,地址範圍0x3~0x5
//
//******************************************************
void Multiple_read_HMC5883(unsigned char *pBuf)
{ uchar i;
HMC5883_Start(); //起始信號
HMC5883_SendByte(SlaveAddress); //發送設備地址+寫信號
HMC5883_SendByte(0x03); //發送存儲單元地址,從0x3開始
HMC5883_Start(); //起始信號
HMC5883_SendByte(SlaveAddress+1); //發送設備地址+讀信號
for (i=0; i<6; i++) //連續讀取6個地址數據,存儲中BUF
{
*(pBuf+i) = HMC5883_RecvByte(); //BUF[0]存儲數據
if (i == 5)
{
HMC5883_SendACK(1); //最後一個數據需要回NOACK
}
else
{
HMC5883_SendACK(0); //迴應ACK
}
}
HMC5883_Stop(); //停止信號
Delay5ms();
}
//初始化HMC5883,根據需要請參考pdf進行修改****
void Init_HMC5883(void)
{
P1DIR |= 0x03;
Single_Write_HMC5883(0x02,0x00); //
}
所得到的數據爲在各個座標軸上的磁場強度,測試發現,計算出的磁場角度並不準確,這個淘寶上買的GY-273模塊自身應該有少許的干擾,需要進行校準。