以前の記事でスイッチサイエンスさんが公開しているPythonライブラリを使って、ラズパイと接続した温湿度センサー(BME280)を動作させました。
でもこれは動作確認をしたに過ぎず、実用的な使い方ではありません。そのため、これから温湿度センサーを実用的な使い方に昇華させていきたいと思います。
その始まりとして、今回はBME280を動かすC言語プログラムを実装します。ラズパイZeroは組み込み的なデバイスなので、やはりC言語で動かしたいですからね。
また、実装時のポイントもまとめたので、BME280に限らずデバイスの実装を行ってみようという方は参考にしてみてください。
ちなみに下記順で見ると、BME280の回路接続方法、温湿度サーバーの作成方法やクライアントアプリの作成方法といった、一通りのことがわかりますので、時間があれば最初からどうぞ。
- 【第1回】Raspberry Piで温湿度センサー(BME280)を動かしてみよう
- 【第2回】プログラムで温湿度センサー(BME280)を操作してみよう!C言語編 ← 今ココ
- 【第3回】温湿度を計測するサーバーの作成
- 【第4回】温湿度サーバーを複数接続に対応する方法
- 【第5回】温湿度を取得するクライアントアプリの作成(iOS版)
BME280操作プログラムの解説
下記のBME280データシートを元にコードを作成しました。
https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bme280-ds002.pdf
作成したコードは下記のgithubに入れています。
詳細まで説明すると長くなるため、インターフェース部分だけ解説します。
公開インターフェース
今回作成したコードでは下記3つのインターフェースを公開しています。
drv_bme280_init()
データ取得する前の初期化処理を行います。
引数:
struct drv_bme280_dev* dev
戻り値:
DRV_BME280_OK :初期化成功
DRV_BME280_ERROR:初期化失敗
ユーザーは引数の"dev"のメンバー2つに値をセットして呼び出す必要があります。
- char* dev_path
I2Cのデバイスファイルのパスをセットします。 - struct drv_bme280_settings
温度(osrs_t)・湿度(osrs_h)・気圧(osrs_p)のオーバーサンプリングの倍数と、IIRフィルター係数(iir_filter)をセットします。
オーバーサンプリングのセット出来る値は下記の6通り
DRV_BME280_OSRS_VALUE_SKIP:サンプリングなし
DRV_BME280_OSRS_VALUE_1 :1倍
DRV_BME280_OSRS_VALUE_2 :2倍
DRV_BME280_OSRS_VALUE_4 :4倍
DRV_BME280_OSRS_VALUE_8 :8倍
DRV_BME280_OSRS_VALUE_16 :16倍
IIRフィルター係数のセット出来る値は下記の5通り
DRV_BME280_IIR_VALUE_OFF:フィルターオフ
DRV_BME280_IIR_VALUE_2 :係数2
DRV_BME280_IIR_VALUE_4 :係数4
DRV_BME280_IIR_VALUE_8 :係数8
DRV_BME280_IIR_VALUE_16 :係数16
実際に設定しているコードは"example/user.c"を参照してください。
ちなみにexampleでセットしている値はデータシートの「3.5.3 Indoor navigation」(室内監視用)をセットしています。
drv_bme280_get_temp_forcemode()
温度・湿度・気圧を取得します。
引数:
struct drv_bme280_dev* dev:デバイス情報
struct drv_bme280_data* comp_data:データ格納領域
戻り値:
DRV_BME280_OK :取得成功
DRV_BME280_ERROR:取得失敗
BME280には「通常モード」と「強制モード」という2つのデータ取得モードがあるのですが、今回は「強制モード」で取得するインターフェースだけ用意しました。
「強制モード」では取得要求を行ったタイミングでBME280が温度・湿度・気圧の計測を行い、その値を読み出すことができます。
引数はdrv_bme280_init()が正常に完了したのであれば、drv_bme280_init()に渡した"dev"と、計測結果を格納する入れ物"comp_data"を渡すだけです。
こちらのインターフェースの使い方も、"example/user.c"をご覧いただければ簡単に分かると思います。
drv_bme280_exit()
終了処理を行います。
引数:
struct drv_bme280_dev* dev:デバイス情報
戻り値:
なし
drv_bme280を使い終わったら、このインターフェースを呼び出してください。処理内容としてはdrv_bme280_init()で取得したリソースを解放します。
ラズパイ上での動作確認
ラズパイの準備やクロスコンパイラ環境の構築は済んでいるものとして話を進めます。済んでいない方は下記の関連記事を参考に環境を構築してください。
まずは下記コマンドを実行してコードを取得します。
git clone https://github.com/radical-kei/BME280.git
コードの取得ができたら、下記コマンドを実行してディレクトリを移動します。
cd BME280/example/simple
ディレクトリ移動が済んだら、下記コマンドを実行して実行ファイルを生成します。
mkdir build
cd build
cmake ..
make
これで"sample_bme280"というファイルが生成されるので、下記コマンドでこのファイルをラズパイ上に送ります。(ホスト名を変更している場合は合わせてください)
scp sample_bme280 pi@raspberrypi.local:
あとはラズパイにSSH接続して実行ファイルを実行すると、温度・湿度・気圧が取得できます。実際に実行するとこんな感じ。
pi@raspberrypi:~ $ ./sample_bme280
24.12 deg C, 991.77 hPa, 43.68%
実装におけるポイント
さて、今回はBME280を動作させるコードをC言語で実装したわけですが、いくつか実装時におけるポイントがあります。
BME280に限らず、デバイスを動かすコードを実装する上で抑えておくと良いポイントなので、ぜひ参考にしていただければと思います。
ポイント1:データシートをよく見る
デバイスを動かすときデータシートを見て実装する必要がありますが、さらっと眺めるのではなく、隅から隅まで見ることをお勧めします。
今回のBME280のデータシートでもそうですが、重要なことが案外サラッと書いています。
たとえばBME280のデータシートをよく見ると、以下のようなことがサラッと書いています。
- "ctrl_meas"レジスタへの書き込みは、"ctrl_hum"を変更した後でないと反映されない
- read時はアドレスが自動インクリメントされるが、write時は自動インクリメントされない
など
この辺りを見逃すとデバイスが思い通りに動作せず、プログラミングの闇に飲まれてしまいます。早くコードを書きたくなる気持ちをグッと抑えて、データシートをよく見ましょう。
ポイント2:少しずつ機能を盛る
今回作成したコードもそうですが、いきなり全部の機能を盛々にせず、一部の機能から実装していくことをお勧めします。
一部の機能を実装して動かすことで、そのデバイスの特性を把握することができますし、実装のポイントも見えてくることが多いです。
BME280は比較的機能の少ないデバイスですが、より機能の多いデバイスになると、さらにこの「少しずつ機能を盛る」ということが重要になってきます。
ポイント3:リファレンスコードが無いか探す
実装を進めていると、「本当にこれで合っているのか?」という疑問を持つ場面があります。そんなときに役立つのがリファレンスとなるコードです。
今回で言えばPythonで実績のあるコードが合ったのでそれを参考にしたり、BME280のデータシートを読み進めると、デバイスの製造元であるBoshcもコードを公開していました。
このように参考になる、または指標になるコードがないかを探しておくと、実装中の迷いを軽減することができますよ。
余談
BME280のデータシートを読むと「基本的にBosch Sensortecが提供しているAPIを使った方がいいぞ」的なことが書かれていたので、「これがあれば楽できる!」と思い下記リンクからソースコードを取得することにしました。
そして、取得したコードを動かしてみたのですが…動きませんでした(汗)
コードを見てみると"linux_userspace.c"がぶっ壊れてるように見えます。そこでPull Requestを見てみたのですが、やはりバグってるらしい…だけどマージが一向にされていない状況のようです。
他にもopenしたドライバをcloseしていなかったり(exitでcloseされるが明示的にした方が良いと思っている)、測定待ち時間がms単位で戻ってくるのにus単位でsleepしていたりと、ちょいちょい怪しいところがあります。
おそらくAPI側(bme280.c)は問題ないと思いますが、バグが仕込まれたコミットID "bdf4e57" のコミット内容が不穏すぎるので、とりあえず今回は簡易的にBME280を動かすコードを自作することにしました。
コメント