Arduino Uno Rev3とBME280センサ、SSD1309搭載の2.42インチOLED(有機ELディスプレイ)で作った気圧・温湿度計の表示画面をu8g.drawXBMP()で日本語表記するスケッチ(プログラム)作成時のメモです。
準備したパーツ
昨年作った気圧・温湿度計の「ESP32-DevkitC」を「Arduino Uno Rev3」に置き換えました。ArduinoのI2C信号レベルに合わせて5Vから3.3Vへの双方向電圧レベル変換とU8glib.h対応のスケッチ修正を行います。
OLEDの仕様、集めたパーツ
ネット通販で集めたOLEDの仕様です。サイズ、発光色の異なる2個で試しました。
# | 発光色 | サイズ解像度 | 接続方式(I2Cアドレス) | ドライバーIC | 電源電圧(V) |
1 | 2.42インチ 黄色 | 128×64 | I2Cに設定変更(0x3C) ※デフォルトはSPI | SSD1309 | 3.3 |
2 | 0.96インチ 青色 | 128×64 | I2C(0x3C) | SSD1306 | 3.3〜5.0 |
OLED以外のパーツです。モジュールの電源電圧とI2Cの電圧レベルは3.3Vで統一しました。ArduinoのI2C電圧レベルは5Vなので双方向電圧レベル変換モジュールを入れて3.3Vにしています。
# | パーツ | 個数 |
1 | Arduino Uno Rev3 | 1 |
2 | I2Cバス用双方向電圧レベル変換モジュール(PCA9306) プルアップ抵抗付き(1kΩx4個) | 1 |
3 | BME280 温湿度・気圧センサーモジュール Vin、I2Cレベル変換回路付き | 1 |
4 | サンハヤト ニューブレッドボード SAD-101 | 1 |
5 | ジャンパーワイヤ(オス-オス、メス-オス) | 適量 |
6 | USBケーブル(USB A オス to B オス、PC接続用) | 1 (手持ち) |
今回購入したBME280モジュールは基板裏面に電源電圧Vccのレギュレータ(LDO:Low Dropout)と I2Cの電圧レベル変換回路を実装しているので、5V系(Arduinoなど)と3.3V系(ESP32-DevkitCなど)のどちらとも直接つないで使えます。
このモジュールのデフォルトのI2Cアドレスは0x76です。
2.42インチOLED(有機ELディスプレイ)をSPI接続からI2C接続に変更
購入した2.42インチOLED(発光色は黄色)はSPI接続がデフォルトでした。転送速度はSPIが高速ですが、気圧・温湿度計や時計などへの利用なので配線数が少ないI2C接続に変更しました。
ブレッドボード上で結線
モジュール間の結線は、I2Cの2線(SCL、SDA)と電源の2線(3.3V、GND)の4線なので容易です。Arduino Uno Rev3とブレッドボード上に配置した双方向電圧レベル変換モジュール、BME280モジュール、OLEDを4色に色分けしたジャンパーワイヤでつないでいきます。
それぞれのOLED単体でも動作しますが、今回両方のOLEDを同じI2CアドレスのままI2Cバスにつないで、一つのスケッチで同時表示しています。
OLED表示のスケッチ、漢字は16×16ピクセルのHEXデータをu8g.drawXBMP()で描画
U8glibライブラリ
OLEDモジュール表示に必要なライブラリ「U8glib.h」は、Arduino IDEメニューの ツール –> ライブラリの管理 からライブラリマネージャで「U8glib」を検索してインストールします。
u8g.setFont()で使うフォント見本は fontsize | olikraus/u8glib を参考にさせていただきました。今回は英数字の表示用フォントとして「u8g_font_helvR08」と「u8g_font_fub17」を使っています。u8g_font_helvR08は、16×16ピクセルでは表現が難しかった(hpa)表示に使っています。
気圧・温湿度計で使った漢字と記号は「気、圧、温、湿、度、(℃)、(%)」と少ないので、メモリ消費を抑えるために、利用する特定の文字のみをHEXデータで表示します。これらの漢字と記号は画像(BMPファイル)から変換した16×16ピクセルのHEXデータをu8g.drawXBMP()で描画します。
最大32256バイトのフラッシュメモリのうち、スケッチが25710バイト(79%)を使っています。
最大2048バイトのRAMのうち、グローバル変数が763バイト(37%)を使っていて、ローカル変数で1285バイト使うことができます。
記号や漢字のBMPファイルは、Windows標準アプリのペイント3Dで100×100ピクセル程度で作った後、キャンパスを16×16ピクセルに変更して圧縮します。このBMPファイルをHEXデータに変換します。HEXデータへの変換にはProgramResource.netサイトの「nfBmptoHex.exe」を利用させていただきました。
BME280センサライブラリ
BME280センサ(0x76)から測定データを取得するライブラリとしてGitHub掲載の adafruit/Adafruit_BME280_Library と adafruit/Adafruit_Sensor を利用させていただきました。
スケッチ
arduino_bme280_oled.ino
※ここをクリックするとコード表示を開閉できます。
#include <Wire.h>
#include <U8glib.h> // U8gライブラリ
#include <Adafruit_Sensor.h> // https://github.com/adafruit/Adafruit_Sensor
#include <Adafruit_BME280.h> // https://github.com/adafruit/Adafruit_BME280_Library
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_DEV_0 | U8G_I2C_OPT_NO_ACK | U8G_I2C_OPT_FAST);
Adafruit_BME280 bme;
float temp;
float pressure;
float humid;
// 漢字画像(BMP)から変換したHEXデータ
const unsigned char kii_bmp[] PROGMEM = {0x08, 0x00, 0x0C, 0x00, 0xFC, 0x3F, 0x06, 0x00, 0xFA, 0x1F, 0x00, 0x00, 0xFE, 0x1F, 0x00, 0x10, 0x04, 0x12, 0x1C, 0x13, 0x30, 0x11, 0xE0, 0x11, 0x60, 0x93, 0x18, 0xB6, 0x0E, 0xE4, 0x00, 0x60, };
const unsigned char atu_bmp[] PROGMEM = {0x00, 0x00, 0xFC, 0x7F, 0x06, 0x00, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0xF6, 0x7F, 0x06, 0x03, 0x06, 0x03, 0x06, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0xF9, 0x7F, 0x00, 0x00, };
const unsigned char onn_bmp[] PROGMEM = {0x00, 0x00, 0xE2, 0x1F, 0x24, 0x20, 0x24, 0x20, 0xE0, 0x3F, 0x22, 0x20, 0xE4, 0x3F, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x3F, 0x94, 0x24, 0x94, 0x24, 0x96, 0x24, 0x92, 0x24, 0xFA, 0x7F, 0x00, 0x00, };
const unsigned char doo_bmp[] PROGMEM = {0x00, 0x00, 0x00, 0x01, 0xF8, 0x7F, 0x44, 0x08, 0x44, 0x08, 0xF4, 0x7F, 0x44, 0x08, 0xC4, 0x0F, 0x04, 0x00, 0xF4, 0x1F, 0x64, 0x10, 0xC4, 0x18, 0x00, 0x07, 0x82, 0x0F, 0x78, 0x70, 0x00, 0x00, };
const unsigned char stu_bmp[] PROGMEM = {0x00, 0x00, 0xC0, 0x3F, 0x24, 0x20, 0x28, 0x20, 0xE0, 0x3F, 0x22, 0x20, 0xE4, 0x3F, 0x00, 0x05, 0x20, 0x25, 0x20, 0x25, 0x28, 0x25, 0x04, 0x25, 0x44, 0x05, 0x06, 0x0D, 0xF0, 0x7F, 0x00, 0x00, };
const unsigned char pac_bmp[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x58, 0x8A, 0x4C, 0x8A, 0x46, 0x8B, 0x82, 0x71, 0x81, 0x81, 0x8E, 0xC3, 0x92, 0x42, 0x93, 0x22, 0x53, 0x34, 0x4C, 0x00, 0x00, 0x00, 0x00, };
const unsigned char dig_bmp[] PROGMEM = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x20, 0x3A, 0x40, 0xAA, 0x47, 0x7A, 0x48, 0x63, 0x80, 0x21, 0x80, 0x21, 0x80, 0x23, 0xC0, 0x62, 0x50, 0xC2, 0x4C, 0x82, 0x47, 0x04, 0x20, 0x00, 0x00, };
void setup(void) {
u8g.setColorIndex(1);
u8g.setContrast(0); // 明るさも多少変わる(0~255)@2022-05-19追加
bool status;
status = bme.begin(0x76);
while (!status) {
Serial.println("BME280 sensorが使えません");
delay(1000);
}
}
void loop() {
u8g.firstPage();
do {
// BME280センサ
temp=bme.readTemperature();
pressure=bme.readPressure() / 100.0F;
humid=bme.readHumidity();
// OLECD表示
u8g.drawXBMP( 0, 1, 16, 16, kii_bmp);
u8g.drawXBMP(16, 1, 16, 16, atu_bmp);
u8g.setFont(u8g_font_helvR08);
u8g.setPrintPos(33,14);
u8g.print("(hPa)");
u8g.setFont(u8g_font_fub17);
u8g.setPrintPos(65,17);
u8g.print(pressure,0); // 気圧
u8g.drawXBMP( 0, 24, 16, 16, onn_bmp);
u8g.drawXBMP(16, 24, 16, 16, doo_bmp);
u8g.drawXBMP(34, 24, 16, 16, dig_bmp);
u8g.setPrintPos(65,39);
u8g.print(temp,1); // 気温
u8g.drawXBMP( 0, 48, 16, 16, stu_bmp);
u8g.drawXBMP(16, 48, 16, 16, doo_bmp);
u8g.drawXBMP(34, 48, 16, 16, pac_bmp);
u8g.setPrintPos(65,63);
u8g.print(humid,1); // 湿度
} while ( u8g.nextPage() );
delay(1000);
}