温湿・気圧センサモジュールキット AE-BME280


# センサモジュールキットの概要

- [AE-BME280](http://akizukidenshi.com/catalog/g/gK-09421/)（秋月電子通商）
- [マニュアル](http://akizukidenshi.com/download/ds/akizuki/AE-BME280_manu_v1.1.pdf)
- [AE-BME280データシート](http://akizukidenshi.com/download/ds/bosch/BST-BME280_DS001-10.pdf)

[マニュアル](http://akizukidenshi.com/download/ds/akizuki/AE-BME280_manu_v1.1.pdf)の``Memory Map``と[AE-BME280データシート](http://akizukidenshi.com/download/ds/bosch/BST-BME280_DS001-10.pdf)のP22-P23あたりを押さえておけば、とりあえずの測定はできそうです。


# 使い方

## 半田付け

- ブッレドボードに取り付けるため製品付属のピンヘッダを取り付ける。
- I2Cで接続するため、J3ジャンパ（半田ジャンパ）を結線する。

とりあえず、RaspberryPiで使いう場合、J1、J2ジャンパを結線する必要はないそうです。「プルアップ抵抗」の意味がよく分かっていませんが、RaspberryPiは内蔵しているとのこと。


## RaspberryPi2との接続

BME280の各端子 - RasPiを下記のように結線します。

- VDD : 3.3V
- GND : 0V
- SDI : GPIO2
- SDO : 0V
- SCK : GPIO3

SDO - 0Vに接続した場合I2Cアドレスが0x76、SDO - VDDに接続した場合0x77になります。I2Cアドレスは2パターンだけなので、I2Cポート一つあたり2個まで接続可能？なんですかね。


## サンプルソース

### 概要

細かい内容はデータシートを読んでいる最中なので詳細までの理解はできていませんが、Normal Modeで各測定結果を取得する流れは下記のようになります。
湿度、気圧を算出するためには気温情報もパラメータとなるため、測定値を人が見てわかる形にするためには、まず気温情報を計算する必要があるようです。

1. 設定パラメータをレジスタに書き込む
2. calibration dataの読み込み
3. 気温、湿度、気圧測定値の読み込み
4. 気温情報の測定値変換
5. 湿度、気圧情報の測定値変換

AE-BME280にはNormal Mode、Force Mode、Sleep Modeの3状態があり、Normal Mode、Force Modeの時に測定を行います。Normal Modeは周期的に測定を行う場合のModeで、Force Modeは何かのイベント契機で測定をするModeっぽいです。


### サンプルソース

RaspberyPiでwiringpiを使用する場合、まず最初に``wiringpiの初期化処理``が必要です。また、C++やPythonでやりたい場合は、``参考サイト``のリンク先を参照してください。


```c:rasp_sample.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>

#include<wiringPi.h>
#include<wiringPiI2C.h>

#define DEVID (0x76)

int t_fine;
u_int16_t digT0 = 0;
int16_t   digT[3] = {};

u_int16_t digH0 = 0, digH2 = 0;
int16_t   digH[6] = {};

u_int16_t digP0 = 0;
int16_t   digP[9] = {};

void init_bme280(int *devfd)
{
    if((*devfd=wiringPiI2CSetup(DEVID)) < 0) {
        printf("wiringPiI2CSetup error(%d):%s\n", errno, strerror(errno));
        exit(EXIT_FAILURE);
    }
    //printf("  devfd = %d\n", *devfd);

    /* Humidity oversampling x1(osrs_h=0x1) */
    if(wiringPiI2CWriteReg8(*devfd, 0xf2, 0x01) < 0) {
        printf("write error register 0xf2(%d):%s\n", errno, strerror(errno));
        exit(EXIT_FAILURE);
    }

    /* Temparature oversampling x1(osrs_t=0x1),
     * Pressure oversampling x1   (osrs_p=0x1),
     * Normal mode                (mode=0x3)
     */
    if(wiringPiI2CWriteReg8(*devfd, 0xf4, 0x27) < 0) {
        printf("write error register 0xf4(%d):%s\n", errno, strerror(errno));
        exit(EXIT_FAILURE);
    }

    /* Standby 1000ms(t_sb=0x10), Filter off(filter=0x4), spi3w_en=0x0 */
    if(wiringPiI2CWriteReg8(*devfd, 0xf5, 0xa0) < 0) {
        printf("write error register 0xf4(%d):%s\n", errno, strerror(errno));
        exit(EXIT_FAILURE);
    }
}

void get_calib_param(int devfd)
{
    digT0 = wiringPiI2CReadReg16(devfd, 0x88);
    digT[1] = wiringPiI2CReadReg16(devfd, 0x8a);
    digT[2] = wiringPiI2CReadReg16(devfd, 0x8c);
    //printf("digT0=0x%04x, digT1=0x%04x, digT2=0x%04x\n", digT[0], digT[1], digT[2]);

    digP0 = wiringPiI2CReadReg16(devfd, 0x8e);
    digP[1] = wiringPiI2CReadReg16(devfd, 0x90);
    digP[2] = wiringPiI2CReadReg16(devfd, 0x92);
    digP[3] = wiringPiI2CReadReg16(devfd, 0x94);
    digP[4] = wiringPiI2CReadReg16(devfd, 0x96);
    digP[5] = wiringPiI2CReadReg16(devfd, 0x98);
    digP[6] = wiringPiI2CReadReg16(devfd, 0x9a);
    digP[7] = wiringPiI2CReadReg16(devfd, 0x9c);
    digP[8] = wiringPiI2CReadReg16(devfd, 0x9e);
    //printf("digP0=0x%04x, digP1=0x%04x, digP2=0x%04x digP3=0x%04x\n", digP0, digP[1], digP[2], digP[3]);
    //printf("digP4=0x%04x, digP5=0x%04x, digP6=0x%04x digP7=0x%04x\n", digP[4], digP[5], digP[6], digP[7]);
    //printf("digP8=0x%04x\n", digP[8]);

    digH0 = wiringPiI2CReadReg8(devfd, 0xa1);
    digH[1] = wiringPiI2CReadReg16(devfd, 0xe1);
    digH2 = wiringPiI2CReadReg8(devfd, 0xe3);
    digH[3] = (wiringPiI2CReadReg8(devfd, 0xe4) << 4) | (wiringPiI2CReadReg8(devfd, 0xe5) & 0x0f);
    digH[4] = (wiringPiI2CReadReg8(devfd, 0xe6) << 4) | ((wiringPiI2CReadReg8(devfd, 0xe5) >> 4) & 0x0f);
    digH[5] = wiringPiI2CReadReg8(devfd, 0xe7);
    //printf("digH0=0x%04x, digH1=0x%04x, digH2=0x%04x, digH3=0x%04x, digH4=0x%04x, digH5=0x%04x\n",
    //    digH[0], digH[1], digH[2], digH[3], digH[4], digH[5]);
}

float measure_temperature(int devfd)
{
    unsigned int raw_temp = 0;
    unsigned char raw_data[3] = {};

    raw_data[0] = wiringPiI2CReadReg8(devfd, 0xfa);
    raw_data[1] = wiringPiI2CReadReg8(devfd, 0xfb);
    raw_data[2] = wiringPiI2CReadReg8(devfd, 0xfc);

    raw_temp = (raw_data[0] << 12) | (raw_data[1] << 4) | (raw_data[2] >> 4);
    //printf("raw temperature = %d(0x%x)\n", raw_temp, raw_temp);

    int temp_data = 0;
    temp_data =
        (((((raw_temp >> 3) - (digT0 << 1))) * digT[1]) >> 11) +
        ((((((raw_temp >> 4) - digT0) * ((raw_temp >> 4) - digT0)) >> 12) * digT[2]) >> 14);
    //printf("temp = %d(0x%x)\n", temp_data, temp_data);
    t_fine = temp_data;

    return( (float)((temp_data * 5 + 128) >> 8) / 100.0f );
}

float measure_humidity(int devfd)
{
    unsigned int raw_humid = 0;
    int v_x1 = 0;

    raw_humid = (wiringPiI2CReadReg8(devfd, 0xfd) << 8) | wiringPiI2CReadReg8(devfd, 0xfe);

    v_x1 = t_fine - 76800;
    v_x1 =  (((((raw_humid << 14) - (((int32_t)digH[3]) << 20) - (((int32_t)digH[4]) * v_x1)) +
               ((int32_t)16384)) >> 15) * (((((((v_x1 * (int32_t)digH[5]) >> 10) *
                                            (((v_x1 * ((int32_t)digH2)) >> 11) + 32768)) >> 10) + 2097152) *
                                            (int32_t)digH[1] + 8192) >> 14));
    v_x1 = (v_x1 - (((((v_x1 >> 15) * (v_x1 >> 15)) >> 7) * (int32_t)digH0) >> 4));
    v_x1 = (v_x1 < 0 ? 0 : v_x1);
    v_x1 = (v_x1 > 419430400 ? 419430400 : v_x1);

    return( ((float)(v_x1 >> 12)) / 1024.0f );
}

float measure_pressure(devfd)
{
    unsigned int raw_pressure = 0;
    int32_t var1, var2;
    unsigned int press;

    raw_pressure = (wiringPiI2CReadReg8(devfd, 0xf7) << 12)
                    | (wiringPiI2CReadReg8(devfd, 0xf8) << 4)
                    | (wiringPiI2CReadReg8(devfd, 0xf9) >> 4);
    //printf("raw_pressure = %04x\n", raw_pressure);

    var1 = (t_fine >> 1) - 64000;
    var2 = (((var1 >> 2) * (var1 >> 2)) >> 11) * digP[5];
    var2 = var2 + ((var1 * digP[4]) << 1);
    var2 = (var2 >> 2) + (digP[3] << 16);
    var1 = (((digP[2] * (((var1 >> 2)*(var1 >> 2)) >> 13)) >> 3) + ((digP[1] * var1) >> 1)) >> 18;
    var1 = ((32768 + var1) * digP0) >> 15;
    if (var1 == 0) {
        return 0;
    }
    press = (((1048576 - raw_pressure) - (var2 >> 12))) * 3125;
    if(press < 0x80000000) {
        press = (press << 1) / var1;
    } else {
        press = (press / var1) * 2;
    }

    var1 = ((int32_t)digP[8] * ((int32_t)(((press >> 3) * (press >> 3)) >> 13))) >> 12;
    var2 = (((int32_t)(press >> 2)) * (int32_t)digP[7]) >> 13;
    press = (press + ((var1 + var2 + digP[6]) >> 4));

    return( ((float)press) / 100.0f );
}

int main()
{
    int devfd = 0;

    if(wiringPiSetupGpio() < 0) {
        return(EXIT_FAILURE);
    }

    init_bme280(&devfd);
    get_calib_param(devfd);

    printf("Temperature: %-6.1f℃\n", measure_temperature(devfd));
    printf("Humidity   : %-6.1f％\n", measure_humidity(devfd));
    printf("Pressure   : %-7.1f hPa\n", measure_pressure(devfd));

    return(EXIT_SUCCESS);
}
```

- 当初、``calibration data``はunsigned shortだよね、と勝手に思って、すごい測定結果になりました。
- レジスタを2バイト読み込みしてますが、エンディアン気にしなくていいのかな、と思っていつつ、それなりの測定結果が得られたので、あまり深く突っ込んで調べていません。インターネット上を見る限り、RaspberryPiはリトルエンディアンらしい。


# 参考サイト

## C++
- [BME280 - a mercurial repository | mbed](https://developer.mbed.org/users/MACRUM/code/BME280/)

## Python

- [ラズベリーパイで温度・湿度・気圧をまとめて取得！AE-BME280でIC2通信 | Device Plus - デバプラ](http://deviceplus.jp/hobby/raspberrypi_entry_039/)
- [08/14　秋月電子のAK-BME280とRaspberry Piで温度・湿度・気圧を測る | 二丁目で働く社長の日記](http://www.erde.co.jp/blog/?p=2927)
- [Raspberry PiとBME280でXivelyにデータを送信するガジェットをつくる - ペンギン養殖中](http://penta.hatenablog.jp/entry/2015/07/01/134714)