目次

3. I2C の使い方

概要

CHIRIMEN with micro:bit(以下 「CHIRIMEN microbit」) を使ったプログラミングを通じて、Web I2C API の使い方を学びます。

前回 は温度センサを使いながら Web I2C API の基本的な利用方法を学びました。今回は温度センサ以外のI2Cセンサの使い方を見ていきましょう。

ここでは例として光センサ、距離センサ、加速度センサの 3 つについて詳しく説明しますが、最後に「他の I2C モジュールも使ってみる」として紹介しているように、CHIRIMEN ではそれ以外にも多くの I2C デバイス (あるいは I2C の ADC を使って様々なアナログセンサ類) が簡単に扱えるようになっており、 examples ページ に回路図とサンプルコードが用意されています。各自興味のあるセンサを順に試していってください。

今回からは、スターターキットに入っている部品を超えたチュートリアルになります。必要なパーツを各自調達する必要があります。

前回までのおさらい

本チュートリアルを進める前に前回までのチュートリアルを進めておいてください。

前回までのチュートリアルで学んだことは下記のとおりです。

1.準備

用意するもの

上記に加え今回紹介するセンサが必要となりますが、センサについては各センサの説明のパートに記載します。

2. 光センサを使ってみる

光の強度 (明るさ) に反応するセンサを使ってみましょう。

a. 部品と配線について

「1.準備」のパートに記載したものに加え、下記を用意してください。

Raspberry Piとの接続方法については、下記回路図を参照ください。

回路図

b. 接続確認とexampleの実行

i2cdetect webAppで接続を確認しておきましょう。

SlaveAddress 0x23 が見つかれば接続OKです。次に exampleのcodesandbox を動かします。

https://codesandbox.io/s/github/chirimen-oh/chirimen-micro-bit/tree/master/examples/I2C_BH1750

いつもの通り、別ウィンドでwebAppsを起動し、CONNECTボタンを押しmicro:bitを接続すると・・

画面左上の LIGHT[lx] : に表示されてる数値が明るさです。センサに当たる光を遮断してみてください。数値が小さくなるはずです。逆にセンサに LED の光を直接当てると数値が大きくなることが確認できるでしょう。

c. コード解説

example のコードから、光センサに関係する部分を見ていきます。今回はドライバーライブラリの中までは深入りせずに、アプリケーションの流れを追ってみましょう。ADT7410(又はSHT31) の時とほとんど同じであることがわかるはずです。

c-1. index.html

下記がindex.htmlの中から主要な部分を抜き出したコードです。

index.html

    :
    <script src="https://cdn.jsdelivr.net/npm/@chirimen/microbit"></script>
    <script src="https://cdn.jsdelivr.net/npm/@chirimen/bh1750"></script>
    <script src="./main.js" defer></script>
    :
  <body>
    :
    <table>
      <tr>
        <td>LIGHT[lx] : </td>
        <td id="light"></td>
      </tr>
    </table>
  </body>

HTML は ADT7410(又はSHT31) の時とほとんど同じです。ドライバーライブラリは、https://cdn.jsdelivr.net/npm/@chirimen/bh1750 に変わりました。

c-2. main.js

次に、main.jsを見てみましょう。(重要な部分以外は削っています)

main.js

function connect(){
    microBitBle = await microBitBleFactory.connect();
    var i2cAccess = await microBitBle.requestI2CAccess();
    var i2cPort = i2cAccess.ports.get(1);
    bh1750 = new BH1750(i2cPort);
    await bh1750.init();
    await bh1750.set_sensitivity(128);
    readData();
}

function readData(){
  while (readEnable) {
    var val = await bh1750.measure_high_res();
    light.innerHTML = val;
    await sleep(300);
}

main.js も温度センサとほとんど同じです。最初に UIボタン経由でconnect()を呼び出しmicro:bitを接続した後、I2C デバイスを操作するため I2CAccess、Port と順に取得したら SlaveAddress と一緒にドライバに渡して初期化し、あとはセンサーの値を読みたいときに read() の代わりに measure_high_res() します。詳しく見てみましょう。

var light = new BH1750(port, 0x23)

ここで光センサ用の ドライバーライブラリのインスタンス生成 を行なっています。

ライブラリ名が変わっただけで ADT7410(又はSHT31) と同様に、port オブジェクトと、SlaveAddress をパラメータで渡しています。

bh1750.init()

init()I2C ポートを開いてセンサーを初期化 します。

内部ではインスタンス生成時に指定したportオブジェクトと slaveAddress(0x23) を用いて I2CPort.open() を行ない、返却される I2CSlaveDevice を保存後に resolve() で呼び出し元に処理を返しています。

bh1750.measure_high_res()

BH1750 の仕様に基づく データ読み出し処理 をここで実施しています。

3. 測距センサを使ってみる

モノまでの距離を測定する測距センサ (I2C-VL53L0X) を使ってみましょう。

a. 部品と配線について

「1.準備」のパートに記載したものに加え、下記を用意してください。

raspi との接続方法については、こちらの回路図を参照ください。

VL53L0X回路図

このセンサモジュールは 4 本のピンヘッダ経由で接続します。あらかじめピンヘッダをハンダ付けしておいてください。また、製品によってはチップ表面に黄色の保護フィルムがついているものがあります。剥して使用してください。

ピンの加工例 (保護フィルムが残っている状態)

加工例

b. 接続確認と example の実行

i2cdetect webAppで接続を確認しておきましょう。

SlaveAddress 0x52 が見つかれば接続OKです。次にcodesandboxでexampleを動かします。

codesandbox

センサの前面 (VIN、GND、SCL、SDA等の文字が書いてある方) に手を近づけたり離したりしてみてください。距離の値が変化するはずです。

VL53L0X が計測できる距離は およそ 3〜200 cm (30-2000 mm) までです。

c.コード解説

example のコードから、測距センサに関係する部分を見ていきます。

c-1. index.html

下記がVL53L0X.htmlの中から主要な部分を抜き出したコードです。

VL53L0X.html

    :
    <script src="https://cdn.jsdelivr.net/npm/@chirimen/microbit"></script>
    <script src="https://cdn.jsdelivr.net/npm/@chirimen/vl53l0x"></script>
    <script src="main.js"></script>
    :
  <body>
    :
    <input type="button" value="Connect" onclick="connect();"/>
    <div id="msg">---</div>
    :
  </body>

HTML は ADT7410(又はSHT31) の時とほとんど同じです。ドライバーライブラリは https://cdn.jsdelivr.net/npm/@chirimen/vl53l0x に変わりました。

c-2. main.js

次に、main.js を見てみましょう。(重要な部分以外は削っています)

main.js

async function connect(){
	microBitBle = await microBitBleFactory.connect();
	var i2cAccess = await microBitBle.requestI2CAccess();
	var i2cPort = i2cAccess.ports.get(1);
	vl53 = new VL53L0X(i2cPort, 0x29);
	await vl53.init();
	readEnable = true;
	readData();
}
:
async function readData(){
	while ( readEnable ){
		var distance = await vl53.getRange();
		msg.innerHTML= distance + "mm";
		await sleep(1000);
	}
}

main.js も温度センサとほとんど同じです。

vl53 = new VL53L0X(i2cPort, 0x29)

ドライバーライブラリのインスタンス生成処理です。

await vl53.init()

こちらも、内部で I2CSlaveDevice インタフェースを取得する処理で、他のセンサと同様です。

distance = await vl53.getRange()

測距センサ VL53L0X の仕様に基づくデータ読み出し処理をここで実施しています。計測範囲内に遮蔽物がない場合には値が数値で得られないことに注意してください。

4. 加速度、角加速度センサを使ってみる

傾きなどに反応するセンサを使ってみましょう。

a. 部品と配線について

「1.準備」のパートに記載したものに加え、下記を用意してください。

raspi との接続方法については、下記回路図を参照ください。

回路図

b. 接続確認とexampleの実行

i2cdetect webAppで接続を確認しておきましょう。

SlaveAddress 0x68 が見つかれば接続OKです。次に codesandboxでexample を動かします。

https://codesandbox.io/s/github/chirimen-oh/chirimen-micro-bit/tree/master/examples/I2C_MPU6050

画面の左上に表示されている Gx Gy Gz が加速度センサの値、Rx Ry Rz が角加速度を表しています。センサを動かすと数値が変化するはずです。

c. コード解説

exampleのコードを見てみましょう。

c-1. index.html

下記がindex.htmlの中から主要な部分を抜き出したコードです。

index.html

    :
    <script src="https://cdn.jsdelivr.net/npm/@chirimen/microbit"></script>
    <script src="https://cdn.jsdelivr.net/npm/@chirimen/mpu6050"></script>
    <script src="main.js"></script>
    :
  <body>
    :
    <table>
      <tr>
          :
        <td>Gx</td>
        <td id="gx"></td>
          :
        <td>Gy</td>
        <td id="gy"></td>
          :          :
        <td>Rz</td>
        <td id="rz"></td>
      </tr>
    </table>
  </body>

今回のドライバーライブラリは、https://cdn.jsdelivr.net/npm/@chirimen/mpu6050 です。そして出力が Gx Gy Gz Rx Ry Rz と6つの値を表示するため要素が6つに変わりましたが、それ以外はこれまでとほとんど同じです。

c-2. main.js

次に、main.js を見てみましょう。(重要な部分以外は削っています)

main.js

:
async function connect(){
    microBitBle = await microBitBleFactory.connect();
    var i2cAccess = await microBitBle.requestI2CAccess();
    var i2cPort = i2cAccess.ports.get(1);
    mpu6050 = new MPU6050(i2cPort, 0x68);
    await mpu6050.init();
    :
    readData();
}

async function readData(){
    :
    while ( readEnable ){
        var val = await mpu6050.readAll();
        temp.innerHTML = val.temperature;
        gx.innerHTML = val.gx;
        gy.innerHTML = val.gy;
        gz.innerHTML = val.gz;
        rx.innerHTML = val.rx;
        ry.innerHTML = val.ry;
        rz.innerHTML = val.rz;
        await sleep(1000);
    }
}

main.js もこれまでの他のセンサーとほとんど同じです。

var mpu6050 = new MPU6050(port, 0x68);

ここで加速度センサ用のドライバーライブラリのインスタンス生成を行なっています。

mpu6050.init()

これまでのドライバーライブラリ同様に init() では、インスタンス生成時に指定した port オブジェクトと slaveAddress(0x68) を用いて I2CPort.open() を行ない、返却される I2CSlaveDevice を保存後にresolve()で呼び出し元に処理を返しています。

mpu6050.readAll()

readAll() では、Gx Gy Gz Rx Ry Rz の値が一度に返却されます。

5. 演習: 複数のセンサを組み合わせて使ってみよう

下記のような組み合わせで2つのセンサを繋いで動かしてみましょう。

a. 部品と配線について

「1.準備」のパートに記載したものに加え、下記を用意してください。

b. モジュールを複数接続する

I2C モジュールを複数利用するのは一見難しそうに見えるかもしれませんが、実際には I2C モジュールの各ピン (VDD GND SDA SCL) を並列に接続すれば問題なく動作します。

b-1. I2C モジュール側の準備をする

ブレッドボードに挿せるよう、 I2C モジュールの各ピンにジャンパ線を接続します。

b-2. ブレッドボードにジャンパ線を接続する

接続例

i2cdetect webAppを使って、センサーの接続を確認します。下図のように、Slave Address 0x23(BG1750), 0x44(SHT31)が確認できれば、配線はうまくできています。

c. コードを編集する

実際に2つのモジュールからデータを取得するコードを書いてみましょう。

c-0. 利用するモジュール各々のコードを用意する

Examples 等を参考にして、それぞれのモジュール用のコードを用意します。

自分で一からコーディングする場合には不要です。

c-1. HTML を書く

それではcodesandboxを使ってプログラムを組んでいきます。

c-2. JavaScript(main.js) を書く

6. 他の I2C モジュールも使ってみる

前回からこれまでに 4 つの I2C センサを使ってみました。

CHIRIMEN microbit には、他にも examplesに例えば下記のような I2C モジュールの examples が含まれています。それぞれの回路図、デイバスドライバ、サンプルコードもあるので、お手持ちのデバイスを使ってみてください。

I2C デバイスを複数使う場合の注意事項

I2Cデバイスを同時に接続して使用するとき、重要な注意事項があります。それは I2C アドレスの衝突です。チュートリアル2-2 の図に書かれているように I2C デバイスは個々のアドレスを持っています。このアドレスは I2C デバイスの製品ごとに固有のアドレスが設定されていますが、偶然同じアドレスを持ったデバイスを手にすることもあります。

アドレスが衝突しているデバイスは同時に接続できません。 このチュートリアルで使ったデバイスのアドレスを以下の表に掲載します。NativeAddr がそのデバイスのオリジナルの状態のアドレスです。すでに衝突しているものがいくつかあるのがわかると思います。

一方、I2C デバイスのによってはこのアドレスを変更でき、アドレスの衝突を回避できる場合があります。但しアドレスの変更は JavaScript から行うのではなく、デバイスの基板上でハードウェア的(電気的)に設定するジャンパによって設定します。(ジャンパはピンヘッダとして用意され、ジャンパ線などで設定できるものもありますが、多くの場合は半田を盛ってジャンパとするタイプです。詳しくは各デバイスを購入すると付属しているデータシートを参照してください。)

下表の ChangedAddr はアドレス変更可能なデバイスでジャンパーを設定し、他のデバイスのアドレスと衝突しないようにする例です。

Device NativeAddr ChangedAddr
ADT7410 0x48 => 0x49
ADS1115 0x48
VEML6070 0x38, 0x39
S11059 0x2a
PCA9685 0x40 => 0x41
grove-touch 0x5a
grove-oledDisplay 0x3c
grove-gesture 0x73
grove-light 0x29
grove-accelerometer 0x53

まとめ

このチュートリアルでは 下記について学びました。

このチュートリアルで扱ったコードは以下のページで参照できます: