編集履歴一覧に戻る
Fukaのアイコン画像

Fuka が 2026年01月31日22時09分39秒 に編集

体裁変更

メイン画像の変更

メイン画像が設定されました

本文の変更

## はじめに

-

今回は Sony SPRESENSE を使って温度センサ DHT11 の値 1.54インチ 240×240 ピクセルのカラー液晶にリアルタイム表示する方法紹介しま

+

1月も終わりに差し掛かってきたところではありますが、まだまだ寒い日が続きます。 温度を見ながら暖房をつけることが多いと思いますが、その際に現在の温度だけでなく、直前の温度変化がどのように変わっているのかも見れたらよいだろうと感じました。 そこで、今回は SPRESENSEを使って簡易温度モニタ作成してみました。 液晶を使用して温度の表示を行うだけでなく、直前の履歴をグラフ化することで温度の変化量確認できるように工夫しました

-

単純に温度をシリアルモニタに出すだけでなく、過去 5 回分の履歴をグラフ化して表示することで、より分かりやすく温度の変化を確認できます。 また、USB接続だけでなく、単体電源でも安定して表示できるように工夫しています。

## 使用するもの 今回の製作では以下の部品を使用しました。

-

Sony SPRESENSE メインボード

+

| 部品 | 数量 | |:---:|:---| | Spresense メインボード | 1 | | Spresense 拡張ボード | 1 | | 温度センサ(DHT11) | 1 | | 液晶モジュール | 1 | | 配線類 | 適宜 | | 筐体(自作) | 1 |

-

DHT11 温湿度センサ

+

Spresense メインボード、Spresense 拡張ボードについては機材提供をしていただきました。ありがとうございます。 その他、センサ、ディスプレイについては市販品のものを使用。 筐体については3Dをプリンタを使用して製作を行いました。

-

1.54インチ 240×240 SPI グラフック液晶(ST7789)

+

## 配線と接続について SPRESENSEボードに対してデスプレイとセンサを接続していきます。 それぞれの接続先は以下のとおりです。

-

配線用ジャンパーワイヤ、ブレッドボード 配線と接続

+

### 液晶の接続

| 液晶ピン番号 | SPRESENNSE側ピン番号 | |:---:|:---| | GND | GND | | VCC | 3.3V | | SCL | D13 | | SDA | D11 | | RES | D8 | | DC | D9 | | CS | D10 | | BLK | 3.3V |

-

温度センサ

+

### 温度センサの接続

| DHT11側ピン | SPRESENSE側ピン | |:---:|:---| | DATA | D5 | | VCC | 3.3V | | GND | GND |

-

ソースコード

+

## ソースコード プログラムコードは以下のようになります。

```arduino:SPRESENSE #include <SPI.h> #include <Adafruit_GFX.h> #include <Adafruit_ST7789.h> #include <DHT.h>

-

/* ===== 色定義 ===== */

+

#define COLOR_GRAY 0x8410 // RGB565 グレー /* ===== ピン定義 ===== */ #define TFT_CS 10 #define TFT_DC 9 #define TFT_RST 8 #define DHT_PIN 5 #define DHT_TYPE DHT11 /* ===== オブジェクト ===== */ Adafruit_ST7789 tft(TFT_CS, TFT_DC, TFT_RST); DHT dht(DHT_PIN, DHT_TYPE); /* ===== 設定 ===== */ #define HISTORY_SIZE 5 float tempHistory[HISTORY_SIZE]; int historyIndex = 0; unsigned long lastMeasure = 0;

-

const unsigned long interval = 10000; // 10秒(1分なら60000)

+

const unsigned long interval = 300000; // (1分なら60000)

static float lastValidTemp = NAN;

-

/* ===== ヘッダ描画 ===== */

+

/* ===== ディスプレイ描画 ===== */

void drawHeader(float temp) { tft.fillRect(0, 0, 240, 40, ST77XX_BLACK); tft.setTextColor(ST77XX_WHITE); tft.setTextSize(2); tft.setCursor(8, 8); tft.print("ONDO : "); tft.setTextSize(3); tft.setCursor(150, 5); if (temp > -90) { tft.print(temp, 1); tft.print("C"); } else { tft.print("--.-C"); }

-

// 区切り線 tft.drawFastHLine(0, 39, 240, COLOR_GRAY);

+

tft.drawFastHLine(0, 39, 240, COLOR_GRAY); // 区切り線

}

-

/* ===== グラフ描画(フル活用) ===== */

+

void drawGraph() { const int graphX = 40; const int graphY = 235; const int graphW = 195; const int graphH = 190; // === min / max 自動算出 === float minT = 1000.0; float maxT = -1000.0; int valid = 0; for (int i = 0; i < HISTORY_SIZE; i++) { if (!isnan(tempHistory[i])) { minT = min(minT, tempHistory[i]); maxT = max(maxT, tempHistory[i]); valid++; } } if (valid < 2) { minT = 20; maxT = 30; } float margin = max(1.0, (maxT - minT) * 0.2); minT -= margin; maxT += margin;

-

// グラフエリアクリア

+

// グラフエリアクリア なるべく大きく

tft.fillRect(0, 40, 240, 200, ST77XX_BLACK); // 枠 tft.drawRect(graphX, graphY - graphH, graphW, graphH, ST77XX_WHITE); // === Y軸(温度)=== tft.setTextSize(1); for (int i = 0; i <= 6; i++) { float t = minT + (maxT - minT) * i / 6.0; int y = graphY - (graphH * i / 6); tft.drawFastHLine(graphX - 5, y, 5, ST77XX_WHITE); tft.drawFastHLine(graphX, y, graphW, COLOR_GRAY); tft.setCursor(2, y - 4); tft.print(t, 1); } // === データ描画 === int prevX = -1, prevY = -1; for (int i = 0; i < HISTORY_SIZE; i++) { int idx = (historyIndex + i) % HISTORY_SIZE; float temp = tempHistory[idx]; if (isnan(temp)) continue; int x = graphX + i * (graphW / (HISTORY_SIZE - 1)); int y = graphY - map(temp * 100, minT * 100, maxT * 100, 0, graphH); tft.fillCircle(x, y, 4, ST77XX_RED); if (prevX >= 0) { tft.drawLine(prevX, prevY, x, y, ST77XX_RED); } prevX = x; prevY = y; } }

-

/* ===== 初期化 ===== */

+

/* ===== init ===== */

void setup() { Serial.begin(115200); delay(500); dht.begin();

-

delay(2000); // DHT安定待ち(超重要)

+

delay(2000); // DHT安定動作のおまじない

tft.init(240, 240);

-

tft.setRotation(3); // 向き

+

tft.setRotation(3); // ディスプレイの表示向き

tft.fillScreen(ST77XX_BLACK); // 履歴初期化 for (int i = 0; i < HISTORY_SIZE; i++) { tempHistory[i] = NAN; } drawHeader(-99); drawGraph(); } /* ===== メインループ ===== */ void loop() { unsigned long now = millis(); if (now - lastMeasure < interval) return; lastMeasure = now; float temp = dht.readTemperature(); if (!isnan(temp)) { lastValidTemp = temp; } if (isnan(lastValidTemp)) return; Serial.print("Temp: "); Serial.print(lastValidTemp); Serial.println(" C"); tempHistory[historyIndex] = lastValidTemp; historyIndex = (historyIndex + 1) % HISTORY_SIZE; drawHeader(lastValidTemp); drawGraph(); }

+

```

-

今回は5分おきに温度を計測していきます。 計測した値をディスプレイに表示しつつ、直近の温度変化をグラフとして表示する仕様とした

+

計測した値をディスプレイに表示しつつ、直近の温度変化をグラフとして表示するようにてい

-

今回は液晶使用

+

## 製作時の様子 ブレッドボードで動作確認た後、すべの部品を内部に収められるつくりとし

-

tft.setRotation(3); // 横向き この関数で作画表示の向きを決定していきます。

+

↓筐体印刷時の画面 ![3Dプリンタでの製作過程](https://camo.elchika.com/784e8183d775c0ea4fd9e57e4e6ab27203b69291/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f33313639316266322d353532392d343163372d383035302d6631303634653461393532652f34303336313065382d666232622d343763352d393164642d313161376461326465643931/)

-

## 製作時の様子

+

↓部品全体の様子 ![キャプションを入力できます](https://camo.elchika.com/5390293cde209aa821d22f26058112f29b6f0ca4/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f33313639316266322d353532392d343163372d383035302d6631303634653461393532652f35333237386164622d303062652d346238662d396334652d616235316564656130666666/)

-

マイコン、センサ本体などがるよう筐体用意しまし

+

↓部品をすべてれたところ ![内部部品入れところ](https://camo.elchika.com/24c1c97a32a16a37090686659d0e5f40f7b7c77f/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f33313639316266322d353532392d343163372d383035302d6631303634653461393532652f30393833333932392d376664362d343563362d383366362d386662373931653834326437/)

-

![キャプション入力きま](https://camo.elchika.com/6e00267ea43e7df81ba0335067746cb2bbe6f603/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f33313639316266322d353532392d343163372d383035302d6631303634653461393532652f64633439383065632d646362302d346333372d383335342d313732323131646161366435/) 内部部品入れころ

+

## 出来上がったもの 最終的に出来上がったものは写真のとおりです。 現在の温度と過去の温度変化赤線示して可視化を行いました。 また、別途持っている温度計を比較してみたところ、測定温度は近似値であり普段使いでは問題ないことも確認ができました。 ![比較](https://camo.elchika.com/1c204769f24dcdf2a83923e4b9a1ad3bb7549248/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f33313639316266322d353532392d343163372d383035302d6631303634653461393532652f63653165663564362d376234332d343239612d383636632d323065613563386632653233/) ## まとめ 今回はSpresenseを使用して”温度”という状態の可視化を行いました。 他も様々なセンサ使用することで身の回りの情報を可視化、生活を豊かにできる工夫があると思うので、いろいろ試していき感じました。