sea side she side

写真と山、資格が好きなアラフォーエンジニアのブログ

Arduinoで温度計(LM35DZ) w/ オペアンプ(LMC662CN)

      2018/02/18

前回にも書きましたが、LM35DZは0℃で0V、1℃当たり10mVの出力が得られ、それを読み取るArduinoのアナログ入力最大電圧は5V、取得値は0~1023(1024段階)の数値として取得できます。

しかし1024段階ある変換能力は温度センサーが100℃で1Vまでしか出力しないため、204段階までしか利用できず、100 / 204 = 0.49℃刻みでしか計測できません。

もし1024段階全力で利用することができれば、100 / 1024 = 0.098℃ともう少し細かい値で計測することができるようになります。

ではどうすればよいかというと、100℃で1Vのところを100℃で5Vまで引き上げれば1024段階の数値で読み取ることができます。

この5Vに増幅させるのにオペアンプを利用します。

LM35DZ w/ LMC662CN

オペアンプ自体の仕組みや使い方については他を参考にしていただくとして、

G(増幅率) = 1 + (R1 / R2)
5V(出力電圧) = (1 + (R1 / R2)) × 1V(差動入力電圧)

より、

R1 : R2 = 4 : 1

となります。R0は差動入力のバランスが取れるようにR2と同じ値を使います。

/* 
  1秒ごとに摂氏温度を計測
  シリアルモニタに出力
  
  OPAmpで5倍に増幅しているので、
  5 * xV : v = A_val : 1024
  xV[V] = (((v * A_val) / 1024) / 5)
        = (v * A_val) / 5120
  LM35DZは10mVで1℃より1mV当たり0.1℃であり
  xV[V] = 1000 * xV[mV]であることを踏まえると
  ℃ = xV * 1000 / 10
     = xV * 100
     = (v * A_val * 1000) / 5120
*/

int    A_inPin    = 0;     // アナログ入力ピン番号
int    A_val;              // アナログ入力値(0〜1023)
float  v          = 5;     // 基準電圧値( V )
float  tempC      = 0;     // 摂氏値( ℃ )

void setup() {
  Serial.begin(9600);
}

void loop() {
  A_val = analogRead( A_inPin );
  tempC = (((v * A_val) / 1024) / 5) * 100;
  Serial.println( tempC );
  delay(1000);
}

実際にやってみるとわかりますが、値結構ふらつきます。毎秒計測し、10秒ごとの平均値を出力するようにします。また毎秒計測する=簡易な時計ともなりますので、日時の表示用ライブラリを読み込んで計測時間を表示させてみます。

DateTimeライブラリ
をArduino/library/フォルダ配下に入れます。

ただしこの時計、内部クロックを利用しているため月差(というより日差)が激しいです。あくまで目安ぐらいで。

/* 
  10秒ごとに平均摂氏、最大摂氏温度、最小摂氏温度を
  シリアルモニタに出力
  */

// DateTimeライブラリをインポート
#include <DateTime.h>

// プログラム開始日付時刻
int    year       = 2011;  // 年
int    month      = 5;     // 月
int    day        = 22;    // 日
int    hour       = 22;    // 時
int    minute     = 15;     // 分
int    second     = 0;     // 秒

int    A_inPin    = 0;     // アナログ入力ピン番号
int    A_val;              // アナログ入力値(0〜1023)
int    outputTerm = 10;    // 計測結果出力ターム
                          // (10秒ごとに平均摂氏値を出力する)
float  v          = 5;     // 基準電圧値( V )
float  tempC      = 0;     // 摂氏値( ℃ )
float  tempCPlus  = 0;     // 10秒ごとの合計摂氏値( ℃ )
float  maxTempC   = 0;     // 10秒ごとの最大摂氏( ℃ )
float  minTempC   = 0;     // 10秒ごとの最小摂氏( ℃ )

void setup() {
  // シリアル通信速度
  Serial.begin(9600);

  // DateTime ライブラリの makeTime() メソッドで日付時刻作成
  time_t prevtime = 
    DateTime.makeTime(second, minute, hour, day, month, year);
  // DateTime ライブラリの sync() メソッドで初期設定(日付時刻設定)
  DateTime.sync(prevtime);
}

void loop() {
  // 1秒に一回、10秒間分温度計測
  for (int i = 0; i < outputTerm; i++ ) {
    // アナログピンから計測値を取得(0〜1023)
    A_val = analogRead( A_inPin );
    // 摂氏に換算
    // tempC = (100 * A_val) / 1024;
    tempC = (((v * A_val) / 1024) / 5) * 100;
    // 現for文ループ内で使わなくなった変数は解放
    A_val = 0;
    // 平均値を取得するために1秒ごとの値を10秒分合計しておく
    tempCPlus += tempC;

    // 1秒過去の最大摂氏値と現在の摂氏値を比較
    // 大きい方を格納
    maxTempC = max( maxTempC, tempC );

    // 1秒過去の最小摂氏値と現在の摂氏値を比較
    // for文1ループ目のみ、現在の摂氏値を格納
    if (i == 0) minTempC = tempC;

    // 小さい方を格納
    minTempC = min( minTempC, tempC );

    // 現for文ループ内で使わなくなった変数は解放
    tempC = 0;

    // 1秒間ストップ
    delay(1000);
  }

  // 10秒間の平均摂氏値
  tempC = tempCPlus / outputTerm;

  // 日付時刻更新
  DateTime.available();

  // シリアルモニタに出力
  // 日付時刻
  Serial.print(DateTime.Year+1900,DEC);
  Serial.print("/");
  Serial.print(DateTime.Month,DEC);
  Serial.print("/");
  Serial.print(DateTime.Day,DEC);
  Serial.print(" ");
  Serial.print(DateTime.Hour,DEC);
  Serial.print(":");
  Serial.print(DateTime.Minute,DEC);
  Serial.print(":");
  Serial.print(DateTime.Second,DEC);

  // 10秒間の平均摂氏値
  Serial.print("  Temp / ");
  Serial.print( outputTerm );
  Serial.print("sec  |  Average : ");
  Serial.print( tempC );
  Serial.print(",  ");

  // 10秒ごとの最大摂氏値
  Serial.print("Max : ");
  Serial.print( maxTempC );
  Serial.print(",  ");

  // 10秒ごとの最小摂氏値
  Serial.print("Min : ");
  Serial.println( minTempC );

  // 次loop()ループの計測に影響を及ぼさないように変数の値を0に戻す
  tempCPlus = 0;
  maxTempC  = 0;
  minTempC  = 0;
}

参考: 偉大なる先人たち
建築農業工作ゼミ
projects : Biotope

 - Make , , , ,