2015年3月6日金曜日

arduinoで気圧計MPL115A1を使いxivelyにアップロードする



使った気圧計はSPI接続のMPL115A1で、レジスタから数値を読み取りめんどくさい計算をすると気圧を求められます。

スペック
Factory Calibrated
50kPa~115kPa Absolute Pressure
1kPa Accuracy
2.375V ~ 5.5V Supply

もともとkPa(キロパスカル)で出力するためのセンサのようで、hPa(ヘクトパスカル)では誤差があるようです。
I2C接続のMPL115A2もあります。

きむ茶工房ガレージハウスさんのスケッチにxivelyへアップロードするスケッチを付け足して使ってみました。

様々なセンサの数値などを送信するとグラフにしてくれるサービスのxivelyですが、利用者が多いのか、新アカウントの登録は順番待ちが続いているようです。



このグラフの上半分は、xivelyで記録したもの。1分毎に送信。
下は気象庁発表の気圧(1時間毎)をグラフにしたもの。
気圧が下がっているときは、雨や曇りでした。


画像処理ソフトで横、縦を合わせて重ねたところ、だいたい一致しています。


気象庁観測地の標高と自宅の標高差(10mあたり1hPa)を考慮しても、9hPaほど低く出力されているようです。個体差でしょうか。

追記:UNOから秋月マイコンボードに交換すると、気象庁発表の数値との差が変化しました。ボードによってSPI接続のセンサの値が変化するのでしょうか?詳しく調べていないので再現するかどうかも不明です。


下から、arduinoUNO、イーサネットシールド、最上段の8ピンの基板が気圧センサMPL115A1。
黄色のジャンパーケーブルでSSをD8に設定しています。
最上段、青い基板は以前使った加速度、ジャイロセンサGY-521(MPU-6050)。


イーサネットシールドのmacアドレス、xivelyKeyとfeedIDはご自分のに合わせて書き換えてください。
以下のスケッチでは、イーサネットのSS(D10)とSDカードのSS(D4)に被らないように、MPL115A1のSSをD8に設定し接続しています。
xivelyのライブラリはこちら

#include <SPI.h>
#include <Ethernet.h>
#include <HttpClient.h>
#include <Xively.h>

//for pressure sensor
#define AVE_NUM     20                   // 圧力・温度のA/D変換値を平均化する回数
#define H_CORRECT   0                    // 自宅でのセンサと実際の高度差補正値(My自宅の標高は100m)
#define PIN_SS_PRESSURE 8                // MPL115A1のSSをイーサネットシールドのSSと被らないようにする
float a0 , b1 , b2 , c12 ;               // 係数のデータを保存する変数
unsigned long Press , Temp ;             // 圧力および温度の変換値を保存する変数

//for ethernet
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };   // MAC address for your Ethernet shield
EthernetClient client;

//for xively
char xivelyKey[] = "xxxxxxxxxxxxxxxxxxxxxxx";    // Your Xively key to let you upload data
char ID_pressure[] = "atmospheric_pressure";                              // Define the strings for our datastream IDs
XivelyDatastream datastreams[] = {
  XivelyDatastream(ID_pressure, strlen(ID_pressure), DATASTREAM_FLOAT),
};
XivelyFeed feed(xxxxxxxxxxxx, datastreams, 1 /* number of datastreams */);  // Finally, wrap the datastreams into a feed
XivelyClient xivelyclient(client);


void setup(){
  Serial.begin(9600) ;
  pinMode(PIN_SS_PRESSURE, OUTPUT);
  digitalWrite(PIN_SS_PRESSURE, HIGH);
  SPI.begin() ;                        // SPIを行う為の初期化
  SPI.setBitOrder(MSBFIRST) ;          // ビットオーダー
  SPI.setClockDivider(SPI_CLOCK_DIV4) ;// クロック(CLK)をシステムクロックの1/4で使用(16MHz/4)
  SPI.setDataMode(SPI_MODE0) ;         // クロック極性0(LOW) クロック位相1(HIGH)

  while (Ethernet.begin(mac) != 1){
    Serial.println("Error getting IP address via DHCP, trying again...");
    delay(5000);
  }
  Serial.print("IP Address:         ");
  Serial.println(Ethernet.localIP());
  Serial.print("Subnet Mask:        ");
  Serial.println(Ethernet.subnetMask());
  Serial.print("Gateway IP Address: "); 
  Serial.println(Ethernet.gatewayIP());
  Serial.print("DNS Server Address: "); 
  Serial.println(Ethernet.dnsServerIP());

  delay(3000) ;                        // 3Sしたら開始
  CoefficientRead() ;                  // メモリーマップから係数を読み出して置く
}

void loop(){
  unsigned long p , t ;
  p = t = 0 ;
  for (int i = 0 ; i < AVE_NUM ; i++) {    // 20回読み込んで平均化する
    PressureRead() ;                       // メモリーマップから圧力および温度のA/D変換値を読み出す
    p = p + Press ;
    t = t + Temp ;
  }
  Press = p / AVE_NUM ;
  Temp  = t / AVE_NUM ;

  float ans = PressureCalc() ;         // 気圧値の計算を行う
  Serial.print(ans) ;                  // 気圧値の表示を行う
  Serial.println(" hPa    ") ;

//upload to xively
  datastreams[0].setFloat(ans);
  Serial.print("Uploading it to Xively >> ");
  Serial.println(datastreams[0].getFloat());
  int ret = xivelyclient.put(feed, xivelyKey);
  Serial.print("xivelyclient.put returned ");
  Serial.println(ret);
  Serial.println();
  delay(60000);

}

// メモリーマップから係数を読み出す処理
void CoefficientRead(){
  unsigned int h , l ;
  digitalWrite(PIN_SS_PRESSURE, LOW) ; // SS(CS)ラインをLOWにする

  // a0の係数を得る
  SPI.transfer(0x88) ;                 // a0(MSB:HIGH byte)係数
  h = SPI.transfer(0x00) ;
  SPI.transfer(0x8a) ;                 // a0(LSB:LOW byte) 係数
  l = SPI.transfer(0x00) ;
  a0 = (h << 5) + (l >> 3) + (l & 0x07) / 8.0 ;

  // b1の係数を得る
  SPI.transfer(0x8c) ;                 // b1(MSB:HIGH byte)係数
  h = SPI.transfer(0x00) ;
  SPI.transfer(0x8e) ;                 // b1(LSB:LOW byte) 係数
  l = SPI.transfer(0x00) ;
  b1 = ( ( ( (h & 0x1F) * 0x100 ) + l ) / 8192.0 ) - 3 ;

  // b2の係数を得る
  SPI.transfer(0x90) ;                 // b2(MSB:HIGH byte)係数
  h = SPI.transfer(0x00) ;
  SPI.transfer(0x92) ;                 // b2(LSB:LOW byte) 係数
  l = SPI.transfer(0x00) ;
  b2 = ( ( ( ( h - 0x80) << 8 ) + l ) / 16384.0 ) - 2 ;

  // C12の係数を得る
  SPI.transfer(0x94) ;                 // c12(MSB:HIGH byte)係数
  h = SPI.transfer(0x00) ;
  SPI.transfer(0x96) ;                 // c12(LSB:LOW byte) 係数
  l = SPI.transfer(0x00) ;
  c12 = ( ( ( h * 0x100 ) + l ) / 16777216.0 )  ;
  SPI.transfer(0x00) ;
  digitalWrite(PIN_SS_PRESSURE, HIGH); // SS(CS)ラインをHIGHにする
}

// メモリーマップから圧力および温度のA/D変換値を読み出す処理
void PressureRead(){
  unsigned int h , l ;

  // 圧力および温度の変換を開始させる
  digitalWrite(PIN_SS_PRESSURE, LOW) ; // SS(CS)ラインをLOWにする
  SPI.transfer(0x24) ;                 // 0x24コマンドの発行(圧力と温度の変換)
  SPI.transfer(0x00) ;
  digitalWrite(PIN_SS_PRESSURE, HIGH) ;// SS(CS)ラインをHIGHにする
  delay(3) ;                           // 変換完了まで3ms待つ
  digitalWrite(PIN_SS_PRESSURE, LOW) ; // SS(CS)ラインをLOWにする

  // 圧力のA/D変換値を得る
  SPI.transfer(0x80) ;                 // 圧力(MSB:HIGH byte)
  h = SPI.transfer(0x00) ;
  SPI.transfer(0x82) ;                 // 圧力(LSB:LOW byte)
  l = SPI.transfer(0x00) ;
  Press = ( ( h * 256 ) + l ) / 64 ;

  // 温度のA/D変換値を得る
  digitalWrite(PIN_SS_PRESSURE, LOW) ; // SS(CS)ラインをLOWにする
  SPI.transfer(0x84) ;                 // 温度(MSB:HIGH byte)
  h = SPI.transfer(0x00) ;
  SPI.transfer(0x86) ;                 // 温度(LSB:LOW byte)
  l = SPI.transfer(0x00) ;
  Temp = ( ( h * 256 ) + l ) / 64 ;
  SPI.transfer(0x00) ;
  digitalWrite(PIN_SS_PRESSURE, HIGH); // SS(CS)ラインをHIGHにする
}

// 気圧値(hPa)を計算する処理
float PressureCalc(){
  float ret , f ;
  f = a0 + ( b1 + c12 * Temp ) * Press + b2 * Temp ;
  ret = f * ( 650.0 / 1023.0 ) + 500.0 ;
  return ret ;
}


複数の数値をxivelyへアップロードする方法は、サンプルスケッチか以前の記事を参照ください。

追記:過去一ヶ月の変化
4/9に急激に変化していますが、プロバイダーのDNSサーバで障害が起こった時間です。
なぜか数値に影響が出ています。
マイコンボードを変更した時にも数値の変化がありましたが、いずれも原因は不明です。



環境:arduinoUNO、arduinoIDE1.6.0、win7(64)

5 件のコメント:

  1. このコメントは投稿者によって削除されました。

    返信削除

  2. はじめまして。WIZNETのKIMと申します
    この度、弊社の製品を使ったプロジェクトを紹介するブログをはじめる予定なのですが
    よろしければ、この投稿をWIZNETにほんブログの方に紹介することと画像の利用について許諾を頂けないでしょうか

    ご検討頂き、ご返信頂けますよう、何卒、宜しくお願い致します。

    doublesk@wiznettechnology.com

    返信削除
  3. WIZNETさんの製品はこの記事では使っていません。
    そのブログとは https://wiznetjapan.wordpress.com/ ですか?
    このような元記事の使い方であれば、許可を出せません。

    ブログがスタートしてから記事の紹介を検討してください。

    返信削除
    返信
    1. 純正品のArduino Ethernet Shieldには弊社のW5100チップが使用されています。

      今、準備中のブログには弊社の新製品紹介や、弊社の製品が使われたプロジェクトを紹介しようとしております。
      画相とともに簡略な紹介文を残す予定ですが、無論、詳細は元の出処で確認できるようにリンクでつなげるつもりです。

      ブログを公開するときまた連絡いたします、よろしければ上のメールアドレスで連絡先を残して頂けますか。

      何卒、前向きな検討を宜しくお願いします。
      失礼しました。

      PS.
      リンクのブログであっています、ただ今大々的な修正作業が行われておりますが、日本語の修正及び可読性を考慮した文章の再配置などを除いては基本的に紹介の仕方は一緒だと思います。しかし、かなり柔軟な運営をしておりますので、ご不満や意見がお有りでしたら、何でもおしゃってください。宜しくお願いします。
      それでは、失礼します。

      削除
    2. http://wizwiki.net/jp/

      今回、ブログをスタートしました。
      色々と参考できるガイドなどの翻訳や紹介が主な内容ですが、よろしければ、お目を通してください。

      削除