全体表示

[ リスト ]

高精度なRTC(リアルタイムクロック)には水晶発振子の温度校正を行うために
温度計が内臓されていて、通常は60秒おきに温度を測定して
RTCの32kHzという周波数を正確に保っているそうで、
OLEDには時刻と共にRTC内臓温度計の温度を表示しています。

イメージ 1
写真1. RTCの時刻とGPSの時刻および温度の表示

温度や湿度計測専用のセンサもあることは知っていたのですが、
大気圧まで3つ同時に測定できるBoschのBME280というチップを搭載したセンサが
売られていることを知ったので早速、アマゾンでで発注しました。

同センサのシリーズには温度と大気圧のみのBMP280というのがあるるので、
表品紹介ページで型番ばBME280であるおとと湿度が測定できることを確認して、
安全のために異なる2つの出品者に1個ずつ注文しました。
例によって中国大陸からの発送なので、到着まで2〜3週間かかります。

ほぼ同時に2個のセンサが届いたので、ESP8266とI2C接続して、プログラムを作ったのですが、
チップIDは0x60のはずが0x58、湿度補正に関するパラメータを読み出してもゼロが返ってきます。
双方の出品者に問い合わせるも、在庫がないので返金対応となってしまいました。
改めて別の出品者に注文しなおして待つこと2週間、またまたBME280ではなくBMP280でした。
ここまでで1ヶ月半ほどを無駄にしてしまいました。
ネットは諦めて、秋葉原にあるAitendoというお店に行って買ってきました。(BME280-6P)
湿度が測定できないBMP280は300円程度なのですが、湿度が測定できるBME280は800円と
少々お高くなっています。

これは製品毎に固有な補正パラメータを決めて書き込む手間がコストに跳ね返っているのでしょう。
恐らく、チップを治具に固定して恒温室にいれて、温度、湿度それに大気圧を複数回変更して
その時に出力されるADC(アナログ-デジタル コンバータ)の値を読み取って、補正パラメータを
計算して書き込んでいるのでしょう。
温度や大気圧は比較的簡単に変更可能ですが、加湿したり除湿するのは手間が掛かりそうですし、
目標値まで安定させるまで時間もかかるだろうなと想像されます。
このことがBME280のコスト増の要因になっているのかもしれません。

イメージ 2
写真2. BME280(右側)とBMP280(左側と中央)

ようやくBME280が入手できました。チップIDは0x60で、湿度補正パラメータも
それなりの値が入っていることが確認できました。
BMP280では温度と大気圧は補正計算で既にそれらしい値が計算できていま。

そこで湿度を補正計算してシリアルに出力してみたのですが、0%となってしまいました。
計算式はPDFのデータシートコピーして使用しています。

リスト1 BME280の湿度補正計算
uint32_t BME280_compensate_humidity(
    int32_t             adc_h,
    struct BME280_tag   *c
)
{
    int32_t     v_x1_u32r;

    v_x1_u32r   =   (c->t_fine - ((int32_t)76800));
    v_x1_u32r   =   (
                        (
                            (
                                (
                                    (adc_h << 14)
                                    -
                                    (((int32_t)c->dig_H4) << 20)
                                    -
                                    (((int32_t)c->dig_H5) * v_x1_u32r)
                                )
                                +
                                (   (int32_t)16384  )
                            ) >> 15
                        )
                        *
                        (
                            (
                                (
                                    (
                                        (
                                            (
                                                (
                                                    v_x1_u32r
                                                    *
                                                    (   (int32_t)c->dig_H6  )
                                                ) >> 10
                                            )
                                            *
                                            (
                                                (
                                                    (
                                                        v_x1_u32r
                                                        *
                                                        (   (int32_t)c->dig_H3 )
                                                    ) >> 11
                                                )
                                                +
                                                (   (int32_t)32768  )
                                            )
                                        ) >> 10
                                    )
                                    +
                                    (   (int32_t)2097152    )
                                )
                                *
                                (   (int32_t)c->dig_H2  )
                                +
                                8192
                            ) >> 14
                        )
                    );
    v_x1_u32r   =   (
                        v_x1_u32r
                        -
                        (
                            (
                                (
                                    (
                                        (v_x1_u32r >> 15) * (v_x1_u32r >> 15)
                                    ) >> 7
                                )
                                *
                                (   (int32_t)c->dig_H1  )
                            ) >> 4
                        )
                    );

    v_x1_u32r   =   ( v_x1_u32r <         0 )?         0 : v_x1_u32r;
    v_x1_u32r   =   ( v_x1_u32r > 419430400 )? 419430400 : v_x1_u32r;

    return( (uint32_t)(v_x1_u32r >> 12) );
}

上記のソースコードでは複数のBME280に対応できるように補正値などを
構造体のポインタ渡しにしてい、見やすいように対応する括弧をインデントで
位置を揃えています。

ADCからの読み取り値はゼロではないのに、計算の途中でゼロになっているようです。
そこで計算の途中の値をシリアルに出力して確認してみると案の定、途中でゼロになっています。
湿度に関する補正値はそれなりの値が読み取れています。
今一度、補正パラメータのアドレスとと対応を確認してみたところ、補正値読み取り関数に
誤りを見つけました。
符号ありと符号なし8ビットと16ビット整数が混在していることは注意していたのですが
湿度の補正パラメータだけ、上位4ビットと下位4ビットに分け、
それぞれ別の8ビットデータくっつけて12ビットにしているパラメータがあります。
しかもPDFファイルのページをまたぐ箇所に記述してあります。
間違った自分が悪いのですが、変則的な扱いをページの境界に記述するのもどうかと思います。
これでようやく湿度が計算できるようになりました。

温度は100で割った値が気温の整数値で、剰余が小数点以下2桁の値、
気圧は256で割った値がPa(パスカル)で、25600で悪とhPa(ヘクトパスカル)、
湿度は1024で割った値が0〜100%で、剰余が小数点です。
気圧と湿度の小数点以下の値は25600や1024で割った値を
必要に応じて小数点以下1桁なら10倍、2桁なら100倍しなければなりません。

また、補正値を保持する変数の符号あり/なしを間違っていたらしく、
湿度が63%までは上がるのですが、その先が1%になるというミスもありました。
変数ほ型はデータシート通りに正しく記述しましょう。


今回入手したBME280を搭載したモジュールはI2CとSPI接続の2つに対応しています。
SDOをハイインピーダンスにすると、SPI接続となり、
LowまたはHighにするとI2C(アドレスはLow:0x76, High=0x77)となります。
今回はI2C接続とし、2個購入したので同時に接続してOLEDに表示してみました。

イメージ 3
写真3. BME280を2個、I2C接続して温湿度・大気圧を測定

絶対的な精度は不明ですが、個体差はそれほどないようです。
また、温度と湿度のレスポンスが早いようで、センサに指を近づけただけで、
数秒で値が変化します。

イメージ 4
写真4. 指を近づける前の値と数秒後の値

手前のセンサに指を近づけて114秒で手前の湿度が10%近く上昇しました。
次に手持ちの温湿度計との比較を行ってみました。

イメージ 5
写真5. 温湿度計どうしの測定値

写真5. の上段は10年ほど前に購入した電波時計、中段は最近購入した安い温湿度計で、
下段はESP8266と温湿度・大気圧センサを組み合わせたの測定結果です。
上段の電波時計の表示値をずっと信用していたのですが、どうやら温度も
湿度も低めに表示されていたようです。
中段の温湿度計はほぼ同じ値を表示していますが環境の変化に鈍いようです。
下段の温湿度・大気圧センサは中段の安物の温湿度計に近い値が出ています。

ようやく温湿度および大気圧が表示できるようになりましたが、
解像度が低く、小さなOLEDでは現在値を表示するくらいしかできません。
時間の経過に伴う変化を記録して、それを表示できたらと思っています。
24時間〜数ヶ月の変化をグラフ表示で表示させてみたいですよね。
それにはもう少し解像度が高くて大型の液晶が必要です。

この記事に

閉じる コメント(0)

コメント投稿

顔アイコン

顔アイコン・表示画像の選択

名前パスワードブログ
絵文字
×
  • オリジナル
  • SoftBank1
  • SoftBank2
  • SoftBank3
  • SoftBank4
  • docomo1
  • docomo2
  • au1
  • au2
  • au3
  • au4
投稿

開く トラックバック(0)


.


プライバシー -  利用規約 -  メディアステートメント -  ガイドライン -  順守事項 -  ご意見・ご要望 -  ヘルプ・お問い合わせ

Copyright (C) 2019 Yahoo Japan Corporation. All Rights Reserved.

みんなの更新記事