■構成■
BME280はボッシュ製の気温湿度気圧センサー。ワンチップでこの3つが計測できてなかなか便利、しかも秋月でOLEDは今や電子工作標準品ともいうべき0.96インチサイズのアレ。作例もライブラリも豊富、I2Cと電源/GNDの合計4本だけで動いてしまいフレームバッファ(画像メモリ)も持っているので何かとラク。
できあがったあとで、WiFiついてるのにセンサーと表示器を同居させてどうすんだ?と自分自身に突っ込みました。
■製作■
何かケースに入れて外に設置したいので、今回もユニバーサル基板で組みました。以前、「いつかきっと使う」という想いで買い集めたaitendoのFRISK大の変換基板を適当に折って使います。基板上にモジュールを挿したヘッダソケットを挿して見て、レイアウトに見当を付けます。ハンダ付けが終わったあとでおとなりと干渉して実装できない、なんてのは悲しすぎますので。それから秋月の資料とOLEDの実物をみながら、簡単に配線メモを書きます。前回のLEDで懲りました。複数の資料をあたりながら裏側での配線を考えるのは私の脳ミソでは無理だ、と。ということで、裏側、配線面で各要素のピンがどうなっているかをメモにしておきます。
上の段からOLED、ESP基板、BME280基板I2Cでの接続(ユニバーサル基板上での位置、I2Cでの接続、BME280基板での名前)と並んでます。下の2つは作業過程のメモで使うのは上の3つです。上から4ピンヘッダソケット、9ピン足長ソケット(10ピンのを切断して使用)、6ピンヘッダソケットを使います。BME280のCSBは3.3v、SDOはGNDに接続しました。SDOはHIGHかLOWかでI2Cのアドレスを切り替えることができますが、GNDに接続するとデフォルトの0x76になり、今回使ったライブラリもそのままで動きます。
VDD、GND、SDA、SCLをそれぞれ接続します。ああ言葉で言うと簡単。朝っぱらから2時間かかったですよ、これ作るのにorz ヘッダソケットで3階建てになっているので、ヤケに高さがあります。
![]() |
一番上で緑の背中を見せているのはBME280 |
■ソフトウェア■
BME280はこちらのライブラリを使い、サンプルを参考にさせていただきました(参考というかほぼ手直しが必要ないのですけども)。OLEDはこちらです。今回、単純な文字表示にしか使わなかったのですが、uiクラスがあってそれを使うと複数画面を指定したアニメーションで入れ替えつつ任意の位置にミリ秒単位で別の画面をオーバーレイできる、という素晴らしい完成度です。また文字表示も素晴らしく、きれいなフォントはサイズが3種類あって右寄せ左寄せなども使えます。残念ながらクラスにラインを引っ張る命令がないので、そのうちDDAか何かで作って貢献したいですが…。
これら素晴らしいライブラリの作者に経緯を表し、感謝申し上げます。
さて、書いたプログラムはごく単純です。setupで各要素を初期化、loopでは1秒ごとに計測して表示を更新し、1分ごとにThingSpeak.comに送っています。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ESP_BME280_SSD1306 by k.kurahashi 2016-01-24 | |
// | |
// thanks: | |
// BME280 Library | |
// https://github.com/embeddedadventures/BME280 | |
// OLED Library | |
// https://github.com/squix78/esp8266-oled-ssd1306 | |
// | |
// ThingSpeak.com | |
// https://thingspeak.com/channels/81094 | |
// | |
#include <Wire.h> | |
#include <Time.h> | |
#include <BME280_MOD-1022.h> | |
#include "SSD1306.h" | |
#include "SSD1306Ui.h" | |
#include <ESP8266WiFi.h> | |
#include <WiFiClient.h> | |
extern "C" { | |
#include "user_interface.h" | |
} | |
// | |
// BME280 | |
// | |
float averageHumidity; // 湿度の計測値はわりとフラフラするので簡単な移動平均を取る | |
// | |
// OLED / SSD1306 | |
// | |
SSD1306 display(0x3c, 4, 5); | |
// | |
// Wifi | |
// | |
const char *ssid = "***********"; | |
const char *password = "***********"; | |
WiFiClient client; | |
// | |
// Setup BME280 ほぼサンプル, thanks for Embedded Adventures | |
// | |
void setup_BME280() { | |
uint8_t chipID; | |
Serial.println("Welcome to the BME280 MOD-1022 weather multi-sensor test sketch!"); | |
Serial.println("Embedded Adventures (www.embeddedadventures.com)"); | |
chipID = BME280.readChipId(); | |
// find the chip ID out just for fun | |
Serial.print("ChipID = 0x"); | |
Serial.print(chipID, HEX); | |
// need to read the NVM compensation parameters | |
BME280.readCompensationParams(); | |
BME280.writeStandbyTime(tsb_0p5ms); // tsb = 0.5ms | |
BME280.writeFilterCoefficient(fc_16); // IIR Filter coefficient 16 | |
BME280.writeOversamplingTemperature(os2x); // temperature x2 | |
BME280.writeOversamplingHumidity(os1x); // humidity x1 | |
BME280.writeOversamplingPressure(os16x); // pressure x16 | |
BME280.writeMode(smNormal); | |
} | |
// | |
// setup | |
// | |
void setup() { | |
Serial.begin(115200); | |
Serial.println(); | |
Serial.println(); | |
// | |
// Wifi | |
// | |
WiFi.begin ( ssid, password ); | |
Serial.println("Started"); | |
// Wait for connection | |
while ( WiFi.status() != WL_CONNECTED ) { | |
delay ( 500 ); | |
Serial.print ( "." ); | |
} | |
Serial.println("Wifi Connected"); | |
// BME and OLED | |
Wire.begin(); | |
setup_BME280(); | |
display.init(); | |
display.flipScreenVertically(); | |
display.displayOn(); | |
display.clear(); | |
} | |
// | |
// loop | |
// | |
void loop() { | |
draw(); | |
delay(1000); | |
} | |
int prevMinute = minute(); // 分ごとに送信するためのフラグ | |
// | |
// OLEDへの描画 | |
// | |
void draw() { | |
float temp, humidity, pressure, pressureMoreAccurate; | |
double tempMostAccurate, humidityMostAccurate, pressureMostAccurate; | |
char buffer[80]; | |
// BME280起動待ち | |
BME280.writeMode(smForced); | |
while (BME280.isMeasuring()) { | |
delay(50); | |
} | |
// BME280計測実行 | |
BME280.readMeasurements(); | |
// BME280各データ取り出し | |
temp = BME280.getTemperature(); | |
humidity = BME280.getHumidity(); | |
pressure = BME280.getPressure(); | |
pressureMoreAccurate = BME280.getPressureMoreAccurate(); // t_fine already calculated from getTemperaure() above | |
tempMostAccurate = BME280.getTemperatureMostAccurate(); | |
humidityMostAccurate = BME280.getHumidityMostAccurate(); | |
pressureMostAccurate = BME280.getPressureMostAccurate(); | |
// 湿度の値を平準化 | |
averageHumidity = (averageHumidity * 9.0 + humidityMostAccurate) / 10.0; | |
// OLEDへ表示 | |
display.clear(); | |
display.setFont(ArialMT_Plain_10); | |
display.setTextAlignment(TEXT_ALIGN_LEFT); | |
display.drawString( 0, 16, "Temperature"); | |
display.drawString( 0, 32, "Humidity"); | |
display.drawString( 0, 48, "Pressure"); | |
display.setFont(ArialMT_Plain_16); | |
display.setTextAlignment(TEXT_ALIGN_RIGHT); | |
dtostrf(tempMostAccurate, 7, 2, buffer); | |
display.drawString(127, 12, buffer); | |
dtostrf(averageHumidity, 7, 2, buffer); | |
display.drawString(127, 28, buffer); | |
dtostrf(pressureMostAccurate, 7, 2, buffer); | |
display.drawString(127, 44, buffer); | |
display.display(); | |
// ThingSpeak.comへ送信 | |
if (minute() != prevMinute) { | |
sendTHP(tempMostAccurate, averageHumidity, pressureMostAccurate); | |
prevMinute = minute(); | |
} | |
} | |
// | |
// ThingSpeakへのパラメータを作って送信 | |
// | |
void sendTHP(float inTemperature, float inHumidity, float inPressure) { | |
char tBuf[10], hBuf[10], pBuf[10]; | |
dtostrf(inTemperature, 7, 2, tBuf); | |
dtostrf(inHumidity, 7, 2, hBuf); | |
dtostrf(inPressure, 7, 2, pBuf); | |
String postStr = "&field1=" + String(tBuf) + "&field2=" + String(hBuf) + "&field3=" + String(pBuf); | |
send(postStr); | |
Serial.println(postStr); | |
} | |
// ThingSpeakへ送信 | |
// | |
void send(String inPostStr) { | |
String apiKey = "********************"; | |
Serial.print("Connecting..."); | |
if (client.connect("184.106.153.149", 80)) { // api.thingspeak.com | |
Serial.print("Connected...."); | |
String postStr = apiKey + inPostStr + "\r\n\r\n"; | |
client.print("POST /update HTTP/1.1\n"); | |
client.print("Host: api.thingspeak.com\n"); | |
client.print("Connection: close\n"); | |
client.print("X-THINGSPEAKAPIKEY: " + apiKey + "\n"); | |
client.print("Content-Type: application/x-www-form-urlencoded\n"); | |
client.print("Content-Length: "); | |
client.print(postStr.length()); | |
client.print("\n\n"); | |
client.print(postStr); | |
Serial.println("posted."); | |
} | |
client.stop(); | |
} |
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。