首先Arduino默认的I2C地址是7位地址,手册上说明有,7位地址为0X1E,读地址为0x3D = (7位地址<<1 +1),写地址为0X3C (7位地址 << 1)
如果要想与HMC5883L进行通信,则需要在HMC5883L上电5ms之后进行。 所以一般写入配置时需要先延时5ms再进行通信。
连入设备后对传感器进行测试、识别的操作与 识别寄存器A、 识别寄存器B、识别寄存器C有关,所以想知道传感器是否正常工作就读取他们的值验证一下,因为他们三个都是只读寄存器,科技静态测试
识别寄存器A 地址 0x0A 默认值为 0x48
识别寄存器B 地址 0x0B 默认值为 0x34
识别寄存器C 地址 0x0C 默认值为 0x33
读取寄存器的值以确保设备正常通信。
对于传感器我们最关心的还是如何读取它的值和如何处理读出来的值。
传感器的测量值放在X,Y,Z 16位寄存器中,关于测量模式有两种 连续测量和单次测量,单次测量我用了一下,感觉不太好,所以下面主要介绍连续测量。
配置成连续测量方式很简单,就是上面的模式寄存器,地址0x02
可以看到,配置成连续测量模式只需要给模式寄存器写入0x00就行。
配置成连续,配置成连续读取模式之后有一个很重要的地方需要记住: 读取XYZ,一次一定要读取6个字节,也就是全部读取,不然的话数据不更新! 手册上没有给出具体的解释,不过我猜测应该是写地址与读地址公用了一个地址导致这个现象。
数据处理:
X,Y,Z 16位数据读取完毕后需要用到转换出角度,刚开始转换出的角度一直不对,而且很纳闷因为看到网上现成的代码中都是那一套公式,atan2(y,x)*180/pi+180 可是自己计算的就是不对。
原来是手册上的X,Y,Z寄存器并不是指的实际的X,Y,Z导致的
实际上的X,Y,Z 是 X,Z,Y存储在数据区域的,伪代码表示为
requestFrom(0x3D,6);
x = Wire.read()<<8 | Wire.read()
z = Wire.read()<<8 | Wire.read()
y = Wire.read()<<8 | Wire.read()
double degree=atan2(y,x) *180/PI+180
这样得出的degree才是HMC5883L与磁北方向的夹角。 我测试的结果为,基本上与iphone自带的传感器数值一致,误差在3-5度之间,这可能是干扰或者我的人工误差引起的,所以做出来的效果还算满意。
下面是测试代码;
#include <math.h> #include <Wire.h> #define ADDRESS 0x1e const int led_Pin=13; const int rady=22; void setup() { pinMode(rady, INPUT); pinMode(led_Pin, OUTPUT); Serial.begin(115200); delay(5); Wire.begin(); Wire.beginTransmission(ADDRESS); Wire.write(0x02); Wire.write(0x00); Wire.endTransmission(); Wire.beginTransmission(ADDRESS); Wire.write(10); Wire.endTransmission(); Wire.requestFrom(ADDRESS,1); if(Wire.available()==1&&Wire.read()==0x48){ Serial.println("connect success"); }else Serial.println("connect failure"); Wire.beginTransmission(ADDRESS); Wire.write(0x02); Wire.endTransmission(); Wire.requestFrom(ADDRESS,1); if(Wire.available()==1) { switch(Wire.read()) { case 00: Serial.println("sequence measure"); break; case 01: Serial.println("single measure"); break; default: Serial.println("other measure"); break; } } } void loop() { Wire.beginTransmission(ADDRESS); Wire.write(0x03); Wire.endTransmission(); Wire.requestFrom(ADDRESS,6); //delay(10); if(Wire.available()==6&&digitalRead(rady)){ Serial.print("receive:"); int x=Wire.read(); x=x<<8|(Wire.read()); int z=Wire.read(); z=z<<8|(Wire.read()); int y=Wire.read(); y=y<<8|(Wire.read()); float rot=atan2(y,x)*180/PI+180; Serial.println(rot); } else{ Serial.print("rady is "); Serial.println(digitalRead(rady)?"HIGH":"LOW"); } delay(1000); }