|
楼主 |
发表于 2013-7-27 07:37:44
|
显示全部楼层
本帖最后由 arduino_ykk 于 2013-7-27 08:08 编辑
(二)
第二集来看看HMC5883怎么读取x,y轴的角度(也就是磁极的方位)。
< 插播广告 > 推荐读物:honeywell HMC5883文档,看寄存器页
首先是三轴方位传感器连接arduino板的图,可以看出非常简单。除了接Vcc=3.3V,接地外,连接数据SDA到模拟A4口,时间同步SLC到模拟A5口。好了,很简单。我的还有个DRDY(reset)接口,不连接了。
HMC5883是如何驱动的呢? 它采用了I2C的接口标准,里面内置了几个寄存器,用来存放数据和运行模式,所以调用上稍微麻烦一点点。
要调用HMC5883,就要记住几个寄存器(也就是临时小内存,黄色标注)- 图中寄存器B(0x01, 存放测量量程), 模式寄存器(0x02, 测量是单次,还是连续),以及数据寄存器X~Z(0x03~0x08)。使用时规定好量程(多多少大小的高斯,因为可以测量强或弱磁场),规定好连续测量,然后读取数据就是了。
如何规定量程和测量模式呢,如下。
写入寄存器B : send 0x3C 0x01 0x40 表示:0x3c - 写入 0x01 - 寄存器b的地址 0x40 - 数值,也就是B0100 0000.
[arduino代码]
Wire.beginTransmission(0x1E); - 数据存放地址
Wire.write(0x01);
Wire.write(0x40);
Wire.endTransmission();
0x40这个数值,可以从寄存器B的定义值看出。0x40就是二进制 0100 0000
0100套入二进制高位,查表可知,量程为+/- 1.9Ga
好了,要连续测量,也照猫画虎写代码,对模式寄存器:
Wire.beginTransmission(0x1E);
Wire.write(0x02);
Wire.write(0x00); - 连续测量
Wire.endTransmission();
接下来要读取x,y,z三个轴上面的数据了。x,y,z轴的寄存器每个有2个字节可用。一个高字节,一个低字节。获取后要自己做合并操作。
因为其实它的指针,每读取一个寄存器,会自动指向下一个寄存器。所以,如果之前读取了模式寄存器,指针下移,下一个就会是xyz轴的数据寄存器了。所以可以直接读取内容。
Wire.requestFrom(0x1E, 6) -> 读取接下来6个字节(刚好就是xyz轴的寄存器,每个寄存器2个字节)。0x1E是这个设备的指针(HMC5883)。
把读到的数据存放到我们设的x,y,z变量里面去。
x= Wire.read() <<8; // x轴的高位寄存器 X msb
x |= Wire.read(); // x轴的低位寄存器 X lsb
z...
y...
x,y,z都读出来,就要请出我们注明的角度公式了:
angle = atan2( y, x ) * 180/3.1415926 + 180
之后再判断角度。这里不赘述。
下面是代码.
[arduino 1.0.5编译通过]
- // megnatometer
- #include <Wire.h>
- // define address of register B, mode register, and the value
- #define HMC5883_WriteAddress 0x1E
- #define HMC5883_RegisterB 0x01
- #define HMC5883_ModeRegister 0x02
- #define HMC5883_ContinusMode 0x00
- #define HMC5883_DataOutputAddress 0x03
- #define HMC5883_MeasureScale 0x40
- int x, y, z;
- double angle;
- void setup()
- {
- Wire.begin(); // initialize Wire library
-
- // setup measurement scale
- Wire.beginTransmission( HMC5883_WriteAddress );
- Wire.write( HMC5883_RegisterB);
- Wire.write( HMC5883_MeasureScale );
- Wire.endTransmission();
-
- // setup measure mode
- Wire.beginTransmission( HMC5883_WriteAddress );
- Wire.write( HMC5883_ModeRegister );
- Wire.write( HMC5883_ContinusMode );
- Wire.endTransmission();
-
- Serial.begin( 9600 );
- }
- // begin measurement
- void loop()
- {
- Wire.requestFrom( HMC5883_WriteAddress, 6 ); // get 6 bytes(xyz register)
- while( 6 <= Wire.available() )
- {
- x = Wire.read() << 8 ; // get axis X msb
- x |= Wire.read(); // get axis X lsb
- z = Wire.read() << 8; // get axis Z msb
- z |= Wire.read(); // get axis Z lsb
- y = Wire.read(); // get axis Y msb
- y |= Wire.read(); // get axis Y lsb
- }
-
- // get its angle, axis Z is not in use, as right now we dont' have direction Z compensation.
- angle = atan2( (double)y, (double)x ) * ( 180 / 3.1415926 ) + 180;
-
- // get its direction.
- if ( (angle < 22.5) || (angle > 337.5) )
- Serial.print( "South" );
- if ( (angle > 22.5) && (angle < 67.5) )
- Serial.print( "South-West" );
- if ( (angle > 67.5) && (angle < 112.5) )
- Serial.print( "West" );
- if ( (angle > 112.5) && (angle < 157.5) )
- Serial.print( "North-West" );
- if ( (angle > 157.5) && (angle < 202.5) )
- Serial.print( "North" );
- if ( (angle > 202.5) && (angle < 247.5) )
- Serial.print( "North-East" );
- if ( (angle > 247.5) && (angle < 292.5) )
- Serial.print( "East" );
- if ( (angle > 292.5) && (angle < 337.5) )
- Serial.print( "South-East" );
-
- Serial.print(": Angle between X-axis and the South direction ");
- if ( angle > 180 )
- angle=360-angle;
-
- Serial.print(angle,2);
- Serial.println(" Deg");
-
- // to return the pointer to xyz register
- Wire.beginTransmission( HMC5883_WriteAddress );
- Wire.write( HMC5883_DataOutputAddress );
- Wire.endTransmission();
-
-
- delay(1000);
- }
复制代码
=================================================
下课前提问: 为啥 z轴的值没有用到公式里?
回答:现在这样测量的方位,必须是传感器水平放置才会准确。如果传感器有个倾角(现实生活中很常见),那么测量的值就会有偏差。z轴(垂直轴)的值需要结合三轴加速度传感器来用,做一个倾斜补偿。至于三轴加速度传感器。。。还在研究中。 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
|