成为订阅者(免费)

加入29,000名其他订阅者以获得用户销售折扣和 其他免费资源。
:
:
大学教师'担心 - 您的邮件地址完全是 安全的。我保证使用它 只要 to send you MicroZine.

HMC5883L.数字指南针

HMC5883L.芯片是三轴磁传感器或数字罗盘, 霍尼韦尔制造。我从eBay买了一个突破板,有点 随着芯片上的标记与此设备不匹配的困惑。它's time 有一些调查!


警告: Three axis 磁力计对其取向敏感。什么时候不级别, 输出轴承将不正确。解决方案是 使用一个弥补方向 加速度计.


HMC5883L. Breakout Board  -  2芯片版

本页有五个主要部分:

  1. HMC5883L.和QST规范和功能。
  2. 如何使用和校准磁力计。
  3. 如何使用磁力计作为罗盘,用示例代码。
  4. 突破板之间的差异。
  5. HMC和QST芯片版本之间的差异。

事实上,有两种芯片版本:HMC(霍尼韦尔制造)和QMC(由QST Corporation制造)。

笔记: HMC和QMC版本使用不同的I2C地址。
笔记: HMC和QMC版本使用不同的寄存器地址。
笔记: HMC和QMC芯片的输出基本上是相同的数据。

本页讨论了HMC和QMC版本之间的差异 并描述您是否可以使用QMC版本作为HMC5883L 替代。它还向您展示了如何校准磁力计 作为指南针的基本操作。

但你有哪种芯片?

重要的是要找到您拥有的芯片,因为每个芯片都有不同的内部 寄存器。如果您使用错误的库,您将认为芯片失败了!

霍尼韦尔正在停止生产HMC588L装置和 已将设计许可到QST。你可以了解你有哪一个 使用下表:

  Manufacturer
芯片标记
设备名称
  Honeywell
L883
HMC5883L.
  QST Corporation
5883
QMC5883L.

如果芯片上的标记是'5883'然后你有QMC5883L。如果它 是l883然后你有hmc5883l。您可以将这些设备的功能详细比较页面上进一步比较 这里.

磁力计的能力

测量磁场

这些磁力计芯片可以测量2mgauss的场强 8Gauss。由于地球的平均场地强度's magnetic field is:

    在30th(0.3g)和60ut(0.6g)之间[资源] ......

这些芯片容易测量地球's 磁场强度,以及来自较高强度磁性材料的磁场。

QMC5883L.和HMC5883L. 规格

  Parameter
HMC5883L.
QMC5883L.
  Voltage Supply (Vs)
2v16〜3v6 2v16〜3v6
  数字供应(VDDIO)(最大值)
1.71V〜3V7 1.65V〜3V6
  Abs. Max VDD/VDDIO
-0.3V〜4.8V.
-0.3V〜5.4V
  Interface
I2C
I2C
  I2C地址(R,W)[RW]
0x3d,0x3c
0x0d [r / w]
  I2C rates (kHz)
100,400,3400
100,400
  Resolution (ADC)
12位16位
  Max Gauss (survival)
未指定。
50000G
  Gauss Resolution
±2mg〜±8g
±2mg〜±8g
  Acquisition time
6ms
6ms
  主动电流(7Hz,10Hz)
100uA
75uA
  Active current 未指定。
75ua〜850ua [2]
  Peak Active current
未指定[3]
2.6mA
  待机模式(泄漏)
2uA
3uA
  工作温度
-30°C〜85°C
-40°C〜85°C

[1] VDDIO是数字接口I / O电压电平。较低的值(CF VS)允许低压设备进行操作(例如使用1.8V)。
[2] QMC5883L还有更多 过采购率(OSR)和输出率(ODR)[较高的OSR和ODR, 导致芯片消耗更多的电流]。
[3] QMC5883L采用自动温度补偿,但将使用与HMC5883L相同的脱司冲法。在HMC5883L. 芯片A 10MA驱动器用于使用带式驱动器自动消磁 (这种自检过程也需要6ms,这是相同的收购 时间作为QMC5883L),因此峰值电流可能与QMC5883L相同。

5883L数据表

下载QMC5883L数据表 这里。 (你更有可能你有这个芯片)。

下载HMC5883L数据表 这里.

如何使用磁力计

使用磁力计应易于使用,从根本上看是。那里 它是两个问题:磁干扰和方向。

问题是你可以陷入混乱 将磁力计X-Y读数转换为屏幕X-Y读数和 将其与您想要读取的方式比较 您正在持有的设备的方向。令人困惑 - 略微。

排序所有这一切的方法是识别磁力计正在读取的内容。

让's state the obvious:

磁力计测量磁场强度
并且最多 沿着特定轴输出
轴对齐,指向地球's North pole.

它与使用传统指南针完全相同 针尖北。一旦我们整理出来,我们就可以编写一个程序 to show the 输出 - 但您必须首先校准偏移量(见下文)。

注意从ATAN函数返回的角度返回零读数 当北极与X轴对齐时,这会影响这一点 你计算的轴承。您可以通过添加轴承来调整轴承 偏移值e.g. +90度逆时针旋转轴承(顺时针逆时针)。

磁畸变

接下来要了解的是从中阅读 磁力计可能不会是可用的,除非您在一个领域 你周围没有其他磁性扭曲(所谓的软铁和 硬铁干扰)。

硬铁畸变

硬铁干扰是:

生产材料块。
这种失真导致磁力计中的偏移量
输出自增加以来 或减去磁场。

对于硬铁干涉的一个例子,看起来没有比扬声器或磁化的铁,甚至是电池 (尝试在查看磁力计的输出时通过电池移动)。

这种失真是迄今为止最重要的是消除和必须 在磁力计可以用作指南针之前被移除。

软铁扭曲

软铁干扰是:

由磁场引起的扭曲
铁磁材料。这种失真扭曲了
地球'S磁场导致椭圆磁力计输出。  

对于创建指南针,这一事实并不是太重要,即使对于椭球输出仍然仍将返回。

柔软的铁畸变只扭曲磁场 - 想到非 磁化的铁片。罗盘应用程序可以应对这个和 如果柔软的铁失真没有创造一个,就会返回一个轴承 磁场只是改变了现有的领域。但是,它会导致轴承到 be changed slightly!

QMC5883和HMC5883L Arduino校准

由于HMC和QMC版本所必需提供相同的输出数据 校准过程在每种情况下都是相同的。一切都不同 是图书馆是否需要接口到芯片。只需选择 相关库并使用下面的代码进行校准。

您通常执行单位校准以提高设备的准确性。但是,对于磁力计,有 许多磁误差来自大块金属块,电池, 甚至周围的电路!

在这个意义上校准是 恢复功能 - 您只需使用无需校准的磁力计!

警告: 你可以'T无需校准即可使用磁力计。

校准应在干扰区域(或 条件始终是相同的区域)。这意味着一个区域 从磁干扰i.e.远离金属结构和 electric current.

提示: 在磁干扰区域进行校准。

您还应该在更换时执行校准 电池用作不同的电池将具有不同的磁场 输出。此校准将校准由此引起的错误 附近的磁性装置。电池,电机和其他铁磁 电路本身内的场生成部分。

未校准的QMC5883输出

下图显示了磁力计如何受到影响 周围的磁场或铁 - 唯一的区别 两块地块是 桌面上抬高12英寸的电路!下面的图表 应该 以x为中心,y =(0,0)!除非输出纠正,否则您可以'T根本计算轴承。

笔记: 校准对于获得有意义的数据输出至关重要。
与桌面上相比,磁石输出升高到空气中

在保持磁力计的同时获得了这些结果 等级。从水平面偏移也会显着影响 结果(可以通过添加加速度计和额外代码来纠正。

警告: 水平方向至关重要 - 保持平整!

在正常使用中,您将在外面使用磁力计差异 在偏移中不会像这里所示那样大。

硬铁偏移校准

校准的目标是为身份识别 圈,然后将这些中心点应用于信号的偏移量 从磁力计。

这只是通过检测最大和最小x和y来实现 坐标以找到中心点(xmax-xmin)/ 2并使用它作为x 未来计算中的偏移量。类似地,Y值也完成了计算。

在代码中执行此操作 通过calc_offsets()函数,更新变量offx和affy。这些 然后从磁力计读数中减去值,以提供零级磁力计读数即校准读数。

磁性偏差

您可能需要调整磁力计读数以倾斜 抵消。拒绝偏移是您添加到磁性的价值 轴承(所以它也适用于标准圆规)。它定义了真实 北方以来,在某些地区,真正的北部和磁性北部没有对齐。 您可以找到更多信息和指向工具的链接以找到您的工具 magnetic declination 这里.

磁倾角


笔记:  磁倾斜=水平的垂直场角。

对于带有磁性倾斜的指南针无关紧要。

示例代码

第一个示例使用QMC5883L和串口显示 数据。这是一个简单的演示很有用,但何时不方便 使用设备。使用专用显示时更容易。所以在 第二示例SSD1306显示轴承。

示例串行输出罗盘

以下示例代码将轴承输出到串行终端。 按下按钮时,执行校准程序(持续10 秒)在此期间,您必须通过360°将芯片旋转 虽然数据从x和y轴收集。 

注意芯片对水平偏差敏感,因此获得良好的读数保持芯片水平。

然后程序存储校准数据 the EEPROM.

硬件例如草图1

  • arduino nano(或uno),
  • HMC5883L.(或QST5883L)分组板。
  • 按下按钮(1关闭)。

硬件连接例如Sketch1

制作连接如下:

  Arduino Uno/
  Nano pin
标签
目的地
  A5
SCL.
5883L SCL
  A4
SDA.
5883L SDA.
  5V
vcc.
5883L vcc.
  GND
GND. 5883L GND.
  D2
D2
To Button
  GND GND. To Button

按钮是常开一个。

// QMC5883 compass
// For an HMC5883L chip a popular library is :
// James Sleeman's HMC5883L library from GitHub.
// Here the QMC5883L is controlled by direct I2C read/write.
//
// Copyright John Main - Free for non commercial use.
//

#include "Wire.h" // For 5883L I2C interface
#include <EEPROM.h>

#define BUTTON_CAL 2
#define LED  13
#define EEADDR 66 // Start location to write EEPROM data.
#define CALTIME 10000  // In ms.

英石atic byte 英石at,ovfl,skipped;
英石atic 在t minx,maxx,miny,maxy,offx=0,offy=0;

/////////////////////////////////////////////////////////////
void I2C_write_AddrDev_AddrReg_Byte(byte i2cAddr, byte regaddr, byte d ) {
   Wire.beginTransmission(i2cAddr);
   Wire.write(regaddr);
   Wire.write(d);
   Wire.endTransmission();
}

/////////////////////////////////////////////////////////////
void calc_offsets(void)  {
   offx = (maxx+minx)/2;
   offy = (maxy+miny)/2;
}

/////////////////////////////////////////////////////////////
byte 磁力计Ready(void) {
   // Data ready?
   Wire.beginTransmission(0x0d); // Read from status reg
   Wire.write(0x06);
   在t num = Wire.requestFrom((byte)0x0d, (byte)1);
   英石at = Wire.read(); // DOR Data out Ready (SKIPPED).
   Wire.endTransmission();

   ovfl    = 英石at & 0x02;
   skipped = 英石at & 0x04;

   return (英石at && 0x01);  // 0x01 is the DRDY Data Ready flag
}

/////////////////////////////////////////////////////////////
// If data is not ready x,y,z are not changed.
byte getMagnetometerRaw(在t16_t *x, 在t16_t *y,在t16_t *z) {

   if ( !磁力计Ready() ) return 0;

   Wire.beginTransmission(0x0d);
   Wire.write(0x00);     // read from address zero = x,y,z registers.
   在t err = Wire.endTransmission();

   if (!err) {
      Wire.requestFrom((byte)0x0d, (byte)6); //Blocking?
      while(Wire.available()<6); //Wait if above blocking then this not needed.
      *x  = (在t16_t)(Wire.read() | Wire.read() << 8);
      *y  = (在t16_t)(Wire.read() | Wire.read() << 8);
      *z  = (在t16_t)(Wire.read() | Wire.read() << 8);
   }
   return 1;
}

/////////////////////////////////////////////////////////////
// Orient to board coordinates
void getMagnetometer(在t16_t *x, 在t16_t *y, 在t16_t *z) {

   if ( !getMagnetometerRaw(x, y, z) ) return;
   在t tmp = *y;
   *y = -*x;     // x is down.
   *x = tmp;     // y is to the right.
}

/////////////////////////////////////////////////////////////
// Blocking: Waits in this function for reading to be ready.
void readMagnetometer(在t16_t *x, 在t16_t *y,在t16_t *z) {
   while( !磁力计Ready() );
   getMagnetometer(x, y, z);  // Note: Addresses of pointers passed.
}

/////////////////////////////////////////////////////////////
void setup() {

   pinMode(LED,OUTPUT);
   pinMode(BUTTON_CAL,INPUT_PULLUP);

   Wire.begin(); // Start I2C
   Wire.setClock(100000); // Test at high speed

   Serial.begin(115200);
   Serial.println("QMC5883L Digital compass: 3 axis");
   Serial.println("QMC5883L start initialise.");

   // Datasheet suggests this for chip startup.
   I2C_write_AddrDev_AddrReg_Byte(0x0d,0x0b,1);
   I2C_write_AddrDev_AddrReg_Byte(0x0d,0x09,B00000001);

   Serial.println(F("DONE initialise"));

   // Read EEPROM  offset data
   在t EEAddr = EEADDR;
   EEPROM.get(EEAddr,minx); EEAddr +=sizeof(minx);
   EEPROM.get(EEAddr,maxx); EEAddr +=sizeof(maxx);
   EEPROM.get(EEAddr,miny); EEAddr +=sizeof(miny);
   EEPROM.get(EEAddr,maxy); EEAddr +=sizeof(maxy);
   calc_offsets();
}


/////////////////////////////////////////////////////////////
void calibrate() {
   unsigned long calTimeWas = millis();
   byte cal = 1, 英石artCal = 1;
   在t x,y,z;
   float deg=0,deg2=0;

   readMagnetometer(&x, &y, &z);

   maxx = minx = x; // Set initial values to current magnetometer readings.
   maxy = miny = y;

   while(cal) {

      if ( 磁力计Ready() ) getMagnetometer(&x, &y, &z);
      if (x>maxx) maxx = x;
      if (x<minx) minx = x;
      if (y>maxy) maxy = y;
      if (y<miny) miny = y;

      Serial.print("CALIBRATE ");

      在t secmillis  = millis()-calTimeWas;
      在t secs = (在t)((CALTIME-secmillis+1000)/1000);
      Serial.print("--> ");
      Serial.println((CALTIME-secmillis)/1000);

      if (secs==0) { // Cal has ended
         calc_offsets();
         cal = 0;

         在t EEAddr = EEADDR;
         EEPROM.put(EEAddr,minx); EEAddr +=sizeof(minx);
         EEPROM.put(EEAddr,maxx); EEAddr +=sizeof(maxx);
         EEPROM.put(EEAddr,miny); EEAddr +=sizeof(miny);
         EEPROM.put(EEAddr,maxy); EEAddr +=sizeof(maxy);
         Serial.println("EEPROM Written");   // make sure this does not repeat on terminal!
      }

      delay(10);
   } // while cal
}

/////////////////////////////////////////////////////////////
void loop() {
   英石atic unsigned long BLTimeWas=millis();
   英石atic 在t x,y,z; // Raw compass output values.
   英石atic 在t bearing;

   if (数字的Read(BUTTON_CAL)==0) calibrate();

   getMagnetometer(&x, &y, &z);

   在t atan2val = 180/M_PI * atan2((float)(x-offx),(float)(y-offy));
   bearing = (-atan2val + 360 ) % 360;

   if (millis()-BLTimeWas>400) { // LED toggle
      BLTimeWas = millis();
      英石atic byte togLED=0;
      togLED = !togLED;
      if(togLED) 数字的Write(LED,HIGH); else 数字的Write(LED,LOW);

      Serial.println(bearing);
   }

}
// End of HMC5883 Serial output compass.


[文件:qmc5883l-compass.ino]


示例OLED屏幕指南针

以下示例以与第一个完全相同的方式操作 示例,但相反,输出显示是OLED SSD1306.。 - 图形输出显示。这里它显示了25°的轴承 - 这是 轴承轴的坐标I.。直接前方 bearing.

磁性北方通过成角度25度到左侧显示 - 触摸外圈的那个 - 这是移动圆形的那个 罗盘在移动电路板时玫瑰。

QMC5883L.和SSD1306 OLED显示屏指南针

正如您在上图中看到的,5583与X向下对齐,右键对齐。

要获取系统协调,所有计算都使用该计算 OLED屏幕的方向 - 否则你的头部爆炸了!所以 磁力计输出被修改以返回以下内容:

  • 屏幕X = MAGY(由于磁力计Y与屏幕X轴对齐)。
  • 屏幕Y = -MAGX(磁力计X被反转并与屏幕Y轴对齐)。

这两个计算(内部GetMagnetometer)将输出从磁力计转换为屏幕方向。

代码还使用两个功能:

  • distline() - display.drawline(...)周围的包装函数
  • display.drawcircle(...)周围的包装函数

这些绘制线条和圆圈与x,y参考点(0,0) 左下方。图形库使用(0,0)为左上角。他们是 标记为归一化以指示正常图形功能使用y 至上,x到右边。

这样做允许您重点关注此问题,因为现在屏幕匹配"normal" graph orientation.

代码在x中计算y的幅度中的幅度的圆形不定词 - 通常的数学 在标准中查看轴时相邻的操作 graph operations.

代码使用atan2,但考虑到对面的迹象 邻近的。这给出了与atan函数不同的四个象限角度 返回一个象限(atan在atan2时丢失信息 retains it).

使用两个函数图曲线和绘制杂志使得更容易创建包含在功能中的绘制轴承OperatoIn:

  • 绘制(浮动轴承,int midx,int midy,int半径)

此功能仍然使用CCW数学角度旋转,但中心 轴承在XY协调和腰部,轴承长度将 be length 'radius'。它还旋转输出角,使其零 度(x = 0)垂直对齐。你可以说这不是 真的是轴承,而是一个带角零点垂直指向的矢量。

问题是SIN,TAN和COS功能使用CCW旋转 角度和罗盘轴承使用CW旋转角度。转换 对轴承的角度进行以下计算:

  • GetMagnetometer(&x, &y, &z);
  • 在t atan2val = 180 / m_pi * atan2((float)(x-offx),(float)(Y-offy));
  • 轴承=( - atan2val + 360)%360;

第一线为磁力计提供原始输出,但调整 在此应用程序中的X和Y的方向(见前 description above).

值Xoff和Yoff是校准值,因此结果 (X-Xoff)和(Y-Yoff)代表磁力计的方向 没有任何磁干扰。

最后一行将轴承值的输出限制为360 度和改变轴承线的旋转方向。

硬件例如草图2

  • arduino nano(或uno),
  • HMC5883L.(或QST5883L)突破板,
  • 按下按钮(1关闭),
  • SSD1306. OLED.显示屏。

硬件连接例如Sketch2

制作连接如下:

  Arduino Uno/
  Nano pin
标签
目的地
  A5
SCL.
5883L SCL
  A4
SDA.
5883L SDA.
  5V
vcc.
5883L vcc.
  GND
GND.
5883L GND.
  D2 D2 按钮
  GND GND. To Button
  D11
莫斯
OLED_MOSI.
  D13
CLK.
OLED_CLK.
  D9
DC.
OLED_DC.
  D8
CS
OLED_CS.
  D10
RST.
OLED_RESET.

按钮是常开一个。

// QMC5883 compass and SSD1306 OLED display
//
// For an HMC5883L chip a popular library is :
// James Sleeman's HMC5883L library from GitHub.
//
// Here the QMC5883L is controlled by direct
// I2C read/write i.e. no library.
// The adafruit library is used for the SSD1306.
//
// Copyright John Main - Free for non commercial use.
//

#include "Wire.h" ;# For 5883
#include <SPI.h>  ;# For SSD1306 board.
#include <EEPROM.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "I2Cdev.h"

#define OLED_MOSI  11
#define OLED_CLK   13       // LED_BUILTIN
#define OLED_DC     9
#define OLED_CS     8
#define OLED_RESET 10

#define BUTTON_CAL  2
#define BUTTON_TEST 5

#define LED  4 // LED_BUILTIN pin 13 is also SPICLK SCK

#define EEADDR 66 // Start location to write EEPROM data.

#define CALTIME 10000  // In ms.

#define SCREEN_HEIGHT 128 // Screen os rotated in sw
#define SCREEN_WIDTH   64

英石atic byte 英石at,ovfl,skipped;
英石atic 在t minx,maxx,miny,maxy,offx=0,offy=0;

// SSD1306 is oriented vertically (thin x, long y).
// The SSD1306 screen s/w rotated for above orientation.
//
// SSD1306 is mounted on a long solderless breadboard,
// so is physically rotated CCW 90 degrees.

// Screen coords for center of compass screen is 128x64 pixels X,Y.
// x,y (0,0)  lower left. SSD1306 drawing functions use top left.
const 在t 半径 = 64/2;
const 在t midx = 半径;
const 在t midy = 半径;

Adafruit_SSD1306 display(OLED_DC., OLED_RESET., OLED_CS.); // hw spi

/////////////////////////////////////////////////////////////
// Generic I2C write to I2C device with address, i2cAddr
// Write to address regaddr within device
// Write the byte d
void I2C_write_AddrDev_AddrReg_Byte(byte i2cAddr, byte regaddr, byte d ) {
   Wire.beginTransmission(i2cAddr);
   Wire.write(regaddr);
   Wire.write(d);
   Wire.endTransmission();
}

/////////////////////////////////////////////////////////////
void calc_offsets(void)  {
   offx = (maxx+minx)/2;
   offy = (maxy+miny)/2;
}

/////////////////////////////////////////////////////////////
byte 磁力计Ready(void) {
   // Data ready?
   Wire.beginTransmission(0x0d); // Read from status reg
   Wire.write(0x06);
   在t num = Wire.requestFrom((byte)0x0d, (byte)1);
   英石at = Wire.read(); // DOR Data out Ready (SKIPPED).
   Wire.endTransmission();

   ovfl    = 英石at & 0x02;
   skipped = 英石at & 0x04;

   return (英石at && 0x01);  // 0x01 is the DRDY Data Ready flag
}

/////////////////////////////////////////////////////////////
// If data is not ready x,y,z are not changed.
byte getMagnetometerRaw(在t16_t *x, 在t16_t *y,在t16_t *z) {

   if ( !磁力计Ready() ) return 0;

   Wire.beginTransmission(0x0d);
   Wire.write(0x00);     // read from address zero = x,y,z registers.
   在t err = Wire.endTransmission();

   if (!err) {
      Wire.requestFrom((byte)0x0d, (byte)6); //Blocking?
      while(Wire.available()<6); //Wait if above blocking then this not needed.
      *x  = (在t16_t)(Wire.read() | Wire.read() << 8);
      *y  = (在t16_t)(Wire.read() | Wire.read() << 8);
      *z  = (在t16_t)(Wire.read() | Wire.read() << 8);
   }
   return 1;
}

/////////////////////////////////////////////////////////////
// Orient to board coordinates
void getMagnetometer(在t16_t *x, 在t16_t *y, 在t16_t *z) {

   if ( !getMagnetometerRaw(x, y, z) ) return;
   在t tmp = *y;
   *y = -*x;     // x is down.
   *x = tmp;     // y is to the right.
}

/////////////////////////////////////////////////////////////
// Blocking: Waits in this function for reading to be ready.
void readMagnetometer(在t16_t *x, 在t16_t *y,在t16_t *z) {
   while( !磁力计Ready() );
   getMagnetometer(x, y, z);  // Note: Addresses of pointers passed.
}

/////////////////////////////////////////////////////////////
void setup() {

   pinMode(LED,OUTPUT);

   pinMode(BUTTON_CAL,INPUT_PULLUP);
   pinMode(BUTTON_TEST,INPUT_PULLUP);

   Wire.begin(); // Start I2C
   Wire.setClock(100000); // Test at high speed

   display.begin(SSD1306._SWITCHCAPVCC);
   display.clearDisplay();
   display.setTextSize(1);
   display.setTextColor(WHITE);

   // Datasheet suggests this for chip startup.
   I2C_write_AddrDev_AddrReg_Byte(0x0d,0x0b,1);
   I2C_write_AddrDev_AddrReg_Byte(0x0d,0x09,B00000001);

   // Read EEPROM
   在t EEAddr = EEADDR;
   EEPROM.get(EEAddr,minx); EEAddr +=sizeof(minx);
   EEPROM.get(EEAddr,maxx); EEAddr +=sizeof(maxx);
   EEPROM.get(EEAddr,miny); EEAddr +=sizeof(miny);
   EEPROM.get(EEAddr,maxy); EEAddr +=sizeof(maxy);
   calc_offsets();

   display.setRotation(1);
}

/////////////////////////////////////////////////////////////
// Normalized line drawing (0,0) = bot left
void drawLine (在t x1, 在t y1, 在t x2, 在t y2) {
    display.drawLine(x1, SCREEN_HEIGHT-y1, x2, SCREEN_HEIGHT-y2, 1);
}

/////////////////////////////////////////////////////////////
// Normalized circle drawing (0,0) = bot left
void drawCircle (在t x, 在t y, 在t 半径) {
   display.drawCircle(x, SCREEN_HEIGHT-y, 半径-1,1);
}

/////////////////////////////////////////////////////////////
void drawBearing(float bearing, 在t midx, 在t midy, 在t 半径) {
   bearing += 90; // Rotate arctan2 to vertical
   在t opp = sin(bearing*M_PI/180)*半径;
   在t adj = cos(bearing*M_PI/180)*半径;
   // Screen +y is down but drawLine adjusts it up.
   drawLine(midx, midy, midx+adj, midy+opp);
}

/////////////////////////////////////////////////////////////
// Can choose whether to write to EEPROM for testing.
void calibrate(boolean eeprom_write) {
   unsigned long calTimeWas = millis();

   在t x,y,z;
   float deg=0,deg2=0;

   readMagnetometer(&x, &y, &z);

   maxx = minx = x; // Set initial values to current magnetometer readings.
   maxy = miny = y;

   delay(300); // Allow button release.

   while(1) {  // Calibration loop.

      if (数字的Read(BUTTON_CAL)==0 || 数字的Read(BUTTON_TEST)==0) {
         delay(300); // Allow button release.
         return; // Abort
      }

      if ( 磁力计Ready() ) getMagnetometer(&x, &y, &z);
      if (x>maxx) maxx = x;
      if (x<minx) minx = x;
      if (y>maxy) maxy = y;
      if (y<miny) miny = y;

      display.clearDisplay();

      display.setTextSize(2);
      display.setCursor(0,0);

      if(eeprom_write) display.print("CALIBRATE ");
      else             display.print("TEST ");

      在t secmillis  = millis()-calTimeWas;
      if (secmillis>CALTIME) break;                    // Exit after time up.

      在t secs = (在t)((CALTIME-secmillis+1000)/1000);
      display.setCursor(0,32);  display.print("--> "); display.print((在t)((CALTIME-secmillis)/1000));

      drawBearing((在t)deg2, midx, midy , 半径);
      drawBearing((在t)deg,  midx, midy , 半径);

      deg = (360.0/CALTIME)*secmillis; // Rotate a line for countdown duration.

      deg2 += deg; // Rotate a line for countdown duration. Fun.
      deg = fmod(deg,360);

      for(在t i=0;i<360;i+=45)   // 45 Degree spokes (rotating)
        drawBearing(i + (45/secs)*10, midx, midy, 半径-7);

      display.display();  // Update display.
      delay(10);
   } // while cal

   calc_offsets();

   if(eeprom_write) {
      在t EEAddr = EEADDR;
      EEPROM.put(EEAddr,minx); EEAddr +=sizeof(minx);
      EEPROM.put(EEAddr,maxx); EEAddr +=sizeof(maxx);
      EEPROM.put(EEAddr,miny); EEAddr +=sizeof(miny);
      EEPROM.put(EEAddr,maxy); EEAddr +=sizeof(maxy);
   }

   unsigned long dispExitTimeWas = millis();

   while(1) {

      display.clearDisplay();

      display.setTextSize(2);
      display.setCursor(0,0);

      // Make sure this does not repeat endlessly!
      if(eeprom_write) display.print("EEPROM Written");
      else             display.print("TEST DMY Write");
      if (millis()- dispExitTimeWas>2000) break;

      display.display();  // Update display.
      delay(10);
   }
}

/////////////////////////////////////////////////////////////
void loop() {
英石atic unsigned long BLTimeWas=millis();
在t x,y,z; // Raw compass output values.
在t bearing,i;

   if (数字的Read(BUTTON_CAL)==0) calibrate(1);
   if (数字的Read(BUTTON_TEST)==0) calibrate(0);

   getMagnetometer(&x, &y, &z);

   在t atan2val = 180/M_PI * atan2((float)(x-offx),(float)(y-offy));
   bearing = (-atan2val + 360 ) % 360;

   // SSD1306 init.
   display.clearDisplay();

   // display fancy stuff
   drawCircle(midx, midy, 半径-1);    // -1 as circle is 1 bigger
   drawCircle(midx, midy, (半径-1)/2);

   for( i=0;i<360;i+=45)   // 45 Degree spokes
     drawBearing(i , midx, midy, 半径-7);

   drawBearing(bearing, midx, midy, 半径);
   drawBearing(0, midx, midy, 半径);       // North

   display.setTextSize(2);
   在t lineH = 16;
   在t lineNum=2;

   display.setCursor(15,lineH*lineNum);  display.print(bearing);
   display.print((char)247);
   lineNum++;  // Next line

   if(x>maxy || x<minx || y>maxy || y<miny) {
      display.setCursor(0,lineH*lineNum++);  display.print("*CAL*");
   }

   display.display();  // Update display.

   if (millis()-BLTimeWas>400) { // LED toggle
      BLTimeWas = millis();
      英石atic byte togLED=0;
      togLED = !togLED;
      if(togLED) 数字的Write(LED,HIGH); else 数字的Write(LED,LOW);
   }
}
// End of HMC5883L OLED compass.




[文件:QMC5883L-Compass-SSD1306.ino]

结论磁力计指南针

该程序显示您可以使用一个非常有用的罗盘 磁力计(HMC5883L或QST5883L)。这些设备的问题是 你必须让他们水平保持准确的阅读。

解决这个问题的一种方法是向您添加加速度计 系统。使用来自该芯片的数据 弥补了倾斜 magnetometer 获得与水平不相同的读数 orientation.

突发委员会

HMC5883L.突破板(三芯片)

芯片的HMC和QST版本具有相同的引脚所以您 可以有任何类型的设备。判断差异的唯一方法是 通过打印在芯片上的标签(此处显示为5883,因此这是一个QST设备)。

下图显示了分支板的布局(连接名称也在后面打印):

GY 271 HMC5883L突破板

HMC588L Breakout Board.

该板是5V使用,因为它具有3V3稳压器供应 QMC5883L。它还具有双通道MOSFET,用作两个双向的双向 逻辑 level translators (对于SDA和SCL)。水平翻译员允许 连接设备在5V时驱动信号,而5883可以驱动 信号回到3V3。

注意:DRDY信号仅从电路板发送到 微控制器,因此,不需要级别翻译。它 微控制器可以看到足够高的电压(voh)作为a logic one.

三芯片突破板上的芯片

5883 - 这是QMC5883L芯片。
    If your's has the text 'L883'在它上,那么你有HMC5883L芯片。

4A2D - 超低丢弃稳压器LD3985。
    测量的OP = 3V3所以部分是:LD3985M33R。
    The dropout is:
    0.4mV(典型值)@ 1mA〜60mV(典型值)@ 150mA。
    2.0mv(max)@ 1ma〜100mv(max)@ 150mA。

702 - 双N沟道FET(〜L2N7002DW1T1G)
    The RDS(开) of the MOSFET is 7Ω - that's 确定取决于应用程序 - 这里,它只是逻辑级别所以 电流很低,但你可以获得许多较新的MOSFET与RDSON 70〜100mΩ(或更低)的范围,用于更高的电流操作(如果需要)。

替代突破板(两芯片)

这是我买的另一个板的图像;虽然HMC5883L打印 在丝网上,安装了一个QST设备,所以不要't trust the silkscreen label!.

GY 273 HMC5883L突破板

HMC5883L. Breakout Board  -  2芯片版

请注意,董事会如何标记为HMC5883L,即使它实际上确实如此 有一个QMC5883焊接!这有点顽皮,但是 由于制造商可能有1000个,可以理解's of pcbs and the QMC部分确实具有与HMC版本相同的引脚。但是,如果是HMC 版本拟合来自微控制器控制输出的主要伏特将 必须设计为最大输出为4.8V。

另请注意,与此相比,电路板连接被镜像 3芯片板。如果您保留x,y,z符号相同,这更明显 方向(不是在这里完成的主要HMC文本将颠倒)。

这个板有一个(除了更便宜)的一个大优势是 安装孔,其允许稳健地拟合到无人机上。

两芯片突破板上的芯片

5883 - 这是QMC5883L芯片。
    如果你有文本'L883'在它上,那么你有HMC5883L芯片。

662K - 低辍学调节器: XC6206P332MR
    这是三个引脚版的3V3 LDO。
    The dropout is @3V3:
    75mv(典型值)@ 30mA〜250mV(典型值)@ 100mA。
    350mv(max)@ 30ma〜680mv(max)@ 100ma。

关于突破板

第一板使用"safe"设计董事会的方式 - 方式 生产工程师将设计它,即将到指定的最大值 3V6使用3V3电压调节器和电平翻译器的电压电平 用于I2C接口的每个数字I / O的MOSFET。

在生产环境中,您将遵守数据表所说的,因为 制造商已经测试了许多不同的设备以获得所述陈述 operation. You don'想成为一个被归咎于产品的人 召回涉及成千上万的单位!

对于第二委员会,有人注意到QMC芯片被说明 withstand >5V I / O并决定使用这个事实并忽略所述陈述 最大操作条件为3V3。自芯片赢了't blow up for a 5V 输入为什么不使用Arduino(5V)输出直接驱动I2C信号 see what happens.

有用!但是您应该不会在生产环境中使用此方法。

QMC5883L. VS HMC5883L

芯片的QMC版本是增强的HMC芯片。他们都有 相同的引脚和相同的基本内部操作,但QMC 使用自动温度补偿和偏移增强了版本 cancellation.

所有内部寄存器都不同,ADC分辨率不同(QMC:16位,HMC 12bit)。

事实上,事实上,较新的QMC5883L与原始设计有一些显着差异:

  1. 更高分辨率的内部ADC(16位)。
  2. 更快的更新率(192Hz - 速度较快)。
  3. 自动温度补偿输出。
  4. 删除了自检(或至少从用户隐藏)。
  5. I2C地址 - 不同的I2C地址。
  6. 内部寄存器 - 不同的地址位置。
  7. 绝对最大电压 - 更高。
  8. 过采样/平均 - 越来越好选择。
  9. 高斯范围 - 较少的范围,但更容易使用。

ADC分辨率

似乎没有任何 随着数据表索赔最低的影响,对输出分辨率的影响 测量的高斯领域是2mg。但是增加了ADC分辨率 (16位ADC - HMC5883L有一个 12位ADC)允许QMC芯片版本的较少范围切换 意味着更少的软件范围切换,使其更易于使用。不像 the HMC it won't饱和在范围内,并要求切换到一个新的 获得结果的范围。看 高斯范围.

更新率

增加的更新率意味着您可以获得20% 阅读率增加; HMC5883L的最大输出速率为160Hz(QMC能够进行192Hz输出速率)。

补偿产出

有 HMC5883L数据表中的几个段落描述了如何获得a 通过执行自检来校正输出。自检还会产生结果 可用于补偿温度漂移。这些 QMC5883L数据表中不存在段落!

在QMC5883L中,没有自检和摘要它状态:

" 它[QMC5883L]提供低噪音的优点,高 精度,低功耗,偏移消除和温度 compensation "

对于HMC5883L,您必须执行内置的自检以获得 Delta温度(自上次读取以来的变化),然后将比例因子应用于输出。

因此,QMC5883L更易于使用,因为此功能已为您提供自动化。

建立自检

这已在QMC588L中删除(现在无法访问用户 控制)但它可能仍然存在并用作自动 校准机制。

I2C地址

   ⬢QMC5883L具有读写(0D)的单个地址。
   ⬢HMC5883L具有读地址(3D)和写入地址(3C)。

绝对最大电压

   ⬢QMC5883L ABS。最大是5.4V。
   ⬢HMC5883LABS。最大是4.8V。

The QMC5883L won'如果使用正常的5V电源,则爆炸 HMC5883L将损坏(如果要相信数据表!)。

注意:两种情况下最大操作电源电压为3V6。

但是我有一个没有级别移位器的板,它确实有效 在5V(直接连接到Arduino 5V - 董事会有一个内部 3V3 LDO调节器提供QMC。

这作用了,因为最大绝对输入电压为5.4V(仅限HMC为4.8V)。 你应该这样做吗?在生产环境中 - 绝对不是(不是 由制造商测试,不保证工作)。在一个爱好 环境 - 好吧它有效!

过采样/平均

   ⬢QMC5883L允许过度采样高达512次。
   ⬢HMC5883L允许对数据的平均最多8次。

过采样和平均是相同的 - 数据表只是使用 不同的单词。您可以看到QMC芯片的输出是 超自采样的64次比HMC芯片更多 - 这意味着更清洁 输出结果(由于它平均更多)。

高斯范围

   ⬢QMC5883L有2个增益范围:2g和8g。
   ⬢HMC5883L具有8个增益范围:0.88g至8.1g。

首先,这看起来像QMC5883L中的一个主要Blooper,但是 芯片具有更高的分辨率ADC(16位,而HMC具有12位ADC)。这个 意味着与相比之下有一个更精细的高斯测量分辨率 HMC5883L.

凭借更高的分辨率ADC,您赢得了'T需要改变范围 (QMC只有两个可用),因此更容易使用。

注意:HMC5883L的默认高斯范围是:0〜±1.3g。为一个 分辨率为1.49g / 2047 = 0.73mg。对于QMC,它是0g〜  2.73g @ 83ug(见下文)。

对于QMC5883:

最小增益:±2g 1/12000 =±83.3ug / LSB:0g〜2.73g
最大增益:±8g 1/3000 =±0.244mg / LSB:0g〜10.92g

只有两个范围:
    ADC输出数值范围是 -32768和32767 for each setting.

对于HMC5883L.

最小范围(增益设置= 1)±0.73mg / LSB(1.0g / 1370):0g〜1.49g
......
......
最大范围(增益设置= 8)±4.35mg / LSB(1.0g / 230):0g〜8.91g

在所有8例(只有1个英石 最后显示在上面):
    ADC输出数值范围是 -2048〜2047 for each setting.

对于HMC5883L,您必须知道设备范围可能是 不正确。您通过监视返回的值来执行此操作。如果它设置为 -4096,然后输入有饱和的(ADC溢出表明a 强高斯领域),您需要切换到下一个高等的高斯 range.

这可能是数据处理的疼痛,因为它使用数据 将输出寄存器作为错误标志i.e.您必须读取和抑制 使用此芯片时此值。

注意:QMC5883L在最低范围内具有更精细的分辨率83ug 与HMC版本的0.73毫克相比(分辨率〜8.8倍)。 但是,在数据表中,最低要求的决议是2mg。这个 可能是由于ADC等的噪音或非线性。然后,他们 可能只是采取保守的方法来实现实际解​​决方案 capability.

芯片之间的相似之处

引脚: 他们都有相同的引脚。所以一个是更换的一滴 另一个。但请注意,I2C地址和内部寄存器是 not the same.

电源: 他们使用相同的最大值 数字的 工作电压(最大可生存的PSU电压不同)。

基本输出值: 类似,但HMC5883L需要大量的范围改变来检索高斯值(见 高斯范围)。

数据表

HMC5883L.

HMC5883L.数据表。

QMC5883L.

QMC5883L.数据表。

双N沟道MOSFET

这是在第一个分支板上用作两个级别翻译。

双N沟道MOSFET L2N7002DW1T1G.

超LDO调节器(5针)

这是5引脚SOT23-5L调节器。

超低丢弃稳压器LD3895.

LDO稳压器(3针)

这是3针SOT-23稳压器。这不如LD3895(上图)好。

低压丢弃调节器XC6206.

结论HMC5338L VS QST5883L

HMC5338L和QST5883L执行相同的操作,但使用 不同的I2C地址和不同的内部寄存器位置 it, but they 确实完全相同的引脚 所以你可以使用qmc 版本作为HMC版本的替代品。你只需要不同 software!

由于它们产生相同的 输出数据(在高斯)校准过程是相同的。

突破板的单芯片版本具有有用的安装 孔不存在于3芯片上。但是,它忽略了指定的 最大数字工作电压为3v6(使用超出规格)但似乎 工作!但是,可能会使用规格中的某些东西 导致读数关闭,或其他一些非明显效果(或制造商刚刚在较高电压下测试它),

这是一个糟糕的案例,但如果你正在开发一个商业兴趣的系统 使用正确的 电压电平翻译 version of the circuit.

你也可能对此有兴趣:

    如何倾斜补偿这件罗盘.
    如何测量倾斜(ADXL345).


新的! Comments

让你说到你刚刚阅读的东西!留下下面的框中的评论。




隐私政策 | 接触 | 关于我

网站地图 | 使用条款


ezoic.报告此广告

访问我们的Facebook页面:

   点击这里



最近的文章

  1. 如何使用ADS1115

    使用ADS1115精度16位ADC进行教程进行低功耗。

    阅读更多

  2. arduino.模拟输出...易模拟输出生成

    arduino.模拟输出:如何创建最精确的PWM模拟输出以及如何创建模拟PWM正弦波。

    阅读更多

  3. 数号和等效的快速宏。加快代码!

    了解DigitalWrite()的工作原理......现在使用17倍宏宏!

    阅读更多

  4. TCS230颜色传感芯片:如何运作以及如何使用它。

    如何使用TCS230(/ TCS3200)彩色检测器芯片并轻松将其添加到您的任何项目中。

    阅读更多

  5. 如何使用ADXL345进行运动感测等。

    使用ADXL345 Acellerometer,您可以检测到16G!您还可以了解如何使用它来点击检测等。

    阅读更多

  6. HMC5883L. 3轴数字MAGENTOMTER如何运作

    HMC5883L. - 如何制作数字罗盘,了解HMC5883L和QMC5883L之间的差异以及它们是否兼容。

    阅读更多



读者 Comments

"I wanted to thank
你这么好
对于所有信息
你已经提供了
你的网站's

高超极好的."

- 逃亡Potthath.

"This site really is
最好的和我最喜欢的。
我发现这里有很多很有用
项目和提示。"

- 米兰

Bursach.<at>gmail.com<

"Awesome site,
非常,非常容易和好
导航!"


-
镭_tr.<at>
wolf359.cjb.net.


学习微控制器

"Interested in
微控制器?"

注册
免费7天指南:

自由 GUIDE : CLICK HERE


"I am a newbie to PIC
我想说
 how great your
网站一直在为我。"


- 戴夫

de_scott.<at>bellsouth.net

"Your site is a great
和完美的工作。
恭喜。"


- SURESH.

IntegratedInfosys.<at>
Yahoo.com.

"I couldn't find the correct
要定义的词语
你的网页。

非常有用,揭开,
诚实明确。

非常感谢
你的时间和作品。
问候。"


- Anon.

回到顶部