HMC5883L地磁傳感器驅動


   霍尼韋爾 HMC5883L 是一種表面貼裝的高集成模塊,並帶有數字接口的弱磁傳感器芯片,應用於低成本羅盤和磁場檢測領域。HMC5883L 包括最先進的高分辨率 HMC118X 系列磁阻傳感器,並附帶霍尼韋爾專利的集成電路包括放大器、自動消磁驅動器、偏差校准、能使羅盤精度控制在 1°~2°的 12 位模數轉換器.簡易的 I2C 系列總線接口。HMC5883L 是采用無鉛表面封裝技術,帶有 16 引腳,尺寸為 3.0X3.0X0.9mm。HMC5883L 的所應用領域有手機、筆記本電腦、消費類電子、汽車導航系統和個人導航系統

   HMC5883主要有接口是IIC,同時提供一個數據中斷引腳,一般而言,電路設計如下


  該傳感器芯片的驅動並不復雜,主要是設置幾個寄存器,如下所示

//HMC5883寄存器定義
//寄存器地址定義
#define HMC_CONFIG_A_REG	0X00	//配置寄存器A
//bit0-bit1 xyz是否使用偏壓,默認為0正常配置
//bit2-bit4 數據輸出速率, 110為最大75HZ 100為15HZ 最小000 0.75HZ
//bit5-bit5每次采樣平均數 11為8次 00為一次

#define HMC_CONFIG_B_REG	0X01	//配置寄存器B
//bit7-bit5磁場增益 數據越大,增益越小 默認001

#define HMC_MODE_REG		0X02	//模式設置寄存器
//bit0-bit1 模式設置 00為連續測量 01為單一測量

#define HMC_XMSB_REG		0X03	//X輸出結果
#define HMC_XLSB_REG		0X04

#define HMC_ZMSB_REG		0X05	//Z輸出結果
#define HMC_ZLSB_REG		0X06

#define HMC_YMSB_REG		0X07	//Y輸出結果
#define HMC_YLSB_REG		0X08

#define HMC_STATUS_REG		0X09	//只讀的狀態
//bit1 數據更新時該位自動鎖存,等待用戶讀取,讀取到一半的時候防止數據改變
//bit0 數據已經准備好等待讀取了,DRDY引腳也能用

#define HMC_CHEAK_A_REG		0X0A	//三個識別寄存器,用於檢測芯片完整性
#define HMC_CHEAK_B_REG		0X0B
#define HMC_CHEAK_C_REG		0X0C

#define HMC_CHECKA_VALUE	0x48	//三個識別寄存器的默認值
#define HMC_CHECKB_VALUE	0x34
#define HMC_CHECKC_VALUE	0x33

建議選擇最大速率,八倍采樣輸出,同時該傳感器支持讀寫地址指針自動變化,但是針對隨機讀取的驅動而言,該特性不重要

另外,一般而言,地址為0x3c,驅動代碼如下

#include "hmc5883.h"
#include "math.h"

struct HMCVALUE hmcValue;
u8 dataReady = 0;


//IO方向設置
#define HMC_SDA_IN()  {GPIOC->CRH&=0XFFFFFFF0;GPIOC->CRH|=8;}
#define HMC_SDA_OUT() {GPIOC->CRH&=0XFFFFFFF0;GPIOC->CRH|=3;}

//IO操作函數	 
#define HMC_SCL    PCout(9) //SCL
#define HMC_SDA    PCout(8) //SDA	 
#define HMC_READ_SDA   PCin(8)  //輸入SDA 

#define HMC_DRDY	PCin(7)

/**************************HMC5883 IIC驅動函數*********************************/

static void Hmc5883IOInit(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOC, ENABLE );	
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   //推挽輸出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    
	//PC7 drdy引腳 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING ;   //浮空輸入
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
	
    HMC_SCL = 1;
    HMC_SDA = 1;
}



//發送IIC起始信號
static void ComStart(void)
{
	HMC_SDA_OUT();     //sda線輸出
    HMC_SDA=1;	  	  
    HMC_SCL=1;
    DelayUs(5);
    HMC_SDA=0;//START:when CLK is high,DATA change form high to low 
    DelayUs(5);
    HMC_SCL=0;//鉗住I2C總線,准備發送或接收數據
}
//發送IIC停止信號
static void ComStop(void)
{
	HMC_SDA_OUT();//sda線輸出
    HMC_SDA=0;//STOP:when CLK is high DATA change form low to high
    HMC_SCL=1;
    DelayUs(5);
    HMC_SDA=1;//發送I2C總線結束信號
    DelayUs(5);		
}
//等待ACK,為1代表無ACK 為0代表等到了ACK
static u8 ComWaitAck(void)
{
	u8 waitTime = 0;
	HMC_SDA_OUT();//sda線輸出
	HMC_SDA = 1;
	DelayUs(5);
    HMC_SDA_IN();      //SDA設置為輸入
	HMC_SCL=1;
	DelayUs(5);
	while(HMC_READ_SDA)
	{
		waitTime++;
		DelayUs(1);
		if(waitTime > HMC_ACK_WAIT_TIME)
		{
			ComStop();
			return 1;
		}
	}
	HMC_SCL = 0;
	return 0;
	
}

static void ComSendAck(void)
{
	HMC_SCL = 0;
	HMC_SDA_OUT();
    HMC_SDA = 0;
	DelayUs(2);
    HMC_SCL = 1;
    DelayUs(5);
    HMC_SCL = 0;
    DelayUs(5);
}

static void ComSendNoAck(void)
{
	HMC_SCL = 0;
	HMC_SDA_OUT();
    HMC_SDA = 1;
	DelayUs(2);
    HMC_SCL = 1;
    DelayUs(5);
    HMC_SCL = 0;
    DelayUs(5);
}
//返回0 寫入收到ACK 返回1寫入未收到ACK
static u8 ComSendByte(u8 byte)
{
	u8 t;   
    HMC_SDA_OUT(); 	
    for(t=0;t<8;t++)
    {              
        HMC_SDA=(byte&0x80)>>7;
        byte<<=1; 	   
        HMC_SCL=1;
        DelayUs(5); 
        HMC_SCL=0;	
        DelayUs(5);
    }	 
    return ComWaitAck();
}

static void ComReadByte(u8* byte)
{
	u8 i,receive=0;
    HMC_SDA_IN();//SDA設置為輸入
    for(i=0;i<8;i++ )
    {
        receive <<= 1;
        HMC_SCL=1; 
        DelayUs(5);
        if(HMC_READ_SDA)receive++;
        HMC_SCL=0; 
        DelayUs(5); 
    }					  
    *byte = receive;
}

/**************************HMC5883 IIC驅動函數*********************************/


//向HMC寫入一個字節數據,失敗返回1 成功返回0
u8 Hmc5883WriteReg(u8 regValue,u8 setValue)
{
	u8 res;
    ComStart();                 	//起始信號
    res = ComSendByte(HMC_ADDR);    //發送設備地址+寫信號
	if(res)
	{
		#ifdef HMC_DEBUG
		printf("file=%s,func=%s,line=%d\r\n",__FILE__,__FUNCTION__,__LINE__);
		#endif
		return res;
	}
    res = ComSendByte(regValue);    //內部寄存器地址
	if(res)
	{
		#ifdef HMC_DEBUG
		printf("file=%s,func=%s,line=%d\r\n",__FILE__,__FUNCTION__,__LINE__);
		#endif
		return res;
	}
    res = ComSendByte(setValue);    //內部寄存器數據
	if(res)
	{
		#ifdef HMC_DEBUG
		printf("file=%s,func=%s,line=%d\r\n",__FILE__,__FUNCTION__,__LINE__);
		#endif
		return res;
	}
    ComStop();                   	//發送停止信號
	return res;
}

//**************************************
//從I2C設備讀取一個字節數據
//**************************************
u8 Hmc5883ReadReg(u8 regAddr,u8* readValue)
{
    u8 res;
    ComStart();                 		//起始信號
    res = ComSendByte(HMC_ADDR);    	//發送設備地址+寫信號
	if(res)
	{
		#ifdef HMC_DEBUG
		printf("file=%s,func=%s,line=%d\r\n",__FILE__,__FUNCTION__,__LINE__);
		#endif
		return res;
	}
    res = ComSendByte(regAddr);     	//發送存儲單元地址,從0開始	
	if(res)
	{
		#ifdef HMC_DEBUG
		printf("file=%s,func=%s,line=%d\r\n",__FILE__,__FUNCTION__,__LINE__);
		#endif
		return res;
	}
    ComStart();                 		//起始信號
    res = ComSendByte(HMC_ADDR+1);  	//發送設備地址+讀信號
	if(res)
	{
		#ifdef HMC_DEBUG
		printf("file=%s,func=%s,line=%d\r\n",__FILE__,__FUNCTION__,__LINE__);
		#endif
		return res;
	}
    ComReadByte(readValue);     		//讀出寄存器數據
    ComSendNoAck();               		//發送非應答信號
    ComStop();                  		//停止信號
    return res;
}


static void HmcDefaultConfig(void)
{
	Hmc5883WriteReg(HMC_CONFIG_A_REG,HMC_DEFAULT_CONFIGA_VALUE);
	Hmc5883WriteReg(HMC_CONFIG_B_REG,HMC_DEFAULT_CONFIGB_VALUE);
	Hmc5883WriteReg(HMC_MODE_REG,HMC_DEFAULT_MODE_VALUE);
}

//配置HMC drdy引腳中斷
void HmcDrdyPinIntInit(void)
{
	EXTI_InitTypeDef EXTI_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
	
	//GPIOC.7 中斷線以及中斷初始化配置   下降沿觸發
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource7);
    
    EXTI_InitStructure.EXTI_Line=EXTI_Line7;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;	//下降沿中斷
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);	 	//根據EXTI_InitStruct中指定的參數初始化外設EXTI寄存器
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;			//使能所在的外部中斷通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = HMC_DRDY_PreemptionPriority;	//搶占優先級 
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = HMC_DRDY_SubPriority;					//子優先級
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;								//使能外部中斷通道
    NVIC_Init(&NVIC_InitStructure);
}

//對應的外部中斷處理函數
void EXTI9_5_IRQHandler()
{
	if(EXTI_GetFlagStatus(EXTI_Line7) == SET)
	{
		EXTI_ClearFlag(EXTI_Line7);
		dataReady = 1;
	}
}
//失敗返回1,初始化通過之后基本通訊就沒有問題了就可以不再判定通訊結果了
u8 HmcInit(void)
{
    u8 hmcCheckValue = 0x00;
	u8 res = 0;
    Hmc5883IOInit();	//接口初始化
	while(HMC_DRDY == 1);//等待數據引腳正常
	HmcDrdyPinIntInit();//配置中斷
    DelayMs(100);
	//驗證A識別
    res = Hmc5883ReadReg(HMC_CHEAK_A_REG,&hmcCheckValue);
	if(res)
	{
		#ifdef HMC_DEBUG
		printf("file=%s,func=%s,line=%d\r\n",__FILE__,__FUNCTION__,__LINE__);
		#endif
	}
    if(hmcCheckValue != HMC_CHECKA_VALUE)	//自檢通過
    {
        return 1;
    }
	//驗證B識別
	res = Hmc5883ReadReg(HMC_CHEAK_B_REG,&hmcCheckValue);
	if(res)
	{
		#ifdef HMC_DEBUG
		printf("file=%s,func=%s,line=%d\r\n",__FILE__,__FUNCTION__,__LINE__);
		#endif
	}
    if(hmcCheckValue != HMC_CHECKB_VALUE)	//自檢通過
    {
        return 1;
    }
	//驗證C識別
	res = Hmc5883ReadReg(HMC_CHEAK_C_REG,&hmcCheckValue);
	if(res)
	{
		#ifdef HMC_DEBUG
		printf("file=%s,func=%s,line=%d\r\n",__FILE__,__FUNCTION__,__LINE__);
		#endif
	}
    if(hmcCheckValue != HMC_CHECKC_VALUE)	//自檢通過
    {
        return 1;
    }
	HmcDefaultConfig();
	//全部驗證通過
    return 0;
}



void Hmc5883Reflush(void)
{
    u16 xValue = 0x00,yValue = 0x00,zValue = 0x00;
	u8 temp;
	Hmc5883ReadReg(HMC_XMSB_REG,&temp);
    xValue |= temp;
	xValue <<=8;
	Hmc5883ReadReg(HMC_XLSB_REG,&temp);
	xValue |=  temp;
	
	Hmc5883ReadReg(HMC_ZMSB_REG,&temp);
	zValue |=  temp;
	zValue <<=8;
	Hmc5883ReadReg(HMC_ZLSB_REG,&temp);
	zValue |=  temp;
	
	Hmc5883ReadReg(HMC_YMSB_REG,&temp);
	yValue |=  temp;
	yValue <<=8;
	Hmc5883ReadReg(HMC_YLSB_REG,&temp);
	yValue |=  temp;
	
	hmcValue.hmcXvalue = (s16)xValue;
	hmcValue.hmcYvalue = (s16)yValue;
	hmcValue.hmcZvalue = (s16)zValue;
	
	hmcValue.hmcAxis = atan2((double)hmcValue.hmcYvalue,(double)hmcValue.hmcXvalue) * (180 / 3.14159265) + 180; // angle in degrees
	#ifdef HMC_DEBUG
	printf("x = %d \t y = %d \t z = %d \t axis = %f\r\n",xValue,yValue,zValue,hmcValue.hmcAxis);
	#endif
}



頭文件定義如下(中斷有優先級請自行定義)

#ifndef __HMC5883_H_
#define __HMC5883_H_

#include "common.h"
#include "stm32f10x.h"
#include "delay.h"
#include "ioremap.h"
#include "uart.h"

#define HMC_DEBUG	1	//是否輸出調試信息

//沒有主機改變地址的話地址是可以自動更新的,不過該驅動沒有用這個模式


//HMC5883寄存器定義
//寄存器地址定義
#define HMC_CONFIG_A_REG	0X00	//配置寄存器A
//bit0-bit1 xyz是否使用偏壓,默認為0正常配置
//bit2-bit4 數據輸出速率, 110為最大75HZ 100為15HZ 最小000 0.75HZ
//bit5-bit5每次采樣平均數 11為8次 00為一次

#define HMC_CONFIG_B_REG	0X01	//配置寄存器B
//bit7-bit5磁場增益 數據越大,增益越小 默認001

#define HMC_MODE_REG		0X02	//模式設置寄存器
//bit0-bit1 模式設置 00為連續測量 01為單一測量

#define HMC_XMSB_REG		0X03	//X輸出結果
#define HMC_XLSB_REG		0X04

#define HMC_ZMSB_REG		0X05	//Z輸出結果
#define HMC_ZLSB_REG		0X06

#define HMC_YMSB_REG		0X07	//Y輸出結果
#define HMC_YLSB_REG		0X08

#define HMC_STATUS_REG		0X09	//只讀的狀態
//bit1 數據更新時該位自動鎖存,等待用戶讀取,讀取到一半的時候防止數據改變
//bit0 數據已經准備好等待讀取了,DRDY引腳也能用

#define HMC_CHEAK_A_REG		0X0A	//三個識別寄存器,用於檢測芯片完整性
#define HMC_CHEAK_B_REG		0X0B
#define HMC_CHEAK_C_REG		0X0C

#define HMC_CHECKA_VALUE	0x48	//三個識別寄存器的默認值
#define HMC_CHECKB_VALUE	0x34
#define HMC_CHECKC_VALUE	0x33


//HMC5883地址定義
#define HMC_ADDR          0X3C          //寫地址,讀地址+1


//HMC5883 初始化宏定義
#define HMC_DEFAULT_CONFIGA_VALUE		0x78	 //75hz 8倍采樣 正常配置
#define HMC_DEFAULT_CONFIGB_VALUE		0x00	 //+-0.88GA增益
#define HMC_DEFAULT_MODE_VALUE			0x00     //連續測量模式


#define HMC_ACK_WAIT_TIME	200		//iic通訊時的ack等待時間

//HMC5883驅動結構體定義
typedef struct HMCVALUE 
{
	s16 hmcXvalue;
	s16 hmcYvalue;
	s16 hmcZvalue;
	double hmcAxis;
}HMCVALUE;



u8 HmcInit(void);

u8 Hmc5883WriteReg(u8 regValue,u8 setValue);

u8 Hmc5883ReadReg(u8 regAddr,u8* readValue);

void Hmc5883Reflush(void);



extern struct HMCVALUE hmcValue;
extern u8 dataReady;


#endif







引腳連接電路如下



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM