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

 前回、デバイス固有の補償データを求めました。そのデータを利用し、温度を求めます。BME680では、ほかのセンサの値は温度に影響されるため、一番最初に導き出します。

温度の変換を要求する設定

 設定に必要なレジスタとその内容をデータシートからピックアップします。

ctrl_meas(0x74);デフォルト0x00

 オーバサンプリングの値を設定します。読み取りの精度とノイズ量とのバランスを設定できます。オーバサンプリングが高いほど、精度が低下しますが、ノイズが大幅に減少します。osrs_t<2:0>は'100'で8倍に設定できます。また、デフォルトの'000'では温度変換を始めません。

 LSB側の2ビットはmodeで、スリープの(0,0)と実行モード(0,1)があり、パワーオン・リセット時はスリープ状態です。測定を開始する前に、実行モードに変更します。
 二つの設定を合成すると、設定値は0b10000001です。bit4~bit2は気圧のオーバサンプリングの設定ですから、デフォルトの'000'のままにします。

bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
osrs_t<2:0> osrs_p<2:0> mode

 実行モードにすると、温度(もし圧力、湿度、およびガス変換が変換する状態に設定されていれば)が順次実行されます。変換は1回だけ実行され、スリープ・モードに戻ります。

IIR_Filter(0x75);デフォルト0x00

 IIRフィルタは、過渡変化に対する温度と圧力センサの読み取り値を安定にします。有効にすると温度の分解能は20ビットになります。filterが'000'のときフィルタ係数0、'001'で1、'010'で3、... '110'で63、'111'で127です。3(0b00001000)に設定します。

bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
  filter<2:0>   SPI_3W_en

温度データの読み出し
 温度の上位バイトが0x22、下位バイトが0x23、分解能16ビット以上のデータが0x24(下の4ビットは0)です。
 3バイト読み出し、利用するのは20ビットなので、読み出した24ビット・データを4ビット右にシフトしてから利用します。

 読み出した20ビットのデータは、BME280/MBMP280のデータシートに掲載されている補正式のサンプル・プログラムによって、摂氏の単位の温度に変換します。

スケッチ

#include <Wire.h>
#define BME680_address 0x76
#define reset 0xe0
#define ID_register 0xd0
#define Temp_register 0x22
#define ctrl_meas 0x74
#define TempMeasStart 0b10000001
#define IIR_Filter 0x75
#define filter3 0b00001000
#define newDataStatus 0x1d // MSB = ready bit5
 温度の設定TempMeasStart は、温度のオーバサンプリングを指定する。サンプルにあるのと同じを設定。このレジスタは、実行モードのフラグも兼ねている。

// 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];
 初期化部分。リセットをし、IDを読み出す。補償データを読み出す関数を呼び出し、IIRフィルタをセットする


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);
}
メイン。
1回の測定でスリープ・モードに戻るため、毎回、実行モードにする


void loop() {
Wire.beginTransmission(BME680_address);
Wire.write(ctrl_meas);
Wire.write(TempMeasStart);
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 = BME680_compensate_T_double((int32_t)temp);
Serial.println("temperature " + String(T/100,1));
delay(2000);
}
データが用意できたかどうかを読み出す


byte newData() {
Wire.beginTransmission(BME680_address);
Wire.write((byte)newDataStatus);
Wire.endTransmission();
Wire.requestFrom(BME680_address, 1);
return (Wire.read()) ;
}
補償データを使って温度を演算する。GitHubにあるサンプル・プログラムを流用。型の一部を変更

int32_t BME680_compensate_T_double(int32_t adc_T){
int32_t var1, var2, T;
var1 = ((((adc_T >> 3) - ((int32_t)dig_T1 << 1))) * ((int32_t)dig_T2)) >> 11;
var2 = (((((adc_T >> 4) - ((int32_t)dig_T1)) * ((adc_T >> 4) - ((int32_t)dig_T1))) >> 12) * ((int32_t)dig_T3)) >> 14;
int32_t t_fine = var1 + var2;
T = (t_fine * 5 + 128) >> 8;
return T;
}
補償データのプログラムで使う符号なし2バイトの読み取り

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] );
}
補償データのプログラムで使う符号なし1バイトの読み取り

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);
}

 実行結果です。

前へ

MAKER UNO + で始めるSTEM (9) WireライブラリでBoschのセンサ③補償データ

次へ

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