センサモジュールキットの概要
- AE-BME280(秋月電子通商)
- マニュアル
- AE-BME280データシート
マニュアルのMemory Map
とAE-BME280データシートの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で各測定結果を取得する流れは下記のようになります。
湿度、気圧を算出するためには気温情報もパラメータとなるため、測定値を人が見てわかる形にするためには、まず気温情報を計算する必要があるようです。
- 設定パラメータをレジスタに書き込む
- calibration dataの読み込み
- 気温、湿度、気圧測定値の読み込み
- 気温情報の測定値変換
- 湿度、気圧情報の測定値変換
AE-BME280にはNormal Mode、Force Mode、Sleep Modeの3状態があり、Normal Mode、Force Modeの時に測定を行います。Normal Modeは周期的に測定を行う場合のModeで、Force Modeは何かのイベント契機で測定をするModeっぽいです。
サンプルソース
RaspberyPiでwiringpiを使用する場合、まず最初にwiringpiの初期化処理
が必要です。また、C++やPythonでやりたい場合は、参考サイト
のリンク先を参照してください。
# 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はリトルエンディアンらしい。