2014年9月19日金曜日

arduinoを使った温度測定webサーバ


きっかけ

震災以来,会社で「節電要求」が厳しく,エアコンもぎりぎりまで絞られてしまい,会社の実験室が暑いため,管理部門に文句を言おうと思い,温度を自動で図る手段をarduinoで作ってみた.

実現した機能

LM35DZという温度センサーを用いて,0℃~100℃の温度をシリアルモニターに摂氏で表示させるのと,httpでのアクセスで測定結果を摂氏で答える機能を入れてみた.ついでに,設定値以上に温度がなった場合は,基板上のLEDがつきっぱなしになるようにもなっている.

参考URL

以下のようなwebの情報をみて作った.

  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

  pingのライブラリの情報


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

使ったハードウェア


Arduino Ethernet R3

あちこちで売っているけど,千石電商の店頭で買ったので,リンクも千石のものARDUINO-A000068

スイッチサイエンスのUSBシリアルボード

電源供給とPCとのシリアル接続を兼ねてUSBインターフェースを追加.
FTDI USBシリアル変換アダプター(5V/3.3V切り替え機能付き)

高精度IC温度センサ

これもあちこちで売っていると思うけどけど,秋月電子で買ったので,リンクも秋月のものLM35DZ

その他のパーツ(LEDなど)

他の部品は以前千石で買ったarduinoの初心者向けのパーツだけをまとめた部品キットのものを流用.ただし,キットのURLは見当たらない.

回路

arduinoでは皆がEagle CADを使っているみたいなので,それで書いた回路図からイメージファイルに変換したものを張っておきます.



Eagle CADの回路図

写真もつけておきますが,USBインターフェースは外したものになってます.


ソース

ソースコード(TemperatureWebServer.ino)は以下のようになってます.ソースが見づらいのは,また後で直します.



/*
  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
  pingのライブラリ
  http://playground.arduino.cc/Code/ICMPPing
*/

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

#include <SPI.h>
#include <Ethernet.h>
#ifdef USE_PING
#include <ICMPPing.h>
#endif /* USE_PING */

/*
 * 配線関連の定数
 */
int TempSensorPin = 0;  // センサ用のアナログI/Fは0番を利用
boolean useLED = true;  // インジケーター用LEDを用いる場合は true
/* 以下の定義は,インジケーター用のLEDを使わない場合は適当な整数で良い */
int RedPin=8;           // 赤色は8番ピン
int GreenPin=9;         // 緑色は9番ピン

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

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

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


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

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

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

void setup()
{
  if (debugFlag) {
    // シリアル通信速度
    Serial.begin(9600);
  }
  if (useLED) {
    // LED用のピンの設定
    pinMode(RedPin,OUTPUT);
    pinMode(GreenPin,OUTPUT);
    // LEDで起動がわかるよう,短時間点灯する
    digitalWrite(RedPin,HIGH);
    digitalWrite(GreenPin,HIGH);
    delay(300);
    digitalWrite(RedPin,LOW);
    delay(300);
    digitalWrite(GreenPin,LOW);
  }
  // MACアドレスとIPアドレスの設定
  // 参考URL http://arduino.cc/en/Reference/EthernetBegin
  if (useDhcp) {
    if ((Ethernet.begin(mac)==0) && (debugFlag)) {
      Serial.println(\"Failed to configure Ethernet using DHCP\");
    }
  } else {
    Ethernet.begin(mac, ip, dnsServer, gatewayAddress, netMask);
#ifdef USE_PING
    // ルータのアドレスにping
    // 参考URL http://playground.arduino.cc/Code/ICMPPing
    Serial.println(\"Manual ip confuguration of ethernet\");
    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());
  }
  if (debugFlag) {
    // 温度センサの温度取得テスト
    Serial.println(\"testing temperature sensor : start\");
    float temperature = getTemperature(TempSensorPin,false);
    Serial.println(\"testing temperature sensor : done\");
  }
  // サーバの実行
  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();
          
          // 温度読み取り  
          float temperature = getTemperature(TempSensorPin,useLED);
        
          client.print(\"Temperature: \");
          client.print(temperature);
          client.print(\" degrees Celsius\");
          client.println(\"<br />\");
          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();
  }
}

//
// 温度読み取り関数
//
float getTemperature(int pin,int ledFlag){
  float tmp;
  if (ledFlag) {
    digitalWrite(GreenPin,HIGH);
    delay(500);
  }
  tmp = analogRead( pin );
  tmp = ((v * tmp) / 1024) * 100;
  tmp = tmp + offset;
  if (debugFlag) {
    // 温度のシリアルへの出力
    Serial.println(\"temperature is\");
    Serial.println(tmp);
  }
  if (useLED) {
    digitalWrite(GreenPin,LOW);
    if (tmp > Threshold ) {
      digitalWrite(RedPin,HIGH);
    } else {
      digitalWrite(RedPin,LOW);
    }
  }
  return tmp;
}

0 件のコメント: