2022年8月23日 星期二

磁力計 HMC5883L 與 NodeMCU 的接口

 

介紹

磁力計 HMC5883L 模塊

磁力計 HMC5883L 模塊

HMC5883L 是一款三軸磁力計,用於測量地球磁場的方向和大小。它用於低成本羅盤和磁力測量。

它沿 X、Y 和 Z 軸測量從毫高斯到 8 高斯的地球磁場值。

它可用於查找設備航向的方向。

它使用 I2C 協議與微控制器通信。

有關磁力計 HMC5883L 及其使用方法的更多信息,請參閱傳感器和模塊部分中的主題HMC5883L 磁力計模塊

NodeMCU 可以使用 I2C 通信協議與該模塊進行通信。要了解有關 NodeMCU 中 I2C 功能的更多信息,請參閱 NodeMCU I2C with ESPlorer IDENodeMCU I2C with Arduino IDE

 

接口圖

磁力計 HMC5883L 與 NodeMCU 的接口

將 HMC5883L 模塊與 NodeMCU 連接

例子

從 HMC5883L 磁力計模塊讀取 x、y、z 軸,計算這三個軸的航向角,並在串行監視器上顯示航向角。

 

首先,按照上面的接口圖進行連接。

現在讓我們編寫 NodeMCU 程序來讀取 HMC5883L 磁力計的值。

我們可以用 Lua 腳本或 C/C++ 語言為 NodeMCU DevKit 編寫代碼。我們使用 ESPlorer IDE 用 Lua 腳本編寫代碼,使用 Arduino IDE 用 C/C++ 編寫代碼。要了解更多信息,請參閱 使用 ESPlorer IDE 開始使用 NodeMCU(對 NodeMCU 使用 Lua 腳本)和使用 Arduino IDE 開始使用 NodeMCU(對 NodeMCU 使用基於 C/C++ 語言的 Arduino 草圖)。

 

HMC5883L 的 NodeMCU 功能

以下是 NodeMCU 固件中用於 HMC5883L 模塊的函數。我們需要在構建 NodeMCU 固件時添加該模塊,以利用其功能。

 

hmc5883l.init()

該函數初始化 HMC5883L 模塊並設置引腳配置。

注意:根據 NodeMCU 文檔所說,“hmc5883l.init() 該功能已棄用,將在即將發布的版本中刪除。改為使用hmc5883l.setup()”。但是,雖然測試hmc5883l.init()有效,但hmc5883l.setup()沒有。所以要確定要初始化哪個函數。

句法: hmc5883l.init(sda, scl)

參數:

sda i2c接口的串行數據引腳。

scl i2c接口的串行時鐘引腳。

回報:

 

hmc5883l.setup()

該函數初始化模塊。

句法: hmc5883l.setup()

參數:

返回:

例子:

local sda, scl = 1, 2
i2c.setup(0, sda, scl, i2c.SLOW) -- call i2c.setup() only once
hmc5883l.setup()

 

hmc5883l.read()

此函數對傳感器進行採樣並返回 X、Y 和 Z 軸數據。

句法: hmc5883l.read()

返回: x,y,z 測量值(整數)溫度乘以 10(整數)

例子:

local sda, scl = 1, 2
hmc5883l.init(sda, scl)
local x, z ,y = hmc5883l.read()
print(string.format("x = %d, y = %d, z = %d", x, y, z))

 

讓我們編寫 Lua 腳本從 HMC5883l 讀取 x、y、z 並從中計算航向角

NodeMCU 的 Lua 腳本

id  = 0 -- always 0
scl = 5 -- set pin 6 as scl
sda = 6 -- set pin 7 as sda


--Define declination of location from where measurement going to be done.
--e.g. here we have added declination from location Pune city, India.
--we can get it from http://www.magnetic-declination.com 
pi = 3.14159265358979323846
Declination = -0.00669


function arcsin(value)
    local val = value
    local sum = value 
    if(value == nil) then
        return 0
    end
-- as per equation it needs infinite iterations to reach upto 100% accuracy
-- but due to technical limitations we are using
-- only 10000 iterations to acquire reliable accuracy
    for i = 1, 10000, 2 do
        val = (val*(value*value)*(i*i)) / ((i+1)*(i+2))
        sum = sum + val;
    end
    return sum
end

function arctan(value)
    if(value == nil) then
        return 0
    end
    local _value = value/math.sqrt((value*value)+1)
    return arcsin(_value)
end

function atan2(y, x)
    if(x == nil or y == nil) then
        return 0
    end

    if(x > 0) then
        return arctan(y/x)
    end
    if(x < 0 and 0 <= y) then
        return arctan(y/x) + pi
    end
    if(x < 0 and y < 0) then
        return arctan(y/x) - pi
    end
    if(x == 0 and y > 0) then
        return pi/2
    end
    if(x == 0 and y < 0) then
        return -pi/2
    end
    if(x == 0 and y == 0) then
        return 0
    end
    return 0
end

hmc5883l.init(sda, scl)       --initialize hmc5883l
while true do   --read and print accelero, gyro and temperature value
    local x,z,y = hmc5883l.read()
    Heading = atan2(y, x) + Declination

    if (Heading>2*pi) then    --Due to declination check for >360 degree 
        Heading = Heading - 2*pi
    end
    if (Heading<0) then       --Check for sign
        Heading = Heading + 2*pi
    end

    Heading = Heading*180/pi  --convert radian to angle
    print(string.format("Heading angle : %d", Heading))
    tmr.delay(10000)   -- 10ms timer delay
end

ESPlorer 串行輸出窗口

上述 Lua 腳本的 ESPlorer IDE 串口窗口的輸出窗口如下圖所示

ESPlorer 串口窗口

 

現在讓我們在 Arduino ide 中為 NodeMCU 編寫相同的示例

用於 NodeMCU 的 Arduino 草圖

#include <Wire.h>

/* Define declination of location from where measurement going to be done. 
e.g. here we have added declination from location Pune city, India. 
we can get it from http://www.magnetic-declination.com */
#define Declination       -0.00669
#define hmc5883l_address  0x1E


void setup() {
  Serial.begin(9600); /* begin serial for debug */
  Wire.begin(D6, D5); /* join i2c bus with SDA=D6 and SCL=D5 of NodeMCU */
  hmc5883l_init();
}

void loop() {
  Serial.print("Heading Angle : ");
  Serial.println(hmc5883l_GetHeading());
  delay(150);
}

void hmc5883l_init(){   /* Magneto initialize function */
  Wire.beginTransmission(hmc5883l_address);
  Wire.write(0x00);
  Wire.write(0x70); //8 samples per measurement, 15Hz data output rate, Normal measurement 
  Wire.write(0xA0); //
  Wire.write(0x00); //Continuous measurement mode
  Wire.endTransmission();
  delay(500);
}

int hmc5883l_GetHeading(){
  int16_t x, y, z;
  double Heading;
  Wire.beginTransmission(hmc5883l_address);
  Wire.write(0x03);
  Wire.endTransmission();
  /* Read 16 bit x,y,z value (2's complement form) */
  Wire.requestFrom(hmc5883l_address, 6);
  x = (((int16_t)Wire.read()<<8) | (int16_t)Wire.read());
  z = (((int16_t)Wire.read()<<8) | (int16_t)Wire.read());
  y = (((int16_t)Wire.read()<<8) | (int16_t)Wire.read());

  Heading = atan2((double)y, (double)x) + Declination;
  if (Heading>2*PI) /* Due to declination check for >360 degree */
   Heading = Heading - 2*PI;
  if (Heading<0)    /* Check for sign */
   Heading = Heading + 2*PI;
  return (Heading* 180 / PI);/* Convert into angle and return */
}

/* Uncomment below function for reading status register */
//uint8_t readStatus(){
//  Wire.beginTransmission(hmc5883l_address);
//  Wire.write(0x09);
//  Wire.endTransmission();
//  Wire.requestFrom(hmc5883l_address, 1);
//  return (uint8_t) Wire.read();
//}

Arduino 串行輸出窗口

上述 Arduino 草圖的 Arduino IDE 串行窗口的輸出窗口如下所示

Arduino 串行輸出窗口

 

請注意,航向也會受到設備傾斜和附近磁性設備影響的影響。附件中提供了補償方法。


資料來源:https://www.electronicwings.com/nodemcu/magnetometer-hmc5883l-interfacing-with-nodemcu

沒有留言: