初めてのArduino ⑦ UNOボードで温度を測る(その2 TMP117)

 前回、アナログ出力の温度センサLM35DZを使いました。確度±0.5℃です。温度センサを利用するとき、確度が高いことが望まれる利用例は多いでしょう。確度±0.05℃のLMT70があります。

  温度センサ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されていると思われます。

#include <Wire.h> 
#define TMP117address 0x48
#define TemperatureRegister 0x00
#define ConfigurationRegister 0x01
 
 これらは前回から利用している変数です。
 
int16_t sensorValue;
float analogSensorData;
 
 setup()内で、
 
Wire.begin();
 
 I2Cライブラリを初期化します。バスの転送スピードはデフォルトで100kHzです。
 温度の読み取りは、read_tempdata() 関数にしました。
 
  Wire.beginTransmission(TMP117address); 
    Wire.write((uint8_t)TemperatureRegister);
  Wire.endTransmission();
  Wire.requestFrom(TMP117address, 2);
 
 TMP117のスレーブ・アドレス0x48を送り、つづいてTemperatureRegisterの0x00を送ります。
 続いて、デバイスTMP117から2バイトのデータを読みます。バッファにデータは入ります。
 
  while(Wire.available() == 0);
 
 バッファに入りました。バッファには8ビットのデータが二つ入っています。16ビットの変数Tに読み込みます。
 
  uint16_t T = Wire.read();
 

 最初に読み込んだ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

 もう1バイトのデータをバッファから読み出してきて、論理orをとります。
 
T = T << 8 | Wire.read() ; 
 

 読み出した値が0x01であれば、中身は次のような16ビット・データになっています。

1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1

 この16ビット・データは2の補数形式です。つまり、一番上のビットMSBは符号です。
 
温度[℃] 温度読み出しレジスタ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


-(T & 0b1000000000000000) | (T & 0b0111111111111111) ) * 7.8125 /1000.0
 
 符号付き数値に変換します。その値に0.0078125をかけて、摂氏の温度に変換します。

 
 メインのスケッチです。
 

#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;
}

 foint.inoです。

/**
 * 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は、小数点第二位が動きます。

前へ

初めてのArduino ⑥ UNOボードで温度を測る(その1 LM35DZ)

次へ

初めてのArduino ⑧ UNOボードで温度を測る(その3 白金測温抵抗体 MAX31865)