你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】基于STM32的三轴数字罗盘HMC5883L模块的测试

[复制链接]
STMCU小助手 发布时间:2022-2-9 20:25
     最近买了个数字罗盘模块,调通后发现很不错,非常灵敏,测试的时候精度在1°以内。连续测量模式下,最快测量、输出速率可达75hz,模块每次测量完毕并将数据更新至寄存器后,其DRDY引脚便产生一个低电平脉冲(可以配置一个外部中断捕获DRDY引脚的下降沿,并在中断服务程序中读取数据),在STM32中可以设置一个下降沿触发的外部中断,并在中断服务程序中调用角度数据读取函数。以下为操作该模块的主要步骤。
一、IIC协议相关操作(单片机作为主机控制时钟线)
宏定义:
  1. //这里用到了STM32的位带区操作,方便实现对一个位的操作
  2. //PB13配置为OD输出,同时外部给上拉电阻,这样既可输出信号给从机,也能
  3. //在PB13为漏极开路状态时接收从机的信号(STM32的IO配置为输出模式时,
  4. //IO口的电平也会不断地被捕获到输入寄存器中)
  5. //PB14配置为推挽输出,PB15配置为浮空输入
  6. #define R_SDA    IPB13          // PB13输入寄存器
  7. #define W_SDA    OPB13          // PB13输出寄存器
  8. #define W_SCL    OPB14          // PB14输出寄存器
  9. #define R_DRDY   IPB15          // PB15输入寄存器
复制代码
  1. #define Xmsb 0     //X轴数字量的高8位
  2. #define Xlsb 1       //X轴数字量的低8位
  3. #define Zmsb 2     //Z轴数字量的高8位
  4. #define Zlsb 3       //Z轴数字量的低8位
  5. #define Ymsb 4     //Y轴数字量的高8位
  6. #define Ylsb 5       //Y轴数字量的低8位
复制代码

附位带宏定义:
  1. #define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C
  2. #define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08   

  3. #define BITBAND_Addr(Addr,num)  ((volatile unsigned long *)(0x42000000+32*(Addr-0x40000000)+4*num))

  4. #define IPB13    *BITBAND_Addr(GPIOB_IDR_Addr,13)
  5. #define OPB13   *BITBAND_Addr(GPIOB_ODR_Addr,13)
  6. #define OPB14   *BITBAND_Addr(GPIOB_ODR_Addr,14)
  7. #define IPB15    *BITBAND_Addr(GPIOB_IDR_Addr,15)
复制代码

启动IIC传输:
  1. void _iic_Start()
  2. {
  3.      W_SCL=1;   
  4.      W_SDA=1;
  5.      _delay();
  6.      W_SDA=0;     //SCL高时,拉低SDA,表示开始IIC传输,占用总线
  7.      _delay();
  8.      W_SCL=0;     //控制SCL
  9.      _delay();
  10. }
复制代码

停止IIC传输:
  1. void _iic_Stop()
  2. {
  3.      W_SCL=1;     //释放SCL(由于没有其他主器件,SCL无需开漏)
  4.      W_SDA=0;     
  5.      _delay();
  6.      W_SDA=1;   //SCL为高时,拉高SDA表示结束ICC传输,释放总线
  7. }
复制代码

发送一个字节:
  1. uint8_t _iic_SendByte(uint8_t dat)         
  2. {
  3.         uint8_t i;
  4.      for(i=0;i<8;i++)
  5.     {
  6.         _delay();
  7.         W_SDA=dat>>7;     //SCL拉高之前写SDA
  8.         dat=dat<<1;
  9.         _delay();
  10.         W_SCL=1;         //拉高SCL,从器件开始读取SDA
  11.         _delay();
  12.         W_SCL=0;         //重新拉低SCL
  13.     }
  14.        W_SDA=1;             //释放SDA
  15.        W_SCL=1;             //拉高SCL,读取从器件应答信号
  16.       //   等待应答
  17.     i=100;
  18.     while(i&&R_SDA)  {i--;_delay();}
  19.     if(i==0)               //无应答
  20.     {
  21.         W_SCL=0;         //重新拉低SCL
  22.         return 0;
  23.     }
  24.     else {                 //有应答
  25.         _delay();
  26.         W_SCL=0;         //重新拉低SCL
  27.         return 1;
  28. }
  29. }
复制代码

接收一个字节:
  1. uint8_t _iic_ReadByte(uint8_t Ack)  
  2. {
  3.      uint8_t temp,i;
  4.      W_SDA=1;              //释放SDA
  5.      _delay();
  6.     for(i=0;i<8;i++)
  7.     {
  8.         _delay();
  9.         W_SCL=1;          //拉高SCL开始读取SDA         
  10.         temp=temp<<1;      
  11.         temp|=R_SDA;      //SCL拉高之后读取SDA
  12.         W_SCL=0;              //拉低SCL,从器件开始放置数据
  13.      }
  14.      //发送应答信号
  15.     if(Ack)W_SDA=0;             //拉低SDA表示应答
  16.     W_SCL=1;             //拉高SCL,从器件接收应答信号
  17.     _delay();
  18.     W_SCL=0;             //重新拉低SCL
  19.     W_SDA=1;             //释放SDA
  20.     return temp;
  21. }
复制代码


二、配置HMC5883L模块
  1. void HMC5883L_Init()
  2. {     
  3.      _iic_Start();
  4.      _iic_SendByte(0x3c); //写操作
  5.      _iic_SendByte(0x00); //指针指向00,配置寄存器A
  6.      _iic_SendByte(0x78);  //数据测量、输出速率75hz
  7.      _iic_Start();          //指针定位到02,模式寄存器
  8.      _iic_SendByte(0x3c);
  9.      _iic_SendByte(0x02);
  10.      _iic_SendByte(0x00);  //连续测量模式
  11.      _iic_Stop();
  12. }
复制代码

三、读取角度数据
接收三轴数据,处理X,Y轴的数据并计算角度:
  1. int16_t HMC5883L_ReadAngle()
  2. {
  3. static uint8_t i;
  4. static uint8_t XYZ_Data[6]; //用来存储三个轴输出的数字量

  5. _iic_Start();
  6. _iic_SendByte(0x3c); // 发送HMC5883L的器件地址0x3c,写操作
  7. _iic_SendByte(0x03); //指针指向03,X msb寄存器   
  8. _iic_Start();         
  9. _iic_SendByte(0x3d); //改为读操作

  10. //依次读取三个轴的数字量
  11. for(i=0;i<5;i++)        //前5次读取发送应答信号
  12. {
  13. XYZ_Data[i]=_iic_ReadByte(1);
  14. }
  15. XYZ_Data[5] =_iic_ReadByte(0);  //不应答
  16. _iic_Stop();
  17. return atan2( (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头文件
  18. }
复制代码


配置好IO口,调用HMC5883L_Init()后,便可调用HMC5883L_ReadAngle()读取角度值,0~360°。
以下为测试时的截图:
272324479545732.png

测试时,模块比较灵敏且精确,稍微旋转模块便有精确的变化。由于该模块是基于对地磁场的测量,此模块容易受到其他磁场的干扰,比如将该模块靠近直流电机时,
便会因为电机内的磁场而降低精度甚至失灵(之前做智能小车时就遇到这个问题,要将电机内的磁场屏蔽起来才行)。

收藏 评论0 发布时间:2022-2-9 20:25

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版