搜索
bottom↓
回复: 18

HMC5883L问题请教

[复制链接]

出0入0汤圆

发表于 2012-9-4 14:45:52 | 显示全部楼层 |阅读模式
新手请教各位大侠,HMC5883L的输出数据的含义是什么啊,也看过些网上的程序,角度的计算只用到X,Y的数据,那Z的输出数据有什么作用啊,计算出的角度与正北有什么关系,谢谢了

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2012-9-4 16:42:06 | 显示全部楼层
为什么不用Z轴数据呢?

出0入0汤圆

发表于 2012-9-4 18:25:43 | 显示全部楼层
看你用来做什么咯。
保证水平放,那Z轴的确可以丢弃。
如果姿态是任意的,就要配合加速度计判断水平面了,这时要用到Z轴。

出0入0汤圆

发表于 2012-9-5 14:59:01 | 显示全部楼层
咱刚想发帖问这个问题,发现这个贴,同问得到的X,Y,Z数据与方位有什么关系?怎样转换。

出0入0汤圆

发表于 2012-11-7 11:11:13 | 显示全部楼层
角度不是线性变化的
纠结

出0入0汤圆

发表于 2012-11-7 11:19:00 | 显示全部楼层
电子罗盘校准比较麻烦,具体看手册
  1. //***************************************
  2. // HMC5883 IIC测试程序
  3. // 使用单片机STC89C51
  4. // 晶振:11.0592M
  5. // 显示:LCD1602
  6. // 编译环境 Keil uVision2
  7. // 参考宏晶网站24c04通信程序
  8. // 时间:2011年3月1日
  9. //****************************************
  10. #include  <REG51.H>       
  11. #include  <math.h>    //Keil library  
  12. #include  <stdio.h>   //Keil library       
  13. #include  <INTRINS.H>
  14. #define   uchar unsigned char
  15. #define   uint unsigned int       
  16. //使用的端口,请按照以下接线
  17. #define   DataPort P0        //LCD1602数据端口
  18. sbit        SCL=P1^0;      //IIC时钟引脚定义
  19. sbit        SDA=P1^1;      //IIC数据引脚定义
  20. sbit    LCM_RS=P2^0;   //LCD1602命令端口               
  21. sbit    LCM_RW=P2^1;   //LCD1602命令端口               
  22. sbit    LCM_EN=P2^2;   //LCD1602命令端口

  23. #define        SlaveAddress   0x3C          //定义器件在IIC总线中的从地址
  24. typedef unsigned char BYTE;
  25. typedef unsigned short WORD;

  26. BYTE BUF[8];                         //接收数据缓存区             
  27. uchar ge,shi,bai,qian,wan;           //显示变量
  28. int  dis_data;                       //变量

  29. void delay(unsigned int k);
  30. void InitLcd();
  31. void Init_HMC5883(void);            //初始化5883

  32. void WriteDataLCM(uchar dataW);
  33. void WriteCommandLCM(uchar CMD,uchar Attribc);
  34. void DisplayOneChar(uchar X,uchar Y,uchar DData);
  35. void conversion(uint temp_data);

  36. void  Single_Write_HMC5883(uchar REG_Address,uchar REG_data);   //单个写入数据
  37. uchar Single_Read_HMC5883(uchar REG_Address);                   //单个读取内部寄存器数据
  38. void  Multiple_Read_HMC5883();                                  //连续的读取内部寄存器数据
  39. //以下是模拟iic使用函数-------------
  40. void Delay5us();
  41. void Delay5ms();
  42. void HMC5883_Start();
  43. void HMC5883_Stop();
  44. void HMC5883_SendACK(bit ack);
  45. bit  HMC5883_RecvACK();
  46. void HMC5883_SendByte(BYTE dat);
  47. BYTE HMC5883_RecvByte();
  48. void HMC5883_ReadPage();
  49. void HMC5883_WritePage();
  50. //-----------------------------------

  51. //*********************************************************
  52. void conversion(uint temp_data)  
  53. {  
  54.      wan=temp_data/10000+0x30 ;
  55.      temp_data=temp_data%10000;   //取余运算
  56.         qian=temp_data/1000+0x30 ;
  57.      temp_data=temp_data%1000;    //取余运算
  58.      bai=temp_data/100+0x30   ;
  59.      temp_data=temp_data%100;     //取余运算
  60.      shi=temp_data/10+0x30    ;
  61.      temp_data=temp_data%10;      //取余运算
  62.      ge=temp_data+0x30;        
  63. }

  64. /*******************************/
  65. void delay(unsigned int k)       
  66. {                                               
  67. unsigned int i,j;                               
  68. for(i=0;i<k;i++)
  69. {                       
  70. for(j=0;j<121;j++)                       
  71. {;}}                                               
  72. }
  73. /*******************************/
  74. void WaitForEnable(void)       
  75. {                                       
  76. DataPort=0xff;               
  77. LCM_RS=0;LCM_RW=1;_nop_();
  78. LCM_EN=1;_nop_();_nop_();
  79. while(DataPort&0x80);       
  80. LCM_EN=0;                               
  81. }                                       
  82. /*******************************/
  83. void WriteCommandLCM(uchar CMD,uchar Attribc)
  84. {                                       
  85. if(Attribc)WaitForEnable();       
  86. LCM_RS=0;LCM_RW=0;_nop_();
  87. DataPort=CMD;_nop_();       
  88. LCM_EN=1;_nop_();_nop_();LCM_EN=0;
  89. }                                       
  90. /*******************************/
  91. void WriteDataLCM(uchar dataW)
  92. {                                       
  93. WaitForEnable();               
  94. LCM_RS=1;LCM_RW=0;_nop_();
  95. DataPort=dataW;_nop_();       
  96. LCM_EN=1;_nop_();_nop_();LCM_EN=0;
  97. }               
  98. /***********************************/
  99. void InitLcd()                               
  100. {                       
  101. WriteCommandLCM(0x38,1);       
  102. WriteCommandLCM(0x08,1);       
  103. WriteCommandLCM(0x01,1);       
  104. WriteCommandLCM(0x06,1);       
  105. WriteCommandLCM(0x0c,1);
  106. }                       
  107. /***********************************/
  108. void DisplayOneChar(uchar X,uchar Y,uchar DData)
  109. {                                               
  110. Y&=1;                                               
  111. X&=15;                                               
  112. if(Y)X|=0x40;                                       
  113. X|=0x80;                       
  114. WriteCommandLCM(X,0);               
  115. WriteDataLCM(DData);               
  116. }                                               

  117. /**************************************
  118. 延时5微秒(STC90C52RC@12M)
  119. 不同的工作环境,需要调整此函数,注意时钟过快时需要修改
  120. 当改用1T的MCU时,请调整此延时函数
  121. **************************************/
  122. void Delay5us()
  123. {
  124.      _nop_();_nop_();_nop_();_nop_();
  125.      _nop_();_nop_();_nop_();_nop_();
  126.         _nop_();_nop_();_nop_();_nop_();
  127.         _nop_();_nop_();_nop_();_nop_();
  128.      _nop_();_nop_();_nop_();_nop_();
  129.         _nop_();_nop_();_nop_();_nop_();
  130.         _nop_();_nop_();_nop_();_nop_();
  131.      _nop_();_nop_();_nop_();_nop_();
  132.         _nop_();_nop_();_nop_();_nop_();
  133.         _nop_();_nop_();_nop_();_nop_();
  134.      _nop_();_nop_();_nop_();_nop_();
  135.         _nop_();_nop_();_nop_();_nop_();
  136.         _nop_();_nop_();_nop_();_nop_();
  137.      _nop_();_nop_();_nop_();_nop_();
  138.         _nop_();_nop_();_nop_();_nop_();
  139.         _nop_();_nop_();_nop_();_nop_();
  140.      _nop_();_nop_();_nop_();_nop_();
  141.         _nop_();_nop_();_nop_();_nop_();

  142. }

  143. /**************************************
  144. 延时5毫秒(STC90C52RC@12M)
  145. 不同的工作环境,需要调整此函数
  146. 当改用1T的MCU时,请调整此延时函数
  147. **************************************/
  148. void Delay5ms()
  149. {
  150.      WORD n = 560;

  151.      while (n--);
  152. }

  153. /**************************************
  154. 起始信号
  155. **************************************/
  156. void HMC5883_Start()
  157. {
  158.      SDA = 1;                    //拉高数据线
  159.      SCL = 1;                    //拉高时钟线
  160.      Delay5us();                 //延时
  161.      SDA = 0;                    //产生下降沿
  162.      Delay5us();                 //延时
  163.      SCL = 0;                    //拉低时钟线
  164. }

  165. /**************************************
  166. 停止信号
  167. **************************************/
  168. void HMC5883_Stop()
  169. {
  170.      SDA = 0;                    //拉低数据线
  171.      SCL = 1;                    //拉高时钟线
  172.      Delay5us();                 //延时
  173.      SDA = 1;                    //产生上升沿
  174.      Delay5us();                 //延时
  175. }

  176. /**************************************
  177. 发送应答信号
  178. 入口参数:ack (0:ACK 1:NAK)
  179. **************************************/
  180. void HMC5883_SendACK(bit ack)
  181. {
  182.      SDA = ack;                  //写应答信号
  183.      SCL = 1;                    //拉高时钟线
  184.      Delay5us();                 //延时
  185.      SCL = 0;                    //拉低时钟线
  186.      Delay5us();                 //延时
  187. }

  188. /**************************************
  189. 接收应答信号
  190. **************************************/
  191. bit HMC5883_RecvACK()
  192. {
  193.      SCL = 1;                    //拉高时钟线
  194.      Delay5us();                 //延时
  195.      CY = SDA;                   //读应答信号
  196.      SCL = 0;                    //拉低时钟线
  197.      Delay5us();                 //延时

  198.      return CY;
  199. }

  200. /**************************************
  201. 向IIC总线发送一个字节数据
  202. **************************************/
  203. void HMC5883_SendByte(BYTE dat)
  204. {
  205.      BYTE i;

  206.      for (i=0; i<8; i++)         //8位计数器
  207.      {
  208.          dat <<= 1;              //移出数据的最高位
  209.          SDA = CY;               //送数据口
  210.          SCL = 1;                //拉高时钟线
  211.          Delay5us();             //延时
  212.          SCL = 0;                //拉低时钟线
  213.          Delay5us();             //延时
  214.      }
  215.      HMC5883_RecvACK();
  216. }

  217. /**************************************
  218. 从IIC总线接收一个字节数据
  219. **************************************/
  220. BYTE HMC5883_RecvByte()
  221. {
  222.      BYTE i;
  223.      BYTE dat = 0;

  224.      SDA = 1;                    //使能内部上拉,准备读取数据,
  225.      for (i=0; i<8; i++)         //8位计数器
  226.      {
  227.          dat <<= 1;
  228.          SCL = 1;                //拉高时钟线
  229.          Delay5us();             //延时
  230.          dat |= SDA;             //读数据               
  231.          SCL = 0;                //拉低时钟线
  232.          Delay5us();             //延时
  233.      }
  234.      return dat;
  235. }

  236. //***************************************************

  237. void Single_Write_HMC5883(uchar REG_Address,uchar REG_data)
  238. {
  239.      HMC5883_Start();                  //起始信号
  240.      HMC5883_SendByte(SlaveAddress);   //发送设备地址+写信号
  241.      HMC5883_SendByte(REG_Address);    //内部寄存器地址,请参考中文pdf
  242.      HMC5883_SendByte(REG_data);       //内部寄存器数据,请参考中文pdf
  243.      HMC5883_Stop();                   //发送停止信号
  244. }

  245. //********单字节读取内部寄存器*************************
  246. uchar Single_Read_HMC5883(uchar REG_Address)
  247. {  uchar REG_data;
  248.      HMC5883_Start();                          //起始信号
  249.      HMC5883_SendByte(SlaveAddress);           //发送设备地址+写信号
  250.      HMC5883_SendByte(REG_Address);                   //发送存储单元地址,从0开始       
  251.      HMC5883_Start();                          //起始信号
  252.      HMC5883_SendByte(SlaveAddress+1);         //发送设备地址+读信号
  253.      REG_data=HMC5883_RecvByte();              //读出寄存器数据
  254.         HMC5883_SendACK(1);   
  255.         HMC5883_Stop();                           //停止信号
  256.      return REG_data;
  257. }
  258. //******************************************************
  259. //
  260. //连续读出HMC5883内部角度数据,地址范围0x3~0x5
  261. //
  262. //******************************************************
  263. void Multiple_read_HMC5883(void)
  264. {   uchar i;
  265.      HMC5883_Start();                          //起始信号
  266.      HMC5883_SendByte(SlaveAddress);           //发送设备地址+写信号
  267.      HMC5883_SendByte(0x03);                   //发送存储单元地址,从0x32开始       
  268.      HMC5883_Start();                          //起始信号
  269.      HMC5883_SendByte(SlaveAddress+1);         //发送设备地址+读信号
  270.          for (i=0; i<6; i++)                      //连续读取6个地址数据,存储中BUF
  271.      {
  272.          BUF[i] = HMC5883_RecvByte();          //BUF[0]存储0x32地址中的数据
  273.          if (i == 5)
  274.          {
  275.             HMC5883_SendACK(1);                //最后一个数据需要回NOACK
  276.          }
  277.          else
  278.          {
  279.            HMC5883_SendACK(0);                //回应ACK
  280.         }
  281.     }
  282.      HMC5883_Stop();                          //停止信号
  283.      Delay5ms();
  284. }

  285. //初始化HMC5883,根据需要请参考pdf进行修改****
  286. void Init_HMC5883()
  287. {
  288.       Single_Write_HMC5883(0x02,0x00);  //
  289. }
  290. //*********************************************************
  291. //主程序********
  292. //*********************************************************
  293. void main()
  294. { // bit sign_bit;
  295.     unsigned int i;
  296.     int x,y,z;
  297.     double angle;

  298.     delay(500);                       
  299.     InitLcd();
  300.     Init_HMC5883();
  301.    while(1)            //循环
  302.    {
  303.      Multiple_Read_HMC5883();      //连续读出数据,存储在BUF中
  304. //---------显示X轴
  305.      x=BUF[0] << 8 | BUF[1]; //Combine MSB and LSB of X Data output register
  306.      z=BUF[2] << 8 | BUF[3]; //Combine MSB and LSB of Z Data output register
  307.      y=BUF[4] << 8 | BUF[5]; //Combine MSB and LSB of Y Data output register

  308.      angle= atan2((double)y,(double)x) * (180 / 3.14159265) + 180; // angle in degrees
  309.      angle*=10;
  310.      conversion(angle);       //计算数据和显示
  311.         DisplayOneChar(2,0,'A');
  312.      DisplayOneChar(3,0,':');
  313.      DisplayOneChar(4,0,qian);
  314.      DisplayOneChar(5,0,bai);
  315.      DisplayOneChar(6,0,shi);
  316.      DisplayOneChar(7,0,'.');
  317.         DisplayOneChar(8,0,ge);

  318.      for (i=0;i<10000;i++);   //延时                  
  319.    }
  320. }
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2012-11-8 11:00:04 | 显示全部楼层
zzycgd 发表于 2012-11-7 11:11
角度不是线性变化的
纠结

可能产生的原因:
1. sensor周边存在干扰,校准不好;
2. 旋转过程中存在倾斜;而未用Gsensor将磁场数据投射水平面计算;
希望以上对你有所帮助

出0入0汤圆

发表于 2012-11-21 17:08:53 | 显示全部楼层
程序读出HMC5883L数据xy轴都正常,但是Z轴数据总保持0不变,请问这是为什么???

出0入0汤圆

发表于 2013-3-7 12:32:46 | 显示全部楼层
dragondslj 发表于 2012-11-21 17:08
程序读出HMC5883L数据xy轴都正常,但是Z轴数据总保持0不变,请问这是为什么??? ...

你看我这数据正不正常啊。怎么感觉三个轴的值都不对啊。 Mode Register 写入0x01(单次测量),  Configuration Register A写入0x70。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2013-3-8 10:29:50 | 显示全部楼层
xaper 发表于 2012-11-7 11:19
电子罗盘校准比较麻烦,具体看手册

有时间拜读一下

出0入0汤圆

发表于 2013-3-8 13:19:44 | 显示全部楼层
wjdb3 发表于 2012-9-5 14:59
咱刚想发帖问这个问题,发现这个贴,同问得到的X,Y,Z数据与方位有什么关系?怎样转换。 ...

如果是水平放置的话,用x,y然后atan函数就可以,如果是全姿态的话就要用z轴数据,然后用解算出的姿态角算出坐标变换矩阵,把磁力计z轴的信息投影到xy平面上,就可以继续用atan函数求解了。

出0入0汤圆

发表于 2013-3-8 13:24:28 | 显示全部楼层
zzycgd 发表于 2012-11-7 11:11
角度不是线性变化的
纠结

因为你没校准,磁力计读出的数据不校准的话如果把xy轴数据看成一个点,N多个这样的点组成的是一个中心不在原点的椭圆,你对这个椭圆上的点用atan函数反解角度当然不是线性的。简单的方法就是把一个轴的最大值最小值加起来除以2算出偏移量,然后在读出数据后减去这个偏移量,这是一个校准。另一个就是例如把y的最大量程除以x的最大量程得到一个缩放系数,然后把x轴乘以这个缩放系数。这样就把之前提到的中心不在原点的椭圆校正成中心在原点的圆了。这时你用atan函数就可以很好的解算出姿态。

出0入0汤圆

发表于 2013-3-8 13:25:05 | 显示全部楼层
COMPASSNAVHK 发表于 2012-11-8 11:00
可能产生的原因:
1. sensor周边存在干扰,校准不好;
2. 旋转过程中存在倾斜;而未用Gsensor将磁场数据 ...

不是,是没校准。

出0入0汤圆

发表于 2013-3-8 13:26:06 | 显示全部楼层
dragondslj 发表于 2012-11-21 17:08
程序读出HMC5883L数据xy轴都正常,但是Z轴数据总保持0不变,请问这是为什么??? ...

这个就不清楚了,有可能是没焊好?总之这个芯片很矫情,焊的时候稍不注意(例如温度过高)就可能出问题。

出0入0汤圆

发表于 2013-3-23 15:44:21 | 显示全部楼层
xaper 发表于 2012-11-7 11:19
电子罗盘校准比较麻烦,具体看手册

按照这个代码测试,只是得到一个固定值,45度,是怎么回事啊?

出0入0汤圆

发表于 2013-4-10 17:07:19 | 显示全部楼层
觋-拂晓 发表于 2013-3-7 12:32
你看我这数据正不正常啊。怎么感觉三个轴的值都不对啊。 Mode Register 写入0x01(单次测量),  Con ...

这个周围不要有金属、电子设备,不然影响特别大

出0入0汤圆

发表于 2013-4-10 17:08:13 | 显示全部楼层
zywei_09 发表于 2013-3-8 13:26
这个就不清楚了,有可能是没焊好?总之这个芯片很矫情,焊的时候稍不注意(例如温度过高)就可能出问题。 ...

包括加速度传感器,好像都是Z轴容易出问题,这是焊接原因吗?

出0入0汤圆

发表于 2013-4-25 10:27:13 | 显示全部楼层
dragondslj 发表于 2013-4-10 17:08
包括加速度传感器,好像都是Z轴容易出问题,这是焊接原因吗?

用HMC5883L,self-test在空旷地方测试一下?

出0入0汤圆

发表于 2013-5-25 00:48:03 | 显示全部楼层
我的Z轴输出一直为F000
为什么呢?求解释
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-23 23:43

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表