2018年8月8日水曜日

温度・湿度・気圧センサーのBME280をArduino Pro Miniで使う。

AliExpressで発注した温度・湿度・気圧センサーのBME280が届いたので動作確認しました。ショップはRoarKitで7月21日発注、8月7日到着で到着まで17日でした。

動作確認


ブレッドボード配線図

まずはArduino Pro mini(3.3V/8MHz)版を使って単体で動作確認です。USB-UART変換の接続はこちら

3.3Vの電源は安定化電源から供給しています。

BME280のモジュール上でI2Cのプルアップが行われているので外付け抵抗は不要です。

プルアップが行われているだけではなく、MOS-FETを使ったI2Cのレベル変換回路も載っているようです。(中華製なので回路図は怪しいですが・・・)

BME280モジュールの回路図

ArduinoのライブラリはSparkFun BME280 Arduino Libraryを使いました。

スケッチ例のSparkfunBME280_Example1_BasicReadingsを一部書き換えれば動作しました。

  mySensor.setI2CAddress(0x76);
  if (mySensor.beginI2C() == false) //Begin communication over I2C
  {
    Serial.println("The sensor did not respond. Please check wiring.");
    while(1); //Freeze
  }

ライブラリのデフォルトのI2Cアドレスは0x77ですが、モジュールのI2Cアドレスが0x76になっているようなので、mySensor.beginI2C() の前に、mySensor.setI2CAddress(0x76); を追加してI2Cアドレスを指定します。

I2Cアドレスをデフォルト(0x77)のままで動作させた場合のI2C信号

ch1:SDA ch2:SCK

動作させるとシリアルモニタにエラーメッセージが表示されますが、I2C信号は出力されています。

I2Cアドレスを0x76にして動作させた場合のI2C信号

ch1:SDA ch2:SCK

比較すると、I2Cアドレスが違っている場合は、マスターがI2Cアドレスを送信後、9ビット目のSDAがLに引っ張られていません。

スレーブが、受信したI2Cアドレスが自身のI2Cアドレスと一致していたとき9ビット目をLに引っ張り(ACK)、その後マスター・スレーブ間でデータの送受信が行われます。

また、スケッチの気温、高度の測定も単位が華氏、フィートになっているので摂氏、メートルに変更しました。

  Serial.print(" Alt: ");
  Serial.print(mySensor.readFloatAltitudeMeters(), 1);
  //Serial.print(mySensor.readFloatAltitudeFeet(), 1);

  Serial.print(" Temp: ");
  Serial.print(mySensor.readTempC(), 2);
  //Serial.print(mySensor.readTempF(), 2);

SSD1306 128x64のOLEDに表示


SSD1306 128x64 SPIのOLEDも同時に購入したので測定値を表示させました。

ブレッドボード配線図


※ブレッドボード配線図と写真は180度回転しています。

Arduinoのスケッチ <BME280_TempMeter_u8g2.ino>

OLEDのライブラリはu8g2を使用しました。


#include <U8g2lib.h>
#include <stdio.h>
#include <Wire.h>
#include "SparkFunBME280.h"

#define TITLE_STR1  ("BME280 Temp Meter")
#define TITLE_STR2  ("20180808")

const int measureInterval = 500;

//U8G2_SSD1306_128X32_UNIVISION_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);  // Adafruit ESP8266/32u4/ARM Boards + FeatherWing OLED
U8G2_SSD1306_128X64_NONAME_1_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);

BME280 bme280;

void setup()
{
  Serial.begin(9600);
  Serial.println();
  Serial.println(TITLE_STR1);
  Serial.println(TITLE_STR2);

  // BME280
  Wire.begin();

  bme280.setI2CAddress(0x76);
  if (bme280.beginI2C() == false) //Begin communication over I2C
  {
    Serial.println("The bme280 did not respond. Please check wiring.");
    while(1); //Freeze
  }
  
  // u8g2
  u8g2.begin();
  u8g2.clearBuffer();
  u8g2.firstPage();
  u8g2.setFont(u8g2_font_8x13_tf);
  do {
    u8g2.drawStr(0,10,TITLE_STR1);
    u8g2.drawStr(0,25,TITLE_STR2);
  } while (u8g2.nextPage());
  u8g2.sendBuffer();

  delay(1000);
}

float calcDiscomfort(float temperature, float humidity) {
  return 0.81 * temperature + 0.01 * humidity * (0.99 * temperature - 14.3) + 46.3;
}

void loop()
{
  char strBuffer[32];
  char strBuffer2[32];

  float humidity = bme280.readFloatHumidity();
  float pressure = bme280.readFloatPressure();
  float Altitude = bme280.readFloatAltitudeMeters();
  float temperature = bme280.readTempC();
  float discomfort = calcDiscomfort(temperature, humidity);
  
  u8g2.firstPage();
  do {
    u8g2.setFont(u8g2_font_logisoso28_tf);
    sprintf(strBuffer2, "%s%cC", dtostrf(temperature, 2, 1, strBuffer), 0xb0);
    u8g2.drawStr(0,32, strBuffer2);
  
    u8g2.setFont(u8g2_font_logisoso20_tf);
    sprintf(strBuffer2, "%s%%", dtostrf(humidity, 2, 1, strBuffer));
    u8g2.drawStr(0,64, strBuffer2);
    sprintf(strBuffer2, "%s", dtostrf(discomfort, 5, 1, strBuffer));
    u8g2.drawStr(64,64, strBuffer2);
  } while (u8g2.nextPage());

  Serial.print(temperature);
  Serial.print("\t");
  Serial.print(humidity);
  Serial.print("\t");
  Serial.print(pressure);
  Serial.println("");
  
  delay(measureInterval);
}

温度、湿度と不快指数を計算してOLEDに表示しています。

Serialには温度、湿度、気圧を出力しています。

電源電流はほぼ一定していて16mA程度です。