マスタリングWireライブラリ その3 温度センサMCP9808のアラート
組み込み用途で温度センサは、ある設定値より高温になったら警告(アラート)を出す、という用途で使われます。Arduinoを使っていれば、常に温度を測定して、設定値を超えたら、どこかのポートに信号を出して警告用ランプを点灯するということはたやすくできます。最初にスケッチを作って実験します。
次に、温度センサ自体に判断機能があるので、Arduinoのスケッチで設定をします。
●Arduinoのスケッチでアラート
前回のスケッチの温度測定部分を関数readTemp()に分離し、loop()内を見通しよくします。設定温度tMaxを超えたら、13番のLEDを1秒点灯します。 13番のLEDは、Arduino UNOでは最初から取り付けられています。プリント基板の13というシルク印刷の近くの'L'文字の隣にあります。
#include <Wire.h>
unsigned char MCP9808_address = 0x18;
unsigned char Temp_register = 0x05;
float temperature;
const int alartLED = 13 ;
const int tMax = 50 ;
void setup() {
Wire.begin();
Serial.begin(9600);
Serial.println("start ");
Wire.beginTransmission(MCP9808_address);
Wire.write(Temp_register);
Wire.endTransmission();
pinMode(alartLED, OUTPUT);
}
void loop() {
temperature = readTemp();
Serial.println(temperature);
if (temperature >tMax) digitalWrite(alartLED, HIGH);
delay(1000);
digitalWrite(alartLED, LOW);
}
float readTemp() {
Wire.requestFrom(MCP9808_address, 2);
int temp1 = Wire.read();
int temp2 = Wire.read();
int tempSign = ((temp1 & 0b00011111 ) << 8 ) + temp2;
int temp = tempSign & 0x0fff;
if (tempSign >>12 ) temp = -( (~temp & 0x0fff) +1);
return temp * 0.0625 ;
}
●温度センサMCP9808のアラート機能
アラート端子はオープン・ドレインで通常プルアップしておきます。Low時3mAの電流が取り出せます。
アラートは二通りの設定方法があります。
- 上限下限の温度を設定する
- 臨界温度を設定する
上限の温度は0x02、下限の温度は0x03、臨界温度は0x04レジスタに設定します。それぞれ10ビットで、同じフォーマットです。
bit15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 |
- | - | - | 符号 | 2^7℃ | 2^6 | 2^5 | 2^4 |
7 | 6 | 5 | 4 | 3 | 2 | 1 | bit0 |
2^3 | 2^2 | 2^1 | 2^0 | 2^-1 | 2^-2 | - | - |
設定はコンフィギュレーション・レジスタ0x01で行います。
bit15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 |
- | - | - | - | - | ヒステリシス | シャットダウン | |
7 | 6 | 5 | 4 | 3 | 2 | 1 | bit0 |
臨界温度書き込みロック | 上下の温度書き込みロック | 割り込みクリア | アラート・ステータス | アラート・イネーブル | アラート・セレクト | アラート正/負論理 | アラート出力がコンパレータか割り込みか選択 |
0x05レジスタは温度が常に更新されているレジスタですが、最初の3ビットは、アラートの情報が読み出せます。
- bit15 0;臨界温度未満、1;臨界温度以上
- bit14 0;上限温度以下、1;上限温度を超える、臨界温度以上
- bit13 0;下限温度以上、1;下限温度未満
パワーオン・リセット時(電源が入った直後の状態)、0x01~0x05はすべて0です。したがって、設定レジスタは次の状態です。
- コンパレータ・モード
- アクティブLow出力
- アラート、臨界出力
- 出力ディセーブル
- アラートはアサートされていない
- 割り込みクリア
- アラート限界アンロック
- 臨界限界アンロック
- 連続変換
- ヒステリシスは0℃
●50℃以上だとアラートを出す設定
50℃は12ビットで0011 0010 0000です。上位3ビットも0とすると、0000 0011 0010 0000=0x0320です。マニュアルのプログラム事例でも16ビットのデータにしてレジスタに書き込んでいます。
この値を臨界温度設定レジスタ0x04に書き込みます。
Wire.beginTransmission(MCP9808_address);
Wire.write(0x04);
Wire.write(0b00000011);
Wire.write(0b00100000);
return Wire.endTransmission();
この温度以上ならアラートを発生という条件をコンフィギュレーション・レジスタに書き込みます。温度変化がゆっくりなとき境界が1点だとシビアなので、通常ヒステリシスを持たせます。0x01レジスタのbit10とbit9で、デフォルトは0℃の'00'です。3℃の'10'に変更します。アラートを有効にするために、bit3を'1'にします。 00000100 00001000を書き込みます。
Wire.beginTransmission(MCP9808_address);
Wire.write(0x01);
Wire.write(0b00000100);
Wire.write(0b00001000);
return Wire.endTransmission();
この状態で実行すると、常にアラート信号が出ます。温度データの最上位ビットは常に'1'で臨界温度を超えているというステータスです。上限温度を設定していなくてデフォルトの0℃なので、常温がそれ以上のためだと思われます。
そこで、コンフィギュレーション・レジスタのbit2を'1'にします。そうすると、臨界温度だけにアラートが対応します。この状態で実行すると、設定どおり、臨界温度を超えるとアラートが出ます。
アラート信号は、デフォルトではHIGH、設定条件を超えたときにLOWになります。次の回路でLEDを接続しています。電流制限抵抗は6.8kΩを使ったので、流れる電流は1mA以下です。高輝度LEDならば十分明るいですが、暗いときは、3mAまで電流は増やせるので、1.5~2.2kΩを使うとよいでしょう。
ヘアー・ドライアでMCP9808を加熱します。50℃を超えるとLEDは点灯し、ヘアー・ドライアを遠ざけて、47℃以下になるとLEDは消灯しました。
readTemp()関数は、読み出す温度レジスタの番号を引数にして温度を読み出すように修正しました。前半のスケッチに比べてこちらを利用するメリットは、警告以外のメインの仕事がある場合に、その処理に集中できることです。
#include <Wire.h>
unsigned char MCP9808_address = 0x18;
float temperature;
const unsigned char config_register = 0x01 ;
const unsigned char upperTemp_register = 0x02 ;
const unsigned char underTemp_register = 0x03 ;
const unsigned char crticalTemp_register = 0x04 ;
const unsigned char Temp_register = 0x05 ;
void setup() {
Wire.begin();
Serial.begin(9600);
Serial.println("start ");
Wire.beginTransmission(MCP9808_address);
Wire.write(crticalTemp_register);
Wire.write(0b00000011); // 50
Wire.write(0b00100000);
Wire.endTransmission();
Wire.beginTransmission(MCP9808_address);
Wire.write(config_register);
Wire.write(0b00000100);
Wire.write(0b00001100);
Wire.endTransmission();
}
void loop() {
delay(1000);
temperature = readTemp(Temp_register);
Serial.println(" temp= "+String(temperature));
temperature = readTemp(upperTemp_register);
Serial.println(" upperTemp= "+String(temperature));
temperature = readTemp(underTemp_register);
Serial.println(" underTemp= "+String(temperature));
temperature = readTemp(crticalTemp_register);
Serial.println(" crticalTemp= "+String(temperature));
}
float readTemp(unsigned char registerNumber) {
Wire.beginTransmission(MCP9808_address);
Wire.write(registerNumber);
Wire.endTransmission();
Wire.requestFrom(MCP9808_address, 2);
int temp1 = Wire.read();
int temp2 = Wire.read();
int tempSign = ((temp1 & 0b00011111 ) << 8 ) + temp2;
int temp = tempSign & 0x0fff;
if (tempSign >>12 ) temp = -( (~temp & 0x0fff) +1);
return temp * 0.0625 ;
}
(※1)Arduino IDEは1.8.5を利用しています。プログラム・リストは、表示の関係でTabキーが無視されるので、スペースに代えてあります。また、リスト中を2回クリックすると全選択になるので、CTRL-Cでコピーし、テキスト・エディタにCTRL-Vで貼り付けて利用してください。エディタに持っていくと、スペースやリターン・コードなどが化けていることがあるので、一度消して、Arduino IDEのテキスト・エディタで修正してください。