Help us understand the problem. What is going on with this article?

Arduino NanoとBME280を使って温度・湿度・気圧を計測する

implemented

Arduino と温湿度気圧センサ BME280 を接続し、温度・湿度・気圧を測定します。
ここでは Arduino Nano と、BME280 を使いやすくした AE-BME280 を使用し、I2C と SPI 接続両方について解説します。
回路とプログラムは Arduino Uno にも対応しています。

Arduino 自体の使い方については他の記事をご参照ください。

用意するもの

部品名 画像 はんだ付け 入手先 (参考)
Arduino Nano
(Arduino UNO でも可)
Arduino Nano 必要なし 秋月電子
千石電商 など
AE-BME280
温湿度・気圧センサモジュール
AE-BME280 必要 秋月電子
AE-PCA9306
I2Cバス用双方向電圧レベル変換モジュール
※I2C接続時のみ
AE-PCA9306 必要 秋月電子
AE-LCNV4-MOSFET
4ビット双方向ロジック変換モジュール
※SPI接続時のみ
AE-LCNV4-MOSFET 必要 秋月電子

Arduino Nano は 5V で駆動し、ロジックレベル(IOピンの電圧レベル)も 5V のため、3.3V で駆動する BME280 に直接接続できません
3.3V は Arduino Nano に搭載されているレギュレータから供給しますが、5V <-> 3.3V のロジックレベル変換回路は別途用意しなくてはなりません。

各部品は 1 つずつ必要ですが、ロジックレベル変換モジュールは接続方法に合わせてご用意ください。配線の難易度や部品の配置を考えると I2C 接続が SPI 接続よりも容易ですが、AE-BME280 に少なくとも1箇所にはんだジャンパを作る必要があります。

ブレッドボード、ジャンパ、ケーブル、はんだ用具などは別途、お好きなものをご用意ください。

AE-BME280のはんだジャンパについて

solder_jumper

I2C で接続する場合は J3 に、さらに SDA, SCL をともにプルアップする必要がある場合は J1, J2 にもはんだジャンパを行います (画像左)。

ただし、前述した I2Cバス用双方向電圧レベル変換モジュールにはプルアップ抵抗が内蔵されている ため、これを使う場合は J3 のみ、はんだジャンパを行ってください (画像中央)。
以降、I2C 接続する場合は J3 のみ、はんだジャンパがされているものとして回路図を示します。

SPI で接続する場合は、はんだジャンパは しません (画像右)。

回路

接続方式 回路図 実装例 配線例
I2C schematic_i2c.png i2c_implemented i2c_wiring.jpg
SPI schematic_spi.png spi_implemented.jpg spi_wiring.jpg

前述の通り、配線量は 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 を使うためです。

bme280_i2c.ino
#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 ピン番号を指定します。

bme280_spi.ino
#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);
}

計測

measuring

プログラムを書き込んだあと、シリアル通信を開くと 温度、湿度、気圧 が 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 I2C 0x77
GND 0x76 I2C 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 関数で高度(標高)を求めることができます。気圧から計算をしているため、10m 程度の誤差があります。
単位はメートル (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);

参考文献

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした