研究了一晚上稍微有点成果分享下 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.csdn.net/do335maomao/article/details/43916467