温度湿度データをLCDに表示した際の覚書
先日センサーを壊してしまいましたが、それにもめげずいろいろいじってます。
今回はタイトル通り、温度センサーから得られたデータをLCDに表示してみたので、それらをまとめてみます。
利用したパーツ類
マイコン:M5Stamp Pico
センサー:BME280 温湿度センサー
LCD:OLED LCDディスプレイ 0.96in 128×64 SSD1306
その他、ブレッドボードや配線材、電源はM5Atom用を流用、、トグルスイッチとLED(抵抗入り)は特に意味はありません。付けてみたかっただけです😆
マイコンとの接続はセンサー LCDともI2Cで、G21(SDA) G22(SCL) につなげています。
プログラムに利用したライブラリ
センサー:Adafruit_BME280
LCD: LovyanGFX
これらで一通り組んでみて、LCDに表示されたもののセンサーデータが更新されない。。。LCDをはずしてシリアルモニタに出力するとちゃんと更新されてるよ???
いろいろ調べてみたところ、センサーとLCDが同じピンを使っているために、毎回センサーをリセットする必要があるようでした。
そのために、まず試してみたコードは
void loop() {
bme.begin(0x76);
…
}
ですが、確かにこのコードならセンサーデータが更新されます。でもbme.begin()はsetup()内で使うのがスジだと思ったので、じゃぁどうしようとAdafruit_BME280のインクルードファイルの中をのぞいてみたら、ネット上で説明されているサンプルコードには記載されていないメソッドがいっぱいあるじゃないですか。その中の bme.init() を利用してみたら、こちらの意図した通りの動きをしたので、やっと完成の目処がたちました。
あと、Twitterでつぶやいていた BMEライブラリの I2C接続時のピン指定方法は結局わからずじまいでしたが、ここは時間をかけるトコロではないので、現時点では追求はしないことにします。
完成したコード
1行目のインクルードは、本来は <M5Atom.h> とするようですが、FastLEDや本体ボタン等の不要なコードが含まれているので、 <Arduino.h> にしちゃいました。
2行目は I2C接続のお約束。
BME280 関連は、サンプルコードや公開されている方々のコードとは違い、I2C専用?ということで、 <SPI.h> <Adafruit_Sensor.h> は削除です。
LovyanGFXライブラリは不要部分は極力削除して、逆にコンストラクタ内の設定は外出しにしてみました。
メインループ内は、まずは bme.init() でセンサーをリセットして、前半はセンサーデータを変数に代入し、後半に変数データをLCDに出力します。
これを前半後半を分けずに、例えば
display.printf("温度:%2.1fC\n", bme.readTemperature());
というように、センサーデータ取得とLCD出力を混在させると、以降センサーデータを取得できません。。
ということで、書き上げたコードは以下の通りです。
#include <Arduino.h>
#include <Wire.h>
const int delayTime = 1000; // 画面描画更新頻度
// BME280をI2C利用での設定
#include <Adafruit_BME280.h>
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 bme; // I2C
// LovyanGFXでの設定 コンストラクタ内の設定は、直書きから外出しにしてみた
#define LGFX_USE_V1
#include <LovyanGFX.hpp>
#define D_PANEL_TYPE Panel_SSD1306 // 接続するパネルの型にあったインスタンスを用意
#define D_BUS_TYPE Bus_I2C // パネルを接続するバスのインスタンスを用意 I2Cバスのインスタンス(ESP32のみ)
const int C_I2C_PORT = 1; // 使用するI2Cポートを選択 (0 or 1)
const int C_PIN_SDA = 21; // SDAを接続しているピン番号
const int C_PIN_SCL = 22; // SCLを接続しているピン番号
const int C_I2C_ADDR = 0x3C; // I2Cデバイスのアドレス
const int C_PANEL_WIDTH = 128; // 実際に表示可能な幅
const int C_PANEL_HEIGHT = 64; // 実際に表示可能な高さ
const int C_OFFSET_ROTATION = 0; // 回転方向の値のオフセット 0~7 (4~7は上下反転)
class LGFX : public lgfx::LGFX_Device { // 独自クラスをLGFX_Deviceから継承
lgfx::D_PANEL_TYPE _panel_instance;
lgfx::D_BUS_TYPE _bus_instance;
public:
LGFX(void) { // コンストラクタ
{ // I2Cバス制御設定
auto cfg = _bus_instance.config(); // I2Cバス設定用の構造体を取得
cfg.i2c_port = C_I2C_PORT;
cfg.freq_write = 400000; // 送信時のクロック
cfg.freq_read = 400000; // 受信時のクロック
cfg.pin_sda = C_PIN_SDA;
cfg.pin_scl = C_PIN_SCL;
cfg.i2c_addr = C_I2C_ADDR;
_bus_instance.config(cfg); // 設定値をバスに反映
_panel_instance.setBus(&_bus_instance); // バスをパネルにセット
}
{ // 表示パネル制御の設定を行います。
auto cfg = _panel_instance.config(); // 表示パネル制御設定用の構造体を取得
cfg.panel_width = C_PANEL_WIDTH;
cfg.panel_height = C_PANEL_HEIGHT;
cfg.offset_rotation = C_OFFSET_ROTATION;
_panel_instance.config(cfg);
}
setPanel(&_panel_instance); // 使用するパネルをセットします。
}
};
LGFX display; // 準備したクラスのインスタンスを作成
void setup() {
bme.begin(0x76);
display.init();
}
void loop() {
bme.init(); // センサーをリセットする
float tmp = bme.readTemperature();
float hum = bme.readHumidity();
float prs = bme.readPressure() / 100;
float alt = bme.readAltitude(SEALEVELPRESSURE_HPA);
display.setCursor(0, 0);
display.setFont(&fonts::lgfxJapanGothic_16); // ゴシック体(8,12,16,20,24,28,32,36,40)
display.printf("温度:%2.1fC\n湿度:%2.0f%%\n気圧:%2.0fhPa\n高度:%2.0fm\n", tmp, hum, prs, alt);
delay(delayTime);
}
個人的には、bme.init() じゃなくて bme.update() という記述の方が好きなんですが。だからといって意図的にライブラリファイルを書き換えるのもね。。
おまけ
たまたま見つけたAdafruit_BME280のリファレンスです。すごく便利😊
http://adafruit.github.io/Adafruit_BME280_Library/html/class_adafruit___b_m_e280.html