目次
- 2. I2C 基本編 (ADT7410 温度センサー)
- 概要
- 1.準備
- 2.I2C とは
- 3.温度センサー(ADT7410)を使ってみる
- 4.温度センサー(ADT7410)example のコードを読んでみる
- 4.温度センサー(ADT7410)の値をドライバーを使わずに読むコードを書いてみる
- まとめ
2. I2C 基本編 (ADT7410 温度センサー)
概要
CHIRIMEN for Raspberry Pi 3 (以下「CHIRIMEN Raspi3」)を使ったプログラミングを通じて、Web I2C API の使い方を学びます。
前回までのおさらい
本チュートリアルを進める前に「Hello World 編」と、「GPIO 編」で CHIRIMEN Raspi3 の基本的な操作方法とプログラミング方法を確認しておいてください。
前回までのチュートリアルで学んだことは下記のとおりです。
- CHIRIMEN Raspi3 では、各種 example が
~/Desktop/gc/
配下においてある。配線図も一緒に置いてある。 - CHIRIMEN Raspi3 で利用可能な GPIO Port 番号と位置は壁紙を見よう。
- CHIRIMEN Raspi3 では Web アプリからの GPIO の制御にはWeb GPIO API を利用する。GPIO ポートは「出力モード」に設定することで LED の ON/OFF などが行える。また「入力モード」にすることで、GPIO ポートの状態を読み取ることができる
- async function を利用すると複数ポートの非同期コードがすっきり書ける
1.準備
用意するもの
このチュートリアル全体で必要になるハードウエア・部品は下記の通りです。
- Hello World 編 に記載の「基本ハードウエア」
- [ジャンパーワイヤー (メス-メス)] x 4
- 温度センサADT7410 x 1 ※付属のピンヘッダでなく、通常サイズのピンヘッダをハンダ付けしておいてください
2.I2C とは
I2C とは 2 線式の同期式シリアル通信インタフェースです。「アイ・スクエア・シー」とか「アイ・ ツー・シー」などと読みます。
SDA(シリアルデータ)と SCL(シリアルクロック)の 2 本の線で通信を行います。
上図のように、i2c の SDA、SCL は複数のモジュール間で共有します。(「I2C バス」と言います。)
I2C ではマスターとスレーブの間で通信が行われます。常にマスター側からスレーブ側に要求が行われます。スレーブ側からマスター側へ要求を行うことはできません。
マスターは、スレーブが持つ「SlaveAddress」を用いて、特定のスレーブとの通信を行います。
このため、同じ I2C バス上に同じ SlaveAddress のスレーブを繋ぐことはできません。
通信するモジュール同士が同一基板上にない場合には、SDA、SCL の 2 本の通信線に加え電源や GND の線を加えて 4 本のケーブルを用いて接続するのが一般的です。
詳細は下記をご参照ください。
ここでは I2C の概要として下記を押さえておきましょう。
- I2C には複数のモジュールが繋がる(I2C バス)
- I2C に繋がるモジュールにはマスターとスレーブがある
- I2C では必ずマスターからスレーブに対して通信要求が行われる
- I2C スレーブは SlaveAddress を持っている
- 同じ I2C バスに同じ SlaveAddress のスレーブは繋げない
3.温度センサー(ADT7410)を使ってみる
それでは実際に I2C に対応したモジュールを使ってみましょう。
CHIRIMEN Raspi3 では、センサーなど、いくつかの I2C モジュールのサンプルがプリインストールされています。
/home/pi/Desktop/gc/i2c/
この中から、ADT7410 という温度センサーモジュールを使ってみたいと思います。
Raspberry Pi 3 と ADT7410 との接続方法(回路図)と example コードは下記フォルダに格納されています。
/home/pi/Desktop/gc/i2c/i2c-ADT7410/
I2C バス上、Raspi3 がマスター、ADT7410 がスレーブになります。
a. 部品と配線について
まずは、下記ファイルをダブルクリックしてください。回路図が表示されます。
/home/pi/Desktop/gc/i2c/i2c-ADT7410/schematic.png
この回路を作成するのに必要な部品は下記の通りです。(Raspi3 基本セットを除く)
これらのパーツを下記回路図の通りに接続してみてください。ADT7410 は 4 本のジャンパーピンを左右逆に繋いでしまうと、短時間で非常に高温になり故障するだけでなく火傷してしまいます ので、配線には注意してください。
下記が Raspi3 側の接続ピンの位置を拡大した図になります。
間違えないよう接続をお願いします。
b. 接続がうまくいったか確認する
ここで、ターミナルを起動して下記コマンドを入力してみてください。
$ i2cdetect -y -r 1
すると、下記のような画面が表示されるはずです。
48
という表示が見えます。これは 16 進数表示ですので0x48
という意味です。
i2cdetect
コマンドでは I2C バスに接続されている SlaveAddress を確認することができます。
0x48
は、ADT7410 の SlaveAddress と思われるものですが、念のためデータシートも確認してみましょう。
データシートの P.17 に「SERIAL BUS ADDRESS」の項があり、ここに SlaveAddress の記載があります。
ADT7410 は0x48
がデフォルトの SlaveAddress で、A0,A1 ピンの HIGH/LOW により SlaveAddeess の下位 2bit を変更できることがわかります。
(ADT7410 Data Sheet より抜粋)
試しに、一度 Raspi3 の 3.3V に接続している線を抜いて、もう一度 i2cdetect -y -r 1
を実行してみてください。
0x48
が見つからなくなりました。
これで、ADT7410 の SlaveAddress が0x48
となっていることが確認できました。
再度、先ほど外した 3.3V の線を戻して ADT7410 に電源を供給しておいてください。
c. example を実行してみる
配線と SlaveAddress が確認できましたので、さっそく動かしてみましょう。
ADT7410 のためのサンプルコードは先ほどの配線図と同じフォルダに格納されています。
/home/pi/Desktop/gc/i2c/i2c-ADT7410/index.html
ダブルクリックすると、ブラウザが起動し下記のような画面になります。
画面の回路図の下の数値が温度(摂氏)になります。
ADT7410 センサに触ると、ゆっくりと温度が上がるはずです。
ADT7410 は I2C という通信方式でセンサーデータを送出するモジュールです。
この情報を Web I2C API 経由で Web アプリが読み取り、画面に情報を表示しているわけです。
4.温度センサー(ADT7410)example のコードを読んでみる
それでは、コードを見てみましょう。
/home/pi/Desktop/gc/i2c/i2c-ADT7410/
配下の index.html
、main.js
をみてみます。
d-1. index.html
下記が index.html の中から主要な部分を抜き出したコードです。
index.html
:
<script src="../../polyfill/polyfill.js"></script>
<script src="../../drivers/i2c-ADT7410.js"></script>
<script src="./main.js"></script>
:
<body>
:
<p id="head">TEST</p>
:
</body>
まず最初に読み込んでいるのが polyfill.js
。Web GPIO API の時に出てきた https://chirimen.org/chirimen-raspi3/gc/polyfill/polyfill.js
と同じ Web GPIO API と Web I2C API の Polyfill です。
次に読み込んでいるのが、i2c-ADT7410.js
。このファイルは、Web I2C API を使って ADT7410 との通信を行うためのドライバーとなるライブラリです。
最後に読み込んでいる main.js
が、ドライバーライブラリを使ってこのアプリケーションの動作を記述している部分です。
d-2. main.js
次に、main.js
を見てみましょう。
main.js
window.onload = async function mainFunction() {
var head = document.querySelector("#ADT7410value");
var i2cAccess = await navigator.requestI2CAccess(); // i2cAccessを非同期で取得
var port = i2cAccess.ports.get(1); // I2C I/Fの1番ポートを取得
var adt7410 = new ADT7410(port, 0x48); // 取得したポートの0x48アドレスをADT7410ドライバで受信する
var value;
await adt7410.init();
for (;;) {
// 無限ループ
value = await adt7410.read();
head.innerHTML = value ? `${value} degree` : "Measurement failure";
await sleep(1000);
}
};
ここで温度センサーの情報を定期的に取得し、画面に出力する処理が行われています。 少し詳し解説してみます。
await navigator.requestI2CAccess()
Web I2C API を利用するための I2CAccess
インタフェースを取得するための最初の API 呼び出しです。この関数も非同期処理の関数で、
処理完了を待機し、その結果正しくインタフェースが取得されたら i2cAccess
オブジェクトに保持されます。
i2cAccess.ports.get()
I2CAccess.ports
は、利用可能な I2C ポートの一覧です。
var port = i2cAccess.ports.get(1);
CHIRIMEN Raspi3 で利用可能な I2C ポート番号は1
番だけです。
ここでは、ポート番号に1
を指定して、port
オブジェクトを取得しています。
var adt7410 = new ADT7410(port,0x48)
ここで ADT7410 用のドライバーライブラリのインスタンス生成を行なっています。
await adt7410.init()
ADT7410 用のドライバーライブラリのインスタンス (adt7410) が持つ非同期処理の関数 init()
は、その内部でインスタンス生成時に指定した port
オブジェクトと slaveAddress(0x48)
を用いて I2CPort.open()
を行なっています。
I2CPort.open()
が成功すると、I2CSlaveDevice
という I2C ポートへデータ書き込みや読み込みなどを行うインタフェースが返されます。
I2CSlaveDevice
インタフェースは、ライブラリ内に保存され、その後の処理でこのインターフェースを使って I2C デバイスである adt7410 との通信が可能になります。
await adt7410.read()
ADT7410 の仕様に基づくデータ読み出し処理をここで実施しています。
内部では、I2CSlaveDevice.read8()
という API を 2 回呼び出すことで、温度データの MSB, LSB を 8bit ずつ読み出し、両方の読み出しが終わった時点で MSB と LSB を合成、16bit データとしたのちに、温度データに変換して返却しています。
Web I2C API に着目して流れをまとめると
ADT7410 ドライバーライブラリの内部の処理をまとめると以下のようなことが行われています。
- await navigator.requestI2CAccess() で I2CAccess インタフェースを取得
- i2cAccess.ports.get(1) で、1 番ポートの
port
オブジェクトを取得 - await port.open(0x48) で、SlaveAddress 0x48 番の I2CSlaveDevice インタフェースを取得
- i2cSlave.read8() で 温度データ を読み込み (ADT7410 の場合、常に 2 回セット)
となります。
この流れは、ADT7410 以外の他の I2C デバイスでも基本的に同様になります。
I2C デバイスにより変わるのは、port.open()
に指定する SlaveAddress と、4.の実際の処理 になります。
CHIRIMEN Raspi3 の example として用意されているサンプルコードとドライバーが提供されている I2C デバイスは下記リストの通りですが、下記リストに無い I2C デバイスでも、上記流れを押さえておけば対応するコードを書くのはそれほど難しくありません。
新たな I2C デバイスへの対応方法については、下記記事も参考にしてください。
(CHIRIMEN Raspi3 ではなく、CHIRIMEN ボード向けの記事ですが、Web I2C API への対応観点では同じ方法論で対応が可能です)
4.温度センサー(ADT7410)の値をドライバーを使わずに読むコードを書いてみる
それでは、ADT7410 ドライバー内部での処理の流れがだいたいわかったところで、ドライバーを使わずに自力で値を読み込むコードを一応書いてみましょう。
example と同じコードを書いても面白くないので、今回はi2c-ADT7410.js
は使わずに、JSFiddle を使って一通り温度を読み込む処理を書いてみましょう。
もし、ブラウザで /home/pi/Desktop/gc/i2c/i2c-ADT7410/index.html
開いている場合、一度閉じておいてください。
JSFiddle で HTML を書く
それでは始めましょう。
JSFiddle の HTML ペインに Polyfill の読み込みと、温度表示のためのタグだけ書いておきます。
<div id="ADT7410value">---</div>
<script src="https://chirimen.org/chirimen-raspi3/gc/polyfill/polyfill.js"></script>
こんな感じで良いでしょう。
JavaScript を書いてみる
次に JavaScript です。async function を使って書いてみます。
今回は定期的なポーリング処理が必要になるので、GPIO 編 c. スイッチに反応するようにする (port.read()を使ってみる) の時に書いたコードが参考になります。
// ADT7410のドライバを使わず、自力でADT7410の値を読むサンプル
window.onload = async function mainFunction() {
var head = document.querySelector("#ADT7410value");
var i2cAccess = await navigator.requestI2CAccess(); // i2cAccessを非同期で取得
var port = i2cAccess.ports.get(1); // I2C I/Fの1番ポートを取得
var i2cSlaveDevice = await port.open(0x48); // アドレス0x48のI2Cスレーブデバイスを得る
var MSB;
var LSB;
var temperature;
for (;;) {
// 無限ループ
MSB = await i2cSlaveDevice.read8(0x00); // これ以下の3行が肝です
LSB = await i2cSlaveDevice.read8(0x01);
temperature = ((MSB << 8) | (LSB & 0xff)) / 128.0;
head.innerHTML = `${temperature} ℃`;
await sleep(1000);
}
};
JavaScript を書いたら、▷ Run
を押して実行してみましょう。
温度センサーの値が表示されたはずです。
ADT7410 を指で触って温度が変わることを確認してみてください。
まとめ
このチュートリアルでは下記について学びました。
- I2C の基礎知識
- i2cdetect コマンドを使った Raspi 3 に接続された I2C モジュールの SlaveAddress 確認方法
- Web I2C API を使った処理の流れ
- ADT7410 温度センサーの制御方法
このチュートリアルで書いたコードは以下のページで参照できます:
- GitHub リポジトリで参照
- ブラウザで開くページ (各ステップ)
次の『チュートリアル 3. I2C 応用編(その他のセンサー)』では加速度センサーなど他のセンサーも触っていきます。