初めてのArduino ⑦ UNOボードで温度を測る(その2 TMP117)
前回、アナログ出力の温度センサLM35DZを使いました。確度±0.5℃です。温度センサを利用するとき、確度が高いことが望まれる利用例は多いでしょう。確度±0.05℃のLMT70があります。
アナログ出力をマイコンに取り込む際、ビット数の多いA-Dコンバータが必要なので、簡単には利用できません。ここでは、確度±0.1℃でArduino UNOにディジタル(I2C)で直接つないで使えるTMP117を利用します。
●使用環境
- Windows10 Home 21H2
- Arduino IDE 2.0 RC(2.0.0-rc5)
- Arduino UNO R3
●温度センサTMP117のおもなスペック
- 動作電圧 1.8~5.5V
- 分解能 16ビット、LSBは0.007812℃
- 動作温度範囲 -55~150℃
- 確度
- -20~+50℃ の範囲で±0.1℃ (最大値)
- -40~+100℃ の範囲で±0.2℃ (最大値)
- -55~+150℃ の範囲で±0.3℃ (最大値)
- 消費電流 1Hzの変換サイクルで3.5uA
- インターフェース I2Cバス(1~400kHz)
- データ長 2の補数形式の16ビット
- 平均化出力が可能
- 温度設定のアラートあり
●I2Cバス
LEDマトリクス表示器はSPIバスにつなぎました。バスという名前がついているように、複数のデバイスをつなぐとき、MOSI、MISO、SCKの三つの信号は共通に、SS(CS)はデバイスごとに独立して用意します。
比較的低速な通信に使われるのがI2Cバスです。クロックSCL、データのSDAの2本の信号をすべてのデバイスが共有します。二つの信号はプルアップしておきます。Arduino UNOではマイコンボード側にはプルアップ抵抗はついていません。
ArduinoではWireライブラリを使います。
●TMP117のレジスタ類
デバイスによっては、読み出すだけで、温度データが読めるものがあります。読み書きに必要なレジスタは二つです。アドレス0x00にある温度読み出しレジスタと0x01にあるConfigurationレジスタです。
温度読み出しレジスタの電源ON直後の内容は0x8000なので、この値を読み出すと、設定ができていないことがわかります。
ICに電源が入ったら、Configurationレジスタの設定内容に従って動作します。特にスリープ・モードに入る動作はないようです。レジスタの初期値0x220では連続変換モードになっているので、特に変更する必要はないようです。
●接続
TMP117はとても小さなパッケージ(0.98×1.5mm)に入っていてリード線は出ていません。Adafruitのブレークアウト・ボードを利用します。このボード上のSCLと端子には、10kΩのプルアップ抵抗が装着されています。
ボードの左右についている4ピンのコネクタは、I2C専用です。アラート機能を使うときは、ピンヘッダを使います。
I2Cはデバイスをスレーブ・アドレスで判別します。TMP117のデフォルトは0x48で、裏面のADDRをショートすると0x49になります。データシートによれば、0x4a、0x4bも設定できます。
TMP117ボードのコネクタ | Arduino UNO |
---|---|
GND | GND |
V+ | 5V |
SDA | SDAもしくはA4 |
SCL | SCLもしくはA5 |
●スケッチ
Wireライブラリをincludeします。アドレス類を用意します。LEDマトリクスライブラリを使うときSPIライブラリを明示的にincludeしませんでした。たぶん、LEDMatrixDriver.hpp内でincludeされていると思われます。
最初に読み込んだTに0x80が入っているとすると、次のように収まっています。
- | - | - | - | - | - | - | - | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
8回左にシフトすれば、下のけたには0がfillされます。
1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
読み出した値が0x01であれば、中身は次のような16ビット・データになっています。
1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
温度[℃] | 温度読み出しレジスタTemperatureRegisterの値 分解能 0.0078125℃ |
|
---|---|---|
バイナリ | 16進 | |
–256 | 1000 0000 0000 0000 | 8000 |
–25 | 1111 0011 1000 0000 | F380 |
–0.1250 | 1111 1111 1111 0000 | FFF0 |
–0.0078125 | 1111 1111 1111 1111 | FFFF |
0 | 0000 0000 0000 0000 | 0000 |
0.0078125 | 0000 0000 0000 0001 | 0001 |
0.1250 | 0000 0000 0001 0000 | 0010 |
1 | 0000 0000 1000 0000 | 0080 |
25 | 0000 1100 1000 0000 | 0C80 |
100 | 0011 0010 0000 0000 | 3200 |
255.9921 | 0111 1111 1111 1111 | 7FFF |
#include <Wire.h>
#define TMP117address 0x48
#define TemperatureRegister 0x00
#define ConfigurationRegister 0x01
#include <LEDMatrixDriver.hpp>
#define LEDMATRIX_CS_PIN 10
#define LEDMATRIX_SEGMENTS 4
#define LEDMATRIX_WIDTH LEDMATRIX_SEGMENTS * 8
int16_t sensorValue;
float analogSensorData;
// This is the font definition. You can use http://gurgleapps.com/tools/matrix to create your own font or sprites.
// If you like the font feel free to use it. I created it myself and donate it to the public domain.
byte font[14][8] = { {0,0,0,0,0,0,0,0}, // SPACE
{0x60,0x60,0x1c,0x12,0x20,0x20,0x12,0x0c}, // `C
{0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60}, // DOT
{0,0,0,0,0,0,0,0},
{0x30,0x48,0x48,0x48,0x48,0x48,0x30,0x00}, // 0
{0x20,0x60,0x20,0x20,0x20,0x20,0x70,0x00}, // 1
{0x30,0x48,0x08,0x08,0x30,0x40,0x78,0x00}, // 2
{0x30,0x48,0x08,0x30,0x08,0x08,0x70,0x00}, // 3
{0x10,0x10,0x30,0x50,0x78,0x10,0x10,0x00}, // 4
{0x70,0x40,0x40,0x30,0x08,0x08,0x70,0x00}, // 5
{0x30,0x40,0x40,0x70,0x48,0x48,0x30,0x00}, // 6
{0x78,0x48,0x10,0x20,0x20,0x20,0x20,0x00}, // 7
{0x30,0x48,0x48,0x30,0x48,0x48,0x30,0x00}, // 8
{0x30,0x48,0x48,0x38,0x08,0x08,0x30,0x00}, // 9
};
LEDMatrixDriver lmd(LEDMATRIX_SEGMENTS, LEDMATRIX_CS_PIN);
void setup() {
Serial.begin(9600);
while(!Serial);
Serial.println("\nTMP117 test");
Wire.begin();
//Wire.beginTransmission(TMP117address);
// Wire.write((uint8_t)ConfigurationRegister);
// Wire.write((uint8_t)0x00); // high
// Wire.write(0x60); // low
//Wire.endTransmission();
// init the display
lmd.setEnabled(true);
lmd.setIntensity(2); // 0 = low, 10 = high
}
void loop() {
Serial.println("====");
float temp = read_tempdata();
Serial.println(temp,4);
String sensorValueSTR = String(temp, DEC);
char Buf[10]="11.890";
sensorValueSTR.toCharArray(Buf, 10);
drawString(Buf, 5, 0, 0);
drawSprite( font[1], 24, 0, 8, 8 );
lmd.display();
delay(1000);
}
float read_tempdata() {
Wire.beginTransmission(TMP117address);
Wire.write((uint8_t)TemperatureRegister);
Wire.endTransmission();
Wire.requestFrom(TMP117address, 2);
// wait for response
while(Wire.available() == 0);
int16_t T = Wire.read();
T = T << 8 | Wire.read() ;
//Serial.println(T);
return ( -(T & 0b1000000000000000) | (T & 0b0111111111111111) ) * 7.8125 /1000.0;
}
/**
* This function draws a string of the given length to the given position.
*/
void drawString(char* text, int len, int x, int y ){
//Serial.println("===");
int flag=0;
for( int idx = 0; idx < len; idx ++ ){
int c = text[idx] ;
//Serial.println(c);
// stop if char is outside visible area
if( x + idx * 5 > LEDMATRIX_WIDTH )
return;
// only draw if char is visible
if( 4 + x + idx * 4 > 0 )
if (!flag) {
drawSprite( font[c-44], x+1 + idx * 5, y, 5, 8 );
} else {
drawSprite( font[c-44], x-1 + idx * 5, y, 5, 8 );
flag = 1;
}
if (c==46) flag = 1;
}
}
/**
* This draws a sprite to the given position using the width and height supplied (usually 8x8)
*/
void drawSprite( byte* sprite, int x, int y, int width, int height ){
// The mask is used to get the column bit from the sprite row
byte mask = B10000000;
for( int iy = 0; iy < height; iy++ ){
for( int ix = 0; ix < width; ix++ ){
lmd.setPixel(x + ix, y + iy, (bool)(sprite[iy] & mask ));
// shift the mask by one pixel to the right
mask = mask >> 1;
}
// reset column mask
mask = B10000000;
}
}
実行しました。前回のLM35DZと同じです。何もしないでじっと観測していると、LM35DZは小数点第一位が動きます。TMP117は、小数点第二位が動きます。