気圧センサー(MPL115A1)で大気圧と標高を測定して見ます

〔MPL115A2〕 〔LPS331AP/LPS25H〕   〔Arduinoの動かせ方入門に戻る〕


PS.  *1)
センサーを壊したと思い新しくセンサーを購入して下記実験を再度行ったのですがぁ
なんだかデータを上手く読み込めないです、最初は動いていたのですがぁ.....
読み込めてもデータ値がえらく上下ふらついておかしいです。
(動いていた時は10hPa以内に収まっていたのですが)
他のサイトのサンプルスケッチを動かしても同じでだめです。
SPIのタイミングがずれている様な感じでぇ、センサーがデータを読めていない様な気がします、
でもぉ、ArduinoのSPIライブラリを使っているしぃ、センサー側が少し独特なタイミング?
こんな時は何時もロジックアナライザーが欲しいと思う今日この頃............
やり方が有るのかもですがぁ、よく分かりません、めげてしまいました、アナライザー...欲しい...。
ですので原因がわかるまでは下記記事は参考程度に考えて下さい。
(実験する人はとりあえずぅMPL115A2を利用しましょう)


 農作業をしているとぉ、とってもお天気が気になる今日この頃、
朝からネットで天気予報と雲の流れを見たりすればなんとかぁ本日の天気は大体わかるのですがぁ.
....ゲリラ豪雨とかぁ急な夕立なんかまではねえ.....
そんなこんなでぇ、ゆくゆくは大気圧のデータをSD辺りに書き込んでその推移から予想するような事をって思っては いるのですがぁ、まずは気圧センサーを動作させてみなくてはですね。
で、本日のセンサーはMPL115A1です、 これはピエゾ抵抗型の半導体式センサーです。
SPI接続で、秋月電子で一番安い、しかもモジュールになっています。

尚、I2C接続でのMPL115A2センサーの記事はこちらを参照下さい。
また、ArduinoでSPIの基本概要等はこちらを参考にして下さい。

この頁ではArduinoとMPL115A1でSPI接続を行い、大気圧を表示させて見ます。
それと、標高(高度)の計算をさせこれも表示させて見ます。

MPL115A1の秋月電子にあるデータシートは古いです。
なので、こちらを見て下さい、 レビジョン(Rev 6,10/2011)が新しいです、
新しいデータシートは校正係数のC11とC22は使用しない様に変更されています。
おそらく今までもこの係数を読み出しても0で意味がなかったのではと思えます。

《 配線図 》

配線図
左図のMPL115A1は右上がピン1番です。

  ピンの構成図

4−5番ピン間に有るLEDは電源通電用です。
また、電源ラインにはパスコンも付いています。

SHDNピンについて
通常はVDDに接続します、GNDに接続すると スリープ状態に移行し1uAの消費電流になる様です。
(LEDは点灯したままだけどね)


《arduinoのスケッチ》

@上記の回路の様に配線を行います。

Aarduinoボード(Arduino Duemilanove 328)はUSBケーブルで接続して、arduino IDEを起動させます。

BIDEに下記のスケッチプログラムをコピーペーストして貼り付けて下さい。
 スケッチをダウンロードしたい方はこちら。(Arduino IDE 1.0.1にてコンパイル)
 ダウンロードスケッチの保存先と開き方はこちらを参照下さい。
---------------------------------------------------------------------
#include <SPI.h>
#include "pins_arduino.h"

#define AVE_NUM     20                    // 圧力・温度のA/D変換値を平均化する回数
#define H_CORRECT   80                    // 自宅でのセンサと実際の高度差補正値(My自宅の標高は100m)

float a0 , b1 , b2 , c12 ;                // 係数のデータを保存する変数
unsigned long Press , Temp ;              // 圧力および温度の変換値を保存する変数

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

     delay(3000) ;                        // 3Sしたら開始
     CoefficientRead() ;                  // メモリーマップから係数を読み出して置く
}
void loop()
{
     int i ;
     float ans ;
     unsigned long p , t ;

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

     ans = PressureCalc() ;               // 気圧値の計算を行う
     Serial.print(ans) ;                  // 気圧値の表示を行う
     Serial.print(" hPa    ") ;
     ans = AltitudeCalc(ans,H_CORRECT) ;  // 高度の計算を行う
     Serial.print(ans) ;                  // 高度の表示を行う
     Serial.println(" m") ;

     delay(1000) ;                        // 1秒後に繰り返す
}
// メモリーマップから係数を読み出す処理
void CoefficientRead()
{
     unsigned int h , l ;

     digitalWrite(SS,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(SS,HIGH) ;              // SS(CS)ラインをHIGHにする
}
// メモリーマップから圧力および温度のA/D変換値を読み出す処理
void PressureRead()
{
     unsigned int h , l ;

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

     digitalWrite(SS,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(SS,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(SS,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 ;
}
// 気圧値(hPa)から高度を計算する処理
float AltitudeCalc(float pressure,int Difference)
{
     float h ;

     h = 44330.8 * (1.0 - pow( (pressure/1013.25) ,  0.190263 )) ;
     h = h + Difference ;
     return h ;
}
---------------------------------------------------------------------
CIDEツールバーの赤枠部分「Upload」ボタンをクリックしてコンパイルとarduinoボードに書込みを行い
 ます。

upload

D正常終了後、画面の右側に有るアイコン「SerialMonitor」ボタンをクリックしてシリアルモニター画面
 を起動させます。
実行結果1
 この左図の様に表示されると思います。
 この表示データは、圧力・温度のA/D変換値の生データを
 20回読み込んで単純平均化したデータで計算させた内容です。
 左数値が大気圧で、右数値が高度の値を表示しています。

 まだ、2hPa程ふるふるしていますね〜、
 2hPaの差を高度に変換したら10m〜20m位の差が有りそうですね〜
 本当は移動平均の方が良いのですけどね、
 めんどいのでパスでーす。

 圧力・温度のA/D変換値のデータと校正係数データから大気圧を
 計算させるにはめんどくて複雑な処理をさせないとだめですが、
 この頁ではその説明は省きます、興味が有る人はデータシートや
 他のサイト様を参考にして下さい。

 この左のデータは2012/12/25 温度3℃ 標高100m 外は曇り です。
 また、計算した高度に+80m補正を加えた内容で表示されています。


スケッチについて

スケッチはArduinoのSPIライブラリを使用しています、SPIライブラリについては
「Arduino 日本語リファレンス」を参照下さい、または、こちらの頁を参照下さい。

尚、このセンサー(MPL115A1)のSPIクロックは最大8MHzまでとなっています、
今回のスケッチは4MHzで使用しているので8MHzにしたい人は下記の様に変更して下さい。
     SPI.setClockDivider(SPI_CLOCK_DIV2) ;// クロック(CLK)をシステムクロックの1/2で使用(16MHz/2)

CoefficientRead( )
 校正係数が工場出荷時にセンサー内部のメモリマップに保存されています、大気圧を計算する時に
 利用するのでこれを読み出して置く必要が有ります、立ち上げ時に1回読み出せばOKです。
 係数はa0,b1,b2,c12の4つです。
 古いデータシートのレビジョンではc11,c22も使用していたのですが新しいレビジョンでは使いません。

PressureRead( )
 メモリーマップから圧力と温度のA/D変換値データを読み出します。
 読み出したデータはそれぞれ Press 、Temp の変数に格納されます。
 注意として、ここで読み出す温度データ(Temp)は実際の温度として利用するには無理っぽいです。
 なので、温度を測定したい人は別に温度センサーを用意しましょう。(温度センサーの話はこちら)

 このスケッチではこのデータを20回読み込んで単純平均化して計算で使用します。
 20回を変更したい人は下記の部分の数値を変更して下さい。
  #define AVE_NUM     20                  // 圧力・温度のA/D変換値を平均化する回数
ans = PressurCalc( )
 読み出した係数と圧力・温度のA/D変換値データから大気圧を計算します。
  ans : 大気圧値を hPa (float)で返します。

ans = AltitudeCalc(float pressure,int Difference)
 大気圧のデータから高度(標高)を計算します。
 ICAO(国際民間航空機関)標準大気での計算になります
 (平均海水面での気圧が1013.25hPa、気温が15℃、対流圏の約11km以下での条件となります)
 なので実際は場所や季節や天気状態等でICAO標準大気と誤差が出るので補正が必要でしょう。
  pressure :計算した大気圧値を hPa でセットします。
  Difference:標高の差を指定します。(下のH_CORRECTについてを参照下さい)
  ans     :高度値を m (float)で返します。

  H_CORRECTについて
    #define H_CORRECT   80                // 自宅でのセンサと実際の高度差補正値(My自宅の標高は100m)
  これはセンサー値から計算した高度値(ICAO標準大気)と実際の高度値(実測する場所)に誤差が
  有る為の補正値用データです。
  まず、自宅でセンサー値から計算した高度値を表示させます。(H_CORRECT=0で計算させる)
  次に調べた自宅の高度と表示させた高度値の差をH_CORRECTにm値で変更して下さい。
  この操作は天気が穏やかな日が良いでしょう。(我が家では80mの差が有りました)
  尚、自宅の標高を調べるには、こちらの国土地理院のWeb地図で分かります。

実行結果2  高度補正操作について

 H_CORRECTの補正を行っても、季節や天気状態などなどで常に毎日
 誤差がしょうじます。(大気圧が変化します)
 左のデータは2012/12/28 温度7℃ 標高100m 外は雨での内容です、
 上のシリアルモニター画面結果表示と比べて見て下さい。
 10hPa位違います、高度で100m位違いますね。

 だから高度計を使用する時に高度補正操作が必要になって来ます。
 例えば登山を行う場合、標高が分かっている場所で高度値を表示させ、
 その差を加えて表示させて校正します、
 以降しばらくは表示される高度は大体合うはずです。
 そして、この校正から1時間たったら、または500m程の標高差に達したら
 標高が分かっている場所でまた校正しなおします。
 と、この様な高度補正操作が随時出来る様な仕組みを作らないとだめでしょうね。


ライブラリについて

上記のサンプルスケッチを簡単に利用出来る様にライブラリ化して置きました。
ライブラリを利用したい人は↓からダウンロードして下さい。
skMPL115A1.lzh(2012/12/27)

解凍すると下の様に展開されます。
[skMPL115A1]─┬─[examples]───[Pressure]--- Pressure.pde
        ├ skMPL115A1.cpp
        ├ skMPL115A1.h
        └ keywords.txt
ArduinoIDE 1.0.1 がインストールされているフォルダー、インストール先を変更していないなら
[C:\Program Files\arduino-1.0.1\libraries]です。
この場所に上記解凍ファイルを[skMPL115A1]ディレクトリ丸ごと移動します。
また、ライブラリの登録や利用方法などの話はこちらを参考にして下さい。

《その他》

実験風景
 左写真は実験時の物です。

 ん〜ん、なんとなくもう一歩
 デンプシィロールがぁ、じゃ〜なっくてぇ
 精度が欲しい様なぁ、
 そんな感じがぁしますぅ、みたいなぁ
 お天気予報を行うにはこのセンサーでも
 OKでしょうが?、たぶん、きっとぉ、
 高度計を作るならこちらのセンサーが
 高分解能で性能が良くて、温度センサー
 出力も有ります、
 ただちょっとぉ、お値段お高いですがね。
 (まぁその内購入出来たら実験ですかね)

 お天気予報の実験はその内にでも行う
 と言う事でぇ.....
 (データ取るのがメンドそうなのでぇ..)
 お天気予報はこちらo-Familyさん
 を参考にして下さい。




追記(*1) 2013/01/15


【きむ茶工房ガレージハウス】
Copyright (C) 2006-2013 Shigehiro Kimura All Rights Reserved.