BME680使用 温湿度・気圧・ガスセンサモジュールキット (秋月電子通商[AE-BME680]通販コードK-14469)の温湿度・気圧情報を送信します。
説明
本プログラムは,BME680使用 温湿度・気圧・ガスセンサモジュールキット(秋月電子通商[AE-BME680]通販コードK-14469)を使って,温度,湿度,気圧を取得し,その値をCLIP Viewer Liteの温度・湿度・気圧ペイロードのフォーマット仕様に合わせてELTRES送信します.
ELTRESエラー,測定開始エラー時を除き,初回GNSS電波受信後にELTRES送信を開始し継続します.温度・湿度・気圧ペイロードに設定した値はシリアルモニタで確認することができます.また,ELTRESエラー,測定開始エラー時を除き,5秒毎に取得した温度,湿度,気圧をシリアルモニタへ出力します.
ELTRESエラー,測定開始エラー時は異常終了状態でループします.
LEDの動きについては補足事項を確認してください.
動作環境
Arduino IDEを利用するSpresense Arduino 開発環境(2.5.0)上で利用できます.
以下のArduinoライブラリを利用します.
・ELTRESアドオンボード用ライブラリ(1.1.0)
・Adafruit BME680 Library(2.0.2)
https://github.com/adafruit/Adafruit_BME680
利用方法
- ELTRESアドオンボード用ライブラリをArduino IDEにインストールします.
- Adafruit BME680 LibraryをArduino IDEにインストールします.
以下の手順でインストールできます.
2-1. Arduino IDEの上部メニューから「ツール」->「ライブラリの管理」を選択します.
2-2. ライブラリマネージャを起動するので,検索バーに「BME680」を入力します.
2-3. ライブラリの一覧が更新されると,「Adafruit BME680 Library」が表示されます.
「Adafruit BME680 Library」の「インストール」ボタンをクリックします.
2-4. Dependencies確認のウインドウが表示された場合,
「Install all」ボタンをクリックします.
※他のライブラリのインストール状況により,
この確認ウインドウは表示されない場合があります. - 本プログラムをArduino IDEで開き,Spresenseに書き込みます.
- 電源を入れてプログラムを起動します.
シリアルモニタを確認したい場合,Arduino IDEと接続し,
Arduino IDEの上部メニューから「ツール」->「シリアルモニタ」を選択し,シリアルモニタを起動します.
・温度・湿度・気圧ペイロードに設定した値は"[setup_payload_temp_hum]","[setup_payload_pres]"から始まる出力で確認できます.
・取得した温度,湿度,気圧は"[measure]"から始まる出力で確認できます.
注意事項
本プログラムは,ELTRES送信間隔が1分であることを前提としてます.
3分契約の場合,EltresAddonBoard.begin()の引数 ELTRES_BOARD_SEND_MODE_1MIN を
ELTRES_BOARD_SEND_MODE_3MIN に変更してください.
補足事項
本プログラムは,下記のようにLEDを用いて状態を表現します.
LED0:[プログラム状態] 起動中:点灯,正常・異常終了:消灯
LED1:[GNSS電波状態] 受信中:点灯,未受信:消灯
LED2:[ELTRES状態] 送信中:点灯,待機中:消灯
LED3:[エラー状態] GNSS受信エラー:点滅,ELTRESエラー,測定開始エラー:点灯,エラー無し:消灯
※GNSS受信エラー発生時はGNSS電波受信するまで待ち続けます.(LED0は点灯,LED3は点滅)
※ELTRESエラー,測定開始エラー発生時は異常終了状態でループします.(LED0は消灯,LED3は点灯)
製品情報
BME680使用 温湿度・気圧・ガスセンサモジュールキット
https://akizukidenshi.com/catalog/g/gK-14469/
参考情報
温湿度・気圧・ガスセンサ(BOSCH製BME680)の詳細仕様については下記を参照してください.
https://akizukidenshi.com/download/ds/bosch/bme680.pdf
eltres_bme680.ino
#include <Wire.h>
#include <SPI.h>
#include <EltresAddonBoard.h>
// BME680用ライブラリのインクルード
#include <Adafruit_Sensor.h>
#include "Adafruit_BME680.h"
#define SEALEVELPRESSURE_HPA (1016.2) // 東京の海面気圧
Adafruit_BME680 bme; // I2C
// PIN定義:LED(プログラム状態)
#define LED_RUN PIN_LED0
// PIN定義:LED(GNSS電波状態)
#define LED_GNSS PIN_LED1
// PIN定義:LED(ELTRES状態)
#define LED_SND PIN_LED2
// PIN定義:LED(エラー状態)
#define LED_ERR PIN_LED3
// プログラム内部状態:初期状態
#define PROGRAM_STS_INIT (0)
// プログラム内部状態:起動中
#define PROGRAM_STS_RUNNING (1)
// プログラム内部状態:終了
#define PROGRAM_STS_STOPPED (3)
// プログラム内部状態
int program_sts = PROGRAM_STS_INIT;
// GNSS電波受信タイムアウト(GNSS受信エラー)発生フラグ
bool gnss_recevie_timeout = false;
// 点滅処理で最後に変更した時間
uint64_t last_change_blink_time = 0;
// イベント通知での送信直前通知(5秒前)受信フラグ
bool event_send_ready = false;
// ペイロードデータ格納場所
uint8_t payload[16];
// ペイロードデータの内容
bool send_temp_hum = true;
// 最新値(温度)
float last_temp = 0;
// 最新値(湿度)
float last_hum = 0;
// 最新値(気圧)
float last_pres = 0;
/**
* @brief イベント通知受信コールバック
* @param event イベント種別
*/
void eltres_event_cb(eltres_board_event event) {
switch (event) {
case ELTRES_BOARD_EVT_GNSS_TMOUT:
// GNSS電波受信タイムアウト
Serial.println("gnss wait timeout error.");
gnss_recevie_timeout = true;
break;
case ELTRES_BOARD_EVT_IDLE:
// アイドル状態
Serial.println("waiting sending timings.");
digitalWrite(LED_SND, LOW);
break;
case ELTRES_BOARD_EVT_SEND_READY:
// 送信直前通知(5秒前)
Serial.println("Shortly before sending, so setup payload if need.");
event_send_ready = true;
break;
case ELTRES_BOARD_EVT_SENDING:
// 送信開始
Serial.println("start sending.");
digitalWrite(LED_SND, HIGH);
break;
case ELTRES_BOARD_EVT_GNSS_UNRECEIVE:
// GNSS電波未受信
Serial.println("gnss wave has not been received.");
digitalWrite(LED_GNSS, LOW);
break;
case ELTRES_BOARD_EVT_GNSS_RECEIVE:
// GNSS電波受信
Serial.println("gnss wave has been received.");
digitalWrite(LED_GNSS, HIGH);
gnss_recevie_timeout = false;
break;
case ELTRES_BOARD_EVT_FAULT:
// 内部エラー発生
Serial.println("internal error.");
break;
}
}
/**
* @brief setup()関数
*/
void setup() {
// シリアルモニタ出力設定
Serial.begin(115200);
while (!Serial);
Serial.println(F("ELTRES BME680 program"));
// LED初期設定
pinMode(LED_RUN, OUTPUT);
digitalWrite(LED_RUN, HIGH);
pinMode(LED_GNSS, OUTPUT);
digitalWrite(LED_GNSS, LOW);
pinMode(LED_SND, OUTPUT);
digitalWrite(LED_SND, LOW);
pinMode(LED_ERR, OUTPUT);
digitalWrite(LED_ERR, LOW);
// ELTRES起動処理
eltres_board_result ret = EltresAddonBoard.begin(ELTRES_BOARD_SEND_MODE_1MIN,eltres_event_cb, NULL);
if (ret != ELTRES_BOARD_RESULT_OK) {
// ELTRESエラー発生
digitalWrite(LED_RUN, LOW);
digitalWrite(LED_ERR, HIGH);
program_sts = PROGRAM_STS_STOPPED;
Serial.print("cannot start eltres board (");
Serial.print(ret);
Serial.println(").");
return;
}
// 測定開始
if (!bme.begin()) {
// 測定開始エラー
Serial.println("Could not find a valid BME680 sensor, check wiring!");
EltresAddonBoard.end();
digitalWrite(LED_RUN, LOW);
digitalWrite(LED_ERR, HIGH);
program_sts = PROGRAM_STS_STOPPED;
return;
}
// 正常
program_sts = PROGRAM_STS_RUNNING;
// オーバーサンプリングのセットアップとフィルタ初期化
bme.setTemperatureOversampling(BME680_OS_8X);
bme.setHumidityOversampling(BME680_OS_2X);
bme.setPressureOversampling(BME680_OS_4X);
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme.setGasHeater(320, 150); // 320*C for 150 ms
}
/**
* @brief loop()関数
*/
void loop() {
if (! bme.performReading()) {
Serial.println("Failed to perform reading :(");
return;
}
switch (program_sts) {
case PROGRAM_STS_RUNNING:
// プログラム内部状態:起動中
if (gnss_recevie_timeout) {
// GNSS電波受信タイムアウト(GNSS受信エラー)時の点滅処理
uint64_t now_time = millis();
if ((now_time - last_change_blink_time) >= 1000) {
last_change_blink_time = now_time;
bool set_value = digitalRead(LED_ERR);
bool next_value = (set_value == LOW) ? HIGH : LOW;
digitalWrite(LED_ERR, next_value);
}
} else {
digitalWrite(LED_ERR, LOW);
}
if (event_send_ready) {
// 送信直前通知時の処理
event_send_ready = false;
if (send_temp_hum){
setup_payload_temp_hum(last_temp, last_hum);
// 気温,湿度送信ペイロードの設定
EltresAddonBoard.set_payload(payload);
send_temp_hum = false;
} else {
setup_payload_pres(last_pres);
// 気圧ペイロードの設定
EltresAddonBoard.set_payload(payload);
send_temp_hum = true;
}
}
// BME680から値を取得し,最新値を更新
measure_bme680();
break;
case PROGRAM_STS_STOPPED:
// プログラム内部状態:終了
break;
}
// 次のループ処理まで100ミリ秒待機
delay(100);
}
/**
* @brief 温度・湿度 ペイロード設定
* @param temp 温度
* @param hum 湿度
*/
void setup_payload_temp_hum(float temp, float hum) {
// 設定情報をシリアルモニタへ出力
Serial.print("[setup_payload_temp_hum]");
Serial.print("tem:");
Serial.print(temp, 6);
Serial.print(",hum:");
Serial.print(hum, 6);
Serial.println();
// ペイロード領域初期化
memset(payload, 0x00, sizeof(payload));
// ペイロード種別[温度・湿度・CO2ペイロード]設定
payload[0] = 0x82;
// 温度設定
uint32_t raw;
raw = *((uint32_t*)&temp);
payload[1] = (uint8_t)((raw >> 24) & 0xff);
payload[2] = (uint8_t)((raw >> 16) & 0xff);
payload[3] = (uint8_t)((raw >> 8) & 0xff);
payload[4] = (uint8_t)((raw >> 0) & 0xff);
// 湿度設定
raw = *((uint32_t*)&hum);
payload[5] = (uint8_t)((raw >> 24) & 0xff);
payload[6] = (uint8_t)((raw >> 16) & 0xff);
payload[7] = (uint8_t)((raw >> 8) & 0xff);
payload[8] = (uint8_t)((raw >> 0) & 0xff);
}
/**
* @brief 気圧 ペイロード設定
* @param pres 気圧
*/
void setup_payload_pres(float pres) {
// 設定情報をシリアルモニタへ出力
Serial.print("[setup_payload_pres]");
Serial.print("pres:");
Serial.print(pres, 6);
Serial.println();
// ペイロード領域初期化
memset(payload, 0x00, sizeof(payload));
// ペイロード種別[気圧・圧力・照度・距離ペイロード]設定
payload[0] = 0x85;
// 気圧設定
uint32_t raw;
raw = *((uint32_t*)&pres);
payload[1] = (uint8_t)((raw >> 24) & 0xff);
payload[2] = (uint8_t)((raw >> 16) & 0xff);
payload[3] = (uint8_t)((raw >> 8) & 0xff);
payload[4] = (uint8_t)((raw >> 0) & 0xff);
}
/**
* @brief BME680から温度,湿度,気圧を取得し,最新値を更新
*/
void measure_bme680() {
// 最新値の更新
last_temp = bme.temperature;
last_hum = bme.humidity;
last_pres = bme.pressure / 100.0;
// 最新値をシリアルモニタへ出力
Serial.println("[measure]:");
Serial.print("Temperature = ");
Serial.print(last_temp, 6);
Serial.println(" °C");
Serial.print("Humidity = ");
Serial.print(last_hum, 6);
Serial.println(" %");
Serial.print("Pressure = ");
Serial.print(last_pres, 6);
Serial.println(" hPa");
Serial.println();
}
-
kayrlas
さんが
2022/09/26
に
編集
をしました。
(メッセージ: 初版)
ログインしてコメントを投稿する