MAKER UNO + で始めるSTEM (11) WireライブラリでBoschのセンサ⑤温度/湿度/気圧

 温度に続き、BME680の湿度と気圧を読み出します。
 四つ目のガスは、データの読み出し行う前に設定するレジスタが多く、ヒータの温度設定と時間を複数回実行して適正な値を求めるなど運用が複雑なので、別の機会に取り上げる予定です。

 前回、温度のオーバサンプリングを設定するレジスタctrl_meas(0x74)は気圧のオーバサンプリングも設定するので、TempPressMeasStartとし、0b10001101を設定します。
 湿度のオーバサンプリングはctrl_hum(0x72)レジスタで設定します。HumMeasStartとし、0b00000010を設定します。これら二つのレジスタを設定しないと、変換は行われません。
 IIRフィルタは温度のときと同じ設定です。

 気圧の入っているレジスタは0x1fから3バイトで、温度と同じく有効なのは20ビットです。湿度の入っているレジスタは0x25から2バイトです。有効なのは16ビットです。

スケッチ

 読み出した温度の補償と算出はcalc_temperature()、気圧はcalc_pressure()、湿度はcalc_humidity()です。いずれもGitHubにあるサンプル例を利用しています。この算出式ではキャストが多用されています。これは、8ビット・マイコンと32ビット・マイコンでは、同じintでもメモリに確保される領域が異なるため、齟齬が出ないようにするためです。
 算出式のサンプルでは、ここで利用した整数演算以外に実数によるプログラムも掲載されています。Cortex-M4のような浮動小数点演算ユニットが搭載されたマイコンに向いています。

#include <Wire.h>
#define BME680_address 0x76
#define reset 0xe0
#define ID_register 0xd0
#define Temp_register 0x22 // 20bits
#define Press_register 0x1f // 20bits
#define Hum_register 0x25 // 16bits
#define ctrl_meas 0x74
#define ctrl_hum 0x72
//#define TempMeasStart 0b10000001
#define TempPressMeasStart 0b10001101
// Temp oversampling ×8 Press oversampling ×4
#define HumMeasStart 0b00000010 // oversampling ×2
#define IIR_Filter 0x75
#define filter3 0b00001000
#define newDataStatus 0x1d // MSB = ready bit5

int32_t t_fine ;

// calibrated humidity data
uint16_t dig_H1;
uint16_t dig_H2;
int8_t dig_H3;
int8_t dig_H4;
int8_t dig_H5;
uint8_t dig_H6;
int8_t dig_H7;
// calibrated gas data
int8_t dig_G1;
int16_t dig_G2;
int8_t dig_G3;
// calibrated temperature data
uint16_t dig_T1;
int16_t dig_T2;
int8_t dig_T3;
// calibrated pressure data
uint16_t dig_P1;
int16_t dig_P2;
int8_t dig_P3;
int16_t dig_P4;
int16_t dig_P5;
int8_t dig_P6;
int8_t dig_P7;
int16_t dig_P8;
int16_t dig_P9;
uint8_t dig_P10;

byte readbuffer[6];

void setup() {
Wire.begin();
Serial.begin(9600);
Serial.println("\nstart ");
Wire.beginTransmission(BME680_address);
Wire.write(reset);
Wire.endTransmission();
delay(10);
Wire.beginTransmission(BME680_address);
Wire.write(ID_register);
Wire.endTransmission();
Wire.requestFrom(BME680_address, 1);
uint8_t ID = Wire.read();
Serial.println("\nID = " + String(ID,HEX));

readCoefficients();

Wire.beginTransmission(BME680_address);
Wire.write(IIR_Filter);
Wire.write(filter3);
Wire.endTransmission();
delay(100);
}
void loop() {
Wire.beginTransmission(BME680_address);
Wire.write(ctrl_hum);
Wire.write(HumMeasStart);
Wire.endTransmission();
Wire.beginTransmission(BME680_address);
Wire.write(ctrl_meas);
Wire.write(TempPressMeasStart);
Wire.endTransmission();

Serial.println("bit8=newdata stored='1',bit6=Measuring ready='0' " + String(newData(),BIN));

Wire.beginTransmission(BME680_address);
Wire.write((byte)Temp_register);
Wire.endTransmission();
Wire.requestFrom(BME680_address, 3);
uint32_t temp = Wire.read();
temp = temp << 8 | Wire.read();
temp = temp << 8 | Wire.read();
temp = temp >> 4;
Serial.println("\nReadTempData = " + String(temp));
float T = calc_temperature((int32_t)temp);
Serial.println("Temperature " + String(T/100,1));

Wire.beginTransmission(BME680_address);
Wire.write((byte)Hum_register);
Wire.endTransmission();
Wire.requestFrom(BME680_address, 2);
uint32_t hum = Wire.read();
hum = hum << 8 | Wire.read();
Serial.println("\nReadHumData = " + String(hum));
float H = calc_humidity((uint16_t)hum);
Serial.println("Humidity " + String(H/1000,0));

Wire.beginTransmission(BME680_address);
Wire.write((byte)Press_register);
Wire.endTransmission();
Wire.requestFrom(BME680_address, 3);
uint32_t press = Wire.read();
press = press << 8 | Wire.read();
press = press << 8 | Wire.read();
press = press >> 4;
Serial.println("\nReadPressData = " + String(press));
float P = calc_pressure((int32_t)press);
Serial.println("Pressure " + String(P/100.0,1));

delay(2000);
}

byte newData() {
Wire.beginTransmission(BME680_address);
Wire.write((byte)newDataStatus);
Wire.endTransmission();
Wire.requestFrom(BME680_address, 1);
return (Wire.read()) ;
}

int16_t calc_temperature(uint32_t temp_adc){
int32_t var1, var2, var3;
int16_t calc_temp;
var1 = ((int32_t) temp_adc >> 3) - ((int32_t) dig_T1 << 1);
var2 = (var1 * (int32_t) dig_T2) >> 11;
var3 = ((var1 >> 1) * (var1 >> 1)) >> 12;
var3 = ((var3) * ((int32_t) dig_T3 << 4)) >> 14;
t_fine = (int32_t) (var2 + var3);
calc_temp = (int16_t) (((t_fine * 5) + 128) >> 8);
return calc_temp;
}

uint32_t calc_humidity(uint16_t hum_adc) {
int32_t var1, var2, var3, var4, var5, var6;
int32_t temp_scaled;
int32_t calc_hum;
temp_scaled = (((int32_t)t_fine * 5) + 128) >> 8;
var1 = (int32_t) (hum_adc - ((int32_t) ((int32_t)dig_H1 * 16)))
- (((temp_scaled * (int32_t)dig_H3) / ((int32_t) 100)) >> 1);
var2 = ((int32_t)dig_H2
* (((temp_scaled * (int32_t)dig_H4) / ((int32_t) 100))
+ (((temp_scaled * ((temp_scaled * (int32_t)dig_H5) / ((int32_t) 100))) >> 6)
/ ((int32_t) 100)) + (int32_t) (1 << 14))) >> 10;
var3 = var1 * var2;
var4 = (int32_t)dig_H6 << 7;
var4 = ((var4) + ((temp_scaled * (int32_t)dig_H7) / ((int32_t) 100))) >> 4;
var5 = ((var3 >> 14) * (var3 >> 14)) >> 10;
var6 = (var4 * var5) >> 1;
calc_hum = (((var3 + var6) >> 10) * ((int32_t) 1000)) >> 12;
if (calc_hum > 100000) /* Cap at 100%rH */
calc_hum = 100000;
else if (calc_hum < 0)
calc_hum = 0;
return (uint32_t) calc_hum;
}

uint32_t calc_pressure(uint32_t pres_adc){
int32_t var1, var2, var3;
int32_t pressure_comp;
var1 = (((int32_t)t_fine) >> 1) - 64000;
var2 = ((((var1 >> 2) * (var1 >> 2)) >> 11) *
(int32_t)dig_P6) >> 2;
var2 = var2 + ((var1 * (int32_t)dig_P5) << 1);
var2 = (var2 >> 2) + ((int32_t)dig_P4 << 16);
var1 = (((((var1 >> 2) * (var1 >> 2)) >> 13) *
((int32_t)dig_P3 << 5)) >> 3) +
(((int32_t)dig_P2 * var1) >> 1);
var1 = var1 >> 18;
var1 = ((32768 + var1) * (int32_t)dig_P1) >> 15;
pressure_comp = 1048576 - pres_adc;
pressure_comp = (int32_t)((pressure_comp - (var2 >> 12)) * ((uint32_t)3125));
if (pressure_comp >= 0x40000000L)
pressure_comp = ((pressure_comp / var1) << 1);
else
pressure_comp = ((pressure_comp << 1) / var1);
var1 = ((int32_t)dig_P9 * (int32_t)(((pressure_comp >> 3) *
(pressure_comp >> 3)) >> 13)) >> 12;
var2 = ((int32_t)(pressure_comp >> 2) *
(int32_t)dig_P8) >> 13;
var3 = ((int32_t)(pressure_comp >> 8) * (int32_t)(pressure_comp >> 8) *
(int32_t)(pressure_comp >> 8) *
(int32_t)dig_P10) >> 17;
pressure_comp = (int32_t)(pressure_comp) + ((var1 + var2 + var3 +
((int32_t)dig_P7 << 7)) >> 4);
return (uint32_t)pressure_comp;
}

unsigned int read16(byte dig_registor){
Wire.beginTransmission(BME680_address);
Wire.write(dig_registor);
Wire.endTransmission();
Wire.requestFrom(BME680_address, 2);
readbuffer[0] = Wire.read();
readbuffer[1] = Wire.read();
return ( readbuffer[1] << 8 | readbuffer[0] );
}

unsigned int read8(byte dig_registor){
Wire.beginTransmission(BME680_address);
Wire.write(dig_registor);
Wire.endTransmission();
Wire.requestFrom(BME680_address, 2);
return ( Wire.read() );
}

void readCoefficients(){
dig_T1 = read16(0xE9);
dig_T2 = (int16_t)read16(0x8A);
dig_T3 = (int8_t)read8(0x8C);

dig_P1 = read16(0x8E);
dig_P2 = (int16_t)read16(0x90);
dig_P3 = (int8_t)read8(0x92);
dig_P4 = (int16_t)read16(0x94);
dig_P5 = (int16_t)read16(0x96);
dig_P6 = (int8_t)read8(0x99); //
dig_P7 = (int8_t)read8(0x98); //
dig_P8 = (int16_t)read16(0x9C);
dig_P9 = (int16_t)read16(0x9E);
dig_P10 = (uint8_t)read8(0xA0);

dig_H1 = read8(0xE3) << 4 | read8(0xE2) & 0x0f ;
dig_H2 = read8(0xE1) << 4 | read8(0xE2) >> 4 ;
dig_H3 = (int8_t)read8(0xE4);
dig_H4 = (int8_t)read8(0xE5);
dig_H5 = (int8_t)read8(0xE6);
dig_H6 = (uint8_t)read8(0xE7);
dig_H7 = (int8_t)read8(0xE8);

dig_G1 = (int8_t)read8(0xEd);
dig_G2 = (int16_t)read16(0xEb);
dig_G3 = (int8_t)read8(0xEe);

Serial.print("dig_T1="); Serial.println(dig_T1);
Serial.print("dig_T2="); Serial.println(dig_T2);
Serial.print("dig_T3="); Serial.println(dig_T3);

Serial.print("dig_P1="); Serial.println(dig_P1);
Serial.print("dig_P2="); Serial.println(dig_P2);
Serial.print("dig_P3="); Serial.println(dig_P3);
Serial.print("dig_P4="); Serial.println(dig_P4);
Serial.print("dig_P5="); Serial.println(dig_P5);
Serial.print("dig_P6="); Serial.println(dig_P6);
Serial.print("dig_P7="); Serial.println(dig_P7);
Serial.print("dig_P8="); Serial.println(dig_P8);
Serial.print("dig_P9="); Serial.println(dig_P9);
Serial.print("dig_P10="); Serial.println(dig_P10);

Serial.print("dig_H1="); Serial.println(dig_H1);
Serial.print("dig_H2="); Serial.println(dig_H2);
Serial.print("dig_H3="); Serial.println(dig_H3);
Serial.print("dig_H4="); Serial.println(dig_H4);
Serial.print("dig_H5="); Serial.println(dig_H5);
Serial.print("dig_H6="); Serial.println(dig_H6);
Serial.print("dig_H7="); Serial.println(dig_H7);

Serial.print("dig_G1="); Serial.println(dig_G1);
Serial.print("dig_G2="); Serial.println(dig_G2);
Serial.print("dig_G3="); Serial.println(dig_G3);
}

グラフ

 Arduino IDEでは、シリアルモニタに測定結果を出力できます。ビジュアルに表示ができるシリアルプロッタは、メインメニューのツールから選択します。スケールなどは自動なので、温度と気圧のスケールが大きく異なり、見やすいグラフにはなっていません。湿度が上がっているところは、センサを指先で触っているときです。

 hPaをkPaに変更しました。ヒートガンをLOWモードで30cmほど離して吹き付けてみました。温度と湿度の変化がよくわかります。

 三つの出力をプロットするには、すべてのSerial.print文をコメントアウトし、loop()の終わりにあるdelay()の前で三つの値を出力し、それぞれの出力はカンマで区切ります。

Serial.print(String(T/100,1) + ",");
Serial.print(String(H/1000,0) + ",");
Serial.println(String(P/1000.0,1));

前へ

MAKER UNO + で始めるSTEM (10) WireライブラリでBoschのセンサ④温度

次へ

MAKER UNO + で始めるSTEM (12) 日の出をキャッチ①