0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ESP32をJavascriptでLチカする:I2Cデバイスを制御する

Last updated at Posted at 2021-11-16

前回の投稿 「ESP32をJavascriptでLチカする」の続きです。

前回は、GPIOを制御するJavascriptを記述しました。
今回は、I2Cを制御するJavascriptを記述します。また、Javascriptで行っているように、複数のファイルにモジュール分割する方法も示します。

ソースコードもろもろは、前回同様以下に上げてあります。

poruruba/QuickJS_ESP32

#setup()・loop()をasync/await対応にする

以前は、setup()やloop()の定義を以下のようにしていました。

public/main.js
function setup(){
}

function loop(){
}

このままでもよいのですが、今後、async/awaitを使う機会が増える可能性があるため、以下のように変更します。

public/main.js
async function setup(){
}

async function loop(){
}

async/awaitは、非同期処理を簡単に扱うための構文で、Javascriptではよく目にします。以降は、この記述になっていることを前提としています。

#非同期関数の定義と呼び出し

非同期関数はasyncを付けて定義します。例えば、以下のような、一定時間ウェイトする関数の場合です。

async function wait(msec){
  return new Promise(resolve => {
    setTimeout( () =>{
      console.log("time out");
      resolve();
    }, msec);
  });
}

上記を呼び出す場合は以下のようにします。

  console.log("waiting");
  await wait(1000);
  console.log("waked up");

わかりやすくするために、console.logで挟んでいますが、awaitを付けることで、waitの中の処理が完了するまでブロックされて、完了後に次の「console.log(“waked up”)」が実行されます。
もし、awaitを付けないと、waitの関数が終了するのを待たずに、すぐに次の「console.log(“waked up”)」が実行されます。
まとめるとこんな感じです。

(i)awaitを付けた場合

waiting
time out
waked up

(ii)awaitを付けない場合

waiting
waked up
time out

#I2C呼び出し

I2Cは以下のように呼び出します。wireモジュールを使いますので、あらかじめimportでロードしておく必要があります。
見てお分かりの通り、Arduinoでの記法に合わせています。

import * as wire from "wire";

wire.beginTransmission(address);
wire.write(0x00);
wire.write(0x01);
wire.endTransmission();

#モジュール化

Javascriptの記述をすべてmain.jsに書くと、記載が込み入ってしまいますし、別ファイル(モジュール)に分けて記載した方が他のプログラムに流用しやすくなります。

①複数の関数や変数をモジュールで宣言する場合

モジュール側で以下のようにexportを付けて複数の関数や変数を定義したとします。

public/math.js
export function add(a, b){
  return a + b;
}

export function sub(a, b){
  return a - b;
}

これらを使う側では以下のように呼び出します。

public/main.js
import * as math from "math";

var a1 = math.add(1, 2);
var a2 = math.sub(3, 4);

②1つのクラスをモジュールで宣言する場合

モジュール側で以下のようにexportを付けて1つのクラスを定義したとします。

export default class Test {
  constructor() {
  }

  func() {
    return 1;
  }
}

これらを使う側では以下のように呼び出します。

import Test from "Test";

var test = new Test();
var a3 = test.func();

ファイルがmain.jsとモジュールのJavascriptで複数のファイルに分かれるようになりましたので、ESP32へのロード方法を少し変えます。
以下のJSONファイル「modules.json」を作成します。

public/modules.json
{
	"modules": [
		{
			"name": "math",
			"url": "http://【WebサーバのURL】/math.js"
		}
	]
}

このmodules.jsonがWebサーバ上にあれば、ここに記載されたモジュールを先にロードしてから、main.jsをロードするようにしてあります。
ちなみに、nameで指定した名前が、importのfromで指定した文字列になります。

main.cppの以下の部分を環境に合わせて変更してください。

Arduino\QuickJS_M5StickC\src\main.cpp
const char *jscode_modules_url = "http://【WebサーバのURL】/modules.json"; //【モジュールJsonの取得先URL】

#ENV Ⅱ Hatを制御する

それではさっそくI2Cデバイスを制御してみます。
以下の、M5StickCに取り付け可能なENV Ⅱ Hatを使います。

これには、2つ(+1つ)のI2Cデバイスが入っているようです。

・SHT30
・BMP280

C言語のサンプル実装を参考に、Javascriptのモジュールに起こしてみました。

public/SHT30.js
export default class SHT30 {
  constructor(wire, address = 0x44) {
    this.wire = wire;
    this._address = address;
    this.cTemp = 0;
    this.fTemp = 0;
    this.humidity = 0;
  }

  async get() {
    // Start I2C Transmission
    this.wire.beginTransmission(this._address);
    // Send measurement command
    this.wire.write(0x2C);
    this.wire.write(0x06);
    // Stop I2C transmission
    if (this.wire.endTransmission() != 0)
      return 1;

	await this.sleep(500);

    // Request 6 bytes of data
    this.wire.requestFrom(this._address, 6);

    // Read 6 bytes of data
    // cTemp msb, cTemp lsb, cTemp crc, humidity msb, humidity lsb, humidity crc
    var data = this.wire.read(6);

    await this.sleep(50);

    if (this.wire.available() != 0)
      return 2;

    // Convert the data
    this.cTemp = ((((data[0] * 256.0) + data[1]) * 175) / 65535.0) - 45;
    this.fTemp = (this.cTemp * 1.8) + 32;
    this.humidity = ((((data[3] * 256.0) + data[4]) * 100) / 65535.0);

    return 0;
  }
  
  async sleep(msec){
  	return new Promise(resolve => setTimeout(resolve, msec));
  }
};

※BMP280.jsは、GitHubをご参照ください。

#呼び出してみる

public/main.js
import * as wire from "wire";
import SHT30 from "SHT30";
import BMP280 from "BMP280";

var sht30;
var bmp280;

async function setup()
{
    var ipaddress = esp32.getIpAddress();
    console.log("ipaddress=" + ((ipaddress >> 24) & 0xff) + "." + ((ipaddress >> 16) & 0xff) + "." + ((ipaddress >> 8) & 0xff) + "." + (ipaddress & 0xff));

    wire.begin(0, 26);

    sht30 = new SHT30(wire);
    bmp280 = new BMP280(wire);
    await bmp280.begin();
}

async function loop()
{
    await sht30.get();
    console.log("cTemp=" + sht30.cTemp.toFixed(2));
    console.log("fTemp=" + sht30.fTemp.toFixed(2));
    console.log("humidity=" + sht30.humidity.toFixed(2));

    var tmp = bmp280.readTemperature();
    console.log("Temperature=" + tmp);
    var press = bmp280.readPressure();
    console.log("Pressure=" + press);
    console.log("");

    delay(1000);
}

#終わりに

次回はLCDの呼び出し方を紹介する予定です。

以上

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?