กลับไปหน้ารวมไฟล์
temperature-humidity-data-logging-d2e389.md

โปรเจคนี้จะแสดงให้เห็นว่า การทำแผงแสดงผลง่ายๆ (สำหรับเทอร์โมสตัท) น่ะมันง่ายโคตรๆ แค่เชื่อมต่อจออัจฉริยะ Matrix Orbital GTT Intelligent TFT HMI เข้ากับ Arduino Nano ผ่าน I2C เท่านั้นเอง เราใช้เซ็นเซอร์วัดอุณหภูมิและความชื้น DHT22 ในการดึงข้อมูล จากนั้น Arduino Nano ก็จะประมวลผลข้อมูลเพื่อแสดงกราฟย้อนหลังรายชั่วโมง, 24 ชั่วโมง และรายสัปดาห์ รวมถึงมีกราฟสดให้ดูค่าปัจจุบันด้วย

ถ้าเราเพิ่มระบบไฟฟ้าหรือระบบไฟฟ้า-กลไกเข้าไปด้านหลังแผงแสดงผลนี้ล่ะก็ มันก็จะกลายเป็นเทอร์โมสตัทสุดเท่ที่มีจอ TFT สีสันสดใสเลยล่ะ

ภาพรวมโปรเจค

"Temp-Humid-Logger" นี่คือการนำ Asynchronous Hygrometric-Forensics และ I2C-Temporal HMI Orchestration มาทำกันแบบจริงจังเลยทีเดียว ออกแบบมาให้เป็นโหนดตรวจวัดสภาพแวดล้อมระดับอุตสาหกรรม ใช้จออัจฉริยะตระกูล GTT จาก Matrix Orbital ในการแสดงผลสถาปัตยกรรมข้อมูลที่ซับซ้อนผ่านการเชื่อมต่อแบบ I2C โปรเจคนี้จะพาไปสำรวจการแมปสตรีมบิตจากเซ็นเซอร์ให้กลายเป็นกริดข้อมูลรายชั่วโมง, รายสัปดาห์ และรายเดือน โดยใช้ Statistical-Accumulation Heuristic ในการจัดการกราฟที่มีจุดข้อมูลมากกว่า 180 จุดแบบเรียลไทม์ โฟกัสที่การวินิจฉัยการสื่อสาร HMI แบบไฮไฟเดลิตี้, การตรวจสอบความสมบูรณ์ของ resistive-pullup และความเสถียรทางความร้อนในระยะยาว

ขั้นตอนที่ 1: ออกแบบส่วนติดต่อผู้ใช้ (UI)

GTT Designer Suite ช่วยให้เราลากวางวิดเจ็ตต่างๆ ลงบนหน้าจอได้ง่ายๆ สามารถนำเข้าไฟล์รูปภาพและฟอนต์มาใช้สร้าง GUI ได้ด้วย สำหรับโปรเจคนี้ เราสร้างหลายหน้าจอ ซึ่งจะถูกประมวลผลเป็นสคริปต์อัตโนมัติเมื่อกดปุ่มต่างๆ

สำหรับหน้าจอแรก (HOME) เราได้ลากวาง:

  • ป้ายข้อความ (label) (ป้ายบน: แสดงข้อมูลอุณหภูมิเป็น °C; ป้ายล่าง: แสดงข้อมูลความชื้นเป็น % rh)
  • ปุ่ม (ปุ่มล่องหนที่ซ่อนอยู่บนป้ายข้อความ ซึ่งจะเปิดกราฟสดของอุณหภูมิหรือความชื้น และปุ่ม 'MAX' สำหรับตั้งค่าการแจ้งเตือนความชื้นสูงสุด)

หน้าจอที่ 2 คือหน้าตั้งค่าการแจ้งเตือนความชื้นสูงสุด (MAX) เริ่มต้น เราใช้วิดเจ็ต:

  • ปุ่มสามเหลี่ยมสองปุ่ม (ขึ้นและลง) ใช้สำหรับปรับตั้งค่าความชื้นสูงสุด ค่าเริ่มต้นจะแสดงไว้ (ตั้งไว้ที่ 70%) และปุ่มสามเหลี่ยมนี้จะส่งรายงานไปยัง Arduino เพื่อให้ Arduino ประมวลผลเพื่อเพิ่มหรือลดค่าการตั้งค่า
  • ปุ่ม ('HOME' ที่จะพากลับไปยังหน้าจอแรก)

หน้าจอที่ 3 คือหน้าจอแจ้งเตือน (ALERT) เมื่อความชื้นถึงค่าสูงสุดที่ตั้งไว้ Arduino จะยังคงตรวจสอบข้อมูลความชื้นต่อไป และจะพากลับไปที่หน้าจอ HOME เมื่อระดับความชื้นต่ำกว่าค่าที่ตั้งไว้

หน้าจอต่อไปนี้: LiveTGraph, TGraph_1HR, TGraph_24HR, TGraph_1WK คือกราฟย้อนหลังของข้อมูลอุณหภูมิ ส่วน LiveHGraph, HGraph_1HR, HGraph_24HR, HGraph_1WK คือกราฟย้อนหลังของข้อมูลความชื้น เราใช้วิดเจ็ต:

  • กราฟ (กราฟสดมี 30 จุดข้อมูล, ส่วนกราฟย้อนหลัง: 1 ชม., 24 ชม. และ 1 สัปดาห์ มี 180 จุด)
  • ปุ่ม (ปุ่ม 1 ชั่วโมง, 24 ชั่วโมง และ 1 สัปดาห์ สำหรับเปิดกราฟแต่ละแบบ)

Matrix Orbital Temperature and Humidity Demo GUI

เมื่อออกแบบเสร็จแล้ว ก็สามารถดีพลอยโปรเจคไปยังจอ GTT ได้เลย แค่เชื่อมต่อพีซีของคุณเข้ากับหัวต่อ Mass Storage ของ GTT แล้วกด "Deploy" ใน GTT Designer ไฟล์ที่จำเป็นทั้งหมดจะถูกสร้างและส่งตรงไปยังจอแสดงผล

In action

ขั้นตอนที่ 2: ต่อ GTT เข้าไป

สำหรับงานนี้ เราจะใช้ I2C ในการคุยกันระหว่าง Arduino Uno กับ GTT ใช้สายบรัดบอร์ดต่อเฮดเดอร์ 4 พินเข้ากับพอร์ต I2C ของ GTT จากนั้นต่อสายสีแดง (ไฟเลี้ยง 5V) และสายสีดำ (กราวด์) ให้เรียบร้อย สายสีเหลือง (SDA) และสีเขียว (SCL) ให้ต่อเข้ากับขา SDA (A4) และ SCL (A5) ของ Arduino Nano ตามลำดับ ไม่ต้องใช้ตัวต้านทานดึงขึ้น (Pull-up Resistor) กับ GTT นะ เพราะไลบรารี Wire ของ Arduino เปิดตัวดึงขึ้นภายในให้อัตโนมัติอยู่แล้ว ถ้าอยากจ่ายไฟเพิ่มก็เสียบผ่านเบอร์เรลแจ็กของจอได้เลย

GTT35A with Arduino Nano in Case

ขั้นตอนที่ 3: ต่อ DHT22

ห้ามลืม! ต้องต่อตัวต้านทาน (Resistor) 4.7k โอห์มดึงขึ้น (Pull-up) ระหว่างขาข้อมูลของ DHT22 กับไฟ +5V ด้วย ไม่งั้นเซนเซอร์จะคุยกับเราไม่รู้เรื่อง ขาข้อมูลของ DHT22 ต่อเข้ากับขาดิจิทัลไหนของ Arduino ก็ได้ ในตัวอย่างนี้เราเลือกใช้ขา 8

DHT22 and Arduino Nano

ขั้นตอนที่ 4: ติดตั้งไลบรารี

ก่อนจะไปต่อ ดาวน์โหลดและแตกไฟล์ไลบรารีสำหรับ GTT Client นี้ซะ ไลบรารีพวกนี้ก็หาได้ในไฟร์แวร์ล่าสุดของ GTT นั่นแหละ พอดาวน์โหลดมาแล้ว ให้คัดลอกเนื้อหาในโฟลเดอร์ GttClient ไปไว้ที่ \\Users\\ชื่อUserของนาย\\Documents\\Arduino\\libraries\\gtt ให้เรียบร้อย

.c and .h files in the Demo Source directory

ล้วงลึกเทคนิค (Technical Deep-Dive)

  • การจัดการข้อมูลความชื้นและนิติวิทยาศาสตร์ I2C:
    • โพรบเก็บข้อมูล DHT22: ใช้เซนเซอร์วัดความชื้นแบบ capacitive กับเทอร์มิสเตอร์วัดอุณหภูมิ กระบวนการตรวจสอบเกี่ยวข้องกับการวัด "ช่วงเวลาสัญญาณบนบัสเดียว (Single-Bus Signal-Timing)" เซนเซอร์จะส่งแพ็กเก็ตข้อมูล 40 บิต $(16\text{ bit ความชื้น, } 16\text{ bit อุณหภูมิ, } 8\text{ bit เช็คซัม})$ การวินิจฉัยจะโฟกัสที่ "การวิเคราะห์ความถูกต้องของเช็คซัม (Checksum-Fidelity Analytics)" เพื่อให้แน่ใจว่าจับการเปลี่ยนแปลงของสิ่งแวดล้อมได้โดยไม่เกิดข้อผิดพลาด
    • ฮับกำหนดเวลาของ I2C: ทำงานที่ความถี่นาฬิกา $100\text{kHz}$ ที่กำหนดไว้ การตรวจสอบรวมถึงการวัด "ความหน่วงเวลาของการแลกเปลี่ยนแพ็กเก็ต (Packet-Transaction Latency)" ระหว่าง Nano กับ GTT35A การวินิจฉัยใช้รูทีน i2cWrite แบบกำหนดเอง โดยจำกัดขนาดข้อมูลที่ 32 ไบต์ เพื่อป้องกันไม่ให้บัสค้าง (bus-hang) บนบัฟเฟอร์ Wire ภายในของ Arduino
  • การสร้างภาพกราฟิกและสถิติสำหรับวินิจฉัย:
    • การวิเคราะห์จอแสดงผลอัจฉริยะ GTT: ใช้สคริปต์เอนจินแบบกำหนดเองเพื่อวาดกราฟความละเอียดสูง การตรวจสอบรวมถึงการคำนวณ "ค่าเฉลี่ยเคลื่อนที่ (Rolling-Average Harmonics)" โดยสะสมค่าเฉลี่ยจาก 10 ตัวอย่าง $(ช่วงเวลา 20\text{ วินาที})$ เพื่อเติมข้อมูลลงในกริดเทเลเมทรีสำหรับ 1 ชั่วโมง, 24 ชั่วโมง และ 1 สัปดาห์
    • การตรวจสอบความคงทนของหน่วยความจำแฟลช: ใช้การ์ด uSD ในการเก็บชุดข้อมูลเทเลเมทรี .dat การวินิจฉัยจะโฟกัสที่ "ความสมบูรณ์ของระบบไฟล์ (File-System Integrity)" ทำให้สามารถกู้สถานะและโหลดข้อมูลเทเลเมทรีย้อนหลังได้หลังจากเปิด-ปิดเครื่อง

ขั้นตอนที่ 5: เขียนโค้ด

//GTT Arduino Tempearature and Humidity Demo
//Arduino Uno with Matrix Orbital GTT35A and DHT22
//Created by R Malinis, 25/05/2018
//support@matrixorbital.ca
//www.matrixorbital.ca/appnotes
#include <Dhcp.h>
#include <Dns.h>
#include <Ethernet.h>
#include <EthernetClient.h>
#include <EthernetServer.h>
#include <EthernetUdp.h>
#include <gtt.h>
#include <gtt_device.h>
#include <gtt_enum.h>
#include <gtt_events.h>
#include <gtt_ext_types.h>
#include <gtt_packet_builder.h>
#include <gtt_parser.h>
#include <gtt_protocol.h>
#include <gtt_text.h>
#include <Wire.h>
#include <SimpleDHT.h>
#include "GTTProject12.c"
#include "GTTProject12.h"
#include <stdlib.h>
#define I2C_Address 0x28  //Define default 8bit I2C address of 0x50 >> 1 for 7bit Arduino
// Buffer for incoming data
uint8_t rx_buffer[128];
// Buffer for outgoing data
uint8_t tx_buffer[256];
gtt_device gtt; //Declare the GTT device
typedef enum
{
 NOGraph =0,
 TempGraph=1,
 HumiGraph=2
} GraphScreen;
// DHT11
int pinDHT22 = 8;
SimpleDHT22 dht22;
byte defaultMaxHumidity;
bool MaxHumidityScreen = false;
GraphScreen Graph = NOGraph;
typedef struct
{
 byte ChartData;
 byte ChartObject;
 float rawData;
}DataSourceType;
DataSourceType Temperature;
DataSourceType Humidity;
void LiveGraph(float temperature, float humidity)
{
 if (Graph == NOGraph)
   return;
 DataSourceType source;
 if (Graph == TempGraph)
 {
   source = Temperature;
   source.rawData = temperature;
   source.ChartData = id_livetgraph_t_live_data0;
   source.ChartObject = id_livetgraph_t_live_;
 }
 else
 {
   source = Humidity;
   source.rawData = humidity;
   source.ChartData = id_livehgraph_h_live_data0;
   source.ChartObject = id_livehgraph_h_live_;
 }
 gtt25_dataset_push_data(&gtt, source.ChartData, (float) source.rawData);
 gtt25_visualobject_invalidate(&gtt, source.ChartObject);
 Serial.println("drawing LIVE graph");
 return;
}
void GTT25ButtonHandler(gtt_device* device, uint16_t ObjectID, uint8_t State)
{
 Serial.print("button handler: ");
 Serial.print(ObjectID);
 Serial.print(" state: ");
 Serial.println(State);
 if (State != 1)
   return;
 MaxHumidityScreen = false;
 Graph = NOGraph;
 switch (ObjectID)
 {
   case id_screen2_triangle_button_1:
     defaultMaxHumidity++;
     break;
   case id_screen2_triangle_button_2:
     defaultMaxHumidity--;
     break;
   case id_screen1_max_btn:
     break;
   case id_screen1_image_button_1:
     Graph = TempGraph;
     return;
     break;
   case id_screen1_image_button_2:
     Graph = HumiGraph;
     return;
     break;
   // the following buttons take care of themselves as designed in the GTT Designer
   // only used here for serial debug
   case id_screen2_home_btn:
   case id_screen3_home_btn:
   case id_livehgraph_home_btn:
   case id_hgraph_1hr_home_btn:
   case id_hgraph_24hr_home_btn:
   case id_hgraph_1wk_home_btn:
   case id_livetgraph_home_btn:
     Serial.println("==== back to HOME screen");
     return;
     break;
   case id_livetgraph_1_hr_btn:
   case id_tgraph_1hr_1_hr_btn:
   case id_tgraph_24hr_1_hr_btn:
   case id_tgraph_1wk_1_hr_btn:
   case id_livehgraph_1_hr_btn:
   case id_hgraph_1hr_1_hr_btn:
   case id_hgraph_24hr_1_hr_btn:
   case id_hgraph_1wk_1_hr_btn:
     Serial.println("==== displaying 1 HOUR");
     return;
     break;
   case id_livetgraph_24_hr_btn:
   case id_tgraph_1hr_24_hr_btn:
   case id_tgraph_24hr_24_hr_btn:
   case id_tgraph_1wk_24_hr_btn:
   case id_livehgraph_24_hr_btn:
   case id_hgraph_1hr_24_hr_btn:
   case id_hgraph_24hr_24_hr_btn:
   case id_hgraph_1wk_24_hr_btn:
     Serial.println("==== displaying 24 HOUR");
     return;
     break;
   case id_livetgraph_1_wk_btn:
   case id_tgraph_1hr_1_wk_btn:
   case id_tgraph_24hr_1_wk_btn:
   case id_tgraph_1wk_1_wk_btn:
   case id_livehgraph_week_btn:
   case id_hgraph_1hr_week_btn:
   case id_hgraph_24hr_week_btn:
   case id_hgraph_1wk_week_btn:
     Serial.println("==== displaying 1 WEEK");
     return;
     break;
 }
 char buf[] = {0};
 int16_t humid = defaultMaxHumidity;
sprintf(buf, "%d", humid); //แปลงค่าความชื้นเป็นสตริง
 gtt_set_screen2_humi_label_1_text(&gtt, gtt_make_text_ascii(buf)); //อัพเดทป้ายบน GTT
 Serial.println("defaultMaxHumidity is set");
 Serial.println(humid);
}
void HumidityCheck(float humidityVal)
{
 if (humidityVal > defaultMaxHumidity)
 {
   Serial.print("max: "); Serial.print((int)defaultMaxHumidity);
   Serial.print(" current:"); Serial.println((int)humidityVal);
   if (MaxHumidityScreen == false)
   {
     gtt_run_script(&gtt, (char*)("GTTProject12\\\\Screen3\\\\Screen3.bin"));
     MaxHumidityScreen = true;
     delay(2000);
   }
 }
 if (MaxHumidityScreen == true &&  (humidityVal < defaultMaxHumidity))
 {
     gtt_clear_alltraces(&gtt);
     gtt_run_script(&gtt, (char*)("GTTProject12\\\\Screen1\\\\Screen1.bin"));
     MaxHumidityScreen = false;
     delay(2000);
 }
 return;
}
float TempData[10] = {0,0,0,0,0,0,0,0,0,0};
float HumiData[10] = {0,0,0,0,0,0,0,0,0,0};
bool OldDataLoaded = false;
void UpdateDataCollection(float temperature, float humidity)
{
     float avgTempData, avgHumiData;
     static byte counter20sec = 0; // 180 จุดข้อมูล = 1 ชม.
     static byte counter8mins = 0; // 180 จุดข้อมูล = 24 ชม.
     static byte counter56mins = 0;// 180 จุดข้อมูล = 1 สัปดาห์
     DataSourceType dataSource;
     static byte HrMaxH = 15;
     static byte HrMinH = 25;
     static byte HrMaxT = 20;
     static byte HrMinT = 25;
     static byte T24HrMaxH = 15;
     static byte T24HrMinH = 25;
     static byte T24HrMaxT = 20;
     static byte T24HrMinT = 25;
     //debug
     static byte count20secP = 0;
     static byte count8minP = 0;
     static byte count56minP = 0;
     LiveGraph(temperature, humidity);
     //Serial.print("Data (not collected): ");
     //Serial.print((float)temperature); Serial.print(" *C, ");
     //Serial.print((float)humidity); Serial.println(" RH%");
     eStatusCode r;
     if (OldDataLoaded == false)
     {
       OldDataLoaded = true;
       r = gtt25_dataset_load(&gtt, id_tgraph_24hr_24_hr_chart_data0, gtt_make_text_ascii("Temp24hrMax.dat"));
       r = gtt25_dataset_load(&gtt, id_tgraph_24hr_24_hr_chart_data1, gtt_make_text_ascii("Temp24hrMin.dat"));
       r = gtt25_dataset_load(&gtt, id_hgraph_24hr_24_hr_chart_data0, gtt_make_text_ascii("Humidity24hrMax.dat"));
       r = gtt25_dataset_load(&gtt, id_hgraph_24hr_24_hr_chart_data1, gtt_make_text_ascii("Humidity24hrMin.dat"));
       r = gtt25_dataset_load(&gtt, id_tgraph_1wk_1_wk_chart_data0, gtt_make_text_ascii("Temp1WkMax.dat"));
       r = gtt25_dataset_load(&gtt, id_tgraph_1wk_1_wk_chart_data1, gtt_make_text_ascii("Temp1WkMin.dat"));
       r = gtt25_dataset_load(&gtt, id_hgraph_1wk_1_wk_chart_data0, gtt_make_text_ascii("Humidity1WkMax.dat"));
       r = gtt25_dataset_load(&gtt, id_hgraph_1wk_1_wk_chart_data1, gtt_make_text_ascii("Humidity1WkMin.dat"));
       if (r != eStatusCode_Success)
       {
         Serial.println("Check uSD card");
       }
     }
     // รวบรวมข้อมูลเพื่อหาค่าเฉลี่ยทุก 20 วินาที (10 การอ่านค่า)
     TempData[counter20sec] = temperature;
     HumiData[counter20sec] = humidity;
     //Serial.print("temp: ");
     //Serial.print(temperature);
     //Serial.print(" humidity: ");

ข้อมูล Frontmatter ดั้งเดิม

apps:
  - "1x GTT GUI Designer Software"
  - "1x Arduino IDE"
author: "MatrixOrbital"
category: "Screens & Displays"
components:
  - "1x USB Cable A to Mini-B"
  - "1x Matrix Orbital Center Pos +5V Adapter (optional)"
  - "1x Arduino Nano R3"
  - "1x Resistor 4.75k ohm"
  - "1x GTT35A"
  - "1x Matrix Orbital 4 pin Breadboard Cable"
  - "1x DHT22 Temperature Sensor"
  - "1x Jumper wires (generic)"
description: "ระบบล็อกข้อมูลวัดอุณหภูมิกับความชื้นแบบเทพๆ จัดไปกับกราฟดูข้อมูลรายชั่วโมง รายสัปดาห์ รายเดือน งานง่ายแต่หล่อมาก!"
difficulty: "Intermediate"
documentationLinks: []
downloadableFiles:
  - "https://github.com/MatrixOrbital/GTT-Arduino-TempHumid-Demo"
encryptedPayload: "U2FsdGVkX1/t+rchziI6t7et30b8/FrVVXh5UMRLTT6/DRH7+xqMicsrVaTtyJuLat8kAWQsMrJrrP7YQ/j8ZQ+MGxGvGAQbo+F7P58lez9+JG/b1Rzkh5VnxMSm8rxbh6hMP7gVAwemn+ILYCqPqg=="
heroImage: "https://cdn.jsdelivr.net/gh/bigboxthailand/arduino-assets@main/images/projects/temperature-humidity-data-logging-d2e389_cover.jpg"
lang: "en"
likes: 10
passwordHash: "5e84df452a5cc010dbd394cb4a9385008a15b37bfcbc983de36cb944636bcaae"
price: 299
seoDescription: "Temperature & Humidity Data Logging system to track and visualize hourly, weekly, and monthly data points."
tags:
  - "environmental sensing"
  - "embedded"
  - "data collection"
title: "เก็บข้อมูลอุณหภูมิ-ความชื้นแบบตึงๆ ดูได้ทุกช่วงเวลา"
tools: []
videoLinks:
  - "https://www.youtube.com/embed/YOaDp4v3lI8"
views: 14819