マスタリングWireライブラリ その6 温度センサLM75B リピーテッド・スタート・コンディション
温度センサLM75Bのデータシートによれば、I2Cの読み書きのなかで、スタート・コンディションとストップ・コンディション以外にリピート(リピーテッド)スタート・コンディションがあります。I2Cバスは、複数のデバイスがつながっています。バスが空いていると、だれでも通信を開始でき、都合の悪いことがあります。
MCP9808の温度データ読み取りでは、最初にマスタがアドレスを出し、温度の入ったポインタのアドレスを続けてバスに出したら書き込みが終了するので、いったんストップ・コンディションになり、すぐさまスタート・コンディションにしてアドレスを出し、今度は読み取りを行います。この読み書きの方向が切り替わる時に、いったんストップ・コンディションになると、バスはフリー状態なので、ほかのデバイスが通信を始められます。そこで、スレーブ・デバイスがACKを返した後、ストップ・コンディションにはせずにスタート・コンディションにします。これをリピート・スタート・コンディションと呼び、ほかのデバイスが通信を始められないようにできます。
●LM75Bのおもなスペック
動作電源電圧は3.3Vもしくは5Vです。スレーブ・アドレスは、A0、A1、A2ピンをGNDやVddに接続して変更ができます。I2Cのデータ転送速度は最大で400kHzです。
測定温度範囲は-55~+125℃、-25~+100℃間の確度は±2℃で、11ビットでデータを扱うときの分解能は0.125℃です。内部でアラートの温度設定ができ、その温度を超えるとOS端子に信号を出せます。
●接続
スイッチサイエンスでボードを入手しました。ラズパイで実験したので、プルアップ抵抗のR1とR2は取り去りました。購入時、A0、A1、A2はいずれもGNDへ配線されているので、0x48です。A0をVddへつなぎなおしたので、0x49で利用します。スレーブ・デバイスが1個だけならば、変更する必要はありません。OS端子は10kΩでプルアップされています。
●スケッチ
スレーブ・アドレスは0x49です。温度のデータが入っているレジスタは、ポインタ0x00で指定し、二つの8ビット・データが読み出せます。最初の8ビットが上位の桁で、もう一つの8ビットのうち3ビットが下位データです。合計11ビットのデータになります。LSBの温度は0.125℃なので、読み出したデータに0.125を乗ずると温度が得られます。データは2の補数の形式です。最上位ビットd10が符号で、1ならばマイナスの温度です。
次に示すコンフィギュレーション・レジスタは、ポインタ0x01で指定します。パワーオン・リセットで内容は0x00です。
bit7:5 | 予約 |
bit4:3 | 設定温度を超える回数の設定 |
bit2 | OS出力の極性 |
bit1 | OSはコンパレータか割り込みかの選択 |
bit0 | 1ならシャットダウン、0がノーマル |
コンフィギュレーション・レジスタは何も変更しないのですが、0x00を書き込みます。設定していない割り込み発生温度Tos(高)は80℃、割り込み発生温度Thyst(低)は75℃がデフォルト値です。常温では割り込みはかかりません。マイナスは考慮していないスケッチです。
#include <Wire.h>
unsigned char LM75B_address = 0x49; //A0=HIGH
const unsigned char config_pointer = 0x01 ;
const unsigned char Temp_pointer = 0x00 ;
void setup() {
Wire.begin();
Serial.begin(9600);
Serial.println("start ");
Wire.beginTransmission(LM75B_address);
Wire.write(config_pointer);
Wire.write(0x00);
Wire.endTransmission();
}
void loop() {
Wire.beginTransmission(LM75B_address);
Wire.write(Temp_pointer);
Wire.endTransmission();
Wire.requestFrom(LM75B_address, 2);
float temp = ( ( (Wire.read()<<8) | Wire.read() ) >> 5 ) * 0.125 ;
Serial.println(temp);
delay(100);
}
このときの波形を観測します。最初に温度のポインタをセットし、温度データ2バイトを読み込みます。読んだデータは正常です。
温度ポインタを書き込んだ後、LM75Bはリピート・スタート・コンディションを想定していますが、拡大してみると、ストップ・コンディション->スタート・コンディションになっています。
ほんとうは、次のように、ストップ・コンディションを起こさせないようになっていなければなりません(画像を修正)。LM75Bは温度ポインタを保持してくれるので、温度が正常に読み出せましたが、そうでないデバイス(ADT7410、ADS1015)があるようです。
Arduino 1.0.1以降、endTransmission()に引数を入れられるように修正されました。デフォルトはtrueで、ストップ・コンディションにします。falseのときは、バスを開放しません。18行目をWire.endTransmission(false); に変更し、波形を観測します。リピート(リピーテッド)スタート・コンディションになっていることが確認できました。マルチマスタで使うときなどは、デバイスのデータを正しく読めるこの機能は重要ですね。
次のスケッチは、温度ポインタの指定をsetup()内で済ませ、loop()では読み出しだけを行います。
#include <Wire.h>
unsigned char LM75B_address = 0x49; //A0=HIGH
const unsigned char config_pointer = 0x01 ;
const unsigned char Temp_pointer = 0x00 ;
void setup() {
Wire.begin();
Serial.begin(9600);
Serial.println("start ");
Wire.beginTransmission(LM75B_address);
Wire.write(config_pointer);
Wire.write(0x00);
Wire.endTransmission();
Wire.beginTransmission(LM75B_address);
Wire.write(Temp_pointer);
Wire.endTransmission();
}
void loop() {
Wire.requestFrom(LM75B_address, 2);
float temp = ( ( (Wire.read()<<8) | Wire.read() ) >> 5 ) * 0.125 ;
Serial.println(temp);
delay(100);
}
波形です。温度ポインタは一度設定すると、以降、有効になっていることが確認できました。