連日のMARK-X赤道儀モータードライブ製造 ― 2021年09月23日 20時36分12秒
コピペ記事が技術をダメにする ― 2017年09月28日 06時25分30秒
Sensirion製温湿度センサーの湿度が100%になる? ― 2016年05月09日 07時34分56秒
現象
Weatherduinoという製品のサンプルライブラリをベースにセンシリオン製のSHT-11という温湿度センサーからのデータ取得を行っておりました。
ソースコードを何度確認してもデータシート通りの演算のように見えるのに、観測結果の湿度がいとも簡単に頻繁に100%に達してしまうのです。
Weatherduino用のライブラリはこちらから入手可能です。
このセンサーの入手はストロベリーリナックスが比較的安くて良いでしょう。
Weatherduinoのサンプルプログラムのバグ
さて、本題です。 上記の菅工房のサンプルライブラリG7Weather3.cppのSHT-11の処理では以下の演算部分があります。
// SHT11 温度(℃)・湿度(%)取得
void G7Weather::get_sht11 (float *temp, float *humi) {
unsigned short sot, sorh;
float t, rhl, rht;
// 温度読込み
sht_tsseq();
sht_write(0x03);
SHT_SDA_H;
while (SHT_SDA); // 変換終了待機
sot = (unsigned short)sht_read(1) << 8;
sot |= sht_read(1);
sht_read(0);
// 湿度読込み
sht_tsseq();
sht_write(0x05);
SHT_SDA_H;
while (SHT_SDA); // 変換終了待機
sorh = (unsigned short)sht_read(1) << 8;
sorh |= sht_read(1);
sht_read(0);
// 温度補正 14bit (3.3V)
sot &= 0x3fff;
t = -39.66 + 0.01 * (float)sot;
*temp = t;
// 湿度補正 12bit
sorh &= 0x0fff;
// rhl = -4.0 + 0.0405 * sorh + (-2.8 * 0.000001) * (sorh * sorh); // Ver.3
rhl = -2.0468 + 0.0367 * (float)sorh + (-1.5955 / 1000000.0) * (float)(sorh * sorh); // Ver.4
rht = (t - 25.0) * (0.01 + 0.00008 * (float)sorh) + rhl;
if (rht > 99.0) rht = 100.0;
*humi = rht;
}
この処理の中でのバグは以下です。
(float)(sorh * sorh)
この部分だけですね。問題があるのは。 sorhという変数はunsigned shortで有効なデータは12ビット分です。単独で使う場合は16ビットで十分ですが2乗すると演算結果は16ビットでは足りなくなります。
バグ修正
なので、以下のように修正の必要があります。
(float)((long)sorh * (long)sorh)
観測データは12ビットなので最大値は4095となります。 それを2乗すると16769025となり16ビットの最大値である65535を 超えてしまっていたわけです。
一方、符号付のlongの正の最大値は2147483647ですので十分に格納可能になります。 この修正により、湿度が簡単に100%になる問題は解消しました。 原因解明に3年かかりました。
ちなみに、写真の基板はWeatherduinoではなく自作品です。 ArduinoUnoとの組み合わせで使っています。






























最近のコメント