(Arduino)ESP32モジュールを用いた温湿度気圧センサ(BME280)表示プログラム

#プログラム動作内容
今回は、温湿度気圧センサ(BME280)を使用して取得した「温度、湿度、気圧」を5秒毎に測定値をSPI通信にて受信し、その各値をシリアルモニターとI2C通信のLCDにそれぞれ表示させるプログラムを作成する。
なお、タクトスイッチを外部割り込み処理として使用し、測定開始&終了を制御できる機能も追加する。

#温湿度気圧センサ(BME280)の使用方法
[BME280](http://akizukidenshi.com/catalog/g/gK-09421/)は、動作電源が1.71V~3.6VであるためESP32の駆動電源3.3Vのままで使用でき、SPI通信もしくはI2C通信によって温度・湿度・気圧の3データを測定できるセンサーである。
秋月電子で販売されており、抵抗等が既に接続されたモジュールであるためESP32のピンにそのまま接続するだけで使用可能です。
SPI通信もしくはI2C通信どちらでも使用可能であるが、過去記事にてI2Cを使用したことがあるためSPI通信にて値を取得するようにプログラムを作成する。
BME280を使用するための詳細設定については、プログラム紹介箇所にて説明します。
※[BME280データシート](http://akizukidenshi.com/download/ds/bosch/BST-BME280_DS001-10.pdf)

#SPI通信とは
SPI通信とは、指示を出すマスター側(1台)と指示を受けるスレーブ側(複数台)で、データのタイミングを同期する「クロック信号:SCLK」とデータの入出力関係の「データ入力信号:SDI」、「データ出力信号：SDO」とデータのやりとりを有効にさせる「チップセレクト信号：CS」の4本の信号でデータのやりとりを行う同期式シリアル通信方式です。
I2C通信と比較すると信号線が多くなっており、データ入力と出力が別々の線になっているため、送受信を同時に行うことができることから通信速度が早い特徴が見られる。
ただし、チップセレクト信号(CS)はスレーブの数だけ用意する必要があるため接続やプログラムが多少複雑になってしまう短所がある。
<img width="737" alt="スクリーンショット 2020-03-25 23.01.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595774/522bdde9-7719-f29f-9516-5def465bd303.png">
詳細な仕組みについては、以下サイトにて紹介されているのでそちらにて確認ください。
　.https://www.analog.com/jp/analog-dialogue/articles/introduction-to-spi-interface.html

#回路図
[過去の記事](https://qiita.com/pontaman007/items/f47ead88beacf50e9912)で回路図について作成しているので詳細はそちらを確認ください。
ピン接続は以下の通りにして下さい。
<img width="1321" alt="スクリーンショット 2020-03-25 23.08.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595774/815b435a-c609-6341-8f11-0062089e1a8f.png">

#作成プログラムについて
BME280のライブラリについては以下のページものをそのまま活用させていただきました。
詳しくは下記ページの「自作ライブラリインストール」項目を参照ください。
　・https://www.mgo-tec.com/blog-entry-esp32-bme280-sensor-library.html
ダウンロードしたライブラリは、「書類->Arduino->libraries」内にフォルダを保存ください。

作成したプログラムで実際に動作した状態を以下に示す。
<b>・起動後の測定待機画面</b>
<img width="508" alt="スクリーンショット 2020-03-25 23.42.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595774/7ac4ddcf-db84-bc9f-8ed2-b63ff60c9c2c.png">
<b>・測定開始ボタンを押した直後</b>
<img width="471" alt="スクリーンショット 2020-03-25 23.42.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595774/b243633c-5312-8877-f48e-41124daf04f6.png">
<b>・温湿度気圧値表示</b>　※LCDに℃がなかったのでCで代用している
<img width="479" alt="スクリーンショット 2020-03-25 23.42.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595774/7cfa674e-76dd-4189-adcb-80ef4adf8f11.png">
<b>・測定停止ボタンを押した直後</b>
<img width="447" alt="スクリーンショット 2020-03-25 23.43.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595774/060a6ad6-ee9c-2f0a-3be0-183e3bc2c6e0.png">
<b>・シリアルモニターの表示</b>
<img width="907" alt="スクリーンショット 2020-03-25 23.33.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/595774/7d2a14a6-2a2c-03bb-b6bf-d82562fab90e.png">

以下は今回使用したプログラムなのでコピーして使用してみて下さい。

```C:03_BME280_SPI_TEST1
/*  作成日；2020/3/7
    ファイル名；03_BME280_SPI_TEST1
    プログラム内容；温湿度気圧センサー(BME280)から各データを取得してシリアルモニターとLCDに表示する
    　　　　　　　　タクトスイッチを押すごとに測定開始と終了を切り替える
    使用部品；ESP32、BME280、タクトスイッチ、LCD
    ESP32へのピン接続；(14:BME280_SCK、13:BME280_SDI、12:BME280_SDO、26:BME280_CSB)、(タクトスイッチ:34)、(ESP32側；LCD側)；(21:SDA)、(22:SCL)
 */

#include "ESP32_BME280_SPI.h" //BME280ライブラリ
#include<Wire.h>  //I2C通信ライブラリ

#define LCD_ADRS 0x3E //LCD通信用I2Cアドレス

//各種SPI通信用変数設定
const uint8_t SCLK_bme280 = 14; //クロック入力
const uint8_t MOSI_bme280 =13; //マスター(ESP32):出力、スレーブ(BME280):入力
const uint8_t MISO_bme280 =12; //マスター(ESP32):入力、スレーブ(BME280):出力
const uint8_t CS_bme280 = 26; //チップ選択

//各種BME280測定モード設定用変数設定
uint8_t t_sb = 0; //測定間でのスタンバイ時間=0.5[ms] (0:0.5ms、1:62.5ms、2:125ms、3:250ms、4:500ms、5:1000ms、6:10、7:20ms)
uint8_t filter = 4; //測定値精度=16 (0:フィルターオフ、1:2、2:4、3:8、4以上:16) ※数字が大きいほどサンプリング回数が増える
uint8_t osrs_t = 2; //温度のオーバーサンプリング値=2 (0:無(ノイズ影響受ける)、1:1、2:2、3:4、4:8、5以上:16) ※オーバサンプリングをすると測定時間が伸びるがノイズ影響が減る
uint8_t osrs_p = 5; //気圧のオーバーサンプリング値=5 (0:無(ノイズ影響受ける)、1:1、2:2、3:4、4:8、5以上:16) ※オーバサンプリングをすると測定時間が伸びるがノイズ影響が減る
uint8_t osrs_h = 1; //湿度のオーバーサンプリング値=1 (0:無(ノイズ影響受ける)、1:1、2:2、3:4、4:8、5以上:16) ※オーバサンプリングをすると測定時間が伸びるがノイズ影響が減る
uint8_t Mode = 3; //計測=スリープモード(0:スリープモード(計測しない,電源ON直後)、1or2:フォースドモード(1度だけ測定)、3:ノーマルモード(繰り返し測定))

const uint16_t Tac_SW1 = 34;  //タクトスイッチ1(計測開始、終了ボタン)
bool Mesure_Flag = false;  //タクトスイッチ1割り込みフラグ
bool Mode_Flag = false;  //モード変更フラグ

volatile unsigned long time_prev = 0; //割り込み時刻コピー変数
volatile unsigned long time_now;  //現在の割り込み時刻取得変数
unsigned long time_chat = 500;  //割り込み時刻
 
ESP32_BME280_SPI bme280spi(SCLK_bme280, MOSI_bme280, MISO_bme280, CS_bme280, 10000000); //10MHzにてSPIクラスのインスタンスを生成


/*  初期設定  */
void setup(){
  
  Serial.begin(115200); //シリアル通信レート

  Wire.begin(); //I2C通信開始(ESP32をマスター)
  
  bme280spi.ESP32_BME280_SPI_Init(t_sb, filter, osrs_t, osrs_p, osrs_h, Mode);  //各レジスタに初期設定をSPI通信にて書き込み

  init_LCD(); //LCD初期化
  lcdwriteData("Booting now..."); //LCDへ起動中の表示
  
  /*  ここに起動時に確認する項目を記載  */
  delay(2000);
  /*  ここに起動時に確認する項目を記載  */

  //「Set DDRAM Address」= 1番目：0x○○(液晶表示入りのアドレス値)、2番目:0x80(機械コード「Set DDRAM Address」)
  lcdwriteCommand(0x40+0x80); //2行目へカーソル移動(0x40 = 2行目先頭文字アドレス、0x80 = DDRAMアドレスへの移動)
  lcdwriteData("OK"); //起動OKの表示
  delay(2000);
  lcdwriteCommand(0x01);  //LCD液晶文字クリア([Clear Display])
  lcdwriteData("Mesure Wating"); //測定待ちの表示

  pinMode(Tac_SW1, INPUT);  //タクトスイッチ入力
  attachInterrupt(Tac_SW1, mesure_change, RISING);  //タクトスイッチを押すと計測開始or終了
  
}
/*  初期設定  */


/*  メイン本文  */
void loop(){
  
  if(Mode_Flag){  //測定モード変更スイッチが押されたら

    if(Mesure_Flag){  //計測開始の場合

      //シリアルモニターへ表示
      Serial.println("Mesure START");
      Serial.println();

      //LCDへ表示
      lcdwriteCommand(0x01);  //LCD液晶文字クリア([Clear Display])
      lcdwriteData("Mesure START"); //測定待ちの表示
      
      Mode = 3; //計測モードを繰り返し測定に変数指定
      
    }else{  //計測終了の場合

      //シリアルモニターへ表示
      Serial.println("Mesure STOP");
      Serial.println();

      //LCDへ表示
      lcdwriteCommand(0x01);  //LCD液晶文字クリア([Clear Display])
      lcdwriteData("Mesure STOP"); //測定待ちの表示
      
      Mode = 0; // 計測モードをスリープ状態に変数指定
      
    }

    uint8_t ctrl_meas = (osrs_t << 5) | (osrs_p << 2) | Mode; //測定条件レジスタに書き込む内容を入力
    bme280spi.WriteRegister(0xF4, ctrl_meas); //測定モード変更レジスタ(ctrl_meas 0xF4)へモード変更を書き込み
    Mode_Flag = false;   //モード変更フラグリセット
    
  }

  
  while(Mesure_Flag & !Mode_Flag){  //計測開始になれば
    
    delay(5000);  //5秒毎に表示
    bme_get();  //各値を取得しシリアルモニター&LCDへ出力
    

  }
  
}
/*  メイン本文  */

 
/*  BME280測定  */
void bme_get(){ 
  
  double temperature = bme280spi.Read_Temperature();  //温度を取得
  double humidity = bme280spi.Read_Humidity();  //湿度を取得
  double pressure = bme280spi.Read_Pressure();  //気圧を取得

  //シリアルモニターへ各値を表示
  Serial.println("Temperature = " + String(temperature, 1) + "℃");
  Serial.println("Humidity = " + String(humidity, 1) + "%");
  Serial.println("Pressure = " + String(pressure, 1) + "hPa");
  Serial.println();

  //LCDへ各値を表示
  lcdwriteCommand(0x01);  //LCD液晶文字クリア([Clear Display])
  lcdwriteData("T=" + String(temperature, 1) + "C ");
  lcdwriteData("H=" + String(humidity, 1) + "%");
  lcdwriteCommand(0x40+0x80); //2行目へカーソル移動
  lcdwriteData("P=" + String(pressure, 1) + "hPa");
  
}
/*  BME280測定  */


/*  測定モード変更  */
void mesure_change(){ //タクトスイッチが押されたら

  time_now = millis(); //現在の割り込み時刻を取得
  if( time_now-time_prev > time_chat){  //前回の割り込みから500[ms]以上経過ならば

    Mesure_Flag = !Mesure_Flag; //測定フラグ反転
    Mode_Flag = !Mode_Flag; //モードフラグ反転
  }
  time_prev = time_now; //現在の割り込み時刻を前回の割り込み時刻へコピー
  
}
/*  測定モード変更  */


/*  データ書き込み(複数byte) */
void lcdwriteData(String t_data){
  
  int m_count = t_data.length();  //送信データの文字数をカウント
  
  //全文字を表示
  for(int i=0;i<m_count;i++){

    Wire.beginTransmission(LCD_ADRS); //LCDをI2Cスレーブとして通信開始([slave address])
    Wire.write(0x40); //最終データ、LCDへの表示データ([control byte] = 8bit目 0:最終,1:連続、7bit目 0:命令,1:表示データ)
    Wire.write(t_data[i]);  //1文字をキューに格納
    Wire.endTransmission(); //キューに格納されたデータを送信してI2C通信停止

  }
  
}
/*  データ書き込み(複数byte) */


/*  コマンド書き込み(1byte)  */
void lcdwriteCommand(byte t_command){ //(書き込み順 = [slave address] + [control byte] + [data byte] )
  
  Wire.beginTransmission(LCD_ADRS); //LCDをI2Cスレーブとして通信開始([slave address])
  Wire.write(0x00); //最終データ、LCDへの命令([control byte] = 8bit目 0:最終,1:連続、7bit目 0:命令,1:表示データ)
  Wire.write(t_command);  //命令文を送信([data byte])
  Wire.endTransmission(); //I2C通信停止
  delay(10);  //10ms待つ
  
}
/*  コマンド書き込み(1byteずつ)   */


/*  LCD初期化  */
void init_LCD(){
  
  delay(100); //電源ON後40ms以上待つ
  //[Function set] = 5bit目 0:4ビット,1:8ビット、4bit目 0:1行,1:2行、3bit目 フォントサイズ(0でOK)、1bit目 0:通常状態,1:以降拡張コマンド入力
  lcdwriteCommand(0x38); //8ビット、2行表示、5×8ドット、通常状態([Function set])
  delay(20); //26.3μs以上待つ(「lcdwriteCommand」で10ms待つためなくてもOK)
  lcdwriteCommand(0x39); //8ビット、2行表示、5×8ドット、以降拡張コマンド入力([Function set])
  delay(20); //26.3μs以上待つ(「lcdwriteCommand」で10ms待つためなくてもOK)
  //[Internal OSC frequency] = 4bit目 0:1/5バイアス電圧,1:1/4バイアス電圧、3〜1bit フレーム周波数[Hz]
  lcdwriteCommand(0x14);  //1/5バイアス電圧、フレーム周波数183[Hz]([Internal OSC frequency])
  delay(20); //26.3μs以上待つ(「lcdwriteCommand」で10ms待つためなくてもOK)
  //[Contrast set] = 4〜1bit コントラスト64段階調整([Power/ICONcontrol/Contrast set]と併せて設定)
  lcdwriteCommand(0x73);  //コントラスト設定([Contrast set])
  delay(20); //26.3μs以上待つ(「lcdwriteCommand」で10ms待つためなくてもOK)
  //[Power/ICONcontrol/Contrast set] = 4bit目 0:アイコン無,1:アイコン有(このLCDにはアイコンがないため0で設定)、3bit目 0:ブースターON(3.3V時),1:ブースターOFF(5V時)、
  //                                   2〜1bit コントラスト64段階調整([Contrast set]と併せて設定))
  lcdwriteCommand(0x56);  //アイコン無、ブースターON(3.3Vのため)、コントラスト設定(35)([Power/ICONcontrol/Contrast set]) 
  delay(20); //26.3μs以上待つ(「lcdwriteCommand」で10ms待つためなくてもOK)
  //[Follower control] = 4bit目 0:フォロア回路OFF,1:フォロア回路ON、3〜1bit 増幅率の設定(0〜7)
  lcdwriteCommand(0x6C);  //フォロア回路ON、増幅度6([Follower control])
  delay(500); //200ms以上待つ
  lcdwriteCommand(0x38);  //8ビット、2行表示、5×8ドット、通常状態(拡張コマンド入力終了)([Function set])
  delay(20); //26.3μs以上待つ(「lcdwriteCommand」で10ms待つためなくてもOK)
  lcdwriteCommand(0x01);  //LCD液晶文字クリア([Clear Display])
  delay(20); //26.3μs以上待つ(「lcdwriteCommand」で10ms待つためなくてもOK)
  //[Display ON/OFF] = 3bit目 0:文字表示OFF(RAM内のデータはそのまま),1:文字表示ON、2bit目 0:カーソル表示OFF,1:カーソル表示ON、
  //                   1bit目 0:ブランク表示OFF,1:ブランク表示ON
  lcdwriteCommand(0x0F);  //文字表示ON、カーソル表示ON、ブランク表示ON([Display ON/OFF])
  delay(20); //26.3μs以上待つ(「lcdwriteCommand」で10ms待つためなくてもOK)
  
}
/*  LCD初期化  */
```

以下から各ブロックの説明をしていきます。
※I2CにてLCDへ表示するプログラムについては[過去記事](https://qiita.com/pontaman007/items/4b85cf9406a7bf995e83)で紹介されているため説明は省略します。

①ライブラリ定義、グローバル変数設定等

```C:03_BME280_SPI_TEST1(抜粋)
/*  作成日；2020/3/7
    ファイル名；03_BME280_SPI_TEST1
    プログラム内容；温湿度気圧センサー(BME280)から各データを取得してシリアルモニターとLCDに表示する
    　　　　　　　　タクトスイッチを押すごとに測定開始と終了を切り替える
    使用部品；ESP32、BME280、タクトスイッチ、LCD
    ESP32へのピン接続；(14:BME280_SCK、13:BME280_SDI、12:BME280_SDO、26:BME280_CSB)、(タクトスイッチ:34)、(ESP32側；LCD側)；(21:SDA)、(22:SCL)
 */

#include "ESP32_BME280_SPI.h" //BME280ライブラリ
#include<Wire.h>  //I2C通信ライブラリ

#define LCD_ADRS 0x3E //LCD通信用I2Cアドレス

//各種SPI通信用変数設定
const uint8_t SCLK_bme280 = 14; //クロック入力
const uint8_t MOSI_bme280 =13; //マスター(ESP32):出力、スレーブ(BME280):入力
const uint8_t MISO_bme280 =12; //マスター(ESP32):入力、スレーブ(BME280):出力
const uint8_t CS_bme280 = 26; //チップ選択

//各種BME280測定モード設定用変数設定
uint8_t t_sb = 0; //測定間でのスタンバイ時間=0.5[ms] (0:0.5ms、1:62.5ms、2:125ms、3:250ms、4:500ms、5:1000ms、6:10、7:20ms)
uint8_t filter = 4; //測定値精度=16 (0:フィルターオフ、1:2、2:4、3:8、4以上:16) ※数字が大きいほどサンプリング回数が増える
uint8_t osrs_t = 2; //温度のオーバーサンプリング値=2 (0:無(ノイズ影響受ける)、1:1、2:2、3:4、4:8、5以上:16) ※オーバサンプリングをすると測定時間が伸びるがノイズ影響が減る
uint8_t osrs_p = 5; //気圧のオーバーサンプリング値=5 (0:無(ノイズ影響受ける)、1:1、2:2、3:4、4:8、5以上:16) ※オーバサンプリングをすると測定時間が伸びるがノイズ影響が減る
uint8_t osrs_h = 1; //湿度のオーバーサンプリング値=1 (0:無(ノイズ影響受ける)、1:1、2:2、3:4、4:8、5以上:16) ※オーバサンプリングをすると測定時間が伸びるがノイズ影響が減る
uint8_t Mode = 3; //計測=スリープモード(0:スリープモード(計測しない,電源ON直後)、1or2:フォースドモード(1度だけ測定)、3:ノーマルモード(繰り返し測定))

const uint16_t Tac_SW1 = 34;  //タクトスイッチ1(計測開始、終了ボタン)
bool Mesure_Flag = false;  //タクトスイッチ1割り込みフラグ
bool Mode_Flag = false;  //モード変更フラグ

volatile unsigned long time_prev = 0; //割り込み時刻コピー変数
volatile unsigned long time_now;  //現在の割り込み時刻取得変数
unsigned long time_chat = 500;  //割り込み時刻
 
ESP32_BME280_SPI bme280spi(SCLK_bme280, MOSI_bme280, MISO_bme280, CS_bme280, 10000000); //10MHzにてSPIクラスのインスタンスを生成
```

「＃include "ESP32_BME280_SPI.h"」：温湿度気圧センサBME280ライブラリ

//各種SPI通信用変数ピン設定
「const uint8_t SCLK_bme280 = 14」：クロック入力(データ同期用クロック)
「const uint8_t MOSI_bme280 =13」：マスター(ESP32):出力(13)、スレーブ(BME280):入力
「const uint8_t MISO_bme280 =12」：マスター(ESP32):入力(12)、スレーブ(BME280):出力
「const uint8_t CS_bme280 = 26」：チップセレクト(入出力の情報を許可するピン)

//各種BME280測定モード設定用変数設定
「uint8_t t_sb = 0」：測定間でのスタンバイ時間=0.5[ms] (0:0.5ms、1:62.5ms、2:125ms、3:250ms、4:500ms、5:1000ms、6:10、7:20ms)
「uint8_t filter = 4」：測定値精度=16 (0:フィルターオフ、1:2、2:4、3:8、4以上:16) ※数字が大きいほどサンプリング回数が増える
「uint8_t osrs_t = 2」：温度のオーバーサンプリング値=2 (0:無(ノイズ影響受ける)、1:1、2:2、3:4、4:8、5以上:16) ※オーバサンプリングをすると測定時間が伸びるがノイズ影響が減る
「uint8_t osrs_p = 5」：気圧のオーバーサンプリング値=5 (0:無(ノイズ影響受ける)、1:1、2:2、3:4、4:8、5以上:16) ※オーバサンプリングをすると測定時間が伸びるがノイズ影響が減る
「uint8_t osrs_h = 1」：湿度のオーバーサンプリング値=1 (0:無(ノイズ影響受ける)、1:1、2:2、3:4、4:8、5以上:16) ※オーバサンプリングをすると測定時間が伸びるがノイズ影響が減る
「uint8_t Mode = 3」：計測=スリープモード(0:スリープモード(計測しない,電源ON直後)、1or2:フォースドモード(1度だけ測定)、3:ノーマルモード(繰り返し測定))

//タクトスイッチによる各種変数設定
「const uint16_t Tac_SW1 = 34」：タクトスイッチ1(計測開始、終了ボタン)の接続ピン指定
「bool Mesure_Flag = false」：タクトスイッチ1割り込みフラグ
「bool Mode_Flag = false」：モード変更フラグ(計測開始or停止)
「volatile unsigned long time_prev = 0」：割り込み時刻コピー変数
「volatile unsigned long time_now」：現在の割り込み時刻取得変数
「unsigned long time_chat = 500」：割り込み間隔の下限時刻(500ms以下の割り込みでは割り込みが発生しないようにするため)

「ESP32_BME280_SPI bme280spi(SCLK_bme280, MOSI_bme280, MISO_bme280, CS_bme280, 10000000)」：10MHzにてSPIクラスのインスタンスを生成

②初期設定

```C:03_BME280_SPI_TEST1(抜粋)
/*  初期設定  */
void setup(){
  
  Serial.begin(115200); //シリアル通信レート

  Wire.begin(); //I2C通信開始(ESP32をマスター)
  
  bme280spi.ESP32_BME280_SPI_Init(t_sb, filter, osrs_t, osrs_p, osrs_h, Mode);  //各レジスタに初期設定をSPI通信にて書き込み

  init_LCD(); //LCD初期化
  lcdwriteData("Booting now..."); //LCDへ起動中の表示
  
  /*  ここに起動時に確認する項目を記載  */
  delay(2000);
  /*  ここに起動時に確認する項目を記載  */

  //「Set DDRAM Address」= 1番目：0x○○(液晶表示入りのアドレス値)、2番目:0x80(機械コード「Set DDRAM Address」)
  lcdwriteCommand(0x40+0x80); //2行目へカーソル移動(0x40 = 2行目先頭文字アドレス、0x80 = DDRAMアドレスへの移動)
  lcdwriteData("OK"); //起動OKの表示
  delay(2000);
  lcdwriteCommand(0x01);  //LCD液晶文字クリア([Clear Display])
  lcdwriteData("Mesure Wating"); //測定待ちの表示

  pinMode(Tac_SW1, INPUT);  //タクトスイッチ入力
  attachInterrupt(Tac_SW1, mesure_change, RISING);  //タクトスイッチを押すと計測開始or終了
  
}
/*  初期設定  */
```
「bme280spi.ESP32_BME280_SPI_Init(t_sb, filter, osrs_t, osrs_p, osrs_h, Mode)」：グローバル変数にて定義した温湿度気圧センサーの各レジスタ設定値をSPI通信にて書き込む初期設定関数
※実際に中身の.cppファイルを見ると様々な処理を行っているため興味ある方は見てみてください。簡単に中身の説明をすると、「BME280とSPI通信開始」→「各レジスタに設定値をSPI通信にて書き込み」→「温湿度気圧の初期値を読み込み」をする関数となっています。
「pinMode(Tac_SW1, INPUT)」：タクトスイッチを入力処理に設定
「attachInterrupt(Tac_SW1, mesure_change, RISING)」：タクトスイッチを押すと電圧が変化(RISING:立ち上がり)が起こると測定状態変更関数(mesure_change)の割り込み処理を有効にする

③メイン(ループ)

```C:03_BME280_SPI_TEST1(抜粋)
/*  メイン本文  */
void loop(){
  
  if(Mode_Flag){  //測定モード変更スイッチが押されたら

    if(Mesure_Flag){  //計測開始の場合

      //シリアルモニターへ表示
      Serial.println("Mesure START");
      Serial.println();

      //LCDへ表示
      lcdwriteCommand(0x01);  //LCD液晶文字クリア([Clear Display])
      lcdwriteData("Mesure START"); //測定待ちの表示
      
      Mode = 3; //計測モードを繰り返し測定に変数指定
      
    }else{  //計測終了の場合

      //シリアルモニターへ表示
      Serial.println("Mesure STOP");
      Serial.println();

      //LCDへ表示
      lcdwriteCommand(0x01);  //LCD液晶文字クリア([Clear Display])
      lcdwriteData("Mesure STOP"); //測定待ちの表示
      
      Mode = 0; // 計測モードをスリープ状態に変数指定
      
    }

    uint8_t ctrl_meas = (osrs_t << 5) | (osrs_p << 2) | Mode; //測定条件レジスタに書き込む内容を入力
    bme280spi.WriteRegister(0xF4, ctrl_meas); //測定モード変更レジスタ(ctrl_meas 0xF4)へモード変更を書き込み
    Mode_Flag = false;   //モード変更フラグリセット
    
  }

  while(Mesure_Flag & !Mode_Flag){  //計測開始になれば
    
    delay(5000);  //5秒毎に表示
    bme_get();  //各値を取得しシリアルモニター&LCDへ出力
    
  }
  
}
/*  メイン本文  */
```

//測定モード変更処理
「Mode = 3」：計測モードを繰り返し測定に変数指定　※if(Mesure_Flag)内(計測開始の場合)
「Mode = 0」：計測モードをスリープ状態に変数指定　※else内(計測終了の場合)
「uint8_t ctrl_meas = (osrs_t << 5) | (osrs_p << 2) | Mode」：測定条件レジスタ(ctrl_meas)へ測定モード変更(Mode)を入力
「bme280spi.WriteRegister(0xF4, ctrl_meas)」：測定モード変更レジスタ(ctrl_meas 0xF4)へモード変更を書き込み
「Mode_Flag = false」：測定モード変更フラグをリセット

//温湿度気圧測定値の取得&表示
「while(Mesure_Flag & !Mode_Flag)」：計測開始条件になればループ処理開始
「bme_get()」：各値(温湿度気圧)を取得してシリアルモニター&LCDへ表示

④BME280測定データ取得&表示

```C:03_BME280_SPI_TEST1(抜粋)
/*  BME280測定  */
void bme_get(){ 
  
  double temperature = bme280spi.Read_Temperature();  //温度を取得
  double humidity = bme280spi.Read_Humidity();  //湿度を取得
  double pressure = bme280spi.Read_Pressure();  //気圧を取得

  //シリアルモニターへ各値を表示
  Serial.println("Temperature = " + String(temperature, 1) + "℃");
  Serial.println("Humidity = " + String(humidity, 1) + "%");
  Serial.println("Pressure = " + String(pressure, 1) + "hPa");
  Serial.println();

  //LCDへ各値を表示
  lcdwriteCommand(0x01);  //LCD液晶文字クリア([Clear Display])
  lcdwriteData("T=" + String(temperature, 1) + "C ");
  lcdwriteData("H=" + String(humidity, 1) + "%");
  lcdwriteCommand(0x40+0x80); //2行目へカーソル移動
  lcdwriteData("P=" + String(pressure, 1) + "hPa");
  
}
/*  BME280測定  */
```

//各値を取得
「double temperature = bme280spi.Read_Temperature()」：温度を取得（温度測定レジスタ[0xFA]よりSPI通信にて値を読み込み&計算）
「double humidity = bme280spi.Read_Humidity()」：湿度を取得（湿度測定レジスタ[0xFD]よりSPI通信にて値を読み込み&計算）
「double pressure = bme280spi.Read_Pressure()」：気圧を取得（気圧測定レジスタ[0xF7]よりSPI通信にて値を読み込み&計算）

⑤測定モード変更割り込み関数

```C:03_BME280_SPI_TEST1(抜粋)
/*  測定モード変更  */
void mesure_change(){ //タクトスイッチが押されたら

  time_now = millis(); //現在の割り込み時刻を取得
  if( time_now-time_prev > time_chat){  //前回の割り込みから500[ms]以上経過ならば

    Mesure_Flag = !Mesure_Flag; //測定フラグ反転
    Mode_Flag = !Mode_Flag; //モードフラグ反転
  }
  time_prev = time_now; //現在の割り込み時刻を前回の割り込み時刻へコピー
  
}
/*  測定モード変更  */
```

「time_now = millis()」：プログラムが開始されてから割り込みが発生するまでの経過時間を取得
「if( time_now-time_prev > time_chat)」：前回の割り込み発生から500[ms]以上経過ならば(チャタリング防止)
「Mesure_Flag = !Mesure_Flag」：測定フラグ反転
「Mode_Flag = !Mode_Flag」：モードフラグ反転
「time_prev = time_now」：現在の割り込み時刻を前回の割り込み時刻へコピー

#次回記事予定
過去に作成した各プログラム要素(LCD表示、赤外線リモコン送受信、温湿度気圧取得)全て使用可能なプログラムを作成

#参考文献
・https://www.mgo-tec.com/blog-entry-esp32-bme280-sensor-library.html
・http://trac.switch-science.com/wiki/BME280