Arduino と温湿度気圧センサ BME280 を接続し、温度・湿度・気圧を測定します。
ここでは Arduino Nano と、BME280 を使いやすくした AE-BME280 を使用し、I2C と SPI 接続両方について解説します。
回路とプログラムは Arduino Uno にも対応しています。
Arduino 自体の使い方については他の記事をご参照ください。
用意するもの
部品名 | 画像 | はんだ付け | 入手先 (参考) |
---|---|---|---|
Arduino Nano (Arduino UNO でも可) |
必要なし | 秋月電子 など | |
AE-BME280 温湿度・気圧センサモジュール |
必要 | 秋月電子 | |
AE-PCA9306 I2Cバス用双方向電圧レベル変換モジュール ※I2C接続時のみ |
必要 | 秋月電子 | |
AE-LCNV4-MOSFET 4ビット双方向ロジック変換モジュール ※SPI接続時のみ |
必要 | 秋月電子 |
Arduino Nano は 5V で駆動し、ロジックレベル(IOピンの電圧レベル)も 5V のため、3.3V で駆動する BME280 に直接接続できません。
3.3V は Arduino Nano に搭載されているレギュレータから供給しますが、5V <-> 3.3V のロジックレベル変換回路は別途用意しなくてはなりません。
各部品は 1 つずつ必要ですが、ロジックレベル変換モジュールは接続方法に合わせてご用意ください。配線の難易度や部品の配置を考えると I2C 接続が SPI 接続よりも容易ですが、AE-BME280 に少なくとも1箇所にはんだジャンパを作る必要があります。
ブレッドボード、ジャンパ、ケーブル、はんだ用具などは別途、お好きなものをご用意ください。
AE-BME280のはんだジャンパについて
I2C で接続する場合は J3 に、さらに SDA, SCL をともにプルアップする必要がある場合は J1, J2 にもはんだジャンパを行います (画像左)。
ただし、前述した I2Cバス用双方向電圧レベル変換モジュールにはプルアップ抵抗が内蔵されている ため、これを使う場合は J3 のみ、はんだジャンパを行ってください (画像中央)。
以降、I2C 接続する場合は J3 のみ、はんだジャンパがされているものとして回路図を示します。
SPI で接続する場合は、はんだジャンパは しません (画像右)。
回路
接続方式 | 回路図 | 実装例 | 配線例 |
---|---|---|---|
I2C | |||
SPI |
前述の通り、配線量は I2C 接続のほうが少ないです。
I2C 接続の場合
Arduino Nano側ピン | AE-PCA9306 ピン | AE-BME280 ピン |
---|---|---|
5V | VREF1 | |
3V3 | VREF2 | VDD |
GND | GND | GND |
A4 (SDA) | SDA1 -> SDA2 | SDI |
A5 (SCL) | SCL1 -> SCL2 | SCK |
各モジュール間の配線は上表の通りです。
AE-PCA9306 の VPU、AE-BME280 の CSB ピンは接続しません。SDO ピンには 3.3V を印加します(詳しくは後述)。
SPI 接続の場合
Arduino Nano側ピン | AE-LCNV4-MOSFET ピン | AE-BME280 ピン |
---|---|---|
5V | HV | |
3V3 | LV | VDD |
GND | GND | GND |
D11 (MOSI) | HV1 -> LV1 | SDI |
D12 (MISO) | HV2 -> LV2 | SDO |
D13 (SCK) | HV3 -> LV3 | SCK |
D10 (/SS) | HV4 -> LV4 | CSB |
各モジュール間の配線は上表の通りです。
HVx -> LVx の組み合わせは一例です。Arduino と AE-BME280 の接続が対応さえしていれば、1~4 のどの組み合わせで接続してもかまいません。
スケッチ
I2C と SPI 接続のどちらも、初期化方法が異なるだけで、値の取得方法に差異はありません。
予め SparkFun BME280 Arduino Library をダウンロードし、コンパイラが認識できる場所に配置してください。また、 SparkFunBME280.h
を必ずインクルードしてください。
#include "SparkFunBME280.h"
このライブラリはその名の通り、SparkFun の BME280 モジュール用に設計されていますが、AE-BME280 でも問題なく使用できます。
I2C 接続の場合
Wire.h
を必ずインクルードします。beginI2C
関数を引数なしで呼び出すと、Wire.h
内で宣言された既定の Wire
を使うためです。
#include <Wire.h>
#include "SparkFunBME280.h"
BME280 sensor;
void setup() {
Serial.begin(115200);
Wire.begin();
sensor.beginI2C(); // Wire を用いて I2C 接続開始
}
void loop() {
Serial.print("Temp: ");
Serial.print(sensor.readTempC(), 2);
Serial.print(" °C, Humidity: ");
Serial.print(sensor.readFloatHumidity(), 2);
Serial.print(" %, Pressure: ");
Serial.print(sensor.readFloatPressure() / 100.0, 1);
Serial.println(" hPa");
delay(5000);
}
SPI 接続の場合
beginSPI
関数には SPI の CS ピン番号を指定します。
#include "SparkFunBME280.h"
const int SPI_CS_PIN = 10;
BME280 sensor;
void setup() {
Serial.begin(115200);
sensor.beginSPI(SPI_CS_PIN);
}
void loop() {
Serial.print("Temp: ");
Serial.print(sensor.readTempC(), 2);
Serial.print(" °C, Humidity: ");
Serial.print(sensor.readFloatHumidity(), 2);
Serial.print(" %, Pressure: ");
Serial.print(sensor.readFloatPressure() / 100.0, 1);
Serial.println(" hPa");
delay(5000);
}
計測
プログラムを書き込んだあと、シリアル通信を開くと 温度、湿度、気圧 が 5 秒ごとに出力されます。
値がすべて 0 になってしまう場合は配線を誤っている可能性がありますので、電源を抜いてから回路を再確認してください。
電源投入直後の計測値に注意
[Starting] Opening the serial port - COM4
[Info] Opened the serial port - COM4
Temp: 23.04 °C, Humidity: 38.33 %, Pressure: 666.4 hPa
Temp: 23.30 °C, Humidity: 50.86 %, Pressure: 1003.8 hPa
Temp: 23.24 °C, Humidity: 51.48 %, Pressure: 1003.8 hPa
Temp: 23.14 °C, Humidity: 47.17 %, Pressure: 1003.8 hPa
電源投入直後、気圧が極端に低く計測されたり、湿度が数%高く計測されることがあります。センサが安定するまで、十数秒〜数分は計測値を捨てる(無視)などして対応します。
稀に、この異常な数値が保持されて数分以上継続することがあります。この場合は電源を投入し直すことで解決します。いずれにせよ、計測値が想定の範囲内であるかは確認してください。
発展
I2Cアドレスを変更する
SparkFunBME280 ライブラリのデフォルトのI2Cアドレスは 0x77
ですが、beginI2C
関数を呼び出す前に 0x76
へ変更ができます。
Wire.begin();
sensor.setI2CAddress(0x76);
sensor.beginI2C();
ただし、BME280 側にもアドレスの変更を認識させるために、SDOピンの配線を変える必要があります。
SDOへの入力 | アドレス | 回路図 |
---|---|---|
3.3V | 0x77 | |
GND | 0x76 |
なお、BME280 がどのアドレスになっているか不明な場合でも、beginI2C
関数の返り値で判定ができます。これを応用して、自動的にアドレスを決定することもできます。
void setupBME280() {
Wire.begin();
sensor.setI2CAddress(0x76);
if (sensor.beginI2C()) {
Serial.println("I2C address: 0x76");
return;
}
sensor.setI2CAddress(0x77);
if (sensor.beginI2C()) {
Serial.println("I2C address: 0x77");
return;
}
Serial.println("Sensor connect failed");
while(1) { }
}
フィルタとオーバーサンプリング設定
BME280には以下のモードが存在します。
- SLEEP: 電源投入直後の、計測をせず設定を行うためのモード
- FORCED: 1回のみ計測を行うモード。計測終了後は SLEEP モードに自動で遷移
- NORMAL: 繰り返し計測を行うモード
begin 系関数を呼び出すと、暗黙的に NORMAL モードに遷移します。
オーバーサンプリング設定によって値の精度を高めることができますが、正常な値が取得できるまでの時間が伸びるなどのデメリットも存在します。
void setup() {
Serial.begin(115200);
Wire.begin();
sensor.beginI2C();
sensor.setFilter(1); // フィルタ係数: 2
sensor.setStandbyTime(0); // スタンバイ時間: 0.5 ms
sensor.setTempOverSample(1); // オーバーサンプリング x1
sensor.setPressureOverSample(1); // オーバーサンプリング x1
sensor.setHumidityOverSample(1); // オーバーサンプリング x1
}
フィルタ係数、スタンバイ時間、オーバーサンプリングの詳細については こちら で詳しく解説されているのでご参照ください。
消費電力を抑える
前述した通り、通常は NORMAL モードで繰り返し計測を行うため、値を取得していない間も計測を行っています。FORCED モードにより、必要なときだけ計測を行い、消費電力を最小限にできます。
setMode
関数でモードの変更ができるので、初期化直後に SLEEP モードに遷移させ、計測前に FORCED モードにするだけです。計測後は自動的に SLEEP モードに遷移します。
注意が必要なのは、すぐに値を読み取ると計測途中のために正しい値が取得できないことです。isMeasuring
関数で計測中かどうかを判定できるので、計測中であれば待ちます。
void setup() {
Serial.begin(115200);
Wire.begin();
sensor.beginI2C();
sensor.setMode(MODE_SLEEP);
}
void loop() {
sensor.setMode(MODE_FORCED);
while (!sensor.isMeasuring()) delay(1); // 計測開始前ならば待ち
while ( sensor.isMeasuring()) delay(1); // 計測中ならば待ち
Serial.print("Temp: ");
Serial.print(sensor.readTempC(), 2);
// 以下略
}
高度を求める
readFloatAltitudeMeters
関数で高度(標高)を求めることができます。気圧から計算をしているため、ある程度の誤差があります。単位はメートル (m) ですが、readFloatAltitudeFeet
関数でフィート (ft) を求められます。
Serial.print("Altitude: ");
Serial.print(sensor.readFloatAltitudeMeters(), 0);
Serial.println(" m");
露点温度を求める
dewPointC
関数で露点温度を求めることができます。内部で温度と湿度を計測しています。単位は摂氏 (°C) ですが、dewPointF
関数で華氏 (°F) を求められます。
Serial.print("Dew point: ");
Serial.print(sensor.dewPointC(), 2);
Serial.println(" °C");
不快指数を求める
不快指数を求める関数は SparkFunBME280 ライブラリには存在しないため、定義から求めます。
乾球温度 $T_d$ (°C), 湿度 $H$ (%) とすると不快指数 $\textrm{DI}$ は、
\textrm{DI} = 0.81 T_d + 0.01 H (0.99 T_d - 14.3) + 46.3
と求められるので、これを計算して値を得ます。
double temp = sensor.readTempC();
double humi = sensor.readFloatHumidity();
double di = 0.81 * temp + 0.01 * humi * (0.99 * temp - 14.3) + 46.3;
Serial.print("Discomfort index: ");
Serial.println(di, 1);
参考文献
-
BME280使用 温湿度・気圧センサモジュールキット - 秋月電子通商
https://akizukidenshi.com/catalog/g/g109421/ -
[I2C] 温湿度大気圧センサー (BME280)
https://ht-deko.com/arduino/i2c_bme280.html -
BME280 - スイッチサイエンス
https://trac.switch-science.com/wiki/BME280 -
SparkFun BME280 Arduino Library - GitHub
https://github.com/sparkfun/SparkFun_BME280_Arduino_Library