เนื้อหาในบทความ
Deep Sleep คืออะไร?
Deep Sleep Mode คือโหมดพลังงานต่ำสุดของ ESP32 ที่ปิดการทำงานของ CPU, WiFi, Bluetooth และอุปกรณ์ส่วนใหญ่ โดยเหลือไว้เฉพาะ RTC Memory และ Real Time Clock (RTC) เพื่อรักษาข้อมูลและตั้งเวลาการตื่น
💡 ทำไมต้อง Deep Sleep? ESP32 ในโหมดปกติใช้กระแส ~80-240mA แต่ใน Deep Sleep ใช้เพียง ~10-150µA เท่านั้น! นั่นหมายถึงประหยัดพลังงานได้ 1,000-10,000 เท่า
เหมาะสำหรับโปรเจกต์ประเภทใด?
- 🌡️ เซ็นเซอร์วัดอุณหภูมิ/ความชื้น ส่งข้อมูลทุก 5-15 นาที
- 💧 ระบบรดน้ำอัตโนมัติ ตรวจสอบความชื้นดินทุกชั่วโมง
- 📍 Tracking devices ส่งพิกัดทุก 10-30 นาที
- 🔔 Remote alerts ส่งข้อมูลเฉพาะเมื่อมีเหตุการณ์
- 📊 Data loggers บันทึกข้อมูลเป็นระยะ
โหมดพลังงานของ ESP32
| โหมด | กระแสไฟ | WiFi/BT | การใช้งาน |
|---|---|---|---|
| Active | 80-240 mA | เปิด | ปกติ |
| Modem Sleep | 15-30 mA | ปิดชั่วคราว | CPU ทำงาน |
| Light Sleep | 0.8-15 mA | ปิด | ตื่นได้เร็ว |
| Deep Sleep | 10-150 µA | ปิด | ประหยัดสุด |
| Hibernation | 2.5-5 µA | ปิดทั้งหมด | RTC เท่านั้น |
* ค่ากระแสขึ้นอยู่กับบอร์ดและอุปกรณ์ที่ต่ออยู่ บอร์ดบางรุ่นอาจใช้ไฟมากกว่าใน Deep Sleep
การเตรียมอุปกรณ์
อุปกรณ์ที่ต้องการ
- ESP32 Development Board (NodeMCU, Wemos, หรือ Generic)
- USB Cable สำหรับ programming
- Arduino IDE หรือ PlatformIO
- แหล่งจ่ายไฟแบตเตอรี่ (ถ้าทดสอบจริง)
- (Optional) Multimeter สำหรับวัดกระแส
ข้อควรระวังเรื่อง Hardware
⚠️ บอร์ด ESP32 บางรุ่นมีอุปกรณ์เสริมที่ใช้ไฟเสมอ!
- Power LED (สีแดง/ฟ้า) ใช้ ~2-10 mA - ตัดถ้าต้องการประหยัดสุด
- Voltage Regulator บางรุ่นใช้ไฟมาก
- USB-to-UART Chip ใช้ ~2-5 mA - ต้องตัดถ้าใช้แบตเตอรี่
Tip: สำหรับโปรเจกต์แบตเตอรี่จริง ใช้บอร์ดที่ออกแบบมาสำหรับ Low Power เช่น ESP32-WROOM-32, ESP32-C3, หรือ FireBeetle
Deep Sleep พื้นฐาน
ตัวอย่างที่ 1: Deep Sleep เป็นเวลา N วินาที
นี่คือตัวอย่างพื้นฐานที่สุด - ให้ ESP32 นอน Deep Sleep 30 วินาที แล้วตื่นขึ้นมาทำงาน
#include <WiFi.h>
// ตั้งค่าเวลานอน (เป็นวินาที)
#define uS_TO_S_FACTOR 1000000 /* ปัจจัยแปลงไมโครวินาทีเป็นวินาที */
#define TIME_TO_SLEEP 30 /* เวลาที่จะนอน Deep Sleep (วินาที) */
void setup() {
Serial.begin(115200);
// รอให้ Serial เปิด (สำหรับ debugging)
delay(1000);
// พิมพ์ข้อความต้อนรับ
Serial.println("ESP32 ตื่นขึ้นมาแล้ว!");
Serial.println("กำลังทำงาน...");
// --- ใส่โค้ดของคุณที่นี่ ---
// อ่านเซ็นเซอร์, ส่งข้อมูล, ทำสิ่งที่ต้องการ
Serial.println("เสร็จสิ้น! กำลังเข้าสู่ Deep Sleep...");
Serial.println("--------------------------------");
// เข้าสู่ Deep Sleep เป็นเวลาที่กำหนด
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
Serial.println("ตั้งเวลาตื่น: " + String(TIME_TO_SLEEP) + " วินาที");
Serial.println("กำลังเข้า Deep Sleep ตอนนี้...");
esp_deep_sleep_start();
// โค้ดบรรทัดนี้จะไม่ถูก executed เพราะ ESP32 จะหลับ
Serial.println("นี่คือข้อความที่คุณจะไม่เห็น");
}
void loop() {
// ใน Deep Sleep mode, loop() จะไม่ถูกเรียกใช้
// เพราะ ESP32 จะรีสตาร์ททุกครั้งที่ตื่นจาก Deep Sleep
} 💡 สังเกต: เมื่อ ESP32 ตื่นจาก Deep Sleep มันจะเริ่มทำงานใหม่จาก setup() ไม่ใช่ loop() นั่นเป็นเพราะ Deep Sleep ทำการรีสตาร์ทชิป
ตัวอย่างที่ 2: ตรวจสอบว่าตื่นจากอะไร
ESP32 สามารถตื่นจาก Deep Sleep ได้หลายวิธี ตัวอย่างนี้ตรวจสอบว่าตื่นจากอะไร
#include <WiFi.h>
#include <esp_wifi.h>
#define uS_TO_S_FACTOR 1000000
#define TIME_TO_SLEEP 30
void print_wakeup_reason() {
esp_sleep_wakeup_cause_t wakeup_reason;
wakeup_reason = esp_sleep_get_wakeup_cause();
switch(wakeup_reason) {
case ESP_SLEEP_WAKEUP_EXT0:
Serial.println("ตื่นจากสัญญาณภายนอก (RTC_IO)");
break;
case ESP_SLEEP_WAKEUP_EXT1:
Serial.println("ตื่นจากสัญญาณภายนอก (RTC_CNTL)");
break;
case ESP_SLEEP_WAKEUP_TIMER:
Serial.println("ตื่นจาก Timer");
break;
case ESP_SLEEP_WAKEUP_TOUCHPAD:
Serial.println("ตื่นจาก Touchpad");
break;
case ESP_SLEEP_WAKEUP_ULP:
Serial.println("ตื่นจาก ULP Coprocessor");
break;
default:
Serial.printf("ตื่นจากสาเหตุอื่น: %d\n", wakeup_reason);
break;
}
}
void setup() {
Serial.begin(115200);
delay(1000);
// ตรวจสอบสาเหตุที่ตื่น
print_wakeup_reason();
// ทำงานของคุณ...
Serial.println("ทำงานเสร็จแล้ว กลับไปนอนต่อ...");
// ตั้งเวลา Deep Sleep
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
esp_deep_sleep_start();
}
void loop() {
// ไม่ได้ใช้ใน Deep Sleep
}วิธีปลุกจาก Deep Sleep
1. Timer Wake-up (ตั้งเวลา)
วิธีที่ง่ายที่สุด - ตั้งเวลาให้ตื่นเป็นระยะ
// ตื่นทุก 5 นาที
esp_sleep_enable_timer_wakeup(5 * 60 * 1000000); // ไมโครวินาที
// ตื่นทุก 1 ชั่วโมง
esp_sleep_enable_timer_wakeup(60 * 60 * 1000000);2. External Wake-up (EXT0/EXT1)
ตื่นเมื่อมีสัญญาณจากขา GPIO เช่น ปุ่มกด หรือเซ็นเซอร์
#define BUTTON_PIN 0 // GPIO 0 (Boot button)
// EXT0: ใช้ GPIO ตัวเดียว
esp_sleep_enable_ext0_wakeup(
(gpio_num_t)BUTTON_PIN, // ขา GPIO
0 // 0 = Low, 1 = High (level ที่ตื่น)
);
// EXT1: ใช้หลายขาพร้อมกัน
#define BUTTON1_PIN 0
#define BUTTON2_PIN 35
uint64_t mask = (1ULL << BUTTON1_PIN) | (1ULL << BUTTON2_PIN);
esp_sleep_enable_ext1_wakeup(
mask, // bitmask ของ GPIO
ESP_EXT1_WAKEUP_ANY_HIGH // ANY_HIGH หรือ ALL_LOW
); ⚠️ ข้อจำกัด EXT0: ใช้ได้กับ RTC GPIO เท่านั้น (GPIO: 0, 2, 4, 12-15, 25-27, 32-39)
⚠️ ข้อจำกัด EXT1: ใช้ได้กับ RTC GPIO เหมือนกัน
3. Touch Wake-up (Touchpad)
ตื่นเมื่อมีการสัมผัสที่ Touchpad
// ตั้งค่า threshold สำหรับ touch
int threshold = 40;
touchAttachInterrupt(
T2, // Touch pin 2 (GPIO 2)
NULL, // callback function (NULL = ไม่ใช้)
threshold
);
// เปิดใช้งาน touch wake-up
esp_sleep_enable_touchpad_wakeup();4. ULP Coprocessor Wake-up
ให้ ULP Coprocessor ทำงานขณะนอน และตื่นเมื่อตรงตามเงื่อนไข (Advanced)
ULP คือ coprocessor ขนาดเล็กที่ทำงานขณะ ESP32 นอน Deep Sleep ได้ ใช้สำหรับ:
- อ่านเซ็นเซอร์ ADC ต่อเนื่อง
- ตรวจสอบค่าและตื่นเมื่อเกิน threshold
- นับเวลาแบบกำหนดเอง
เทคนิคประหยัดพลังงานขั้นสูง
1. WiFi Optimization
WiFi ใช้พลังงานมากที่สุด ให้ใช้งานน้อยที่สุด
#include <WiFi.h>
void connectWiFi() {
// ตั้งค่า WiFi mode เป็น STA (Station)
WiFi.mode(WIFI_STA);
// ลดกำลังส่ง (TX power) ลง
WiFi.setTxPower(WIFI_POWER_8_5dBm); // ต่ำสุด
// เชื่อมต่อ WiFi
WiFi.begin("your_SSID", "your_PASSWORD");
// รอการเชื่อมต่อ (timeout 10 วินาที)
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(500);
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("WiFi เชื่อมต่อสำเร็จ!");
Serial.println("IP: " + WiFi.localIP().toString());
} else {
Serial.println("WiFi เชื่อมต่อไม่สำเร็จ");
}
// --- ส่งข้อมูล ---
// ทำ HTTP Request, MQTT, etc.
// --- ปิด WiFi ---
WiFi.disconnect(true); // true = ปิด WiFi และลบการเชื่อมต่อ
WiFi.mode(WIFI_OFF); // ปิด WiFi mode
Serial.println("WiFi ปิดแล้ว");
}2. ปิด Peripherals ที่ไม่ใช้
// ปิด peripherals ที่ไม่ใช้
COST_BEGIN {
// ปิด ADC
adc_power_off();
// ปิด Bluetooth
btStop();
// ปิด I2C, SPI, Serial ถ้าไม่ใช้
// Serial.end();
// ลด clock speed (optional)
setCpuFrequencyMhz(80); // ปกติ 240MHz, ลดเหลือ 80MHz
}
COST_END3. ใช้ RTC Memory อย่างชาญฉลาด
RTC Memory เก็บข้อมูลได้แม้ ESP32 จะ Deep Sleep
// ตัวแปรใน RTC Memory (เก็บไว้ข้าม Deep Sleep)
RTC_DATA_ATTR int bootCount = 0;
RTC_DATA_ATTR float sensorReadings[10];
void setup() {
Serial.begin(115200);
// นับจำนวนครั้งที่บูต
bootCount++;
Serial.println("บูตครั้งที่: " + String(bootCount));
// เขียน/อ่านข้อมูลใน RTC Memory
sensorReadings[0] = 25.5; // เก็บค่าเซ็นเซอร์
// ... ทำงานอื่นๆ ...
// เข้า Deep Sleep
esp_deep_sleep_start();
}คำนวณอายุแบตเตอรี่
สูตรคำนวณ
อายุแบตเตอรี่ (ชั่วโมง) = ความจุแบตเตอรี่ (mAh) / กระแสเฉลี่ย (mA)
โดยกระแสเฉลี่ยคำนวณจาก:
Avg Current = (I_sleep × T_sleep + I_active × T_active) / (T_sleep + T_active)
ตัวอย่างการคำนวณ
| พารามิเตอร์ | ค่า |
|---|---|
| ความจุแบตเตอรี่ | 2000 mAh (2x AA) |
| กระแส Deep Sleep | 0.02 mA (20µA) |
| กระแส Active | 150 mA (avg) |
| เวลา Active | 5 วินาที |
| เวลา Sleep | 295 วินาที (5 นาที) |
📊 ผลลัพธ์:
- กระแสเฉลี่ย = (0.02 × 295 + 150 × 5) / 300 = 2.52 mA
- อายุแบตเตอรี่ = 2000 mAh / 2.52 mA = 793 ชั่วโมง ≈ 33 วัน
เปรียบเทียบ: ถ้าไม่ใช้ Deep Sleep (คงที่ 150mA) → 2000/150 = 13.3 ชั่วโมง เท่านั้น!
แก้ปัญหาที่พบบ่อย
❓ ปัญหา: ESP32 กินแบตเตอรี่เร็วมาก
สาเหตุที่เป็นไปได้:
- ไม่ได้ปิด WiFi ก่อนเข้า Deep Sleep
- มี LED บนบอร์ดสว่างอยู่
- ใช้บอร์ดที่มี power regulator ที่กินไฟมาก
- เซ็นเซอร์ที่ต่ออยู่ใช้ไฟเอง
วิธีแก้: วัดกระแสด้วย Multimeter ตรวจสอบว่า WiFi ปิดแล้ว, ตัด LED, ใช้บอร์ด low-power
❓ ปัญหา: ESP32 ตื่นแล้ว WiFi เชื่อมต่อไม่ได้
สาเหตุ: การเชื่อมต่อ WiFi ต้องการเวลา และบางครั้งล้มเหลว
วิธีแก้: เพิ่ม retry logic, ใช้ WiFi.setAutoReconnect(true), หรือลองเชื่อมต่อใหม่หลายครั้ง
❓ ปัญหา: RTC Memory ไม่เก็บข้อมูล
สาเหตุ: ใช้ตัวแปรธรรมดาแทน RTC_DATA_ATTR
วิธีแก้: ใช้ RTC_DATA_ATTR นำหน้าตัวแปรที่ต้องการเก็บ
❓ ปัญหา: External wakeup ไม่ทำงาน
สาเหตุ: ใช้ GPIO ที่ไม่ใช่ RTC GPIO
วิธีแก้: ตรวจสอบว่าใช้ RTC GPIO เท่านั้น (0, 2, 4, 12-15, 25-27, 32-39)
สรุป
Deep Sleep Mode เป็นเทคนิคสำคัญที่ทำให้โปรเจกต์ IoT ของคุณทำงานด้วยแบตเตอรี่ได้นานเป็นเดือนหรือปี โดยไม่ต้องเปลี่ยนถ่านบ่อยๆ
สิ่งสำคัญที่ต้องจำ:
- ✅ Deep Sleep ใช้กระแสเพียง 10-150µA เทียบกับ 80-240mA ในโหมดปกติ
- ✅ WiFi คือศัตรูหมายเลข 1 ของพลังงาน ให้ใช้น้อยที่สุด
- ✅ ตั้งค่า wakeup source ให้เหมาะสมกับการใช้งาน
- ✅ ใช้ RTC_DATA_ATTR เพื่อเก็บข้อมูลข้าม Deep Sleep
- ✅ วัดกระแสจริงเพื่อคำนวณอายุแบตเตอรี่ที่แม่นยำ
🚀 ถัดไป
- อ่าน สเปก ESP32 เทียบกับ ESP8266
- ศึกษา ESP-IDF Sleep Modes API
- ลองใช้งานกับ CynoIoT Platform