M5Stack と ESP32 で、ガス・気圧・温度湿度センサ BME680 を使ってみた

M5Stack

スケッチの入力

では、まず、BOSCH BME680 ドライバライブラリを使うスケッチ例です。
GitHub の README ページに書いてある使い方に沿って作ってみました。
オーバーサンプリング設定や、フィルタ設定も、それに沿っています。
おそらく、これは屋内推奨設定だと思います。

気圧・温度・湿度のオーバーサンプリングやフィルタ設定については、以下のスイッチサイエンスさんのサイトが分かりやすいです。
(これは BME280 の場合です)

http://trac.switch-science.com/wiki/BME280

だだし、ここで、注意点!

BME680 の測定モードはSleep Mode と Force Mode しかありません

ということで、まず、以下のスケッチを入力してみてください。

【ソースコード】 (※無保証 ※PCの場合、ダブルクリックすればコード全体を選択できます)

#include <Wire.h>
#include "bme680.h"

const int sda = 21;
const int scl = 22;

struct bme680_dev gas_sensor;
struct bme680_field_data data;
uint16_t meas_period;

//***********セットアップ***********
void setup() {
  delay(1000);
  Serial.begin(115200);
  bme680init();
}
//***********メインループ***********
void loop(){
  bme680GetData();
}
//*******BME680セットアップ*********
void bme680init(){
  Wire.begin( sda, scl, 100000 );
  gas_sensor.dev_id = BME680_I2C_ADDR_PRIMARY;
  gas_sensor.intf = BME680_I2C_INTF;
  gas_sensor.read = user_i2c_read;
  gas_sensor.write = user_i2c_write;
  gas_sensor.delay_ms = user_delay_ms;
  /* amb_temp can be set to 25 prior to configuring the gas sensor 
   * or by performing a few temperature readings without operating the gas sensor.
   */
  gas_sensor.amb_temp = 28;

  int8_t rslt = BME680_OK;
  rslt = bme680_init(&gas_sensor);
  Serial.printf( "bme680_init rslt=%d\r\n", rslt );

  uint8_t set_required_settings;

  /* Set the temperature, pressure and humidity settings */
  gas_sensor.tph_sett.os_hum = BME680_OS_2X;
  gas_sensor.tph_sett.os_pres = BME680_OS_4X;
  gas_sensor.tph_sett.os_temp = BME680_OS_8X;
  gas_sensor.tph_sett.filter = BME680_FILTER_SIZE_3;

  /* Set the remaining gas sensor settings and link the heating profile */
  gas_sensor.gas_sett.run_gas = BME680_ENABLE_GAS_MEAS;
  //gas_sensor.gas_sett.run_gas = BME680_DISABLE_GAS_MEAS  ;
  /* Create a ramp heat waveform in 3 steps */
  gas_sensor.gas_sett.heatr_temp = 320; /* degree Celsius */
  gas_sensor.gas_sett.heatr_dur = 150; /* milliseconds */

  /* Select the power mode */
  /* Must be set before writing the sensor configuration */
  gas_sensor.power_mode = BME680_FORCED_MODE; 

  /* Set the required sensor settings needed */
  set_required_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_FILTER_SEL 
      | BME680_GAS_SENSOR_SEL;

  /* Set the desired sensor configuration */
  rslt = bme680_set_sensor_settings(set_required_settings,&gas_sensor);
  Serial.printf( "sensor settings rslt=%d\r\n",rslt );
  /* Set the power mode */
  rslt = bme680_set_sensor_mode(&gas_sensor);
  Serial.printf( "sensor mode rslt=%d\r\n", rslt );

  /* Get the total measurement duration so as to sleep or wait till the
   * measurement is complete */
  bme680_get_profile_dur(&meas_period, &gas_sensor);
}
//**********************************
void bme680GetData(){
  user_delay_ms(meas_period); /* Delay till the measurement is ready */
  //user_delay_ms(3000);
  int8_t rslt = bme680_get_sensor_data(&data, &gas_sensor);

  Serial.printf("T: %.2f degC, P: %.2f hPa, H %.2f %%rH ", (float)data.temperature / 100.0f,
      (float)data.pressure / 100.0f, (float)data.humidity / 1000.0f );
  /* Avoid using measurements from an unstable heating setup */
  if(data.status & BME680_GASM_VALID_MSK)
      Serial.printf(", G: %d ohms", data.gas_resistance);

  Serial.printf("\r\n");

  /* Trigger the next measurement if you would like to read data out continuously */
  if (gas_sensor.power_mode == BME680_FORCED_MODE) {
      rslt = bme680_set_sensor_mode(&gas_sensor);
  }
}
//**********************************
void user_delay_ms(uint32_t period)
{
  delay(period);
}
//**********************************
int8_t user_i2c_read( uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len )
{
  int8_t rslt_read = 0; /* Return 0 for Success, non-zero for failure */

  Wire.beginTransmission( dev_id );
  Wire.write( reg_addr );
  Wire.endTransmission();
  uint8_t req_from_ret = Wire.requestFrom((uint16_t)dev_id, (uint8_t)len, true);

  if( req_from_ret == 0 ){
    Serial.println("------- Error requestForm return 0 --------");
    rslt_read = 1;
  }else{
    for(int i=0; i<len; i++){
      reg_data[i] = Wire.read();
    }
    rslt_read = 0;
  }

  return rslt_read;
}
//******************************
int8_t user_i2c_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len)
{
  int8_t rslt_write = 0; /* Return 0 for Success, non-zero for failure */

  Wire.beginTransmission( dev_id );
  Wire.write( reg_addr );
  for( int i = 0; i < len; i++ ){
    Wire.write( reg_data[i] );
  }
  rslt_write = Wire.endTransmission();

  return rslt_write;
}

【ザッと解説】

●32行目は、英語のコメントにもあるように、ガスセンサを使用しない場合に測定した気温に設定せよ、ということのようです。
その場合、47行目をコメントアウトして、48行目のコメントを外して、ガスセンサを無効にします。
そして、しばらく(30分くらい)測定して、安定した温度を
amb_temp
とするということのようです。
その後、ガスセンサ有効にして、再コンパイルしてください。

●50行目で、ガスセンサのヒーター温度を設定しています。
320℃って、めちゃめちゃ高温ですね。
これが、51行目にあるように、150msで高速加熱しているように見受けられます。

●55行目で Force Mode に設定しています。
BME280 と同様、Force Mode の場合は、測定前に必ずセンサ設定に毎回書き込む必要があります。

70行目と74行目が特に重要です。
meas_period は、センサ測定時間間隔ですが、BME680ドライバライブラリでは70行目のこの関数で meas_period を自動計算してくれます
ただし、これはおそらく、Force モードで一度測定し終わったら、ヒーター等の関係上、次の測定が可能になるまでの最低限の時間間隔を自動計算してくれるだけのようです。
実際に測定してみると、この自動計算された meas_period 間隔では、温度が+5℃も誤差がありました。
温度・湿度の精度を求めるならば、74行目をコメントアウトして、75行目のコメントを解除してください。
meas_period = 3000 ms くらいあれば、かなり精度が上がると思います。
ただ、これが本当に正しい方法かどうかは分かりません。
あくまで、私個人の見解です。

●81行目では、ガスセンサの起動時は値が安定しておらず、使えないデータなので、使えるデータになったら、測定値を表示するというもののようです。

meas_periodを自動計算にして、コンパイル書き込み実行

では、まず、meas_period を自動計算にして測定してみます。

先ほどの解説で述べたように、47-48行目のコメントアウト、コメント解除をして、
BME680_DISABLE_GAS_MEAS
として、ガスセンサを無効にし、Arduino IDE でコンパイル書き込み実行してください。

30分くらい動作させて、温度センサ値が安定したら、その温度整数値を32行目に入力してください。

その後、47-48行目で、
BME680_ENABLE_GAS_MEAS
にして、ガスセンサを有効にしてください。

そうしたら、再度、Arduino IDE でコンパイル書き込み実行させてみてください。

シリアルモニターを115200bps で起動し、センサ起動直後はこんな感じになります。

ガスセンサの値が不安定です。

これがしばらく経つ(20分以上経過)と、こんな値で安定してきます。

ガスセンサの値は落ち着いていますが、温度と湿度が市販の温湿度計と比べて誤差が大き過ぎます。
温度が +5℃も大きく、湿度は -10% になっていました。

これでは使えません。

ということで、次の項では、meas_period を自動計算ではなく、3000ms( 3秒 )に替えてみます。

meas_periodを3秒にして、コンパイル書き込み実行

では、meas_period = 3000; にしてみます。

74行目をコメントアウトして、75行目のコメントを外してみて下さい。
それで、コンパイルし直して、シリアルモニターで見てみます。
起動後、20分以上経過したものです。

市販の温湿度計と比べて、温度の誤差が +1℃、湿度の誤差が + 2% にまでなりました。
この精度であれば問題無く使えますね。

ただ、ガスセンサの抵抗値が、meas_period 自動計算の安定時とは異なることが気になりますね。

ガスセンサ値については、測定間隔が空きすぎると、ヒーターを使っている関係上、安定するまでに時間がかかるものと思われます。

meas_period 自動計算時、安定期の 105000Ω という値と、
meas_period = 3000 時、安定期の 35000Ωという値に注目してみると、
meas_period = 3000 時の値は、センサ起動時の不安定値のような気がします。
これはあくまで個人的見解です。

本当はデータシートを読み込めばこの辺のことは書いてあるかも知れませんが、私の英語力ではしばらくは無理です。
あくまで想像するしかありません。
またどなたかが和訳してくれると助かるんですが・・・。

では、meas_period = 3000時のガスセンサ値は使えるのかどうか、次の項で Ambient へデータを送信するスケッチで考えてみます。

コメント

タイトルとURLをコピーしました