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
引脚连接电路如下
HMC5883L地磁传感器驱动的更多相关文章
- stm32与地磁传感器HMC5883L
1.简介 霍尼韦尔 HMC5883L 是一种表面贴装的高集成模块,并带有数字接口的弱磁传感器芯片,应用于低成本罗盘和磁场检测领域.HMC5883L 包括最先进的高分辨率 HMC118X 系列磁阻传感器 ...
- 玩转X-CTR100 l STM32F4 l HMC5983/HMC5883L三轴磁力计传感器
我造轮子,你造车,创客一起造起来!塔克创新资讯[塔克社区 www.xtark.cn ][塔克博客 www.cnblogs.com/xtark/ ] 本文介绍X-CTR100控制器 扩展HMC ...
- 张高兴的 Windows 10 IoT 开发笔记:三轴数字罗盘 HMC5883L
注意,数据不包含校验,准确的来说我不知道怎么校验,但方向看起来差不多是对的... GitHub:https://github.com/ZhangGaoxing/windows-iot-demo/tre ...
- Android指南针之加速度传感器地磁传感器-android学习之旅(67)
由于andorid不推荐用传统的方向传感器,推荐用加速度传感器和地磁传感器来构造得到方向传感器的数据,其实主要是z轴的旋转角度 具体代码示例 代码如下 public class MainActivit ...
- 地磁应用中的低功耗无线数传模块xbee PRO S2C
地球上每一个地理坐标点,在一段时间内磁场强度是恒定的,当车辆这种铁磁物质经过这个点时,对这个点的磁场强度产生一个连续的扰动,通过磁传感器采样数据与初始采样数据(该点的地球磁场值)进行对比,其差值为车辆 ...
- 博世传感器调试笔记(三)加速度及地磁传感器BMC156
一. 器件简介:1. BMC 156是一款整合三轴地磁传感器与三轴(12bit)加速度传感器于一体的传感器,以BMC 150 电子罗盘模块为基础, 并与Bosch Sensortec 2x ...
- 基于STM32的三轴数字罗盘HMC5883L模块的测试
最近买了个数字罗盘模块,调通后发现很不错,非常灵敏,测试的时候精度在1°以内.连续测量模式下,最快测量.输出速率可达75hz,模块每次测量完毕并将数据更新至寄存器后,其DRDY引脚便产生一个低电平脉冲 ...
- 461在全志r16平台tinav3.0系统下使用地磁计QMC5883L
461在全志r16平台tinav3.0系统下使用地磁计QMC5883L 2018/9/7 14:08 版本:V1.0 开发板:SC3817R SDK:tina v3.0 (基本确认全志tina v3. ...
- 基于ARM-LINUX的温度传感器驱动-DS18B20
转载:http://blog.csdn.net/ayangke/article/details/6883244 作者:冯建,华清远见嵌入式学院讲师. DS18B20数字温度传感器接线方便,封装成后可应 ...
随机推荐
- linux C++通过ntp协议获取网络时间
转自:http://blog.csdn.net/ccjjyy/article/details/42871993 #include <stdio.h> #include <sys/ty ...
- Java成员变量默认值
Java中明确规定:1.如果是引用型的,比如:String,还有类对象,他们的默认值都是:null:2.而如果是值类型:double,int,long,float,char等等,他们都是:0:还有一个 ...
- VBS脚本随笔
1.定时运行程序与关闭程序的VBS处理方法: do set ws=createobject("wscript.shell") ws.run"你要运行的程序的路径(比如说d ...
- win10系统安装oracle11g时遇到INS-13001环境不满足最低要求
升级win10系统之后,需要重新安装Oracle,因为在安装Oralce11g时,使用64位的会出现各种不兼容问题,我每次安装都是使用32位的数据库. 在安装时点击setup.exe之后,出现了:[I ...
- hdu_5555_Immortality of Frog(状压DP)
题目连接:hdu_5555_Immortality of Frog 题意: 给你一个NxN的网格,第N行的每一列都有个青蛙,这些青蛙只会往上走,上帝会在每个膜中放一个长生不老的药,一共有N个膜,每个膜 ...
- jq中的移除事件
unbind([type],[data]); 第一个参数是事件类型,第二个参数是将要移出的函数 说明: 1,如果没有参数,则删除所有绑定的事件 2,如果只提供了事件类型作为参数,则只删除该类型的绑定事 ...
- centos搭建nginx环境
1.yum install pcre* 2.wget http://nginx.org/download/nginx-1.7.8.tar.gz 3.tar -zxvf nginx-1.7.8.tar ...
- centos dmesg
linux dmesg命令详解 功能说明:显示开机信息. 语 法:dmesg [-cn][-s ] 补充说明:kernel会将开机信息存储在ring buffer,若是开机时来不及查看信息,可利用 ...
- C# 经典入门12章-使用泛型-1
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAA8sAAAK5CAIAAAAHDiuGAAAgAElEQVR4nOyd9V9Uzfv/v3/J0t0N0p
- HDU 1711 Number Sequence(KMP匹配数字串)
这个就是kmp的数组形式,不用来处理字符串还真有点不习惯呢... #include<iostream> using namespace std; ,MAXM = ; int T[MAXN] ...