ArduinoでIoTにチャレンジ<その5> Arduino MKR WiFi 1010に接続されたセンサからのデータをWebブラウザに表示する①
MKR WiFi 1010で測定したデータの経過をWebブラウザで表示し、また数値にあわせてグラフ表示するための方法の検討も行います。
センサからの読み取りは関数にして、測定項目の追加が容易になるように考えます。
●使用するセンサはLM75B
今回は、次に示すスイッチサイエンスから販売されている「LM75B温度センサ(I2C接続)」(385円)を使用します。このセンサは、NXPのLM75Bを搭載し、I2Cインターフェースを持ち、0.125℃の分解能があり、スタンドアロンでサーモスタットとして動作できます。スイッチサイエンスでは、ピンヘッダをはんだ付けすればブレッドボードに差し込んで利用できるモジュールにして販売しています。
写真は、モジュールに添付されているピンヘッダをはんだ付けしブレッドボードに差し込んだものです。
LM75Bは、上に示したLM75DPの型番で、幅が3mmの8ピンのTSS0P8パッケージのものが小さなボードにはんだ付けされています。ピンヘッダにはGND、SDA、SCL、OS、Vccが引き出されています。モジュールのピンヘッダをはんだ付けする部分にわかりやすく表示されているので、配線では困りません。
●LM75Bのピン配置
SDA(1ピン)、SCL(2ピン)はI2C用です。OS(3ピン)は、Tosレジスタ設定により設定された温度より上昇したときに割り込み処理や外部のデバイスをON/OFFするなどの処理を行うためのオープン・ドレインの出力です。GNDは電源のマイナス側、Vccは+電源で2.8V~5.5Vに対応しています。
●モジュールの回路図
スイッチサイエンスでは、この次に示すモジュールの回路図が用意されています。SDA、SCL、OSは10kΩのR1、R2、R3の抵抗でVccにプルアップされ、ピンヘッダに接続されています。I2Cのアドレスを設定するA0、A1、A2端子は、基板の裏側にGNDに接続するジャンパSJ1(A0)、SJ2(A1)、SJ3(A2)が用意され、デフォルトでGNDに接続されています。R4、R5、R6のプルアップ抵抗は実装されていません。そのため、ジャンパを切断した場合は対応するプルアップ抵抗を接続しなければなりません。接続するためのパターンとはんだ付けのためのランドは用意されています。
●サンプル・プログラム
スイッチサイエンスの該当商品のページには、このモジュールを動作確認するためのサンプル・プログラムが用意されています。Arduino UNOを用いて温度測定と割り込み処理が含まれています。ここでは、定期的に温度を測定し、測定結果をシリアルモニタに表示します。割り込み処理は、次回詳しく説明する予定です。
●LM75Bを使用するほかの準備
LM75Bには、次の四つのレジスタが用意されています。
(1) ポインタ・レジスタ
ポインタ・レジスタは、それぞれの役割をもったレジスタを選択するために、B0、B1の2ビットの選択ビットが用意されています。
B1 | B0 | 内容 |
---|---|---|
0 | 0 | 測定された温度のデータを格納するレジスタ |
0 | 1 | 操作条件を設定するためのコンフィグレイション・レジスタ |
1 | 0 | ヒステリシスの設定値を格納するレジスタ |
1 | 1 | 温度の上限値を設定するレジスタ |
(2) コンフィグレイション・レジスタ
このレジスタは、LM75Bの割り込み処理を起動する条件の詳細、OS出力の仕様やデバイスを1μAの消費電力まで低減しI2Cの機能以外をシャットダウンするなどの制御を行います。
B4、B3ビットの2ビットで、割り込みを起こすためのイベントの回数、実際に割り込みを起こすまでの累積回数を指定します。これはノイズなどの外乱による誤操作を防止するものです。デフォルトは1で、2,4、6を設定できます。
B4 | B3 | 回数 |
---|---|---|
0 | 0 | 1 |
0 | 1 | 2 |
1 | 0 | 4 |
1 | 1 | 6 |
B2 OSの出力の極性を示し、デフォルトで Active LOWです。
B2 | 出力の極性 |
---|---|
0 | Active LOW |
1 | Active HIGH |
B1 OSのコンパレータか割り込み処理か動作を設定します。デフォルトはコンパレータです。
B1 | OSの動作を設定 |
---|---|
0 | コンパレータ |
1 | 割り込み処理 |
B0 ノーマル動作か低消費のシャットダウンかを設定します。デフォルトはノーマルです。
B0 | 動作内容 |
---|---|
0 | ノーマル |
1 | シャットダウン |
(3) 温度レジスタ(Temperature register)
このレジスタは16ビット読み出し専用のレジスタで、このレジスタをバイト単位で2回呼び出すことで、測定された温度の11ビットのデータが得られます。最上位のビットは正負を表す符号で、負の数は2の補数でセットされています。
このデータはB0からB15のうち上位の11ビットに格納されています。int型の16ビットの整数に最初に読み取ったデータを8ビット左にシフトし格納し、2回目に読み取ったデータを加算した結果が温度レジスタの内容と一致します。この結果の上位11ビットが温度のデータなので、5ビット右にシフトします。具体的な処理はプログラムの記述で示します。
温度のデータは分解能が0.125℃/bitなので、得られたデータに0.125を乗算することで測定温度となります。整数、実数の扱いについてもプログラムの中で示します。
(4) Tos、Thysの設定レジスタ
Tosはコンパレータまたはシャットダウンのための閾値を設定するレジスタで、符号を含めて9ビットのデータです。分解能は0.5℃/bitなので。設定温度の値を0.5で除算時その整数部分をレジスタの上位B16からB8にセットします。Thysのレジスタにも同様の仕様でセットします。
●I2Cインターフェースの接続
Arduino MKR WiFi 1010とLM75Bのモジュールの間は次に示すように、Vcc(3.3V)とGNDの電源のラインと、SDAとSCLのI2Cインターフェースの2本のバスラインをそれぞれ接続します。10kΩのプルアップ抵抗はLM75Bのモジュール内に実装されています。
I2Cのアドレスの設定のためのA0、A1、A2の端子のプルアップ抵抗ははんだ付けのためのパターンは用意されていなくジャンパでGND接続されています。そのためデフォルトのI2Cのデバイス・アドレスは0x48となります。
●マスタが通信相手のデバイスを指定する
I2Cでは、通信の最初にマスタからI2Cバスで接続相手と読み書きのどちらかを指定します。マスタはArduino MKR WiFi 1010です。デバイスの指定は、次のdevice addressで示すように7ビットの1001A2A1A0のアドレスと、読み書きを示すR/Wビットに書き込みを示す0の値をセットして1バイトのデータとして送信します。
次の例は、アドレスの指定を行い、ポインタ・レジスタで0x01を書き込んでコンフィグレーション・レジスタを選択し、次に設定データを書き込んでいます。
●実際の処理
ここではLM75BのA2、A1、A0はすべて0なのでアドレスは0x48となります。割り込み処理は今回行わず測定データの読込みのみ行うので、コンフィグレイション・レジスタに書き込む値はデフォルトの設定値と同じ0x00となります。
アドレス0x48のデバイスにコンフィグレイション・レジスタを選択するための0x01を書き込み、次に設定値0x00を書き込むプログラムは次のようになります。
Wire. beginTransmission(0x48); // Start(スタート・コンディション)を開始し、マスタがアドレスと書き込みビットWを合わせて要求を出す
Wire.write(0x01); // Ackの受信応答を確認しpointer byteを書き込む
Wire.write(0x00); // Ackの受信応答を確認し次のdata byteを書き込む
Wire.endTransmission(); // マスタは送信の終わりのstop(ストップ・コンディション)処理を行い、通信を終わる
endTransmission()関数の戻り値は、通信結果を次のように示します。
0 : 正常に完了
1 : データが送信バッファより長すぎる
2 : アドレスの送信で NACK(Not ACKnowlege)を受信した
3 : データの送信で NACKを受信した
4 : その他の送信エラー
しばしば起きるのは、アドレスの間違い、デバイスが起動していない場合などで 2 の応答になります。
●温度データの読み取り
データの読み取りは次手順で行います。
① 読み取るレジスタを選択するためにポインタ・レジスタで温度レジスタを選択する
② 温度レジスタから2バイトのデータを読み取る
③ 読み取った16ビットのデータから上位11ビットの温度データを取り出す
④ 取り出した温度データに換算係数(0.125/℃)を乗算して温度を求める
次の図の上段が①の処理となり、下段の処理が②の処理となります。①の処理はマスタがデバイスのアドレスとR/WのW(0)を書き込み、次に0x00を書き込んで、温度レジスタを選択します。
②はデータを読み取る処理なのでアドレスとR/WのR(1)を出力し、データを読み出します。マスタはデータを読みだした後は緑色で示したACKを返します。R/Wの1ビットは、Wire関数が自動で付加します。
●プログラム例
実際のプログラムは次のようになります
Wire.requestFrom(0x48,2);
while(Wire.available()){
temp_data = Wire.read() << 8); // 温度レジスタの上位8ビット取得
temp_data =temp_data+Wire.read();
}
temp_dataはintで定義しますから16ビットの符号付きの整数です。そのため、1バイト目の読み込み処理は上位バイトの読み込みなので、読み込んだ値を8ビット分シフトして上位バイトとしてセットしています。
この後得られたtemp_dataに0.125℃を乗算して結果を得ます。
●実際にテストしたプログラム
デフォルトの状態で、レジスタは温度レジスタが設定されています。書き込みの場合はポインタ・レジスタの選択が必須です。しかし、現在選択されているレジスタから読み込む場合、レジスタの選択は省略できます。
今回は、デフォルトの設定で処理を行うのでコンフィグレイション・レジスタの設定は必要なく、デフォルトで選択されている温度レジスタを読み込み、温度に変換してシリアルモニタに表示するだけなので、次のようなシンプルなものになります。
●事前処理は
I2Cライブラリを使用するので、include文でWire.hの読み込みを指定し、温度レジスタの値を格納する変数を設定します。
// 2022/02/17 MKRWIFIM75010
#include <Wire.h>
int temp_data = 0; // LM75Bの温度レジスタの値を格納
●初期化処理
setup()内では、I2Cの処理を行うWireライブラリの開始とシリアル通信の開始を行うだけです。
void setup() {
Wire.begin();
Serial.begin(9600);
}
●次の処理で温度を読み取る
I2CでLM75Bから温度データの上位バイト、下位バイトの順番に読み取り、温度のレジスタを格納するtemp_dataに格納します。
temp_dataの上位11ビットを右に5シフトし、0.125℃/bitの換算係数を掛けて温度のデータにして、シリアルモニタに表示します。
void loop()
{
Wire.requestFrom(LM75Badr, 2);
while (Wire.available()) {
temp_data = (Wire.read() << 8); // 温度レジスタの上位8ビットを取得
temp_data = temp_data + Wire.read(); // 温度レジスタの下位8ビットを取得
}
Serial.println((temp_data >> 5) * 0.125); // レジスタの値を温度に変換
delay(1000);
}
測定された結果を次に示します。センサに指を触れて温度を上げた後なので、少しずつ数値が下がっています。
基本的な温度測定ができました。次回、この他の機能について確認していきます。
(2022/02/20)
<神崎康宏>