matlabでラズパイにつないだBME280からデータをもってくる

　最近、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でログインして変更してください。
![スクリーンショット 2020-10-18 19.32.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/6189a2f5-972f-7cc8-9c8b-2350b63cad6b.png)


###センサBME280の接続
　アマゾンやebayでとても安いBME280を購入すると、送られてくるのはBMP280です。センサは長方形をしています。BME280は真四角です。温度と気圧は、どちらも同じソフトが動きます。
　ブレークアウト・ボードが6ピンタイプだと、I2Cは次のように配線します。I2Cの設定は、基板上で配線がすんでいますが、確認してください。

<img width="400" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/694ea341-1026-3ee8-9c5a-06fc3ea1235f.png">


　秋月電子通商の6ピンは、取説に従ってジャンパを配線し、I2Cの設定にしてください。
<img width="400" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/68914102-6515-95f1-5210-6c83453e8512.png">


　4ピンは、I2C専用なので、4本を配線するだけです。I2Cバスはプルアップ抵抗が必要ですが、ラズパイには本体に実装されています。

<img width="400" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/86071824-845f-fcdc-6149-147205159fba.jpeg">


　接続の確認をするため、I2Cのスキャナ関数で、スレーブ・アドレスを表示します。

```matlab
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で使えるかどうかは試していません。

```matlab
bme280 = i2cdev(rpi, 'i2c-1', '0x76');
```
###wakeup
　BME280は、SPIもしくはI2Cで入出力します。上記のようにI2Cで接続しました。電源を入れた直後はスリープしています。次の書き込みで温度と気圧センサが起きます。

```matlab
Ctrl_OUT = bitor(bitor(osrs_t, osrs_p), mode_normal);
writeRegister(bme280, Ctrl_register, Ctrl_OUT);
```

　次の書き込みで、湿度センサが起きます。このMEMSセンサは、温度と気圧が測れるBMP280に湿度の機能が追加されたらしく、レジスタも拡張されています。ちなみにこの進化系であるBME680は、レジスタの空いているところに四つ目の空気汚れセンサを追加しようとしてうまく実現できず、温度や気圧のレジスタの場所が一部変更されています。

```matlab
 writeRegister(bme280, Ctrl_hum, osrs_h);
```

###まずは温度
　気圧や湿度は、温度で補正を掛けます。変数はt_fineです。なので、温度を最初に読み出します。
　このセンサは、個々の製造上の違いを補正するために、固有の補正係数が書き込まれています。% readCoefficientsの部分に、その読み出し部分を示します。いろいろな型、レジスタ長、二つのレジスタの合成など、面倒な処理をします。ビット処理がほとんどなので、プログラムが正常に値を得ているかが心もとないです。
　そこで、Arduino UNOを使い、AdafruitのBME280のライブラリを利用し、ソースを修正し、Coefficientsの値を表示します。この値は、センサ固有なので、% readCoefficientsの部分の出力値と比較し、正しい処理になっているかどうかを確認しました。
　温度と気圧は、20ビットのデータが三つのレジスタに入っています。三つのレジスタの内容を読み出し合成すると24ビットなので、最後に右に4ビット・シフトしています。
　湿度は16ビットです。

###プログラム
　10回読み出します。

```matlab
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
```