zoukankan      html  css  js  c++  java
  • 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
    ",__FILE__,__FUNCTION__,__LINE__);
    		#endif
    		return res;
    	}
        res = ComSendByte(regValue);    //内部寄存器地址
    	if(res)
    	{
    		#ifdef HMC_DEBUG
    		printf("file=%s,func=%s,line=%d
    ",__FILE__,__FUNCTION__,__LINE__);
    		#endif
    		return res;
    	}
        res = ComSendByte(setValue);    //内部寄存器数据
    	if(res)
    	{
    		#ifdef HMC_DEBUG
    		printf("file=%s,func=%s,line=%d
    ",__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
    ",__FILE__,__FUNCTION__,__LINE__);
    		#endif
    		return res;
    	}
        res = ComSendByte(regAddr);     	//发送存储单元地址,从0开始	
    	if(res)
    	{
    		#ifdef HMC_DEBUG
    		printf("file=%s,func=%s,line=%d
    ",__FILE__,__FUNCTION__,__LINE__);
    		#endif
    		return res;
    	}
        ComStart();                 		//起始信号
        res = ComSendByte(HMC_ADDR+1);  	//发送设备地址+读信号
    	if(res)
    	{
    		#ifdef HMC_DEBUG
    		printf("file=%s,func=%s,line=%d
    ",__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
    ",__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
    ",__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
    ",__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 	 y = %d 	 z = %d 	 axis = %f
    ",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
    
    
    
    
    
    
    

    引脚连接电路如下


  • 相关阅读:
    Eclipse
    文件递归查找
    BeanFactory 和 AppliactionContext的区别?
    文件上传
    Servlet路径的使用
    FileInputStream和FileOutputStream文件复制
    CentOS 7安装Nginx
    C语言程序设计100例之(6):数字反转
    C语言程序设计100例之(5):分解质因数
    C语言程序设计100例之(4):水仙花数
  • 原文地址:https://www.cnblogs.com/dengxiaojun/p/4279443.html
Copyright © 2011-2022 走看看