
研究了一晚上稍微有点成果分享下
HMC5883L使用i2c接口,接线很容易
以Arduino Uno为例:
SDA to A4
SCL to A5
Vcc to 3.3V
GND to GND
基本原理很简单:
方向角其实就是X轴和Y轴读数的反正切
而校准其实就是要排除环境中的磁场对地磁场的干扰
另外别忘了当地的磁偏角
如下代码没有使用专门的传感器库
上电后先进行20秒校准,请把传感器任意乱转,各个方向都要转到
然后就会显示校准值,然后持续显示初始值和方向角
不知道怎么在ide里面用中文写注释,所以就保留英文了
个人测试下来和手机上的指南针相差不超过5度,更精细的校准待研究
刚刚接触Arduino,望高手指教
- #include <Wire.h> //I2C 库
-
- #define address 0x1E //001 1110b(0x3C>>1), HMC5883的7位i2c地址
- #define MagnetcDeclination 4.43 //笔者所在地磁偏角,请根据情况自行百度
- #define CalThreshold 0
-
- int offsetX,offsetY,offsetZ;
-
- void setup()
- {
-
- Serial.begin(9600);
- Wire.begin();
-
-
- Wire.beginTransmission(address);
- Wire.write(0x00);
- Wire.write(0x70);
- Wire.endTransmission();
-
- Wire.beginTransmission(address);
- Wire.write(0x02);
- Wire.write(0x00);
- Wire.endTransmission();
-
- calibrateMag();
- }
- void loop()
- {
- int x,y,z;
- getRawData(&x,&y,&z);
-
-
- Serial.print("x: ");
- Serial.print(x);
- Serial.print(" y: ");
- Serial.print(y);
- Serial.print(" z: ");
- Serial.print(z);
- Serial.print(" angle(x,y): ");
- Serial.println(calculateHeading(&x,&y,&z));
-
- delay(250);
- }
-
- void getRawData(int* x ,int* y,int* z)
- {
- Wire.beginTransmission(address);
- Wire.write(0x03);
- Wire.endTransmission();
-
- Wire.requestFrom(address, 6);
- if(6<=Wire.available()){
- *x = Wire.read()<<8;
- *x |= Wire.read();
- *z = Wire.read()<<8;
- *z |= Wire.read();
- *y = Wire.read()<<8;
- *y |= Wire.read();
- }
- }
-
- int calculateHeading(int* x ,int* y,int* z)
- {
- float headingRadians = atan2((double)((*y)-offsetY),(double)((*x)-offsetX));
-
- if(headingRadians < 0)
- headingRadians += 2*PI;
-
- int headingDegrees = headingRadians * 180/M_PI;
- headingDegrees += MagnetcDeclination;
-
-
- if(headingDegrees > 360)
- headingDegrees -= 360;
-
- return headingDegrees;
- }
-
- 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;
-
- Serial.println("Starting Calibration......");
- Serial.println("Please turn your device around in 20 seconds");
-
- for(int i=0;i<200;i++)
- {
- getRawData(&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;
-
- delay(100);
-
- if(i%10 == 0)
- {
- Serial.print(xMax);
- Serial.print(" ");
- Serial.println(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;
-
- Serial.print("offsetX:");
- Serial.print("");
- Serial.print(offsetX);
- Serial.print(" offsetY:");
- Serial.print("");
- Serial.print(offsetY);
- Serial.print(" offsetZ:");
- Serial.print("");
- Serial.println(offsetZ);
-
- delay(5000);
- }
把冗长的数据手册读完了,有人想看的话,可以把自测试模式,空闲模式等的使用方法也写一下
参考资料:
https://www.sparkfun.com/tutorials/301
转自:http://blog.youkuaiyun.com/do335maomao/article/details/43916467