2015年5月4日月曜日

Arduinoを利用した温度・湿度測定webサーバ(暫定版)


以前の投稿「arduinoを使った温度測定webサーバ」とか「arduinoの気温測定で問題発生」でArduinoを使って,室温を図るwebサーバの作成について書いてきましたが,一冬過ぎて,そろそろオフィスの室温が上がり始めたこと,湿度に関する意見も部署内であることから,湿度センサを増設し,ケースに入れたバージョンを作成しました.


各種参考URL

まずは,参考URLの類.わからないことがあった場合,他の記事と比較したい場合のスタートポイントにしてください.

httpサーバおよび,温度センサ関連


  • http://openhardware.gridshield.net/home/arduino-snmp-temperature-sensor
  • http://d.hatena.ne.jp/a10i/20110607/1307453448
  • http://homepage3.nifty.com/sudamiyako/zk/AVR_ADC/AVR_ADC.html
  • http://makining.com/okuzawats/dht11-temperature-humidity-20150218
  • https://learn.adafruit.com/dht/connecting-to-a-dhtxx-sensor
  • http://mpu.seesaa.net/category/22909809-2.html
  • http://blog.livedoor.jp/hardyboy/tag/LM35DZ
  • http://makining.com/okuzawats/dht11-temperature-humidity-20150218
  • http://qiita.com/masato/items/99e5dac91d13650e90a2


pingのライブラリ


  • http://playground.arduino.cc/Code/ICMPPing

DHTセンサのライブラリ


  • https://github.com/adafruit/DHT-sensor-library

使った部品

リンクは製品販売元じゃなくて,私が買った店や有名代理店の場合もあります.
抵抗は,買った時の情報が無いので,ワット数は違っているかも.コンデンサは転がっていたやつを使ったので,同一容量の製品のwebページです.

ハードウェア

一応,Fritzingの図面も添付しますが,ユニバーサル基板の配線は,Fritzingの練習不足のため,ご勘弁ください.

回路図





現物写真


手元に適当なサイズのユニバーサル基板がなかったので,微妙に大きい.

  • 表側



  • 裏側




ソフトウェア


とりあえず,ソースもここに置いときます.

実装上の工夫

LM35DZの温度を読むと,非常にふらつく上に,時々とんでもない値が出てくるため以下の工夫を入れた.

  • 100回読む
  • ソートする
  • 統計的な中央値を選んでそれを結果とする

現在の問題

わかっている問題は以下の2点

  • 精度
    温度や湿度の校正はしていない(そんな設備がない)ので精度は不明.
  • DHT11とLM35の出力の違い
    DHT11の測定値とLM35の測定値が約2度程度異なり,DHTが常に高い温度を返す.


ソースコード


/*
  LM35DZを用いた温度測定(0℃~100℃)
  シリアルモニターに摂氏で表示させるのと,httpでのアクセスで答える
  参考URL
  httpサーバおよび,温度センサ関連
  http://openhardware.gridshield.net/home/arduino-snmp-temperature-sensor
  http://d.hatena.ne.jp/a10i/20110607/1307453448
  http://homepage3.nifty.com/sudamiyako/zk/AVR_ADC/AVR_ADC.html
  http://makining.com/okuzawats/dht11-temperature-humidity-20150218
  https://learn.adafruit.com/dht/connecting-to-a-dhtxx-sensor
  http://mpu.seesaa.net/category/22909809-2.html
  http://blog.livedoor.jp/hardyboy/tag/LM35DZ
  http://makining.com/okuzawats/dht11-temperature-humidity-20150218
  http://qiita.com/masato/items/99e5dac91d13650e90a2
  pingのライブラリ
  http://playground.arduino.cc/Code/ICMPPing
  DHTセンサのライブラリ
  https://github.com/adafruit/DHT-sensor-library
*/


/* 固定IP設定の時に,pingで設定を確認する機能を有効にする場合に定義する */
#define USE_PING

/* ネットワーク関係のインクルード */
#include 
//#include 
//#include 
#include 
//#include 
//#include 
//#include 
#ifdef USE_PING
#include 
#endif /* USE_PING */

/* DHTセンサ関係のインクルード */
#include "DHT.h"

/*
 * DHT11関係の定義
 */
#define DHTPIN 2     // what pin we're connected to

// Uncomment whatever type you're using!
#define DHTTYPE DHT11   // DHT 11 
//#define DHTTYPE DHT22   // DHT 22  (AM2302)
//#define DHTTYPE DHT21   // DHT 21 (AM2301)

// Connect pin 1 (on the left) of the sensor to +5V
// NOTE: If using a board with 3.3V logic like an Arduino Due connect pin 1
// to 3.3V instead of 5V!
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor

// Initialize DHT sensor for normal 16mhz Arduino
DHT dht(DHTPIN, DHTTYPE);
// NOTE: For working with a faster chip, like an Arduino Due or Teensy, you
// might need to increase the threshold for cycle counts considered a 1 or 0.
// You can do this by passing a 3rd parameter for this threshold.  It's a bit
// of fiddling to find the right value, but in general the faster the CPU the
// higher the value.  The default for a 16mhz AVR is a value of 6.  For an
// Arduino Due that runs at 84mhz a value of 30 works.
// Example to initialize DHT sensor for Arduino Due:
//DHT dht(DHTPIN, DHTTYPE, 30);

/*
 * LM35(温度センサ)関連の定数の定義
 */
float v=5.0;            // MEGA2560やEthernet R3は5.0V駆動
float tempC   = 0;      // 摂氏値( ℃ )
float Threshold=28.0;   // 警告LEDをつける閾値(気温)
float offset = 0;       // センサの温度ズレを修正する変数

#define LOOPNUMBER 100
#define MEDIAN 50

/*
 * 配線関連の定数
 */
int TempSensorPin = 0;  // センサ用のアナログI/Fは0番を利用

/*
 * ネットワーク関係の定数
 */
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0F, 0x92, 0x1A }; //アドレスは手持ちのarduinoのものに変更すること
boolean useDhcp = false; // DHCPで運用する場合は true に変更
                   // DHCPでのアドレス取得失敗時の対策や,長時間経過後のアドレス再割当て等は対応していない
/* 以下は固定IP運用の場合の変数なので適宜変更して使用すること */
IPAddress ip(192,168,0,201);
IPAddress dnsServer(192,168,0,1);
IPAddress gatewayAddress(192,168,0,1);
IPAddress netMask(255,255,255,0);

#ifdef USE_PING
SOCKET pingSocket = 0;
char buffer [256];
#endif /* USE_PING */



/*
 * デバッグ関連
 */
boolean debugFlag=false; // デバッグ目的で,各種情報をシリアルに出力する場合は true

/*
 * プログラム本体
 */

#ifdef USE_PING
ICMPPing ping(pingSocket, (uint16_t)random(0, 255));
#endif /* USE_PING */

EthernetServer server(80); // サーバオブジェクトの定義. 引数はポート番号

void setup() {    
  if (debugFlag) {
    // シリアル通信速度
    Serial.begin(9600);
  }
  // DHT11センサの初期化
  dht.begin();
    // MACアドレスとIPアドレスの設定
  // 参考URL http://arduino.cc/en/Reference/EthernetBegin
  if (useDhcp) {
    Serial.println("configure Ethernet using DHCP");
    if ((Ethernet.begin(mac)==0) && (debugFlag)) {
      Serial.println("Failed.");
    } else {
      Serial.println("Success.");
    }
  } else {
    Serial.println("Manual ip confuguration of ethernet");
    Ethernet.begin(mac, ip, dnsServer, gatewayAddress, netMask);
    Serial.println("done.");
#ifdef USE_PING
    // ルータのアドレスにping
    // 参考URL http://playground.arduino.cc/Code/ICMPPing
    ICMPEchoReply echoReply = ping(gatewayAddress, 4);
    if (debugFlag) {
      if (echoReply.status == SUCCESS) {
        Serial.println("Ping to Gateway address : success");
      } else {
        Serial.println("Ping to Gateway address : fail");
      }
    }
#endif /* USE_PING */
  }
  if (debugFlag) {
    // IPアドレスのシリアルへの出力
    Serial.println("IP address of Ethernet Interface");
    Serial.println(Ethernet.localIP());
    //
    float temperature = getLMTemperature(TempSensorPin);
    float h = getDHTHumidity();
    float t = getDHTCTemperature();
    float f = getDHTFTemperature();
  }
  // サーバの実行
  server.begin();
}

void loop() {
  // 接続してきたクライアントを示すオブジェクトを生成
  EthernetClient client = server.available();
  if (client) {
    if (debugFlag) {
      Serial.println("Connection established by a client");
    }
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read(); //一文字読み取り
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println("Refresh: 5");  // refresh the page automatically every 5 sec
          client.println();
          client.println("");
          client.println("");
          // LM35温度読み取り  
          float temperature = getLMTemperature(TempSensorPin);
          client.println("LM35 output");
          client.println("
");
          client.print("Temperature:  ");
          //client.print(temperature);
          //client.println("  degrees Celsius");
          //client.println("
");
          float temperatureEX = getLMTemperatureEX(TempSensorPin);
          //client.print("Fixed Temperature:  ");
          client.print(temperatureEX);
          client.println("  degrees Celsius");
          client.println("
");
          client.println("
");
          //
          // DHT11の温度湿度
          float h = getDHTHumidity();
          // Read temperature as Celsius
          float t = getDHTCTemperature();
          // Read temperature as Fahrenheit
          float f = getDHTFTemperature();
          float hi = dht.computeHeatIndex(f, h);
          // Check if any reads failed and exit early (to try again).
          if (isnan(h) || isnan(t) || isnan(f)) {
            if (debugFlag) {
              Serial.println("Failed to read from DHT sensor!");
            }
            client.println("Failed to read from DHT sensor!");
            client.println("
");
          } else {
            client.println("DHT11 output");
            client.println("
");
            client.print("Temperature: ");
            client.print(t);
            client.println(" degree Celsius");
            client.println("
");
            /*
            client.print(f);
            client.println(" degree Fahrenheit");
            client.println("
");
            */
            client.print("Humidity:  ");
            client.print(h);
            client.println("  \%");
            client.println("
");
            /*
            client.print("Heat index: ");
            client.print(hi);
            client.println(" degree Fahrenheit");
            client.println("
");
            */
            if (debugFlag) {
              Serial.println("Heat index: ");
              Serial.println(hi);
            }
          }
          //
          //
          client.println("");
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } 
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
    if (debugFlag) {
      Serial.println("client disconnected");
    }
  }
}

//
// DHT11の温度と湿度読み取り関数
float getDHTCTemperature(){
  float t = dht.readTemperature();
  if (debugFlag) {
    // 温度のシリアルへの出力
    Serial.println("DHT11 celcious temperature is");
    Serial.println(t);
  }
  return t;
}
float getDHTFTemperature(){
  float t = dht.readTemperature(true);
  if (debugFlag) {
    // 温度のシリアルへの出力
    Serial.println("DHT11 Faren temperature is");
    Serial.println(t);
  }
  return t;
}
float getDHTHumidity(){
  float h = dht.readHumidity();
  if (debugFlag) {
    // 湿度のシリアルへの出力
    Serial.println("DHT11 Humidity is");
    Serial.println(h);
  }
  return h;
}

//
// LM35の温度読み取り関数
//
float getLMTemperature(int pin){
  float t;
  t = analogRead( pin );
  t = ((v * t) / 1024) * 100;
  t = t + offset;
  if (debugFlag) {
    // 温度のシリアルへの出力
    Serial.println("temperature is");
    Serial.println(t);
  }
  return t;
}

float getLMTemperatureEX(int pin){
  int buff[LOOPNUMBER];
  float tmp;
  if (debugFlag){
    Serial.print("Data = ");
  }
  for (int i=0 ; i < LOOPNUMBER ; i++){
    buff[i] = analogRead( pin );
    if (debugFlag) {
      Serial.print(buff[i]);
      Serial.print(" , ");
    }
  }
  if (debugFlag) {
    Serial.println("");
  }
  sort(buff,LOOPNUMBER);
  if (debugFlag){
    Serial.print("SortData = ");
    for (int i=0 ; i < LOOPNUMBER ; i++){
      if (debugFlag) {
        Serial.print(buff[i]);
        Serial.print(" , ");
      }
    }
  }
  tmp = ((v * buff[MEDIAN]) / 1023) * 100;
  tmp = tmp + offset;
  if (debugFlag) {
    // 温度のシリアルへの出力
    Serial.println("temperature is");
    Serial.println(tmp);
    Serial.println("Pin number = ");
    Serial.println(pin);
  }
  return tmp;
}
void sort(int a[], int size) {
    for(int i=0; i<(size-1); i++) {
        for(int o=0; o<(size-(i+1)); o++) {
                if(a[o] > a[o+1]) {
                    int t = a[o];
                    a[o] = a[o+1];
                    a[o+1] = t;
                }
        }
    }
}

0 件のコメント: