kmzwのブログ

コミック や ガジェット の話題が中心の日記です。

マルチな環境センサを完成させてみた。

作りかけだった環境センサを一応の形にできたのでメモ。 機能的には、センサモジュールに以下の6つのセンサを搭載し、無線経由でPCに表示・記録するシステム。

  • 照度センサ
  • 振動センサ
  • 人感センサ(焦電センサ)
  • 温度センサ
  • 湿度センサ
  • 気圧センサ

大体の構成はこんな感じ。


長いので、続きは折りたたんでおきます。

1:材料と環境の準備

センサモジュールは、Arduinoで作成しました。無線通信はXBee利用です。 Arduinoに関しては、IDEのインストール/使い方や基本的なセンサのサンプルなどを、以下のサイトを参考にするとよいです。

PC用の表示・記録ソフトウェアは、Visual C# 2010で作成。 特に、外部のライブラリなどは利用していないのでMicrosoftから環境をダウンロードすればビルドできるはずです。


センサモジュールとPC側受信ユニットの材料を一覧にしました。

PC側受信ユニット用
品名 参考価格
XBee USBアダプタ \1,590
XBeeシリーズ1 ワイヤアンテナ型 \2,262

その他、半田ごてやニッパー、ブレッドボードなどの基本的な道具や、ユニバーサル基盤や抵抗、コンデンサ、リードなどの基本的なパーツは、省略しますので悪しからず。 おそらく、この記事に興味ある方であれば多分幾らでも持っていそうだし。


材料は、もちろん秋葉原に行けば一通りそろいます。ネット通販でも、Amazonと以下の3店舗で入手可能です。

ちなみに、いずれのお店も代引き対応しています。


2:各センサの回路構成と処理

【照度センサ】

CdSセンサではなく、TEMT6000という照度センサを試してみました。

接続は、以下のとおり。手書きでご容赦。

コードは、後述の通り。センサモジュール全体として、20msのループ間隔で動作し、1000msに1回の間隔で結果をシリアル送信します。照度センサは、1000msに25回計測(2ループに1回、getBrightness()が呼ばれる)して、その中央値を結果として送信(1000msに1回、culcBrightness()が呼ばれる)するようになっています。なんか、たまに外れ値がピョコンと立つので、平均はとれない感じです。

// 動作設定
#define CULC_INTERVAL 20      // 最小処理周期 [ms]
#define SEND_INTERVAL 1000    // 送信周期 [ms]
#define NUM_BRIGHTNESS 25     // 照度センサ 計測回数/送信周期 

// 入出力設定
#define AI_BRIGHTNESS 0    // 照度センサ AIピン

// 送信用変数
int loop_send = 0;    // ループカウント

// 照度センサ用変数
int val_brightness = 0;                // 送信値 [lx]
int tmp_brightness[NUM_BRIGHTNESS];    // 計測値 [lx]
int cnt_brightness = 0;                // 計測カウント
int loop_brightness = 0;               // ループカウント

void setup()
{
    int i;
    // シリアルポート設定
    Serial.begin(9600);
    // センサ用変数の初期化
    for (i=0; i<NUM_BRIGHTNESS; i++) tmp_brightness[i] = 0;
}

void loop()
{
    // 照度センサ
    if (loop_brightness > (int)(SEND_INTERVAL/(CULC_INTERVAL*NUM_BRIGHTNESS)))
    {
        // 計測値取得
        tmp_brightness[cnt_brightness] = getBrightness();
        // カウント処理
        cnt_brightness++;
        loop_brightness = 0;
    }
    loop_brightness++;

    // データ送信
    if (loop_send > (int)(SEND_INTERVAL/CULC_INTERVAL))
    {
        // 送信値の取得
        val_brightness = culcBrightness();      // 照度センサ
        // 結果出力
        Serial.print("Brightness:");     Serial.print(val_brightness);     Serial.print("[lx]\t");       // 照度センサ
        // カウント処理
        cnt_brightness = 0;
    }
    loop_send++;

    // 処理ディレイ
    delay(CULC_INTERVAL);
}

// 照度センサ計測値取得
int getBrightness()
{
    int value = 0;
    value = analogRead(AI_BRIGHTNESS);
    return (value);
}

// 照度センサ送信値計算
int culcBrightness()
{
    int i, j, swap;
    
    // シェルソートで計測値を並び替え後、中央値を送信値とする
    for (i=1; i<NUM_BRIGHTNESS; i++)
    {
        for (j=i-1; j>=0; j--)
        {
            if (tmp_brightness[j] < tmp_brightness[j+1])
            {
                swap=tmp_brightness[j];
                tmp_brightness[j] = tmp_brightness[j+1];
                tmp_brightness[j+1] = swap;
            }
            else
            {
                break;
            }
        }
    }

    return (tmp_brightness[(int)(NUM_BRIGHTNESS/2)-1]);
}
【振動センサ】

振動センサは、圧電スピーカーを代用として用います。いわゆるピエゾ素子なので、電圧をかければ圧力が生じ、圧力がかかれば電圧が生じます。今回は、スピーカーとは逆の使い方をするわけです。

接続もシンプルで、書く必要もないほど。一応以下。

コードの全体的な流れは、照度センサで掲示したコードの通りなので、違う部分のコードのみ示していきます。一連のコードは、最後にまとめて再掲します。
振動センサは、反応がシビアなので計測回数をできるだけ大きくしています。

#define NUM_VIBRATION 50      // 振動センサ 計測回数/送信周期
#define AI_VIBRATION 1     // 振動センサ AIピン

以下関数を呼んで、1000msに50回、すなわち、毎ループ(20ms間隔で)計測します。

// 振動センサ計測値取得
int getVibration()
{
    int value = 0;
    value = analogRead(AI_VIBRATION);
    return(value);
}

振動センサの送信値は、50回計測した計測値の合計としています。反応がシビアなので微動も逃したくないのです。

// 振動センサ送信値計算
int culcVibration()
{
    int i;
    int value = 0;    

    // 計測値の合計を送信値とする
    for (i=1; i<NUM_VIBRATION; i++)
    {
        value += tmp_vibration[i];    // 加算
        tmp_vibration[i];             // クリア
    }
    return (value);
}
【人感センサ(焦電センサ)】

人感センサは、パナソニックのNaPiOnを使います。

接続は、こんな感じ。

出力はHigh/Lowで、反応がチャカチャカします。

#define ON 1
#define OFF 0
#define NUM_NAPION 10         // 人感センサ 計測回数/送信周期 
#define DI_NAPION 8        // 人感センサ DIピン

チャカチャカ対策として、以下のように1秒に10回計測して、

// 人感センサ計測値取得
int getNapion()
{
    int value = OFF;
    if (digitalRead(DI_NAPION) == HIGH)
    {
        value = ON;
    }
    else
    {
        value = OFF;
    }

   return(value); 
}

10回分の計測の合計値を送信値とすることで、一定時間、値を保持するのと同じような効果を期待しています。

// 人感センサ送信値計算
int culcNapion()
{
    int i;
    int value = 0;    
    
    // 計測値の合計を送信値とする
    for (i=1; i<NUM_NAPION; i++)
    {
        value += tmp_napion[i];    // 加算
        tmp_napion[i];             // クリア
    }
    return (value);
}

必要であれば、データ収集側でチャタリング対策をすればよいと思います。

【温湿度センサ】

RHT03という温湿度センサを使いました。 温湿度が両方測れるのに1000円もしないので安いです。 しかも、Arduino用のライブラリまであります。 ライブラリは、参考サイト[2-6]の[Download ZIP]からダウンロードできます。 解凍して、ArduinoIDEのインストールフォルダにある[libraries]フォルダに[DHT]フォルダを作成して、DHT.cppやDHT.hを配置すれば使えます。

接続は、以下の通り。

コードは、ライブラリを利用するための定義がいくつか必要です。計測はライブラリをそのまま利用したので楽チンです。

#include <DHT.h>

#define NUM_DHT 5             // 温湿度センサ 計測回数/送信周期 
#define DI_DHT 9           // 温湿度センサ DIピン 
#define DHTTYPE DHT22      // 温湿度センサ タイプ指定(DHTライブラリ用)

// 温湿度センサ用ライブラリ
DHT dht(DI_DHT, DHTTYPE);

送信値の計算は5回計測の中央値としています。湿度も同じなのでコード省略。

// 温度送信値計算
float culcTemperature()
{
    int i, j;
    float swap;
    
    // シェルソートで計測値を並び替え後、中央値を送信値とする
    for (i=1; i<NUM_DHT; i++)
    {
        for (j=i-1; j>=0; j--)
        {
            if (tmp_temperature[j] < tmp_temperature[j+1])
            {
                swap=tmp_temperature[j];
                tmp_temperature[j] = tmp_temperature[j+1];
                tmp_temperature[j+1] = swap;
            }
            else
            {
                break;
            }
        }
    }

    return (tmp_temperature[(int)(NUM_DHT/2)-1]);
}
【気圧センサ】

MPL115A2センサチップを用いたI2C接続タイプのものです。

接続は以下の通り。今回購入したモジュール(参考サイト[2-8])は、コンデンサ実装済みでピン配置がプリミティブなものと異なるので要注意。

I2C接続のために、下準備がいくつか必要です。

#include <Wire.h>

#define NUM_PRESSURE 5        // 気圧センサ 計測回数/送信周期 
#define I2CADDRESS 0x60    // 気圧センサ用千作用I2Cアドレス

float a0, b1, c11, c12, b2, c22;     // 気圧換算用係数

計測値取得のために、かなりややこしい計算が必要です。データシートを見ながら、参考サイトを見ながら組んでみましたが、参考サイトにライブラリが配布されていましたorz。素直に利用したほうがよいです。

// 気圧センサの変換係数取得
float get_coefficient(int effective_bits, int fraction_bits, int fraction_zeropad)
{
    float get_value = 0.0;
    unsigned char msb, lsb;
    msb = Wire.read();
    lsb = Wire.read(); 
    get_value = (float) ((msb << 8) + lsb) / ((long)1 << 16 - effective_bits + fraction_bits + fraction_zeropad);
    return (get_value);
}

// 気圧 計測値取得
float getPressure()
{
    float value = 0.0;    // 気圧 [hPa]
    unsigned char msb = 0;    // 上位ビットテンポラリ
    unsigned char lsb = 0;    // 下位ビットテンポラリ
    unsigned int padc = 0;    // 気圧データの読み値
    unsigned int tadc = 0;    // 温度データの読み値
    float pcomp = 0.0;        // 気圧取得値(pcomp=0で500hPa, pcomp=1023で1150hPa)

    Wire.beginTransmission(I2CADDRESS);
    Wire.write(0x12);    // 気圧・温度をAD変換(アドレス0x12に0x01を書き込む)
    Wire.write(0x01);
    Wire.endTransmission();

    delay(3);    // AD変換処理待ち

    Wire.beginTransmission(I2CADDRESS);
    Wire.write((uint8_t)0x00);    // 気圧と温度の取得(0x00から4byte取得)
    Wire.endTransmission();
    Wire.requestFrom(I2CADDRESS, 4);
    
    if (Wire.available())
    {
        msb = Wire.read(); 
        lsb = Wire.read();
        padc = (((unsigned int)msb << 8) + lsb) >> 6;
        
        msb = Wire.read(); 
        lsb = Wire.read();
        tadc = (((unsigned int)msb << 8) + lsb) >> 6;

        pcomp = a0 + (b1 + c11 * padc + c12 * tadc) * padc + (b2 + c22 * tadc) * tadc;
        // pcomp = a0 + (b1 + c12 * tadc) * padc + b2 * tadc;
        
        value = pcomp * (650.0 / 1023.0) + 500.0;
    }

    return (value);   
}

送信値は、温湿度と同様に5回計測の中央値を送信値とします。

// 気圧送信値計算
float culcPressure()
{
    int i, j;
    float swap;
    
    // シェルソートで計測値を並び替え後、中央値を送信値とする
    for (i=1; i<NUM_PRESSURE; i++)
    {
        for (j=i-1; j>=0; j--)
        {
            if (tmp_pressure[j] < tmp_pressure[j+1])
            {
                swap=tmp_pressure[j];
                tmp_pressure[j] = tmp_pressure[j+1];
                tmp_pressure[j+1] = swap;
            }
            else
            {
                break;
            }
        }
    }
    return (tmp_pressure[(int)(NUM_PRESSURE/2)-1]); 
}

3:センサモジュールの全体構成

これまでの各センサを一つのモジュールにまとめます。

【コード全体】

これまでのセンサをすべて接続して、コードをガッチャンコすると以下のようになります。 ところどころ、デバッグ表示用のコードがそのままなので無視してください。一応、ここにファイルも置いておきます。

#include <DHT.h>
#include <Wire.h>

#define ON 1
#define OFF 0

// 動作設定
#define CULC_INTERVAL 20      // 最小処理周期 [ms]
#define SEND_INTERVAL 1000    // 送信周期 [ms]
#define NUM_BRIGHTNESS 25     // 照度センサ 計測回数/送信周期 
#define NUM_VIBRATION 50      // 振動センサ 計測回数/送信周期
#define NUM_NAPION 10         // 人感センサ 計測回数/送信周期 
#define NUM_DHT 5             // 温湿度センサ 計測回数/送信周期 
#define NUM_PRESSURE 5        // 気圧センサ 計測回数/送信周期 

// 入出力設定
#define DO_DEBUG 13        // デバッグ用LED指定
#define AI_BRIGHTNESS 0    // 照度センサ AIピン
#define AI_VIBRATION 1     // 振動センサ AIピン
#define DI_NAPION 8        // 人感センサ DIピン
#define DI_DHT 9           // 温湿度センサ DIピン 
#define DHTTYPE DHT22      // 温湿度センサ タイプ指定(DHTライブラリ用)
#define I2CADDRESS 0x60    // 気圧センサ用千作用I2Cアドレス

// 温湿度センサ用ライブラリ
DHT dht(DI_DHT, DHTTYPE);

// 送信用変数
int loop_send = 0;    // ループカウント

// 照度センサ用変数
int val_brightness = 0;                // 送信値 [lx]
int tmp_brightness[NUM_BRIGHTNESS];    // 計測値 [lx]
int cnt_brightness = 0;                // 計測カウント
int loop_brightness = 0;               // ループカウント

// 振動センサ用変数
int val_vibration = 0;               // 送信地
int tmp_vibration[NUM_VIBRATION];    // 計測値
int cnt_vibration = 0;               // 計測カウント
int loop_vibration = 0;              // ループカウント

// 人感センサ用変数
int val_napion = OFF;          // 送信値
int tmp_napion[NUM_NAPION];    // 計測値
int cnt_napion = 0;            // 計測カウント
int loop_napion = 0;           // ループカウント

// 温湿度センサ用変数
float val_temperature = 0.0;       // 温度 送信値 [℃]
float tmp_temperature[NUM_DHT];    // 温度 計測値 [℃]
float val_humidity = 0.0;          // 湿度 送信値 [%]
float tmp_humidity[NUM_DHT];       // 湿度 計測値 [%]
int cnt_dht = 0;                   // 計測カウント
int loop_dht = 0;                  // ループカウント

// 気圧センサ用変数
float val_pressure = 0.0;            // 送信値 [hPa]
float tmp_pressure[NUM_PRESSURE];    // 計測値 [hPa]
int cnt_pressure = 0;                // 計測カウント
int loop_pressure = 0;               // ループカウント
float a0, b1, c11, c12, b2, c22;     // 気圧換算用係数



void setup()
{
    int i;

    // IO設定
    pinMode(DO_DEBUG, OUTPUT);
    pinMode(DI_NAPION, INPUT);

    // シリアルポート設定
    Serial.begin(9600);
    
    // センサ用変数の初期化
    for (i=0; i<NUM_BRIGHTNESS; i++) tmp_brightness[i] = 0;
    for (i=0; i<NUM_VIBRATION; i++) tmp_vibration[i] = 0;
    for (i=0; i<NUM_NAPION; i++) tmp_napion[i] = 0;
    for (i=0; i<NUM_DHT; i++) tmp_temperature[i] = 0.0;
    for (i=0; i<NUM_DHT; i++) tmp_humidity[i] = 0.0;
    for (i=0; i<NUM_PRESSURE; i++) tmp_pressure[i] = 0.0;

    // 温湿度センサ初期化 
    dht.begin();    // DHTライブラリ
    
    // 気圧センサ初期化
    Wire.begin();    // Wireライブラリ
    Wire.beginTransmission(I2CADDRESS);
    Wire.write(0x04);    // 係数取得
    Wire.endTransmission();
    Wire.requestFrom(I2CADDRESS, 12);    // 0x04から12byte要求
    if (Wire.available())    // 各係数取得
    {
        a0 = get_coefficient(16, 3, 0);
        b1 = get_coefficient(16, 13, 0);
        b2 = get_coefficient(16, 14, 0);
        c11 = get_coefficient(11, 10, 11);
        c12 = get_coefficient(14, 13, 9);
        c22 = get_coefficient(11, 10, 15);
    }
    
}



void loop()
{
    // 照度センサ
    if (loop_brightness > (int)(SEND_INTERVAL/(CULC_INTERVAL*NUM_BRIGHTNESS)))
    {
        // 計測値取得
        tmp_brightness[cnt_brightness] = getBrightness();
        
        // カウント処理
        cnt_brightness++;
        loop_brightness = 0;
    }
    loop_brightness++;

    // 振動センサ
    if (loop_vibration > (int)(SEND_INTERVAL/(CULC_INTERVAL*NUM_VIBRATION)))
    {
        // 計測値取得
        tmp_vibration[cnt_vibration] = getVibration();
        
        // カウント処理
        cnt_vibration++;
        loop_vibration = 0;
    }
    loop_vibration++;

    // 人感センサ
    if (loop_napion > (int)(SEND_INTERVAL/(CULC_INTERVAL*NUM_NAPION)))
    {
        // 計測値取得
        tmp_napion[cnt_napion] = getNapion();
        
        // カウント処理
        cnt_napion++;
        loop_napion = 0;
    }
    loop_napion++;

    // 温湿度センサ
    if (loop_dht > (int)(SEND_INTERVAL/(CULC_INTERVAL*NUM_DHT)))
    {
        // 計測値取得
        tmp_temperature[cnt_dht] = dht.readTemperature();
        tmp_humidity[cnt_dht] = dht.readHumidity();

        // カウント処理
        cnt_dht++;
        loop_dht = 0;
    }
    loop_dht++;

    // 気圧センサ
    if (loop_pressure > (int)(SEND_INTERVAL/(CULC_INTERVAL*NUM_PRESSURE)))
    {
        // 計測値取得
        tmp_pressure[cnt_pressure] = getPressure();

        // カウント処理
        cnt_pressure++;
        loop_pressure = 0;
    }
    loop_pressure++;


    // データ送信
    if (loop_send > (int)(SEND_INTERVAL/CULC_INTERVAL))
    {
        // 送信値の取得
        val_brightness = culcBrightness();      // 照度センサ
        val_vibration = culcVibration();        // 振動センサ
        val_napion = culcNapion();              // 人感センサ
        val_temperature = culcTemperature();    // 温度センサ
        val_humidity = culcHumidity();          // 湿度センサ
        val_pressure = culcPressure();          // 気圧センサ


        // 結果出力
        /*
        Serial.print("Brightness:");     Serial.print(val_brightness);     Serial.print("[lx]\t");       // 照度センサ
        Serial.print("Vibration:");      Serial.print(val_vibration);      Serial.print("\t");           // 振動センサ
        Serial.print("MotionDetector:"); Serial.print(val_napion);         Serial.println("\t");         // 人感センサ
        Serial.print("Temperature:");    Serial.print(val_temperature);    Serial.print("[C]\t");        // 温度センサ
        Serial.print("Humidity:");       Serial.print(val_humidity);       Serial.print("[%]\t");        // 湿度センサ
        Serial.print("Pressure:");       Serial.print(val_pressure);       Serial.println("[hPa]\t");    // 気圧センサ
        */
        Serial.print(val_brightness);     Serial.print(",");      // 照度センサ
        Serial.print(val_vibration);      Serial.print(",");      // 振動センサ
        Serial.print(val_napion);         Serial.print(",");      // 人感センサ
        Serial.print(val_temperature);    Serial.print(",");      // 温度センサ
        Serial.print(val_humidity);       Serial.print(",");      // 湿度センサ
        Serial.print(val_pressure);       Serial.println();       // 気圧センサ
        

        // カウント処理
        cnt_brightness = 0;
        cnt_vibration = 0;
        cnt_napion = 0;
        cnt_dht = 0;
        cnt_pressure = 0;
        loop_send = 0;
    }
    loop_send++;


    // 処理ディレイ
    delay(CULC_INTERVAL);
}



// 照度センサ計測値取得
int getBrightness()
{
    int value = 0;
    value = analogRead(AI_BRIGHTNESS);
    return (value);
}



// 照度センサ送信値計算
int culcBrightness()
{
    int i, j, swap;
    
    // シェルソートで計測値を並び替え後、中央値を送信値とする
    for (i=1; i<NUM_BRIGHTNESS; i++)
    {
        for (j=i-1; j>=0; j--)
        {
            if (tmp_brightness[j] < tmp_brightness[j+1])
            {
                swap=tmp_brightness[j];
                tmp_brightness[j] = tmp_brightness[j+1];
                tmp_brightness[j+1] = swap;
            }
            else
            {
                break;
            }
        }
    }

    /*
    // 計測値確認
    for (i=0; i<NUM_BRIGHTNESS; i++)
    {
        Serial.print(tmp_brightness[i]);
        Serial.print(",");
    }
    Serial.println();
    */

    return (tmp_brightness[(int)(NUM_BRIGHTNESS/2)-1]);
}    



// 振動センサ計測値取得
int getVibration()
{
    int value = 0;
    value = analogRead(AI_VIBRATION);
    return(value);
}



// 振動センサ送信値計算
int culcVibration()
{
    int i;
    int value = 0;    

    /*
    // 計測値確認
    for (i=0; i<NUM_VIBRATION; i++)
    {
        Serial.print(tmp_vibration[i]);
        Serial.print(",");
    }
    Serial.println();
    */

    // 計測値の合計を送信値とする
    for (i=1; i<NUM_VIBRATION; i++)
    {
        value += tmp_vibration[i];    // 加算
        tmp_vibration[i];             // クリア
    }

    return (value);
}



// 人感センサ計測値取得
int getNapion()
{
    int value = OFF;
    
    if (digitalRead(DI_NAPION) == HIGH)
    {
        value = ON;
    }
    else
    {
        value = OFF;
    }

    // if (value == ON)    digitalWrite(DO_DEBUG, HIGH);   
    // else    digitalWrite(DO_DEBUG, LOW);
   
   return(value); 
}



// 人感センサ送信値計算
int culcNapion()
{
    int i;
    int value = 0;    

    /*
    // 計測値確認
    for (i=0; i<NUM_NAPION; i++)
    {
        Serial.print(tmp_napion[i]);
        Serial.print(",");
    }
    Serial.println();
    */
    
    // 計測値の合計を送信値とする
    for (i=1; i<NUM_NAPION; i++)
    {
        value += tmp_napion[i];    // 加算
        tmp_napion[i];             // クリア
    }

    return (value);
}



// 温度送信値計算
float culcTemperature()
{
    int i, j;
    float swap;
    
    // シェルソートで計測値を並び替え後、中央値を送信値とする
    for (i=1; i<NUM_DHT; i++)
    {
        for (j=i-1; j>=0; j--)
        {
            if (tmp_temperature[j] < tmp_temperature[j+1])
            {
                swap=tmp_temperature[j];
                tmp_temperature[j] = tmp_temperature[j+1];
                tmp_temperature[j+1] = swap;
            }
            else
            {
                break;
            }
        }
    }

    /*
    // 計測値確認
    for (i=0; i<NUM_DHT; i++)
    {
        Serial.print(tmp_temperature[i]);
        Serial.print(",");
    }
    Serial.println();
    */

    return (tmp_temperature[(int)(NUM_DHT/2)-1]);
}



// 湿度送信値計算
float culcHumidity()
{
    int i, j;
    float swap;
    
    // シェルソートで計測値を並び替え後、中央値を送信値とする
    for (i=1; i<NUM_DHT; i++)
    {
        for (j=i-1; j>=0; j--)
        {
            if (tmp_humidity[j] < tmp_humidity[j+1])
            {
                swap=tmp_humidity[j];
                tmp_humidity[j] = tmp_humidity[j+1];
                tmp_humidity[j+1] = swap;
            }
            else
            {
                break;
            }
        }
    }

    /*
    // 計測値確認
    for (i=0; i<NUM_DHT; i++)
    {
        Serial.print(tmp_humidity[i]);
        Serial.print(",");
    }
    Serial.println();
    */

    return (tmp_humidity[(int)(NUM_DHT/2)-1]); 
}



// 気圧センサの変換係数取得
float get_coefficient(int effective_bits, int fraction_bits, int fraction_zeropad)
{
    float get_value = 0.0;
    unsigned char msb, lsb;
  
    msb = Wire.read();
    lsb = Wire.read();
  
    get_value = (float) ((msb << 8) + lsb) / ((long)1 << 16 - effective_bits + fraction_bits + fraction_zeropad);
  
    return (get_value);
}



// 気圧 計測値取得
float getPressure()
{
    float value = 0.0;    // 気圧 [hPa]
    
    unsigned char msb = 0;    // 上位ビットテンポラリ
    unsigned char lsb = 0;    // 下位ビットテンポラリ
    unsigned int padc = 0;    // 気圧データの読み値
    unsigned int tadc = 0;    // 温度データの読み値
    float pcomp = 0.0;        // 気圧取得値(pcomp=0で500hPa, pcomp=1023で1150hPa)

        
    Wire.beginTransmission(I2CADDRESS);
    Wire.write(0x12);    // 気圧・温度をAD変換(アドレス0x12に0x01を書き込む)
    Wire.write(0x01);
    Wire.endTransmission();

    delay(3);    // AD変換処理待ち

    Wire.beginTransmission(I2CADDRESS);
    Wire.write((uint8_t)0x00);    // 気圧と温度の取得(0x00から4byte取得)
    Wire.endTransmission();
    Wire.requestFrom(I2CADDRESS, 4);
    
    if (Wire.available())
    {
        msb = Wire.read(); 
        lsb = Wire.read();
        padc = (((unsigned int)msb << 8) + lsb) >> 6;
        
        msb = Wire.read(); 
        lsb = Wire.read();
        tadc = (((unsigned int)msb << 8) + lsb) >> 6;

        pcomp = a0 + (b1 + c11 * padc + c12 * tadc) * padc + (b2 + c22 * tadc) * tadc;
        // pcomp = a0 + (b1 + c12 * tadc) * padc + b2 * tadc;
        // Serial.println(padc);
        // Serial.println(tadc);
        // Serial.println(pcomp);
        
        value = pcomp * (650.0 / 1023.0) + 500.0;
    }

    return (value);   
}



// 気圧送信値計算
float culcPressure()
{
    int i, j;
    float swap;
    
    // シェルソートで計測値を並び替え後、中央値を送信値とする
    for (i=1; i<NUM_PRESSURE; i++)
    {
        for (j=i-1; j>=0; j--)
        {
            if (tmp_pressure[j] < tmp_pressure[j+1])
            {
                swap=tmp_pressure[j];
                tmp_pressure[j] = tmp_pressure[j+1];
                tmp_pressure[j+1] = swap;
            }
            else
            {
                break;
            }
        }
    }

    /*
    // 計測値確認
    for (i=0; i<NUM_PRESSURE; i++)
    {
        Serial.print(tmp_pressure[i]);
        Serial.print(",");
    }
    Serial.println();
    */

    return (tmp_pressure[(int)(NUM_PRESSURE/2)-1]); 
}
XBeeの設定】

有線のシリアル通信で一通りの動作確認が取れたところで、通信をXBeeの無線に置き換えます。 コードは特に書き換える必要なく、XBeeの設定をすればシリアル通信が無線化できます。基本的には、参考サイト[2-10]の通りにやるだけでした。X-CTUのバージョンがあがってUIが変更になっています。だいたい感覚で操作はわかると思いますし、旧バージョンもまだダウンロード可能です。

【ユニバーサル基盤への実装】

XBeeの無線通信も問題なければ、ブレッドボードで接続していたセンサ類を、ユニバーサル基盤に実装します。
こんな感じに実装しました。

赤線が表面の被覆リードの配線で、青線が裏面の配線です。


4:PC側の表示ソフトウェア作成

Visual C# 2010 で、適当に表示ソフトウェアを作成しました。

単にシリアル通信でデータを取得しています。取得した直近のデータをグラフを表示して、CSVファイル形式でログ保存することができます。以下、サイトを参考にすれば簡単に作成できました。

参考までに、プロジェクト一式をここに置いておきます。標準コントロールしか使っていないので、Visual C#の開発環境さえ入っていれば問題なく動くと思います。


5:ケース作成

ここまでの実装で、こんな感じになっていると思います。


工作用の厚紙を適当にカットして、、、


こんな感じになりました。左下の穴は、ACアダプタ用です。


PC用の受信ユニットは、剥き出しでもいいかな。



以上、マルチな環境センサの作成メモでした。
どっかで、センサモジュールを複数接続できるようにして、電池駆動化したようなものを、5000円くらいで売ってくれないかしら。 数万もしちゃうと、ちょっと試そうって感じじゃないよね。