2010年3月22日月曜日

ベランダ菜園

暖かくなってきました。

以前からちょっと興味のあった農業ですが、まず土地が必要ということで市民農園の申し込みをしてみました。抽選結果はあいにく落選…。
やむをえなく、ベランダにプランターを設置することにします。一人暮らしにしてはちょっと縦長のベランダのアパートを借りているので、大きめのプランターをとりあえず三つ設置します。

成分
『おいしくとれる野菜の土』
『腐植土』
『鹿沼土』
『鶏糞』
『配合飼料』

上記のものは、すべて近所のホームセンターで手に入ります。


成分図

各プランターごとに
  1. 鹿沼土を2cmほど入れる。
  2. 腐植土2 : おいしくとれる野菜の土8の割合で混ぜ合わせた土を少し入れる。
  3. 鶏糞を二にぎり、配合肥料を一にぎり撒く。
  4. 腐植土2 : おいしくとれる野菜の土8の割合で混ぜ合わせた土をプランターのふちまで入れる。
  5. 散水する。

このまま一週間、土を寝かせておきます。
肥料は上部に撒くと成分の濃度が高すぎ、また根に楽をさせ過ぎてしまうので、土の下部に入れます。
人間でいうと寝転がったまま食べ物が勝手にでてくるようなもので、楽をさせすぎるとろくな人に成長しません。


基本的な指針
  • コンパニオンプランツの考え方に沿って農作物を作ってゆく
  • Arduinoで環境データを取得し、できるだけ楽をして菜園管理する

土地を買う金もなく、時間もない…そのような都市に住む一人暮らしの人間が、どれだけ自分自身で作ったものを口にすることができるのでしょうか。
農業経験はほとんどありませんが、とりあえず興味本位に始めてみたいと思います。

2010年2月25日木曜日

Arduinoで計測した値を指定のwebサーバに送信、保存する

この投稿は、建築発明工作ゼミ2008を参考に、建築発明工作ゼミ2009 『Arduinoで計測した値を指定のwebサーバに送信、保存する』を新しく書き直したものです。
この投稿内容については、上記ブログ管理人のkousakuさんの許可を得ております。

上にのっているのが Ethernet Shield、下にあるのがArduino Duemilanove 328


ArduinoとEthernet Shieldを使用し、計測した温度を指定のwebサーバ上のファイルに記録してみます。
Ethernet Shieldは、Arduinoをネットに接続してデータの送受信を行えるようにするシールドで、上の写真のようにArduinoに装着します。
データのログをとっていく時、通常はPCに常時接続してPCにデータを記録して行きますが、今回はArduinoをスタンドアロンで動かすので常時接続しなくてもよくなります。
この方法の利点は、ネット接続できる環境ならばどこでも取得したデータをほぼリアルタイムで確認できることでしょう。

基本的な流れです。
  1. まずここでやっている回路で温度を計測
  2. ルータに接続したEthernet Shield から、ArduinoのEthernetライブラリを使って指定のサーバにデータを送信
  3. 指定のwebサーバに設置したスクリプトで温度値を受け取り、ファイルに書き込む

回路図


Ethernetライブラリを使用する場合の基本的な入力情報として、
  1. MACアドレス
  2. サーバのIPアドレス
  3. ポート番号
が必要となります。
各値の調べ方はこちらに詳しく明記されています。

加えて、データを保存するwebサーバのIPアドレスが必要です。
それにwebサーバ側で値を受け取ってデータ保存するスクリプトを書く必要があります。
これらは、サーバサイド言語であるPHPを使って実装します。
PHPはサーバ側で動作する言語ですから、データを保存するwebサーバに設置します。

webサーバのディレクトリ構成

http://www.○○○.net/
        + projectsbiotope
        |       + ip.php
        |       + temp_log.php
        + public_data
                + projectsbiotope
                        + text
                                + temp_log.txt


webサーバは私が契約している Yahoo Geocities を使います。
まず、ドキュメントルート直下に、任意のディレクトリを設置します(今回は 'projectsbiotope' という名前にします)。

http://www.○○○.net/projectsbiotope

そして、projectsbiotopeディレクトリ直下に以下のスクリプトを設置します。

データ保存するwebサーバのIPアドレス表示PHPスクリプト(ip.php)

<?php
    $ipAddress = gethostbyname($_SERVER['SERVER_NAME']);
    print $ipAddress;
?>


ブラウザのURL欄に

http://www.○○○.net/projectsbiotope/ip.php

と打ち込めば、IPアドレスがわかります。

Arduinoのスケッチ

/*
  1秒に一回温度を計測し、
  10秒ごとの平均値を取得
  30秒ごとに指定のwebサーバに送信
*/

// Ethernetライブラリ
#include <Ethernet.h>

/* 基本設定 */

// サーバのポート番号を定義
#define PORT 80

// 温度計測のターム(1秒ごとに計測する)
#define MEASURE_TERM 1

// 計測結果出力ターム(10秒ごとに平均摂氏値を出力する)
#define OUTPUT_TERM 10

// 送信のターム(30秒ごとに送信する)
#define LOG_TERM 30

// Ethernet Shild MACアドレス
byte mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

// Ethernet Shild IPアドレス
byte ip[] = { 10 , 0 , 0 , 177 };

// 接続先のIPアドレス
byte server[] = { 000 , 00 , 00 , 000 };

// アナログ入力ピン番号
int A_inPin = 0;

// アナログ入力値(0~1023)
int A_val;

// 摂氏値( ℃ )
float tempC = 0;

// 10秒ごとの合計摂氏値( ℃ )
float tempCPlus = 0;

// 10秒ごとの最大摂氏( ℃ )
float maxTempC = 0;

// 10秒ごとの最小摂氏( ℃ )
float minTempC = 0;

// 指定したIPアドレスとポートに接続するクライアントを生成
Client client = Client(server, PORT);

void setup()
{
    // Ethernetライブラリとネットワーク設定を初期化
    Ethernet.begin(mac, ip);

    delay(1000);
}

void loop()
{
    // 1秒に一回、10秒間分温度計測
    for (int i = 0; i < OUTPUT_TERM; i++) {

        // アナログピンから計測値を取得(0~1023)
        A_val = analogRead( A_inPin );

        // 摂氏に換算
        tempC = (100 * A_val) / 1024;

        // 平均値を取得するために1秒ごとの値を10秒分合計しておく
        tempCPlus += tempC;

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

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

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

    // 指定したwebサーバへの接続開始
    // 成功
    if (client.connect()) {

        // 指定のwebサーバのPHPスクリプトにGET送信
        // 'temp'という名前で計測した温度値を送信
        client.write("GET /projectsbiotope/temp_log.php?temp=");
        client.print(tempC, DEC);
        client.write(" HTTP/1.1\n");
        client.write("HOST: www.○○○.net\n\n");
    
    } else {
        
        // 接続終了
        client.stop();
    }

    // 現loop()ループ内で使わなくなった変数は解放
    tempCPlus = 0;
    tempC = 0;

    // 20秒停止
    delay((LOG_TERM - OUTPUT_TERM) * 1000);
}



// 指定のwebサーバのPHPスクリプトにGET送信
// 'temp'という名前で計測した温度値を送信
client.write("GET /projectsbiotope/temp_log.php?temp=");
client.print(tempC, DEC);
client.write(" HTTP/1.1\n");
client.write("HOST: www.○○○.net\n\n");

の箇所がwebサーバに温度値を送信している記述です。
上記は4列になっていますが、つなげると以下のような文字列を送信していることになります。

GET /projectsbiotope/temp_log.php?temp=○○○(温度値) HTTP/1.1 HOST: www.○○○.net

これは、

http://www.○○○.net/projectsbiotope/temp_log.php

のスクリプトに 'temp' という名前の温度値を送っているということです。
正式には以下のようなリクエストをサーバに投げています。

http://www.○○○.net/projectsbiotope/temp_log.php?temp=○○○(温度値)

注意しなければならないのは、write()メソッドは byte型か char型のデータしか正しく送信しないので、int型の変数値を送信するときは print()メソッドを使うことです。
URLの○○○の箇所に不正な値を書き込まれるとロギングされる値もおかしくなるために、値のチェックもします。
かりに温度値だけではなくて湿度など他の値も送りたいときは、

temp_log.php?temp=○○○(温度値)&humidity=△△△(湿度値)&uv=□□□(紫外線値)

のように、&(アンド)でつなげてゆけばいいのです。


PHPスクリプト(temp_log.php)

<?php

/*** 設定 ***/

    // データ保存ファイルの相対パス
    define('TEMP_FILE_PATH', '../public_data/projectsbiotope/text/temp_log.txt');

    // 限度値下限(0℃まで)
    define('TEMP_LIMIT_MIN', 0);

    // 限度値上限(100℃まで)
    define('TEMP_LIMIT_MAX', 100);

    // 日時情報(YYYY/MM/DD HH:ii:ss形式)
    $strDate = date("Y/m/d H:i:s");

    // 書き込む文字列
    $strLog = '';



/*** 値チェック ***/

    // 'temp'という名前の変数に格納された値を受け取る
    $strTempVal = $_GET['temp'];

    // 条件
    // 一桁の数字もしくは一桁以上の数字から始まって0~1個のドットを含み一桁以上の数字
    // かつ0以上100以下の値のみOK
    if (preg_match("/^\d$|^\d+\.?\d+$/", $strTempVal)
     && $strTempVal >= TEMP_LIMIT_MIN
     && $strTempVal <= TEMP_LIMIT_MAX
    ) {
        // 値をフォーマット(小数点以下の数値を1桁まで切り詰める)
        $strTempVal = number_format($strTempVal, 1);
        
    // 不正な値の場合、0を格納
    } else {
        $strTempVal = 0;
    }



/*** 値を書き込み ***/

    // 書き込み形式
    // 日時情報(YYYY/MM/DD HH:ii:ss) + 温度値(00.0℃) + 改行コード
    $strLog = $strDate . ' | ' . $strTempVal . "℃\n";

    // データを保存するテキストファイルを追記モードでオープン
    $fp = fopen(TEMP_FILE_PATH, "a");

    // ファイルを排他ロック
    flock($fp, LOCK_EX);

    // 送信された値をテキストファイルに書き込み
    fwrite($fp, $strLog);

    // ロックを開放
    flock($fp, LOCK_UN);

    // ファイルポインタをクローズ
    fclose($fp);
?>


セキュリティに配慮して送信される値のチェックを行っています。
データ保存する temp_log.txt は、なければ自動的に作成されます。

上記の準備がすべて終わったら、スケッチをArduino にアップロードしてみてください。

http://www.○○○.net/public_data/projectsbiotope/text/temp_log.txt

に、以下の形式でデータが保存され続けるはずです。

2010/03/01 01:19:32 | 18.0℃
2010/03/01 01:20:33 | 18.0℃
2010/03/01 01:21:32 | 19.5℃
2010/03/01 01:22:33 | 18.0℃
2010/03/01 01:23:33 | 18.0℃
2010/03/01 01:24:33 | 17.0℃
2010/03/01 01:25:33 | 17.7℃
...





2010年2月23日火曜日

mp3データをブログ上で再生する


mp3データをブログ上で再生させる方法。
ものすごく簡単にできてしまいますが、著作権に注意するべし。
引用する場合は、きちんと引用元を明記しましょう。

まず、目的のmp3ファイルを任意のwebサーバにアップします。

例)私の場合 Yahoo Geocities をやっているので、そこにmp3データをアップしたいと思います。
まず、ドキュメントルート直下に "data" というディレクトリを作成します。

http://www.○○○.net/data

そして、この "data" ディレクトリ内に "test.mp3" をアップします。

http://www.○○○.net/data/test.mp3

この時、mp3ファイルを設置する場所は、セキュリティがかかっていないディレクトリに置かなくてはなりません。
(上記のURLをたたくと直接mp3データにアクセスできてしまうので、URLの公開はしません。)
例えば、Yahoo Geocities では、ドキュメントルート直下に "geo_cgi_private" というディレクトリを作成するとセキュリティがかかり、
geo_cgi_privateディレクトリ以下に設置したファイルにはアクセスできません。
ですので、このようなディレクトリ内にmp3ファイルを置いてしまうと音楽が再生されません。

次に、以下のスクリプトをブログに貼り付けます。

<embed
    allowscriptaccess="never"
    bgcolor="#ffffff"
    flashvars="playerMode=embedded"
    height="27"
    quality="best"
    src="http://www.google.com/reader/ui/3247397568-audio-player.swf?audioUrl=○○○"
    type="application/x-shockwave-flash"
    width="400"
    wmode="window">
</embed>


「○○○」の個所に、上記のmp3ファイルへの絶対パスを記述します。
こんな感じになります。

<embed
    allowscriptaccess="never"
    bgcolor="#ffffff"
    flashvars="playerMode=embedded"
    height="27"
    quality="best"
    src="http://www.google.com/reader/ui/3247397568-audio-player.swf?audioUrl=http://www.○○○.net/data/test.mp3"
    type="application/x-shockwave-flash"
    width="400"
    wmode="window">
</embed>


これで、ブログでmp3データが公開できます。




高木正勝タイ・レイ・タイ・リオ【文庫本付き】 / Tai Rei Tei Rio』

2010年2月21日日曜日

Arduinoで湿度・温度を計測する SHT-71使用

この投稿は、建築発明工作ゼミ2009 『温・湿度センサ SHT-71』をもとに、新しく書き直したものです。

図1 温度・湿度センサ SHT-71 データシート

SHTシリーズのセンサをArduinoに接続し、温度と湿度を両方計測してみます。

センサはSHT-71を使いました。SHTシリーズではSHT-11が有名なのですが、小型の基盤にセットしなければ使いづらそうなので、ちょっと値段は高くなりますが4本のピンが並んでいるこちらを使う事にします。
センサとしての性能は全く同じですが、SHT-11とはピンの配置が異なるので注意が必要です。

このセンサの利点はまずその小ささです。センサ部分が4mm×5mmしかありません。
あと、Arduinoへの入力はデジタルインピンを使うので貴重なアナログインピンを節約できます。この小ささで正確な温度と湿度が計測できます。

まずここからライブラリをダウンロードします。 解凍後、「sht1x」というフォルダを以下に設置します。

(Macの場合)
○○○(ユーザディレクトリ)/書類/Arduino/library/

これでライブラリのインストールは完了です。


回路図
VDDからプルアップ抵抗をSCKとDATAに挟まないと正しく計測できません。
SHT-11センサは、参考リンク先のエレキジャックさんがとても詳しく書かれているので、大変参考になります。
SCKピンとDATAピンを差し込む箇所はデジタル2ピン、デジタルD3ピンと決まっているらしいです。
ダウンロードしたライブラリの sht1x_hw.h というファイルのline 26,27 に以下のような記述があります。

# define SHT1X_CLOCK_LINE PD2
# define SHT1X_DATA_LINE PD3

Arduino Duemilanove 168(Atmega168)の場合、'PD2'と'PD3'という定数は読み込まないらしいので、
これを適当なエディタで開き、以下のように書き換えて保存します。

# define SHT1X_CLOCK_LINE PORTD2
# define SHT1X_DATA_LINE PORTD3

これで、Arduino (Atmega328)以降でも読み込むようになります。
ちなみにArduino MEGAの場合、

SCKピン -> デジタル19ピン
DATAピン -> デジタル18ピン

に指す必要があります。

Board sht1x_hw.h line 26,27の記述 ピン番号
Arduino Duemilanove 168 # define SHT1X_CLOCK_LINE PD2
# define SHT1X_DATA_LINE PD3
SCK -> デジタル2ピン
DATA -> デジタル3ピン
Arduino Duemilanove 328 # define SHT1X_CLOCK_LINE PORTD2
# define SHT1X_DATA_LINE PORTD3
SCK -> デジタル2ピン
DATA -> デジタル3ピン
Arduino MEGA # define SHT1X_CLOCK_LINE PORTD2
# define SHT1X_DATA_LINE PORTD3
SCK -> デジタル19ピン
DATA -> デジタル18ピン


SHT-71センサを導線にハンダ付けし、防水用にエキポシ樹脂で固めます。


スケッチ
#include <sht1x.h>
#include <sht1x_hw.h>

void setup()
{
  int timeout = 0;

  Serial.begin(9600);
  delay(11);
  sht1x_init();

  if (sht1x_read_humidity() < 0) {
    Serial.println("soft reset");
    sht1x_reset();
  }
}

void loop()
{
  unsigned int h = sht1x_read_humidity();
  unsigned int t = sht1x_read_temp();

  while (millis() % 1000);

  Serial.print("hum : ");
  Serial.print(-4.0 + 0.0405 * h - 2.8e-6 * h * h, DEC);
  Serial.print(" ");
  Serial.print("temp : ");
  Serial.println(-40.0 + 0.01 * t, DEC);
}


スケッチを実行し、Arduino IDE のシリアルモニタで表示させます。左の値が湿度、右が温度になっています。

追記
Arduino Duemilanove 328だと正常に動かないみたいです。
Atmega168に乗せ変えて、ボードの指定をAtmega168に設定すると動きます。
謎。

Arduino 328、Arduino MEGAでの動かし方は、KOUSAKUさんのアドバイスによりできるようになりました。ありがとうございます。
上記参照。

Arduinoで紫外線を計測する

図1 UVセンサ G5842 データシート

UVセンサ G5842 を使用し、Arduinoで紫外線を計測してみます。
紫外線は太陽光以外ではほとんど反応しません。データシート「短絡電流の直進性」グラフによると、lx(ルクス)による出力電流が pA(ピコアンペア) から uA(マイクロアンペア)です。
つまり、紫外線によって変化する微少電流をオペアンプで電圧変換して、増幅してからArduinoにアナログ入力しなければなりません。
下記回路は、参考書籍に載っている回路をそのまま使いました。


回路図
今回もオペアンプはLMC6032INを使っています。


スケッチ
int val=0; //入力値の変数を用意し、0に設定

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

void loop(){

  //ANALOG INの0番ピンを読み取りvalに代入
  val=analogRead(0);
  
  Serial.println(val,DEC);

  //1秒ループにする
  delay(1000);

  val = 0;
}


『センサ活用の素』

オペアンプについてはけっこうわかりやすく書いてあるのでおすすめ。PICで作る事を前提としていますが、Arduinoを使った回路に応用が効く記述が多いです。光・温度・湿度・超音波・ガス・圧力センサの実装回路が載っています。
今回は、紫外線センサの箇所を参考にさせていただきました。

2010年1月25日月曜日

Arduinoで温度を計測する -2 オペアンプ使用

この投稿は、建築発明工作ゼミ2009 『温度センサ』をもとに、新しく書き直したものです。

デュアルオペアンプLMC6032IN

オペアンプを使って、温度センサの最大出力電圧1Vを5V、五倍に引き上げてみます。
簡単に言うと、1℃につき10mV出力であったのを、回路をいじって1℃につき50mVの出力にしてやるということです。アナログ入力値1に対する分解能は、

100℃ / 1024 = 0.0976...

つまり、0.09℃単位で計測できるようになります。

図1 図2

G(増幅率) = 1 + (R1 / R2)

図1のように、オペアンプは基本的に5つのピンを持っています。
  1. プラス電圧入力「差動入力ピン」
  2. マイナス電圧入力「差動入力ピン」
  3. プラス電源ピン(オペアンプ自身のプラス電源ピン)
  4. マイナス電源ピン(オペアンプ自身のマイナス電源ピン)
  5. 出力ピン
プラスとマイナスの差動入力ピンの電圧差が増幅されて出力される、という電子部品です。
入力された電圧の増幅率(ゲイン)は、二つの抵抗値の比によって決まります。
オペアンプは、自身に入力される電源よりも高い電圧を出力することはできません。
例えば、オペアンプのプラス電源に5V、マイナス電源をGNDに接続するとします。入力が1V、増幅率を10倍に設定しても、理論的には出力は5Vまでしか増幅されません。
しかし、オペアンプの増幅率は105倍というような大きさのため、差動入力電圧がわずかでもあると出力は+か−の最大値しか出力できません。
実用的に使用するには、ネガティブフィードバックという方法を使います。

オペアンプの回路には、大別して「反転増幅回路」と「非反転増幅回路」の二種類があります。
非反転増幅回路は入力された電圧をそのまま増幅(プラスだったらプラス、マイナスだったらマイナス)して出力します。
反転増幅回路は入力された電圧を反転増幅(プラスだったらマイナス、マイナスだったらプラス)して出力します。
反転増幅回路を組む時はマイナス電源が必要になる(マイナス電源ピンに回路のGNDを基準としてマイナスの電圧をつなぐ)ため、簡単には回路を組めません。
非反転増幅回路をプラスの単源源で使用すれば、マイナス電源は回路のGNDに接続すればよいので扱いやすくなります。

図2は非反転増幅回路です。
プラスとマイナスの差動入力ピンの電圧差を極性をそのままに増幅して出力しますが、出力の途中で抵抗R1を通し、出力信号をマイナス差動入力ピンにフィードバックしています。
これにより、差動電圧差がなくなるように働き、結果として二つの抵抗R1とR2で設定した増幅率に落ち着きます。

outputV(出力電圧) = (1 + (R1 / R2)) × inputV(差動入力電圧)


温度センサLM35DZとオペアンプLMC6032INを使用し、回路を組んでみます。

図3
オペアンプはLMC6032を使用しました。
図3の通り、このLMC6032INには二つのオペアンプが内蔵されています。V+ピンは共通のプラス電源ピン、V-は共通のマイナス電源ピンです。今回は一つしか使いません。


回路図

考え方としては、まず計測温度範囲を決めます。0℃〜100℃とします。
温度センサLM35DZは1℃あたり10mV、100℃でちょうど1Vです。Arduinoのアナログ入力最大電圧5Vまでで、フルレンジで使いますから増幅率は5倍です。とすると、上記の式に当てはめて、

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

これを解くと、抵抗の比は

R1 : R2 = 4 : 1

となります。
LM35DZの+VsピンとLMC6032のV+ピンに5Vの電圧をかけます。C というのはコンデンサです。電気を溜めて吐き出す役割があり、上下する不安定な電気の流れを安定化させるバイパスコンデンサとして機能します。
抵抗R0は、R1とパランスをとるために使っています。この回路では、オペアンプのマイナス入力端子をGNDにつないでいるので、入力も出力もGNDとの電圧差が基準となります。

スケッチ
/* 
  温度計測(0℃〜100℃)
*/

int   A_inPin = 0;  // アナログ入力ピン番号
float A_val;        // アナログ入力値(0〜1023)
float tempC   = 0;  // 摂氏値( ℃ )

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

void loop()
{
  // アナログピンから計測値を取得(0〜1023)
  A_val = analogRead( A_inPin );

  // 摂氏に換算
  tempC = (100 * A_val) / 1024;

  // 改行しながら出力
  Serial.println( tempC );

  // 1秒停止
  delay(1000);
}



シリアルモニタで表示してみると、以下のようになりました。

だいたい0.1℃単位で変化しているので、おおむね精密になったと思います。

ついでに、以下のようなスケッチも試してみます。
1秒ごとに摂氏温度を計測し、10秒ごとに平均摂氏、最大摂氏温度、最小摂氏温度をシリアルモニタに出力します。
日付時刻も表示するために、Datetimeライブラリを使ってみます。
DateTimeライブラリは標準でArduinoIDEにインストールされていないので、以下のスケッチをコピーして実行しようとするとエラーになります。
以下のリンクからDateTimeライブラリをダウンロードして解凍し、指定のディレクトリ内に配置しなければなりません。

こちらからダウンロード

ダウンロードして解凍したら、DateTimeというフォルダができます。
その中のDateTimeフォルダとDateTimeStringsフォルダを、以下の場所にコピーします。

(Macの場合)
○○○(ユーザディレクトリ)/書類/Arduino/library/

スケッチ
/* 
  1秒ごとに摂氏温度を計測
  10秒ごとに平均摂氏、最大摂氏温度、最小摂氏温度を
  シリアルモニタに出力
*/

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

// プログラム開始日付時刻
int    year       = 2010;  // 年
int    month      = 1;     // 月
int    day        = 25;    // 日
int    hour       = 18;    // 時
int    minute     = 3;     // 分
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;

    // 現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;
}


DateTimeライブラリは、
// プログラム開始日付時刻
int year = 2010; // 年
int month = 1; // 月
int day = 25; // 日
int hour = 18; // 時
int minute = 3; // 分
int second = 0; // 秒

の部分で初期値をセットしなければなりません。スケッチを実行するごとに新しく日付を記述し直し、アップロードさせます。
また、Arduinoの水晶振動子で物理的にカウントしているため、一日に数秒のずれが出るそうです。


『作る・できる/基礎入門 電子工作の素』

電子工作に必要な電子回路と部品を網羅した本。これ一冊でだいたいの部品の使用方法がわかります。様々な電子部品の役割が一通り載っているので、困ったらとりあえず開く、といった使い方ができます。さらに、実用的に使えそうな実験用電源装置や太陽光発電パネルの作り方まで載っています。電子工作の初心者はとりあえず買っておいて損はないと思います。
『センサ活用の素』

上記の本の著者のセンサ本。記述がかぶるところがありますが、オペアンプについてはけっこうわかりやすく書いてあるのでおすすめ。PICで作る事を前提としていますが、Arduinoを使った回路に応用が効く記述が多いです。光・温度・湿度・超音波・ガス・圧力センサの実装回路が載っています。
『すぐに使える!オペアンプ回路図100』

オペアンプを使いこなしたい人は持っておいた方がいいと思われます。初心者向きではありませんが、覚えきれないほどのオペアンプ回路が載っています。センサ×Arduinoの回路を実装していくと、困った時に必ず役に立つ時が来ます。

Arduinoで温度を計測する -1

この投稿は、建築発明工作ゼミ2009 『温度センサ』をもとに、新しく書き直したものです。

図1 温度センサ LM35DZ
温度センサ LM35DZを使用し、Arduinoで温度を計測してみます。
温度センサといっても、温度計のように温度を表示してくれるわけではありません。センサの三本足のうち、左側(+Vs)はArduinoの5V電源につなぎ、右側(GND)をArduinoのGNDに接続します。Arduinoにスケッチを送り込んで処理を開始させると、真ん中のVoutから、温度に応じた電圧を出力します。これを温度換算し、Arduino Serial Monitorで表示させてみるということです。

この温度センサLM35DZは、0℃で0V、1℃当たり10mVの出力が得られます。25℃だと250mV、100℃だと1000mV(1V)の出力が得られます。Arduinoのアナログ入力最大電圧は5Vなので単純計算で500℃まで計測できる計算になりますが、LM35DZ自体の計測範囲が-55℃〜+150℃なので、ここでは余裕をもって、0℃〜100℃までを計測範囲として回路を考えてみます。

まずは図1のような回路を組んでみます。

回路1
この場合、LM35DZのVoutを直接Analogピンに入れていますから、

0℃で0V、1℃当たり10mV増加
よって、100℃で1V

となります。
Arduinoのアナログ入力最大電圧は5V、取得値は0〜1023(1024段階)の数値として取得できます。
100℃・1Vだと 1024 / 5 で0〜203(204段階)。つまり、

0℃ 〜 100℃ [ 0V 〜 1V ] = 0 〜 203.8(Analog入力値)

の範囲の値を取得できます。1℃当たりの分解能は約2.048(上記のAnalog入力値は小数で書きましたが、実際には0〜203)。
/* 
  温度計測(0℃〜100℃)
*/

int   A_inPin = 0;  // アナログ入力ピン番号
float A_val;        // アナログ入力値(0〜203)
float tempC   = 0;  // 摂氏値( ℃ )

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

void loop()
{
  // アナログピンから計測値を取得(0〜203)
  A_val = analogRead( A_inPin );

  // 摂氏に換算
  tempC = ((5 * A_val) / 1024) * 100;

  // 改行しながら出力
  Serial.println( tempC );

  // 1秒停止
  delay(1000);
}
スケッチ

上記のスケッチをArduinoにアップロードして、シリアルモニタで確認してみます。
PCとArduino はUSB で接続した状態で、スケッチを実行させた後にArduino IDE の一番右上の 『Serial Monitor』ボタンをクリックすると、別ウィンドウでシリアルモニタが表示され、スケッチ中の Serial.print()関数で指定した変数の中身が表示されます。
ちなみに、Serial.print()Serial.println()の違いは、改行するかしないかです。

温度が一秒毎に出力されています。

  // 摂氏に換算
  tempC = ((5 * A_val) / 1024) * 100;


xV : 取得した電圧値
aVal : 取得したアナログ値(0〜1023)

とすると、

xV : 5V = aVal : 1024

となり、

xV = ( 5V × aVal ) / 1024

これを×100した数値が温度になります。
画像の温度値をみてもらうとわかるように、18.55℃、19.04℃、15.63℃を行ったり来たりしています。この中間の値(例えば15.3℃など)は、計測できても表示はできません。最大1Vを出力する温度センサの値に対して、Arduinoは最大5Vまで感知できます。1Vには204まで、5Vには1023までの値を取得できます。最大1Vまでしか感知しないような回路を組んでいたので、0℃〜100℃までの温度を、たった204段階でしか表現できないことになります。

100℃ / 204 = 0.4901...

つまり、取得するアナログ値1は0.49℃単位となるため、18.55℃〜19.04℃の中間の温度は表示できません。もっと精密に温度を計測するには、

0℃〜100℃ 0〜203(204段階)...Arduinoの感知電圧範囲0V〜1V

を、

0℃〜100℃ 0〜1023(1024段階)...Arduinoの感知電圧範囲0V〜5V

と、アナログ値1に対する分解能を上げてやります。
オペアンプを使って、温度センサの最大出力電圧1Vを5V、五倍に引き上げてみます。