最近、MEMSセンサのBME280は価格も安くなり、I2Cインターフェースでつなぐと配線量も少なく、とても使いやすいです。温度のレスポンスはそれほど良くありません。湿度はすぐに反応します。気圧は、机の上に置いていてもほとんど変化しません。
BME280データシート
https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BME280-DS002.pdf
コピペができません。
日本語になっているデータシート。個人の方のページです。
http://www.ne.jp/asahi/o-family/extdisk/BME280/BME280_DJP.pdf
ソースです。https://github.com/BoschSensortec/BME280_driver
AdafruitのArduino用ライブラリです。https://github.com/adafruit/Adafruit_BME280_Library
###ラズパイの設定
アドオンのハードウェアサポート・パッケージをクリックすると、アドオンエクスプローラーが立ち上がります。その中のMATLAB Support Package for Raspberry Pi Hardwareをインストールします。アドオンエクスプローラーの右上のアドオン管理をクリックします。アドオンマネージャが立ち上がります。右上のアドオンの入手からラズパイのパッケージをインストールします。
執筆時の環境です。
- matlabはR2020b update1
- ラズパイはRaspberry Pi 4 Model B 2MB
- Support Packageはバージョン20.2.1
インストールの経過は省略します。
インストール後、IPアドレス、ユーザ名、パスワード、ホスト名は控えておきます。後で探すと見つかりません。デフォルトでは、 'pi', 'raspberry'に設定されているので、セキュリティ的に不安な方はパスワードをsshでログインして変更してください。
###センサBME280の接続
アマゾンやebayでとても安いBME280を購入すると、送られてくるのはBMP280です。センサは長方形をしています。BME280は真四角です。温度と気圧は、どちらも同じソフトが動きます。
ブレークアウト・ボードが6ピンタイプだと、I2Cは次のように配線します。I2Cの設定は、基板上で配線がすんでいますが、確認してください。
秋月電子通商の6ピンは、取説に従ってジャンパを配線し、I2Cの設定にしてください。
4ピンは、I2C専用なので、4本を配線するだけです。I2Cバスはプルアップ抵抗が必要ですが、ラズパイには本体に実装されています。
接続の確認をするため、I2Cのスキャナ関数で、スレーブ・アドレスを表示します。
clear all
%rpi = rpi = raspi('192.168.111.114', 'pi', 'raspberry'); % host name raspberrypi-uMchsTIvew
rpi = raspi
for i = 1:length(rpi.AvailableI2CBuses)
scanI2CBus(rpi, rpi.AvailableI2CBuses{i})
end
多くは0x76にスレーブ・アドレスが設定されています。配線に使ったピンが一番一般的なバス1です。バス0は普通は使いません。現状四つや五つに拡張できますが、matlabで使えるかどうかは試していません。
bme280 = i2cdev(rpi, 'i2c-1', '0x76');
###wakeup
BME280は、SPIもしくはI2Cで入出力します。上記のようにI2Cで接続しました。電源を入れた直後はスリープしています。次の書き込みで温度と気圧センサが起きます。
Ctrl_OUT = bitor(bitor(osrs_t, osrs_p), mode_normal);
writeRegister(bme280, Ctrl_register, Ctrl_OUT);
次の書き込みで、湿度センサが起きます。このMEMSセンサは、温度と気圧が測れるBMP280に湿度の機能が追加されたらしく、レジスタも拡張されています。ちなみにこの進化系であるBME680は、レジスタの空いているところに四つ目の空気汚れセンサを追加しようとしてうまく実現できず、温度や気圧のレジスタの場所が一部変更されています。
writeRegister(bme280, Ctrl_hum, osrs_h);
###まずは温度
気圧や湿度は、温度で補正を掛けます。変数はt_fineです。なので、温度を最初に読み出します。
このセンサは、個々の製造上の違いを補正するために、固有の補正係数が書き込まれています。% readCoefficientsの部分に、その読み出し部分を示します。いろいろな型、レジスタ長、二つのレジスタの合成など、面倒な処理をします。ビット処理がほとんどなので、プログラムが正常に値を得ているかが心もとないです。
そこで、Arduino UNOを使い、AdafruitのBME280のライブラリを利用し、ソースを修正し、Coefficientsの値を表示します。この値は、センサ固有なので、% readCoefficientsの部分の出力値と比較し、正しい処理になっているかどうかを確認しました。
温度と気圧は、20ビットのデータが三つのレジスタに入っています。三つのレジスタの内容を読み出し合成すると24ビットなので、最後に右に4ビット・シフトしています。
湿度は16ビットです。
###プログラム
10回読み出します。
clear all
rpi = raspi('192.168.111.114', 'pi', 'raspberry'); % host name raspberrypi-uMchsTIvew
%rpi = raspi;
global bme280;
bme280 = i2cdev(rpi, 'i2c-1', '0x76');
for i = 1:10
[t, p, h] = read_BME280();
fprintf('\n %.1f`C %.1fhPa %.1fRH%', t, p/100, h);
pause(0.1)
end
function [temperature, pressure, humidity] = read_BME280()
global bme280;
Ctrl_hum = 0xf2;
Ctrl_register = 0xf4;
Config_reg = 0xf5;
Temp_register = 0xfa;
Press_register = 0xf7;
Hum_register = 0xfd;
osrs_t = 0b00100000; % Temp oversampling x 1
osrs_p = 0b00000100; % Press oversampling x 1
osrs_h = 0b00000001; % Humidity oversampling x 1
mode_normal = 0b00000011;
t_sb = 0b10100000; % Tstandby 1000ms
filter = 0b00000100; % Filter 2
Ctrl_OUT = bitor(bitor(osrs_t, osrs_p), mode_normal);
writeRegister(bme280, Ctrl_register, Ctrl_OUT);
Ctrl_OUT = bitor(t_sb, filter);
writeRegister(bme280, Config_reg, Ctrl_OUT);
writeRegister(bme280, Ctrl_hum, osrs_h);
% readCoefficients
dig_T1 = readRegister(bme280, 0x88, 'uint16');
dig_T2 = readRegister(bme280, 0x8A, 'int16');
dig_T3 = readRegister(bme280, 0x8C, 'int16');
dig_P1 = readRegister(bme280, 0x8E, 'uint16');
dig_P2 = readRegister(bme280, 0x90, 'int16');
dig_P3 = readRegister(bme280, 0x92, 'int16');
dig_P4 = readRegister(bme280, 0x94, 'int16');
dig_P5 = readRegister(bme280, 0x96, 'int16');
dig_P6 = readRegister(bme280, 0x98, 'int16');
dig_P7 = readRegister(bme280, 0x9A, 'int16');
dig_P8 = readRegister(bme280, 0x9C, 'int16');
dig_P9 = readRegister(bme280, 0x9E, 'int16');
dig_H1 = readRegister(bme280, 0xA1, 'uint8');
dig_H2 = readRegister(bme280, 0xE1, 'int16');
dig_H3 = readRegister(bme280, 0xE3, 'uint8');
H4_h = int16(bitshift(int16(readRegister(bme280, 0xE4, 'int8')), 4));
H4_l = int16(bitand(readRegister(bme280, 0xE5, 'int8'), 15) );
dig_H4 = bitor(H4_h, H4_l);
dig_H5 = bitor( int16(bitshift(readRegister(bme280, 0xE6, 'int8'), 4)) , int16(bitshift(readRegister(bme280, 0xE5, 'int8'), -4)) );
dig_H6 = readRegister(bme280, 0xE7, 'int8');
%% temperature
temp = readRegister(bme280, Temp_register, 3);
tempC = double(bitshift(uint32(temp(1)), 16)) + double(bitshift(uint16(temp(2)), 8)) + double(temp(3));
temperature = double(bitshift(tempC, -4));
var1 = (temperature / 16384.0 - double(dig_T1) / 1024.0) * double(dig_T2);
var2 = ((temperature / 131072.0 - double(dig_T1) / 8192.0) * (temperature / 131072.0 - double(dig_T1) / 8192.0)) * double(dig_T3);
t_fine = int32(var1 + var2);
temperature = (var1 + var2) / 5120.0;
%% press
press = readRegister(bme280, Press_register, 3);
pressC = double(bitshift(uint32(press(1)), 16)) + double(bitshift(uint16(press(2)), 8)) + double(press(3));
pressD = double(bitshift(pressC, -4));
var1p = double(t_fine) / 2.0 - 64000.0;
var2p = var1p * var1p * (double(dig_P6)) / 32768.0;
var2p = var2p + var1p * (double(dig_P5)) * 2.0;
var2p = (var2p / 4.0) + ((double(dig_P4)) * 65536.0);
var1p = ((double(dig_P3)) * var1p * var1p / 524288.0 + (double(dig_P2)) * var1p) / 524288.0;
var1p = (1.0 + var1p / 32768.0) * (double(dig_P1));
p = 1048576.0 - double(pressD);
p = (p - (var2p / 4096.0)) * 6250.0 / var1p;
var1p = (double(dig_P9)) * p * p / 2147483648.0;
var2p = p * (double(dig_P8)) / 32768.0;
pressure = p + (var1p + var2p + double(dig_P7)) / 16.0;
%% humidity
humi = readRegister(bme280, Hum_register, 2);
humiC = double(bitshift(uint16(humi(1)), 8)) + double(humi(2));
H = double(t_fine) - 76800.0;
Hd = (humiC - (double(dig_H4) * 64.0 + double(dig_H5) / 16384.0 * H)) * (double(dig_H2) / 65536.0 * (1.0 + double(dig_H6) / 67108864.0 * H * (1.0 + double(dig_H3) / 67108864.0 * H)));
%Hdd = ((((humiC * 16384) - (double(dig_H4) * 1048576) - (double(dig_H5) * H) + 16384) / 32768) ...
% * (((((((H * (double(dig_H6))) / 1024) * (((H * (double(dig_H3))) / 2048) + 32768)) / 1024) + 2097152) * (double(dig_H2)) + 8192) / 16384));
%hdd = Hdd/4096/1024;
humidity = Hd * (1.0 - double(dig_H1) * Hd / 524288.0);
end