工場裏のアーカイブス

素人によるiPhoneアプリ開発の学習記 あと機械学習とかM5Stackとか

M5Stackでデータロガーのような温度・湿度計を作ってみた

結構前のことですが、↓のようなアイテムを気紛れに購入しました。いわばM5Stack用の充電スタンドですが、DHT12の温度・湿度センサを内蔵しており、M5Stackに差し込むだけで、それらが測定可能となる中々面白いアイテムです。

f:id:fleron:20200430231035j:plain

…と言いつつ、長らく買ったまま放置してしまっていたのですが、何か活用してみようと思い至り、データロガーのような温度・湿度計を作ってみました。

f:id:fleron:20200501002606j:plain

DHT12から拾った温度・湿度の値を、以下の過去記事でも触れたスプライトのスクロール機能を用いて、リアルタイムにグラフとして描画しています(あくまで見た目がデータロガーっぽいだけで、データを別途記録する機能などは実装していないですが)。
chemicalfactory.hatenablog.com

思い描いたイメージに結構近いものが作れたと感じましたので、どこかで誰かの参考になるかもと願い、ソースコードを公開してみたいと思います。目盛りの描画位置などは試行錯誤で調整した値を用いているなど、あまり美しいコードではありませんが…。

こちらはM5StackのDHT12サンプルスケッチを下敷きにしているので、まずはこれを開きます。
f:id:fleron:20200501012719p:plain

そしてサンプルスケッチの「DHT12」タブのコードを、以下のものに書き換えればOKです。

#include <M5Stack.h>
#include "DHT12.h"
#include <Wire.h>
DHT12 dht12;         

//W、Hは画面の幅,高さ。GW、GHはグラフ領域の幅、高さ。
#define W 320
#define H 240
#define GW 280
#define GH 180

//グラフはスプライトを用いて描画する。初期化
TFT_eSprite graph = TFT_eSprite(&M5.Lcd);

void setup() {
  M5.begin();
  Wire.begin();
  M5.Lcd.fillScreen(TFT_BLACK);

  //グラフ用スプライトの生成。setScrollRect関数を使用しない場合、
  //スプライト全体がスクロール対象となる
  graph.setColorDepth(8);
  graph.createSprite(GW, GH + 1);
  graph.fillSprite(TFT_BLACK);
}

void loop() {
  //DHT12から温度、湿度の値を取得。
  float temp = dht12.readTemperature();
  float humid = dht12.readHumidity();
  
  //グラフ用スプライトの配置、1ピクセルずつスクロールさせていく
  graph.pushSprite((W - GW)/2 - 1, 15);
  graph.scroll(-1, 0);

  //目盛り線の描画(1ピクセルのスクロール → 1ピクセル描画、の繰り返しで線になる)
  //y軸方向に10分割する
  for(int y = 0; y <= GH; y += GH/10) graph.drawPixel(GW-1, y, TFT_DARKGREEN);

  //温度用の目盛り。室温を想定して範囲は-10〜40'Cとし、目盛り線と合うように調整。
  M5.Lcd.setTextColor(TFT_YELLOW);
  M5.Lcd.setTextSize(1);
  M5.Lcd.setCursor(0, 0);
  M5.Lcd.printf("Temp");
  char tempScale[6][4] = {" 40", " 30", " 20", " 10", "  0", "-10"};
  for(int i = 0; i < 6; i++){ 
    M5.Lcd.setCursor(0, 12 + i * GH/10 * 2);
    M5.Lcd.printf("%s", tempScale[i]);
  }

  //湿度用の目盛り。範囲は0〜100 %とし、目盛り線と合うように調整。
  M5.Lcd.setTextColor(TFT_BLUE);
  M5.Lcd.setTextSize(1);
  M5.Lcd.setCursor(W - 30, 0);
  M5.Lcd.printf("Humid");
  char humidScale[6][4] = {"100", "80", "60", "40", "20", "0"};
  for(int i = 0; i < 6; i++){ 
    M5.Lcd.setCursor(GW + (W - GW)/2 + 1, 12 + i * GH/10 * 2);
    M5.Lcd.printf("%s", humidScale[i]);
  }

  //温度のグラフを描画。温度が目盛り範囲(-10〜40'C)から外れる場合は
  //強引に範囲内に収める(そんな環境で使うことは無いだろうけれど)
  if(temp > 40.0) temp = 40.0;
  if(temp < -10.0) temp = -10.0;
  float tc = -18.0 * (temp - 40.0) / 5.0; //実値をグラフ上の座標に変換
  graph.drawFastVLine(GW - 1, (int)tc, 2, TFT_YELLOW); 
   
  //湿度のグラフを描画。こちらは目盛り範囲(0〜100 %)から外れることはないはず
  float hc = -9.0 * (humid - 100.0) / 5.0; //実値をグラフ上の座標に変換
  graph.drawFastVLine(GW-1, (int)hc, 2, TFT_BLUE);

  //グラフの真下に温度、湿度の実値を文字表示する
  M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK); //背景色を設定して、直前の表示が残らないようにする
  M5.Lcd.setTextSize(2);
  M5.Lcd.setCursor((W - GW)/2 - 1, H - 38);
  M5.Lcd.printf("Temperature('C):%5.1f", temp);
  M5.Lcd.setCursor((W - GW)/2 - 1, H - 19);
  M5.Lcd.printf("Humidity(%%):    %5.1f", humid); //湿度の数値のx座標が、温度の数値と並ぶように調節
  
  delay(50);
}