Breadboard demo with ESP32-C3 SuperMini, AHT20 sensor, OLED display showing target temperature, and a 40mm fan spinning

ระดับกลาง

สร้างตัวอย่างการใช้งานเทอร์โมสตัทแบบดิจิทัล

เซ็นเซอร์ระบบอัตโนมัติแอคชูเอเตอร์

อ่านค่าอุณหภูมิที่เกิดขึ้นจริง เปรียบเทียบกับค่าเกณฑ์ และสั่งให้พัดลมทำงาน ซึ่งเป็นการควบคุมแบบวนซ้ำที่คุณสามารถมองเห็นและสัมผัสได้จริง

รวมชิ้นส่วนจริง 8 รายการ

ราคารวมชุดนี้: 1,895.00 ฿

ยังไม่รวมส่วนลดคำสั่งซื้อที่คุณอาจได้รับตอนชำระเงิน

สิ่งที่คุณต้องใช้

เป้าหมายของโครงการ

โครงการนี้สร้างระบบควบคุมแบบวงปิดขนาดเล็ก: อ่านอุณหภูมิจริง เปรียบเทียบกับค่าเกณฑ์ และเปิดหรือปิดพัดลมตามการตอบสนอง ซึ่งเป็นการควบคุมที่คุณสามารถมองเห็นและสัมผัสได้จริง ไม่ใช่แค่การอ่านเป็นตัวเลขบนหน้าจอ เป็นการยกระดับจากโครงการที่เพียงแค่ตรวจจับหรือแสดงผลเท่านั้น เพราะที่นี่การตัดสินใจของตัวควบคุมจะเปลี่ยนแปลงบางสิ่งในโลกทางกายภาพ

สิ่งที่ตัวควบคุมทำ

ESP32-C3 จะอ่านอุณหภูมิปัจจุบันจากเซ็นเซอร์อย่างต่อเนื่อง เปรียบเทียบกับค่าเกณฑ์ที่กำหนดในโค้ด อัปเดตการแสดงผลด้วยค่าที่อ่านได้ปัจจุบัน และเปิดหรือปิดพัดลมตามการเปรียบเทียบนั้น เป็นส่วนเดียวของระบบที่ตัดสินใจได้ — เซ็นเซอร์ จอแสดงผล และพัดลมเพียงแค่รายงานและตอบสนองเท่านั้น

สิ่งที่เซ็นเซอร์ทำ

AHT20 ให้ค่าอุณหภูมิปัจจุบัน (พร้อมกับความชื้น หากคุณเลือกที่จะใช้) ซึ่งตัวควบคุมจะอ่านผ่านบัส I2C เดียวกันที่ใช้สำหรับจอแสดงผล นี่คือส่วนอินพุตของวงจรควบคุม — หากไม่มีการอ่านค่าจริง ตัวควบคุมก็ไม่มีสิ่งใดที่มีความหมายให้เปรียบเทียบกับค่าเกณฑ์

สิ่งที่จอแสดงผลทำ

OLED แสดงทั้งอุณหภูมิปัจจุบันและค่าเกณฑ์ที่กำลังเปรียบเทียบ ทำให้พฤติกรรมของระบบมองเห็นได้และตรวจสอบได้ง่าย — คุณสามารถดูอุณหภูมิที่แสดงผลเข้าใกล้ค่าเกณฑ์และยืนยันว่าพัดลมตอบสนองในเวลาที่เหมาะสม แทนที่จะคาดเดาว่าตรรกะทำงานถูกต้องหรือไม่

สิ่งที่ MOSFET และพัดลมทำ

โมดูล MOSFET ระดับลอจิกจะเปิดหรือปิดพัดลมตามการเปรียบเทียบของตัวควบคุม MOSFET ถูกใช้ที่นี่แทนรีเลย์เชิงกลโดยเฉพาะเนื่องจากพัดลมเป็นโหลดกระแสตรง และ MOSFET สลับกระแสตรงอย่างเงียบ ๆ โดยไม่มีชิ้นส่วนเคลื่อนที่และไม่มีเสียงคลิก และไม่มีการสึกหรอของหน้าสัมผัสเมื่อเวลาผ่านไป โมดูลนี้ได้รับการยืนยันว่าเป็นระดับลอจิก ซึ่งหมายความว่ามันสลับได้อย่างสมบูรณ์ที่ 3.3-5V — ช่วงแรงดันไฟฟ้าเดียวกันกับที่ขา GPIO ของ ESP32-C3 ส่งออกโดยตรง — แทนที่จะต้องการแรงดันเกตที่สูงกว่าซึ่งจะต้องการวงจรขับเคลื่อนเพิ่มเติม

ทำไมต้องใช้ MOSFET แทนรีเลย์

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

แนวคิดซอฟต์แวร์และไลบรารี

ตรรกะหลักคือการเปรียบเทียบค่าเกณฑ์ แต่การใช้งานที่เรียบง่าย — พัดลมเปิดเมื่ออุณหภูมิสูงกว่า X° ปิดเมื่อต่ำกว่า X° — ทำให้เกิดปัญหาจริง: ฮิสเตอรีซิส หากอุณหภูมิคงที่อยู่เหนือค่าเกณฑ์พอดี การผันผวนเล็กน้อยจะทำให้พัดลมเปิดและปิดอย่างรวดเร็วเมื่อค่าที่อ่านได้ข้ามไปมาเหนือจุดเดียวนั้น การแก้ไขคือช่องว่างบัฟเฟอร์ขนาดเล็กระหว่างเกณฑ์การเปิดและปิด — ตัวอย่างเช่น เปิดพัดลมเมื่ออุณหภูมิสูงกว่า 28° แต่ปิดเมื่ออุณหภูมิต่ำกว่า 27° เท่านั้น ช่องว่างหนึ่งองศานั้นหมายความว่าการผันผวนรอบ ๆ ตัวเลขใดตัวเลขหนึ่งจะไม่ทำให้เกิดการหมุนวนอย่างรวดเร็ว เพราะพัดลมจะต้องผ่านช่องว่างทั้งหมดในทิศทางเดียวก่อนที่จะเปลี่ยนสถานะอีกครั้ง นี่เป็นแนวคิดที่สำคัญอย่างแท้จริงของระบบควบคุม ไม่ใช่แค่รายละเอียดการใช้งานเล็กน้อย — หากไม่มีสิ่งนี้ การสลับพัดลมที่เหมือนรีเลย์จะสึกหรอเร็วขึ้นอย่างเห็นได้ชัด และพฤติกรรมจะดูผิดปกติแม้ว่าตรรกะพื้นฐานจะถูกต้อง

การทดสอบและการแก้ไขปัญหา

  • พัดลมไม่เปิดแม้ว่าอุณหภูมิจะสูงกว่าค่าเกณฑ์อย่างชัดเจน — ตรวจสอบสายไฟควบคุมสัญญาณของโมดูล MOSFET และยืนยันว่าโค้ดกำลังเปรียบเทียบกับค่าเกณฑ์ที่ถูกต้องจริง ๆ ไม่ใช่ค่าเริ่มต้นที่เหลืออยู่
  • พัดลมไม่ปิดหรือกะพริบอย่างรวดเร็วรอบ ๆ ค่าเกณฑ์ — เกือบจะเสมอเป็นช่องว่างฮิสเตอรีซิสที่ขาดหายไป เพิ่มเกณฑ์การเปิดและปิดแยกกันห่างกันหนึ่งหรือสององศา
  • อุณหภูมิที่แสดงผลและพฤติกรรมของพัดลมดูไม่ตรงกัน — ตรวจสอบหน่วยและค่าเกณฑ์ที่ใช้ในโค้ดอีกครั้งเทียบกับสิ่งที่เซ็นเซอร์รายงานจริง (AHT20 รายงานเป็นเซลเซียสโดยค่าเริ่มต้น)
  • การอ่านอุณหภูมิดูค้างหรือไม่สมเหตุสมผล — ยืนยันว่า AHT20 เริ่มต้นสำเร็จผ่าน I2C และไม่ขัดแย้งกับ OLED บนบัสเดียวกัน การเริ่มต้นเซ็นเซอร์ล้มเหลวมักจะส่งคืนค่าคงที่หรือค่าขยะอย่างเงียบ ๆ แทนที่จะเป็นข้อผิดพลาด

การอัปเกรดเสริมในอนาคต: การควบคุมความเร็วพัดลมแบบสัดส่วน

แทนที่จะเปิดหรือปิดพัดลมอย่างสมบูรณ์ เวอร์ชั่นในอนาคตสามารถขับเคลื่อนมันด้วย PWM และปรับความเร็วของพัดลมให้เป็นสัดส่วนกับระยะห่างที่อุณหภูมิสูงกว่าค่าเกณฑ์ — ลมเบา ๆ เหนือเส้นเล็กน้อย ความเร็วเต็มที่เมื่ออุณหภูมิสูงขึ้นไปอีก สิ่งนี้สร้างขึ้นโดยตรงบนการเดินสาย MOSFET เดียวกันที่มีอยู่แล้ว เนื่องจาก MOSFET ระดับลอจิกที่รองรับ PWM สามารถจัดการรอบการทำงานที่แตกต่างกันได้เช่นเดียวกับการจัดการสัญญาณเปิด/ปิดอย่างง่าย

การเดินสาย

  • AHT20 sensor VCC → ESP32-C3 3V3
  • AHT20 sensor GND → ESP32-C3 GND
  • AHT20 sensor SDA → ESP32-C3 GPIO8 — บัส I2C ที่ใช้ร่วมกัน (SDA เริ่มต้นบน ESP32-C3/S3 Arduino core)
  • AHT20 sensor SCL → ESP32-C3 GPIO9 — บัส I2C ที่ใช้ร่วมกัน (SCL เริ่มต้น)
  • OLED display VCC → ESP32-C3 3V3
  • OLED display GND → ESP32-C3 GND
  • OLED display SDA → ESP32-C3 GPIO8 — บัสเดียวกับ AHT20 (ที่อยู่ I2C ต่างกัน: AHT20 = 0x38, OLED = 0x3C, จึงไม่มีความขัดแย้ง)
  • OLED display SCL → ESP32-C3 GPIO9 — บัสเดียวกับ AHT20
  • MOSFET module SIG → ESP32-C3 GPIO3 — สัญญาณควบคุมดิจิทัลสำหรับสวิตช์พัดลม
  • MOSFET module VCC → ESP32-C3 3V3 — แหล่งจ่ายไฟลอจิกสำหรับวงจรขับเกตของโมดูล
  • MOSFET module GND → ESP32-C3 GND — ต้องใช้กราวด์ร่วมกับทั้ง ESP32 และแหล่งจ่ายไฟของพัดลม
  • Fan red wire (+) → 5V (ขา 5V ของบอร์ด, มีอยู่เมื่อจ่ายไฟผ่าน USB-C)
  • Fan black wire (−) → ขั้วเอาต์พุตโหลดของโมดูล MOSFET, โดยที่ขั้วโหลดอีกด้านของโมดูล → GND — ซึ่งจะส่งกระแสย้อนกลับของพัดลมผ่านสวิตช์ MOSFET

ติดตั้ง AHT20 และ OLED ก่อน และยืนยันว่าทั้งสองตอบสนองบนบัส I2C ที่ใช้ร่วมกัน ก่อนที่จะเดินสายส่วน MOSFET/พัดลม — ความขัดแย้งของที่อยู่ I2C หรือการเดินสายที่ไม่ถูกต้องจะแก้ไขข้อผิดพลาดได้ง่ายกว่าเมื่อไม่มีพัดลมหมุนในวงจร แถบฮิสเตอรีซิส ±0.5°C คือสิ่งที่ช่วยให้พัดลมไม่เปิด/ปิดอย่างรวดเร็วที่ค่าเกณฑ์ ขยายมันหากพัดลมยังคงทำงานติดขัดในการตั้งค่าของคุณ ห้ามจ่ายไฟให้พัดลมโดยตรงจากขา GPIO — ต้องสลับผ่านโมดูล MOSFET เสมอ

แผนภาพการต่อสาย

VCC → 3V3 GND SDA → GPIO8 SCL → GPIO9 VCC → 3V3 GND SDA → GPIO8 SCL → GPIO9 SIG → GPIO3 VCC → 3V3 GND ESP32-C3 AHT20 sensor OLED display MOSFET module 5V Fan red wire MOSFET module load output… Fan black wire

โค้ดเริ่มต้น

// Digital Thermostat Demo — ESP32-C3 SuperMini + AHT20 + OLED + MOSFET fan
#include <Wire.h>
#include <Adafruit_AHTX0.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// --- Pins — adjust to match your board's silkscreen if different ---
#define SDA_PIN 8
#define SCL_PIN 9
#define FAN_MOSFET_PIN 3

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_ADDR 0x3C

Adafruit_AHTX0 aht;
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

const float TEMP_THRESHOLD_C = 27.0; // fan turns on above this
const float HYSTERESIS_C = 0.5;      // fan turns off once temp drops this far below threshold

bool fanOn = false;

void setup() {
  Serial.begin(115200);
  Wire.begin(SDA_PIN, SCL_PIN);

  pinMode(FAN_MOSFET_PIN, OUTPUT);
  digitalWrite(FAN_MOSFET_PIN, LOW); // fan off at boot

  if (!aht.begin()) {
    Serial.println("AHT20 not found — check wiring");
    while (1) delay(1000);
  }

  if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
    Serial.println("SSD1306 not found — check wiring");
    while (1) delay(1000);
  }
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
}

void updateFan(float tempC) {
  if (!fanOn && tempC >= TEMP_THRESHOLD_C) {
    fanOn = true;
  } else if (fanOn && tempC <= (TEMP_THRESHOLD_C - HYSTERESIS_C)) {
    fanOn = false;
  }
  digitalWrite(FAN_MOSFET_PIN, fanOn ? HIGH : LOW);
}

void loop() {
  sensors_event_t humidity, temp;
  aht.getEvent(&humidity, &temp);

  float tempC = temp.temperature;
  float rh = humidity.relative_humidity;

  updateFan(tempC);

  display.clearDisplay();
  display.setTextSize(2);
  display.setCursor(0, 0);
  display.print(tempC, 1);
  display.println(" C");

  display.setTextSize(1);
  display.setCursor(0, 20);
  display.print("Humidity: ");
  display.print(rh, 0);
  display.println(" %");

  display.setCursor(0, 35);
  display.print("Threshold: ");
  display.print(TEMP_THRESHOLD_C, 1);
  display.println(" C");

  display.setCursor(0, 50);
  display.print("Fan: ");
  display.println(fanOn ? "ON" : "OFF");

  display.display();

  Serial.print("Temp: "); Serial.print(tempC);
  Serial.print(" C  Humidity: "); Serial.print(rh);
  Serial.print(" %  Fan: "); Serial.println(fanOn ? "ON" : "OFF");

  delay(1000);
}

ไม่แน่ใจขั้นตอนไหน? ถามเรา