小v电子技术博文 上海鲤鲸网络科技 小v单片机 物联网云平台管理系统+终端嵌入式软硬件开发!
hmc5883树莓派
  • 首页 > Linux
  • 作者:小v
  • 2018年1月5日 15:31 星期五
  • 浏览:321
  • 字号:
  • 评论:0
  • #include <wiringPi.h>  //I2C 库 
    #include <wiringPiI2C.h>  //I2C 库 
    #include <stdio.h> 
    #include <math.h>
    #include <stdlib.h>
    #include<unistd.h>
    #include <sys/ioctl.h> 
    #include <fcntl.h> 
    #include <linux/i2c-dev.h> 
    #include <linux/i2c.h> 

    #define CHIP "/dev/i2c-1" 
    #define CHIP_ADDR 0x1e 
    #define address 0x1e//001 1110b(0x3C>>1), HMC5883的7位i2c地址  
    #define MagnetcDeclination 4.43 //笔者所在地磁偏角,请根据情况自行百度  
    #define CalThreshold 0  
    #define HMC5883L_DATA_OUT_REG    0x03
    #define HMC5883L_STATUS_REG      0x09
    int offsetX,offsetY,offsetZ;  

    int i2c_fd;
    /*******************************************************************************
    * function name : Hmc5883l_Init
    * description : 完成初始
    * param[in] : none
    * param[out] : none
    * return : 0
    *******************************************************************************/

    void Hmc5883l_Init()  
    {  
      //初始化串口和i2c  
       int  i;
       unsigned char rdaddr[2] = {0, 0};     /* 将要读取的数据在芯片中的偏移量 */      
       unsigned char wrbuf[3] = {0, 0, 0x3c};     /* 要写的数据,头两字节为偏移量 */         
       unsigned char rddata[15];
      printf("Hmc5883l_Init \n");    
     //  printf("write address return: %d\n",write(i2c_fd, rdaddr, 2));     /* 读取之前首先设置读取的偏移量 */     
      write(i2c_fd, rdaddr, 2);
      printf("read data return:%d\n", read(i2c_fd, rddata, 9));   //读取3个字节到buf中 
    for(i=0;i<3;i++)   
    printf(" %x ", rddata[i]); 
         printf("************* \n");
       if(rddata[0]!=0x70)
       {
      //设置HMC5883模式  
       wrbuf[1]  = 0x00;
       wrbuf[2]  = 0x70;
       write(i2c_fd, wrbuf,3); 
       }
       if(rddata[2]!=0x00)
       {
       wrbuf[1]  = 0x02;//选择模式寄存器  
       wrbuf[2]  = 0x00;//连续测量模式:0x00,单一测量模式:0x01  
       write(i2c_fd, wrbuf,3); 
       }

       
      //calibrateMag();  
    }
     /*******************************************************************************
    * function name : getRawData
    * description : 完成初始
    * param[in] : none
    * param[out] : none
    * return : 0
    *******************************************************************************/
    void getRawData(int* x ,int* y,int* z)  
    {  
      
      //Wire.write(0x03); //从寄存器3开始读数据  
      //Wire.endTransmission();  
      //每轴的数据都是16位的  
     // Wire.requestFrom(address, 6);  
      int j,k,l;


      unsigned char rddata[15];      
    unsigned int i;
       unsigned char rdaddr[2] = {0,0};     /* 将要读取的数据在芯片中的偏移量 */      
       unsigned char wrbuf[3] = {0, 0, 0x3c};     /* 要写的数据,头两字节为偏移量 */         

       //printf("write address return: %d\n",write(i2c_fd, rdaddr, 2));     /* 读取之前首先设置读取的偏移量 */ 
       write(i2c_fd, rdaddr, 2);
       printf("read data return:%d\n", read(i2c_fd, rddata, 9));     
    //for(i=0;i<9;i++)   
    //printf("%x ", rddata[i]); 
        // printf("************* \n");
       j = rddata[2];
       j =j<<8| rddata[3] ;
       k = rddata[46];
       k= k<< 8 | rddata[5] ;
       l = rddata[6];
       l=l << 8 | rddata[7] ;
       memset(rddata,0x00,6);
       
       
    /*
        j = wiringPiI2CReadReg8(fd, HMC5883L_DATA_OUT_REG) << 8;
        j |= wiringPiI2CReadReg8(fd, HMC5883L_DATA_OUT_REG + 1);
        k = wiringPiI2CReadReg8(fd, HMC5883L_DATA_OUT_REG + 2) << 8;
        k |= wiringPiI2CReadReg8(fd, HMC5883L_DATA_OUT_REG + 3);
        l = wiringPiI2CReadReg8(fd, HMC5883L_DATA_OUT_REG + 4) << 8;
        l |= wiringPiI2CReadReg8(fd, HMC5883L_DATA_OUT_REG + 5);
    */ 
    if(j>0x7fff)j-=0xffff;
    if(k>0x7fff)k-=0xffff;
    if(l>0x7fff)l-=0xffff;

    *x = j;
    *z=k;
    *y = l;
        
    }
    /*******************************************************************************
    * function name : calculateHeading
    * description : 完成初始
    * param[in] : none
    * param[out] : none
    * return : 0
    *******************************************************************************/
    int calculateHeading(int* x ,int* y,int* z)  
    {  
      float headingRadians = atan2((double)((*y)-offsetY),(double)((*x)-offsetX)) *(180/3.14159265)+180; 
    //  float headingRadians = atan2((double)(*y),(double)(*x)) *(180/3.14159265)+180; 
      // 保证数据在0-2*PI之间  
      //if(headingRadians < 0)  
       // headingRadians += 2*M_PI;  
       
     // int headingDegrees = headingRadians * 180/M_PI;  
     // headingDegrees = MagnetcDeclination; //磁偏角  
     // headingRadians -= MagnetcDeclination; 
      // <span style="font-family: Arial, Helvetica, sans-serif;">保证数据在0-360之间</span>  
     // if(Degrees > 360)  
      //  headingDegrees -= 360;  
       return headingRadians;
    //  return headingDegrees;  

    void loop_test()  
    {  
      int x,y,z; //三轴数据  
      int angle;
      getRawData(&x,&y,&z);  
      
      //输出数据  
     printf("  x: %d \n",x);  
      printf("  y: %d \n",y);  
      printf("  z: %d \n",z);  
    angle = calculateHeading(&x,&y,&z); 
      printf(" angle(x,y): %d\n",calculateHeading(&x,&y,&z));  
    //输出x,y平面方向角  
     if((angle < 62.5) || (angle > 350 ))
            printf("South");
        if((angle > 62.5) && (angle < 135 ))
            printf("South-West");
        if((angle > 135) && (angle < 190 ))
            printf("West");
        if((angle > 190) && (angle < 235.5 ))
            printf("North-West");
        if((angle > 235.5) && (angle < 270 ))
            printf("North");
        if((angle > 270) && (angle < 285 ))
            printf("NorthEast");
        if((angle > 285) && (angle < 315 ))
            printf("East");
        if((angle > 315) && (angle < 350 ))
            printf("SouthEast"); 
      delay(250);  
    }  
    /*
    具体的办法是:
    1,水平匀速旋转,收集 XY轴的数据
    2,转动器材90 度(此时 Z轴水平)匀速旋转以收集 Z轴数据
    3,将读取到的各轴数据的最大值加上最小值除以2,就得到一个各轴的offset 值
    Xoffset=(Xmax+Xmin)/2
    Yoffset=(Ymax+Ymin)/2
    Zoffset=(Zmax+Zmin)/2
    4,然后将磁力计读取的各轴的裸值减去前面计算所得的 offset值,就可以得到用作角度计算的 Heading 值
    XH=X裸-Xoffset
    YH=Y裸-Yoffset
    ZH=Z裸-Zoffset
    如果只用作水平测量,则此时的方位角为
    方位角=arctanYH/XH

    */
    /*******************************************************************************
    * function name : calibrateMag
    * description : 完成初始
    * param[in] : none
    * param[out] : none
    * return : 0
    *******************************************************************************/
    void calibrateMag()  
    {  
      int x,y,z; //三轴数据  
      int xMax, xMin, yMax, yMin, zMax, zMin;  
      //初始化  
      getRawData(&x,&y,&z);    
      xMax=xMin=x;  
      yMax=yMin=y;  
      zMax=zMin=z;  
      offsetX = offsetY = offsetZ = 0;  
       
      printf("Starting Calibration......");  
      printf("Please turn your device around in 20 seconds");  
       
      for(int i=0;i<10;i++)  
      {  
        getRawData(&x,&y,&z);  
        // 计算最大值与最小值  
        // 计算传感器绕X,Y,Z轴旋转时的磁场强度最大值和最小值  
        if (x > xMax)  
          xMax = x;  
        if (x < xMin )  
          xMin = x;  
        if(y > yMax )  
          yMax = y;  
        if(y < yMin )  
          yMin = y;  
        if(z > zMax )  
          zMax = z;  
        if(z < zMin )  
          zMin = z;  
       
           sleep(1);  
       
        if(i%10 == 0)  
        {  
         // printf(xMax);  
         // printf(" ");  
          //printf(xMin);  
        }  
      }  
      //计算修正量  
      if(abs(xMax - xMin) > CalThreshold )  
        offsetX = (xMax + xMin)/2;  
      if(abs(yMax - yMin) > CalThreshold )  
        offsetY = (yMax + yMin)/2;  
      if(abs(zMax - zMin) > CalThreshold )  
        offsetZ = (zMax +zMin)/2;  
       
      printf("offsetX: %d \n",offsetX);   
      printf(" offsetY:%d \n",offsetY);  
      printf(" offsetz:%d \n",offsetZ); 
     
       
      delay(5000);    
    }
    /*******************************************************************************
    * function name : main
    * description : 完成初始
    * param[in] : none
    * param[out] : none
    * return : 0
    *******************************************************************************/
    int main()
    {

      
       printf("hello, this is i2c tester\n");         
        i2c_fd = open(CHIP, O_RDWR);      
       if (i2c_fd < 0) 
       {         
          printf("open "CHIP"failed\n");          
          return -1;     
       }      
       if (ioctl(i2c_fd, I2C_SLAVE_FORCE, CHIP_ADDR) < 0) 
       {         /* 设置芯片地址 */         
          printf("oictl:set slave address failed\n");        
          return -1;      
       }
     //  system("i2cset -y 1 0x1e 0x02 0x00");
       sleep(1);
       Hmc5883l_Init()  ;
       calibrateMag();
    //system("i2cset -y 1 0x1e 0x02 0x00");
       while(1)
    {
       loop_test();
       sleep(1);
    }




    }  

      您阅读这篇文章共花了:  
     本文无需标签!
    二维码加载中...
    本文作者:小v      文章标题: hmc5883树莓派
    本文地址:http://www.xiaovdiy.cn/?post=391
    版权声明:若无注明,本文皆为“”原创,转载请保留文章出处。

    返回顶部| 首页| 手气不错| 捐赠支持| 自定义链接| 自定义链接| 自定义链接| 手机版本|后花园

    Copyright © 2014-2017   京ICP备14059411 Copyright 2014-2015 上海鲤鲸网络科技工作室 版权所有 All Rights Reserved

    sitemap