I2C接続AQMシリーズのキャラクタ表示LCDをMicro:bitで使う (5) 温度センサ

熱を感じよう

 プログラムの開発にArduino IDEを使ったMicro:bitで温度を測るには、

  • アナログ出力の温度センサ
  • ディジタル出力の温度センサ

のどちらでも利用できます。

 知りたい温度範囲が室温付近であればいろいろな温度センサが利用できます。

 100℃以上になる料理中の油の温度やオーブンの内部を測るような用途では、熱電対(ねつでんつい)と呼ばれる温度センサが適しています。熱電対自体は温度に比例した微小な電圧が発生するアナログ温度センサなのですが、ディジタル出力に変換できるICを利用する方法が手軽です。

K型熱電対用デジタル計測モジュール

 MAX31855Kというデバイスを搭載したAdafruitの「K型熱電対アンプ・モジュール」を利用します。秋月電子通商で購入しました。

 熱電対は、JISで規定されています(下の表は一部)。二つの異なる金属線の先端を溶接して使います。工業用にはK型が一番使われているそうです。

記号 測定温度範囲 [℃] 特徴
R 0~+1100 高温で耐久性が高い
K -200~+1200 低価格
E -200~+900 起電力が大きく分解能に優れる

 熱電対は、2種類の金属の接合部計測器側接点の温度差で電圧が発生します。理科の実験では、氷水(0℃)を使って冷接点補償を使いますが、MAX31855Kでは内蔵された別の温度センサ気温を測り温度差を加減する基準接点補償が使われています。熱電対は、温度と発生する電圧が非直線です。コンピュータが使えなかった時代は、アナログ・アンプで複雑な補正をしていました。

 このモジュールに搭載されているMAX31855K は、0.25℃の分解能、-200~+700℃の測定温度範囲で最大±2℃の確度が得られます。

 動作電圧は3.3Vと5Vに対応し、ディジタル・インターフェースはSPIです。

 こちらでも利用しているので、参考にしてください。

   Arduinoで肉を美味しく調理する(3)熱電対センサ・モジュール

接続

 K型熱電対アンプ・モジュールに、ピンヘッダと熱電対をつなげるターミナルをはんだ付けします。

 同時に購入したK型熱電対にはプラグがついていますが、モジュールには合わないので、外します外す前にプラグにある+を目印にマーカで印をつけます。なお、先端に黒いチューブがついていますが、高温では燃えるようです。てんぷら油の温度が測りたいときは、ステンレス管に入った製品を選びます。

  図のように各デバイスを接続します。

データ・フォーマット

 MAX31855Kから読み出したデータは、32ビットの中が、次のように熱電対の測定温度(14ビット)と内部温度(12ビット)が収納されています。必要な温度は、「熱電対の測定温度」です。

D31 D30 ... D18 ... D15 D14 ... D4 ...
熱電対の測定温度
(14ビット)
  内部温度
(12ビット)
 
符号 MSB  ~ LSB   符号 MSB  ~ LSB  

スケッチ

 SPIのライブラリを使います。SPIは通常、マスタ(Micro:bit)から命令クロックとともに送り出し、スレーブ(MAX31855K)からは温度データが送られてきます。

 その通信のやり取りのスタートは、チップ・セレクト信号CSです。Micro:bitには専用のCS信号はありません。ArduinoのSPIライブラリでも、専用のCSは規定されていません。CSは通常HIGHにしておき、通信を始めるときにLOWにし、終わったらHIGHに戻します。

 MAX31855K内部の温度変換は常に行われているので、いつ読み出してもかまいません。したがって、これから読みに行くから、温度を用意しておいてねとかいう命令を出す必要がないので、マスタからスレーブへはどんな命令(ここでは0xff)を送ってもかまいません。

 命令を送るとき、一緒にクロックも出ます。

 1回の転送は8ビットで行われるので、4回命令を送ります。スレーブから送られてくるデータは全部で32ビット=4バイトですが、最初の2バイトが熱電対の測定温度、次の2バイトが内部温度なので、分けて変数(rdata と rdata0 )に入れます。

 熱電対の測定温度は左詰めでデータ(rdata)が14ビット入っているので、右に2シフトして14ビット・データ(t)とします。データは2の補数形式で入っています。最上位が0のときは正の数値、1のときは負の数値です。このスケッチではマイナスの温度を考慮していません。

#include <SPI.h>
int CS = 16;
int rdata;int rdata0;
float t;

void setup() {
pinMode(CS, OUTPUT);
digitalWrite(CS, HIGH);
SPI.begin();
Serial.begin(9600);
}

void loop() {
digitalWrite(CS, LOW);
rdata = SPI.transfer(0xff) << 8;
rdata = rdata + SPI.transfer(0xff);
rdata0 = SPI.transfer(0xff) << 8;
rdata0 = rdata0 + SPI.transfer(0xff);
digitalWrite(CS, HIGH);
t = (rdata >>2) * 0.25;
Serial.print(rdata,HEX);
Serial.print(" temp= ");Serial.print(t);Serial.println(" ");
delay(500);
}

LCDへの表示

 上記のプログラムにLCDへの表示部分を追加しました。

#include <SPI.h>
#include <Wire.h>
unsigned char lcd_address = 0x3e;
int CS = 16;
int rdata;int rdata0;
float t;

int i2cwritecmd(byte cmd) {
Wire.beginTransmission(lcd_address);
Wire.write((byte)0x00);
Wire.write(cmd);
return Wire.endTransmission();
}

int i2cwritedata(byte data) {
Wire.beginTransmission(lcd_address);
Wire.write(0x40);
Wire.write(data);
return Wire.endTransmission();
}

void lcdcu_set(int x, int y) { // xは桁数、0から16が指定できる。yは行数で0が1行目、1が2行目
byte ca = (x + y * 0x40) | (0x80); i2cwritecmd(ca);
}

void lcdclear() {
i2cwritecmd(0x01);delay(1);
}

void i2cprint( String pdata) {
int n = pdata.length();
for (int i = 0; i < n; i = i + 1) {
i2cwritedata(pdata.charAt(i));
delay(1);
}
}

void init_lcd() { // LCDの初期化
delay(145);
i2cwritecmd(0x38);delay(1);
i2cwritecmd(0x39);delay(1);
i2cwritecmd(0x14);delay(1);
i2cwritecmd(0x73);delay(1);
i2cwritecmd(0x56);delay(1); // 3.3V
i2cwritecmd(0x6c);delay(300);
i2cwritecmd(0x38);delay(1);
i2cwritecmd(0x0c);delay(2);
i2cwritecmd(0x01);delay(2);
}

void setup() {
Wire.begin();
init_lcd();
i2cprint("Start");
pinMode(CS, OUTPUT);
digitalWrite(CS, HIGH);
SPI.begin();
Serial.begin(9600);
Serial.println("start ");
delay(1000);
}

void loop() {
digitalWrite(CS, LOW);
rdata = SPI.transfer(0xff) << 8;
rdata = rdata + SPI.transfer(0xff); // 熱電対の温度
rdata0 = SPI.transfer(0xff) << 8;
rdata0 = rdata0 + SPI.transfer(0xff);
digitalWrite(CS, HIGH);
lcdclear();
t = (rdata >>2) * 0.25;
Serial.print(rdata,HEX);
Serial.print(" temp= ");Serial.print(t);Serial.println(" ");
i2cprint("temp="); i2cprint(String(t));i2cprint("C"); // LCDへの温度の表示
delay(500);
}

油の温度を測る

 上記のプログラムを書き込んだMicro:bitを、加温中のフライヤの近くに持っていきました。Micro:bitのマイクロUSBコネクタには、モバイル・バッテリをつなぎました。モバイル・バッテリの電源をONすると、Micro:bitが起動し、書き込まれたプログラムが動作します。

コラム SPIのやり取り

 SPIは高速でデータを転送できる便利なシリアル通信です。単純なプロトコルなのですが、スレーブ・デバイスは、メーカによって独自な実装が行われているので、可視化しないと、ほんとうにデータを受信できているかの確信が持てません。

 USBオシロスコープPicoScopeで観測したアナログ波形です。上の青色がクロックSCKで、下の赤色がデータのMISOです。

 Analog Discovery2のロジック・アナライザで観測した波形です。Select(DIO0)はチップ・セレクトのCS信号です。Clock(DIO3)はクロックSCKです。デフォルトは4MHzです。Data(DIO2)は読み出したデータMISOです。Analog Discovery2のSPIプロトコルを選ぶと4本目のMOSI信号を選べないので、汎用信号でDIO1を選びましたが、なにも信号は出ていませんでした。MOSIはどこにもつながっていません。

 シリアル信号は16進でデコードした値を表示しています。ずっと観測していると、2バイト目にノイズが頻度高く出てきて、その結果、3バイト目のデータが1ビットずれる状況がみられました。