気圧センサー(LPS25H)で大気圧を測定して見ます

〔MPL115A2:I2C〕   〔PICの動かせ方入門に戻る〕


前回の記事でMPL115A2を搭載した大気圧センサーモジュールで気圧と高度を測定して見ました。
がぁ、精度や分解能等の性能が今一つでした。今回は、LPS25Hで測定を行って見ます、
これは精度±0.2hpa(25℃)と良さげな感じです、それに、温度(精度±2℃)も読み出せます。
LPS25HはLPS331APの後継機の様です、FIFO機能が付いているので移動平均が行えそうですね。
また、接続はI2CとSPIの好きな方が選べます。

ここではLPS25Hを使いデバイスで移動平均を行わせてみます、接続はI2Cで行います
尚、SPIで接続の話やLPS331APの話はArduinoのこちらの記事を参照下さい。

LPS25Hは秋月電子のこちらから買っています、ピンの半田付けはしないとダメです。
データシートは秋月電子の販売ページかこちらからダウンロードしましょ。
或いは、O-Familさんのこちらで個人的に翻訳された物が置いて有ります。 *2)
現在、秋月電子ではLPS25Hの後継機LPS25HBとなっております。 *3)

《FIFO機能》

通常はセンサーの値を読み出したらマイコンで平均値を算出するわけですが、LPS331AP/LPS25Hは
デバイス内部でデータを単純平均(1〜512回)してくれます、
ですのでデバイスから読み出している圧力・温度値はこの平均値を読み出している事になります。
でぇ、LPS25Hには更にFIFO(First-In,First-Out)機能が搭載されているのでデバイス自体が移動平均を
行ってくれます
、これを利用すればマイコンで移動平均処理はしなくても良くマイコンの負荷を減らす
事が出来ます。

FIFO機能はレジスタに設定を行うだけで後は圧力値(PRESS_OUT_XL/PRESS_OUT_L/PRESS_OUT_H)
を読み出すだけです。
FIFOの設定は、
・CTRL_REG2(21H)のFIFO_EN(6bit)をON(1)にしてFIFO機能を有効にします。
・FIFO_CTRL(2EH)にてFIFOの動作モード(F_MODE)と移動平均のサンプル数(WTM_POIN)を指定
 します。
 サンプル数は2,4,8,16,32の内から選び、圧力値は3ByteなのでMAX 32x3のFIFOバッファが有ります。

FIFOの入力圧力測定値の収集は、CTRL_REG1(20H)のODR(bit6-4)にて指定した出力レート毎に
行われ、RES_CONF(10H)のAVGP(bit1-0)で指定した内部平均数で平均した内容がFIFOバッファに
送られます。(今回の設定は、出力レートが"1Hz"で、内部平均数が"32")

FIFOのモード

FIFOには4つのモードが有り、FIFO_CTRL(2EH)のF_MODE(bit7-5)にて指定します。

バイパスモード(F_MODE="000")
  FIFOは動作しない、FIFOのバッファは空のままです。
  測定値はPRESS_OUTレジスタに直接で送られます。

FIFOモード(F_MODE="001")
  センサからの測定値は、FIFOバッファに送信されます。
  CTRL_REG2(21H)のWTM_EN(5bit)を有効にすると、バッファが満杯になればウォーターマーク
  割込みが発生します。 バッファが満杯になると、FIFOは、入力圧力測定値の収集を停止します。
  (圧力値を読み出せば、測定値の収集が再開されるのかは実験していません (|||_|||)ガビーン )

ストリームモード(F_MODE="010")
  FIFOモードと同じだがデータは古い順にすてられますので収集の停止はないです。

  FIFOモード/ストリームモードとも移動平均の算出は行われません、自分でデータを読み出さないと
  ダメです、例えば、バッファサンプルが4個ならPRESS_OUTレジスタから4回(4x3Byte)連続して
  読み出す事になります、って事は28Hの先頭番地から12回(4x3Byte)連続読み出しを行えば後は
  デバイスが自動的にアドレスを操作してくれます
  (読み出した後は自分で平均処理をマイコンで行う事になります)

FIFO移動平均モード(F_MODE="110")
  バッファがサンプルの個数溜まったら、データレート(ODR)毎に移動平均されPRESS_OUTレジスタに
  送り出されます。
  このモードは低消費電力での圧力のノイズを低減する為には有効らしい。
  CTRL_REG2(21H)のFIFO_MEAN_DEC(bit4)をONにした場合、出力データレートは"1Hz"固定となり
  バッファサンプル数や内部平均数の組み合わせは"ODR"ビット指定で決まるらしい。
  (下のサンプルプログラムはこのモードでFIFO_MEAN_DEC=OFFでの内容となります)

後ぉ、他に<Extra FIFO modes>が有ります、これは上の4つのモードの組合せみたいなモードです。
トリガ信号とは、INTERRUPT_CFG(24H)によって構成されたINT_SOURCE(25H)のIAビット[2]です。

BYPASS TO STREAM MODE (F_MODE="100")
FIFOは、トリガーイベントまでBYPASSモードである。その後、ストリームモードが起動します。
Stream to FIFO mode (F_MODE="011")
Bypass to FIFO mode (F_MODE="111")

FIFO機能時の温度値読出しについて

FIFO機能が無効時は、レジスタ28Hから連続5Byte読み出せば圧力・温度値が取り出せますが、
例えば)
   PressureReceive(0x28,&dt[0],5) ;
とすれば[28H]>[29H]>[2AH]>[2BH]>[2CH]とデバイスがアドレスを自動で操作します。

FIFO機能が有効になると
[28H]>[29H]>[2AH]>[28H]>[29H]>[2AH]...と言った感じにアドレスが操作されます。
だから温度値は連続では読み出せないです、別途読み出す必要が有ります。
例えば、FIFO移動平均モードとする)
   PressureReceive(0x28,&dt[0],3) ;
   PressureReceive(0x2B,&dt[3],2) ;
とこんな感じです。
尚、FIFOモード/ストリームモードで"4 samples"なら
   PressureReceive(0x28,&dt[0],12) ;
   PressureReceive(0x2B,&dt[12],2) ;
とこんな感じでしょうか。

《 配線図 》

ピンの構成図(PIC)   ピンの構成図(LPS25H)

PICの今回使用するピン番号は20番(VDD)と8/19番(VSS)
を電源に配線します。
I2C関連ピンは14番(SCL)と15番(SDA)です。

LCDは秋月電子の"I2C接続小型LCDモジュール"を使っています、LCDの詳しい記事はこちら
参照下さい。
電源はセンサとLCD表示器が3.3Vなので回路も3.3V電源で統一しています。

配線図  モジュールもPICも右上が1番ピンです。

 小さいブレッドボードに16F1938では少し窮屈
 ですねぇ、約6K(word)程のプログラムサイズ
 なのでその辺でもう少し小さいPICをチョイス
 すれば良いでしょう。

 I2C用プルアップ抵抗ですが、16F1938は
 RC3/RC4のピンでは内部プルアップ抵抗は
 利用出来ないので外付け4.7KΩとしています。

 尚、モジュールやLCDの裏にプルアップ用半田ジャンパーが有るには有ります。

モジュールピンについて

SPIも配線出来るのですが、ここではI2C配線のみ記述して置きます。
SCL(2)/SDA(3)がI2C用接続ピンです。

SAO(4)ピン
 I2Cデバイス・アドレスの下位ビットを決めるピンです。
 VDDに配線すると7ビットアドレスで"1011101:0x5D"となります、
 GNDに配線すると7ビットアドレスで"1011100:0x5C"となります、
 なので同じI2Cバス上には2個まで接続可能です。

アドレス設定  アドレスは7ビットで表します、左図の1〜7ビットです。
 0ビット目はR/Wでこれはデバイスに対する読書き指示ビットです。
 R/W=0 : 書き込み要求です(デバイスは受信モード)
 R/W=1 : 読み込み要求です(デバイスは送信モード)

 今回はVDDに接続していますのでアドレスは、"1011101"(0x5D)です。("1011101"+R/W)
 R/W=0書込みなら"1011101"+"0"で0xBA、R/W=1読込みなら"1011101"+"1"で0xBBとなります。
 よってここでは
 #define LPS25H_ADRS  0x5D  // デバイスのI2Cアドレス(SDO/SAO is HIGH)
 となっています。

CS(5)ピン
 このピンをVDDに接続するとI2Cモードでの通信となります。

INT1(7)ピン
 デバイスから割り込みを出力するピンです、今回は使っていません。
 この割り込みは、設定閾値の圧力より高い/低い場合に出力する時と
 デバイスが新しい圧力データを測定しレジスタに書き込んだ事を知らせる時の場合が設定可能です。
 また、FIFO機能でも利用します。

《ダウンロードプログラムについて》

↓ここからサンプルプログラムソースファイルをダウンロードして下さい。
LPS25H.lzh ライブラリを更新 *1)

プログラムソースをダウンロードしたら、MPLAB Xにてプロジェクトを作成します。
以下のファイルをプロジェクトディレクトリにコピーしてプロジェクトに取込んで下さい。
次にコンパイルPIC書き込みを実行して下さい。
MPLAB(R) XC8 C Compiler Version 1.32コンパイラを使用しています。

ダウンロードファイルを解凍すると下記の様なファイル構成です。
 Pressure.c・・・・・・ 本体のプログラムソースファイル
 skLPS25H.c・・・・・ LPS25Hライブラリ関数ソースファイル
 skLPS25H.h・・・・・ LPS25Hライブラリ用インクルードファイル
 skI2CLCDlib.c・・・ I2C接続LCDライブラリ関数ソースファイル *1)
 skI2CLCDlib.h・・・ I2C接続LCDライブラリ用インクルードファイル *1)
 skI2Clib.c・・・・・・・ I2C通信を行う関数ソースファイル *1)
 skI2Clib.h・・・・・・・ I2C通信を行う関数のインクルードファイル *1)

 尚、CPUのクロックは8MHzを想定しています。
 なので通信速度等(I2C)はシステムクロック8MHzで計算されています。

Pressure.c

実行結果表示  約4秒後位でこんな感じに表示すると思います、
 1行目が気圧(hPa)で2行目が温度(℃)です。
 尚、"Init NG"が表示された場合は、IDチェックエラーか、デバイスが応答
 していません、配線等を見直して見ましょう。

下の様に記述されています、システムクロックやI2Cアドレスを変える人は書き換えて下さい。
 #define _XTAL_FREQ  8000000  // 使用するPIC等により動作周波数値を設定する
 #define LPS25H_ADRS 0x5D     // LPS25HのI2Cアドレス(SDO/SAO is HIGH)

skLPS25H.h

LPS25H関数のインクルードファイルです。
"skLPS25H.c"を利用する場合に
#include "skLPS25H.h" をプログラムの先頭で記述して下さい。

今回は8MHzで利用しているので、
 #ifndef _XTAL_FREQ
  // Unless already defined assume 8MHz system frequency
  // This definition is required to calibrate __delay_us() and __delay_ms()
  #define _XTAL_FREQ 8000000    // 使用するPIC等により動作周波数値を設定する
 #endif
と記述しています、8MHz以外で利用する人は"8000000"を書き換えて下さい。

skLPS25H.c

このライブラリはLPS25Hの移動平均で読み出す機能のみです、割り込みやワンショット読出し等の
機能は有りません。

この関数集にはskI2Clib.c/skI2Clib.hのファイルが必要です。
この関数集を利用する場合は、"skI2Clib.c"の"InitI2C_Master( )"関数を呼び出した後使います、
また、この関数集自体は他のPICでも利用可能でしょう。

LPS25H用関数の使い方を説明します。

ans = PressureInit(id,address)
 デバイスの初期値設定を行う処理です。
 デバイスの動作を確かめる為にデバイスIDのチェックを行い、エラーならans=6を返します。
 分解能のモード(内部平均の数)設定は、デフォルト動作です。
 制御レジスタ1は"動作中モード","1Hzの更新速度",Bit3-0=0 で初期化しています。
 FIFOは"移動平均モード"と"8sample"での初期化です。
 初期化データを変更する場合は、skLPS25H.hのRES_CONF_DATA/CTRL_REG1_DATA等を書き
 換えて下さい。(詳しい設定はデータシートを見ましょ)
 尚、エラー時は制御レジスタの設定は行っていません。

  id         :デバイスの識別IDを指定します(LPS25H=0xBD)
  address :デバイス(スレーブ)のI2Cアドレスを指定します(0x5D or 0x5C)
  ans       :戻り値   0=正常終了、それ以外はエラーです
               1=異常(相手からACKが返ってこない)
               6=デバイスのIDチェックエラー

 ※ "1Hzの更新速度"に設定されているので圧力・温度値データは1秒毎に更新されます。

ans = PressureReceive(reg_adrs,*data,kosu)
 デバイスから指定個数のデータを受信する処理です。
  reg_adrs:読出すデータのレジスターアドレスを指定する
           連続的に読出す場合は、読出すレジスターの先頭アドレスを指定
  *data    :読出したデータの格納先を指定する(格納先配列の個数はkosu分確保する事)
  kosu     :読出すデータのバイト数を指定する
  ans       :戻り値、0=正常終了 1=異常(相手からACKが返ってこない)

ans = PressureSend(reg_adrs,*data,kosu)
 デバイスに指定個数のデータを送信する処理です。
  reg_adrs:書出すデータのレジスターアドレスを指定する
           連続的に書出す場合は、書出すレジスターの先頭アドレスを指定
  *data    :書出すデータの格納先を指定する
  kosu     :書出すデータのバイト数を指定する
  ans       :戻り値、0=正常終了 1=異常(相手からACKが返ってこない)

ans = PressurePD(mode)
 デバイスの"パワーダウン"と"動作中"を切り替える処理です。
 パワーダウン状態から動作中モードへの待機時間は、1msec必要です。
 電源ON時はパワーダウン状態です、
 尚、パワーダウン状態時に圧力・温度値を読み出しても内容は不定です。
  mode     :0=パワーダウンモード , 1=動作中モード の何れかを指定する
  ans       :戻り値、0=正常終了 1=異常(相手からACKが返ってこない)

ans = PressureRead( )
 圧力・温度をデバイスから読込み大気圧値と温度値を計算する処理です。
 計算された大気圧値(hPa)はPress変数に、温度値(℃)はTemp変数に其々格納されます。
 尚、Press/Temp変数はfloat変数で宣言されています。
  ans       :戻り値、0=正常終了 1=異常(相手からACKが返ってこない)

ans = AltitudeCalc(float pressure,int Difference)
 気圧値(hPa)から高度を計算する処理。
 この関数についての説明はArduinoとMPL115A1のこちらの記事を参照下さい。

skI2CLCDlib.c
skI2CLCDlib.h
skI2Clib.c
skI2Clib.h

この内容は”秋月電子I2C接続小型LCDモジュールに表示を行う”を参照下さい。

尚、システムクロックを変えた人は"skI2Clib.c"ファイル内の"InitI2C_Master( )"関数と、
"skI2CLCD.h"のファイルを変更する必要が有ります。
また、LPS25HはI2C通信速度が100KHz/400KHz対応です、ここでは100KHzで行っています。

《その他》

実験風景  左は実験時の風景ですがやっぱり16F1938ではスペースがぁ....

 下はArduinoで実行させた[LPS25H]と[LPS331AP]の表示内容です。
 LPS25Hが6hPa程高いのが解せないですよね、色々設定など変えて
 動作させても大して変わらないです、何故なのだろう?
  実験風景




リンク切れ見直し(*3) 2020/03/25
一部追記(*2) 2017/01/11
ライブラリ変更(*1) 2015/10/14


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