わらべのごとく

ものづくり・物欲・興味あるものなどをツイッター+αぐらいのノリで

arduinoで温度計を作る

クルマの水温計でも作ろうと思って。
f:id:RyoNawa:20130929094531j:plain


マイコンはarduino UNO

【永久保証付き】Arduino Uno

【永久保証付き】Arduino Uno


温度センサはヨシムラのデジタルテンプメーター用を流用


表示は7セグディスプレイ
f:id:RyoNawa:20130929102846j:plainhttp://www.switch-science.com/catalog/1127/
を2つ使用。

水温と油温をそれぞれディスプレイしようという目論見。

現状、センサ1つしか入手してないので水温用、油温用の入力ピンを短絡してます。

とりあえず今は気温を表示。


//
//センサ2つの定数を別個に測定して精度を確保
//小数点の点滅は警告に応用できそう
//

#include <MsTimer2.h>

#include <Wire.h>

#define display1 0x72

#define display2 0x71  //i2cアドレス 0x72が1番 0x71が2番

long cycles = 0;  //intだと10分ちょいでオーバー風呂するからlong

boolean dispFlg = false;  //割り込んだ関数内でtrueにする。trueの時に一回だけdispに書き込み
boolean Blink = false;  //点滅用フラグ

int valueW[ 100 ];  //100個の成分を持つintの集合 loop内で宣言すると結果がおかしくなる
int valueO[ 100 ];

/////////////////////////////////////////////
const float T0 = 25 + 273.15;  //基準温度(セ氏→絶対温度)

const float R0Water = 48000; //基準温度での抵抗値  測って実測値を入れる
const float BconstWater = 4235;  //B定数
const float RdivWater = 3840;  //分圧抵抗の値

const float R0Oil = 47000; //基準温度での抵抗値
const float BconstOil = 4235;  //B定数
const float RdivOil = 3950;  //分圧抵抗の値

const int dispSpeed = 500;  //表示の更新頻度 ms単位
/////////////////////////////////////////////


void setup()
{
  Wire.begin();  //i2c通信

//  Serial.begin( 9600 );  //デバッグ用にいちおう

  MsTimer2::set( dispSpeed , warikomi );  //dispSpeed ms毎にwarikomiを実行
  MsTimer2::start();  //start
}


void loop()
{
  cycles++;
  int myCycles = cycles % 100;  //100で割った余り

  valueW[ myCycles ] = analogRead( A0 );  //サイクルごとに順番に値を格納
  valueO[ myCycles ] = analogRead( A1 );

  if( dispFlg == true )  //Flgが立った時のみ実行
  {
    dispFlg = false;  //falseに戻すのを忘れない。割り込みの意味が無くなる

    Blink = ! Blink;  //trueとfalseを交互に入れ替える
    
//    Serial.println();

    int Twater = calcTemp( valueW , R0Water , BconstWater , RdivWater );  //計算してもらう 結果の値は10倍されてintになってる
    int Toil   = calcTemp( valueO , R0Oil   , BconstOil   , RdivOil );
    
//    Serial.println();

    writeDisplay( Twater , display1 );  
    writeDisplay( Toil   , display2 );
  }

  delay( 10 );  //だいたい1000msごとに0に戻る
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


void warikomi()
{
  dispFlg = true;  //フラグをたてる
}


//センサ値の平均→センサの抵抗と分圧抵抗を割合に→計算→loopに結果を返す

int calcTemp( int value[ 100 ] , const float R0 , const float Bconst , const float Rdiv ) 
{  
  long Sum = 0;  //最初に0に戻すのを忘れない。前回の合計値にさらに足してしまう。

  for( int i = 0; i < 100; i++ )   //value[]の100個の値を全て足す
  {
    Sum = Sum + value[ i ];
  }
  
//0  Serial.println( Sum );
  
  float Vsense = (( float )Sum ) / 102400;  //0-1の割合に変換   
  float Rth = Rdiv * Vsense / ( 1 - Vsense );  //サーミスタの抵抗値 がんばって導出
  float Tth = 10 / ( log( Rth / R0 ) / Bconst + 1 / T0 ) - 2731.5 ;  //温度の値 がんばって導出 小数点のために10倍している

  return( Tth );  // CalcTemp の値は Tth 
}



//ディスプレイ出力用データ変換 10倍された値のまま表示&小数点をあと付け

void writeDisplay( int value , int Display )  
{
  int number = abs( value );  //abs()は絶対値 int専用
  int kilo = number / 1000;  //キロ 
  int hecto = ( number % 1000) / 100;  //ヘクト
  int deca = ( number % 100) / 10;  //デカ
  int one =   number % 10;  //one から

  if(kilo == 0){
    kilo = 0x10;//空白を表示
  } 

  if(kilo == 0x10 & hecto == 0){  //kが空白かつhが0ならば
    hecto = 0x10;  //100の位も空白
  }

  if (value < 0){
    kilo = 0x2d;//-を表示
  } 

  Wire.beginTransmission( Display ); // DisplayのアドレスにI2C送信
  
  Wire.write(0x76);  //clear display

  if( Blink == true )  //表示を更新するたびにつけたり消したり 邪魔なら消す 
  {
    Wire.write(0x77);  //小数点のコマンド
    Wire.write(0x04);  //2桁目に小数点
  }

  Wire.write(kilo); //左から順番に
  Wire.write(hecto);
  Wire.write(deca);
  Wire.write(one);
  
  Wire.endTransmission(); //Stop I2C transmission

}


センサ読み取り値を約100回分平均して温度計算に使用。
MsTimer2は本家arduinoのHPからライブラリをダウンロードしとかないと使えない。

回路図の書き方とかプログラミングのお作法とかこれから勉強しつつぼちぼちアップデートしてそのうち車載しましょう。
がんばるぞ。