基于STM32的三轴数字罗盘HMC5883L模块的测试方案

最近买了个数字罗盘模块,调通后发现很不错,非常灵敏,测试的时候精度在1°以内。连续测量模式下,最快测量、输出速率可达75hz,模块每次测量完毕并将数据更新至寄存器后,其drdy引脚便产生一个低电平脉冲(可以配置一个外部中断捕获drdy引脚的下降沿,并在中断服务程序中读取数据),在stm32中可以设置一个下降沿触发的外部中断,并在中断服务程序中调用角度数据读取函数。以下为操作该模块的主要步骤。
一、iic协议相关操作(单片机作为主机控制时钟线) 宏定义:
//这里用到了stm32的位带区操作,方便实现对一个位的操作
//pb13配置为od输出,同时外部给上拉电阻,这样既可输出信号给从机,也能
//在pb13为漏极开路状态时接收从机的信号(stm32的io配置为输出模式时,
//io口的电平也会不断地被捕获到输入寄存器中)
//pb14配置为推挽输出,pb15配置为浮空输入
#definer_sdaipb13//pb13输入寄存器
#definew_sdaopb13//pb13输出寄存器
#definew_sclopb14//pb14输出寄存器
#definer_drdyipb15//pb15输入寄存器
#definexmsb0//x轴数字量的高8位
#definexlsb1//x轴数字量的低8位
#definezmsb2//z轴数字量的高8位
#definezlsb3//z轴数字量的低8位
#defineymsb4//y轴数字量的高8位
#defineylsb5//y轴数字量的低8位
附位带宏定义:
#definegpiob_odr_addr(gpiob_base+12)//0x40010c0c
#definegpiob_idr_addr(gpiob_base+8)//0x40010c08
#definebitband_addr(addr,num)((volatileunsignedlong*)(0x42000000+32*(addr-0x40000000)+4*num))
#defineipb13*bitband_addr(gpiob_idr_addr,13)
#defineopb13*bitband_addr(gpiob_odr_addr,13)
#defineopb14*bitband_addr(gpiob_odr_addr,14)
#defineipb15*bitband_addr(gpiob_idr_addr,15)
启动iic传输:
void_iic_start()
{
w_scl=1;
w_sda=1;
_delay();
w_sda=0;//scl高时,拉低sda,表示开始iic传输,占用总线
_delay();
w_scl=0;//控制scl
_delay();
}
停止iic传输:
void_iic_stop()
{
w_scl=1;//释放scl(由于没有其他主器件,scl无需开漏)
w_sda=0;
发送一个字节:
uint8_t_iic_sendbyte(uint8_tdat)
{
uint8_ti;
for(i=0;i《8;i++)
{
_delay();
w_sda=dat》》7;//scl拉高之前写sda
dat=dat《《1;
_delay();
w_scl=1;//拉高scl,从器件开始读取sda
_delay();
w_scl=0;//重新拉低scl
}
w_sda=1;//释放sda
w_scl=1;//拉高scl,读取从器件应答信号
//等待应答
i=100;
while(i&&r_sda){i--;_delay();}
if(i==0)//无应答
{
w_scl=0;//重新拉低scl
return0;
}
else{//有应答
_delay();
w_scl=0;//重新拉低scl
return1;
}
}
_delay();
w_sda=1;//scl为高时,拉高sda表示结束icc传输,释放总线
}
接收一个字节:
uint8_t_iic_readbyte(uint8_tack)
{
uint8_ttemp,i;
w_sda=1;//释放sda
_delay();
for(i=0;i《8;i++)
{
_delay();
w_scl=1;//拉高scl开始读取sda
temp=temp《《1;
temp|=r_sda;//scl拉高之后读取sda
w_scl=0;//拉低scl,从器件开始放置数据
}
//发送应答信号
if(ack)w_sda=0;//拉低sda表示应答
w_scl=1;//拉高scl,从器件接收应答信号
_delay();
w_scl=0;//重新拉低scl
w_sda=1;//释放sda
returntemp;
}
二、配置hmc5883l模块 voidhmc5883l_init()
{
_iic_start();
_iic_sendbyte(0x3c);//写操作
_iic_sendbyte(0x00);//指针指向00,配置寄存器a
_iic_sendbyte(0x78);//数据测量、输出速率75hz
_iic_start();//指针定位到02,模式寄存器
_iic_sendbyte(0x3c);
_iic_sendbyte(0x02);
_iic_sendbyte(0x00);//连续测量模式
_iic_stop();
}
三、读取角度数据 接收三轴数据,处理x,y轴的数据并计算角度:
int16_thmc5883l_readangle()
{
staticuint8_ti;
staticuint8_txyz_data[6];//用来存储三个轴输出的数字量
_iic_start();
_iic_sendbyte(0x3c);//发送hmc5883l的器件地址0x3c,写操作
_iic_sendbyte(0x03);//指针指向03,xmsb寄存器
_iic_start();
_iic_sendbyte(0x3d);//改为读操作
//依次读取三个轴的数字量
for(i=0;i《5;i++)//前5次读取发送应答信号
{
xyz_data[i]=_iic_readbyte(1);
}
xyz_data[5]=_iic_readbyte(0);//不应答
_iic_stop();
returnatan2((double)((int16_t)((xyz_data[ymsb]《《8)+xyz_data[ylsb])),(double)((int16_t)((xyz_data[xmsb]《《8)+xyz_data[xlsb])))*(180/3.14159265)+180;//计算角度,需要包含math.h头文件
}
配置好io口,调用hmc5883l_init()后,便可调用hmc5883l_readangle()读取角度值,0~360°。以下为测试时的截图:
测试时,模块比较灵敏且精确,稍微旋转模块便有精确的变化。由于该模块是基于对地磁场的测量,此模块容易受到其他磁场的干扰,比如将该模块靠近直流电机时,便会因为电机内的磁场而降低精度甚至失灵(之前做智能小车时就遇到这个问题,要将电机内的磁场屏蔽起来才行)。

移动互联网有哪些应用?移动互联网的发展趋势及创业项目
可燃气体报警器价格一览:如何选择性价比最高的产品?
详解伺服、步进、变频三大控制要点
我国2020年智能制造市场规模将超过2200亿元
ROHM开发出超低阻值贴片电阻器“PML100系列”
基于STM32的三轴数字罗盘HMC5883L模块的测试方案
什么是远传式磁翻板液位计?
戴尔斥资12亿美元收购SonicWall
DeepMind正在开发可以利用基因序列预测蛋白质结构的新AI工具
哪款蓝牙耳机防水效果比较好?防水效果好的蓝牙耳机盘点
物联网时代的图形辨识的相关技术
红米Note 5,价格揭晓
红米Note4X评测:对比红米4高配版,颜值机身售价性能全方位比对,红米你青睐谁?
汽车安防市场掀手机远程遥控风暴
魅族曲面屏手机亮相,雷军颤抖了!
组合式空气消声过滤器的原理特点和应用分析
华硕ROG CROSSHAIR VIII DARK HERO主板,采用标准的ATX版型设计
手机电池经常故障解决处理方案
高度集成微处理器XC167CI-16F40F的性能特点及应用
关于几种室内无线定位技术介绍