บทความ: ESP32 Deep Sleep สำหรับโปรเจกต์พลังงานแบตเตอรี่ - คู่มือฉบับสมบูรณ์ 2026

เรียนรู้วิธีการประหยัดพลังงานด้วย Deep Sleep Mode บน ESP32 พร้อมเทคนิคขั้นสูงในการออกแบบฮาร์ดแวร์และเขียนโปรแกรมเพื่อยืดอายุการใช้งานแบตเตอรี่ให้นานขึ้นถึง 10 เท่า พร้อมตัวอย่างโค้ดและการคำนวณที่แม่นยำ

📅 ⏱️ 15 นาที 🎯 ระดับกลาง - ขั้นสูง 🔋 ประหยัดไฟ
10-100µA
Deep Sleep Current
6-12 เดือน
อายุแบตเตอรี่
5+ โหมด
Sleep Modes
ULP
Co-processor

🔋 ทำไมต้อง Deep Sleep?

เมื่อสร้างโปรเจกต์ IoT ที่ใช้แบตเตอรี่เป็นแหล่งจ่ายไฟ การประหยัดพลังงานเป็นสิ่งสำคัญที่สุด ESP32 ในโหมดปกติใช้กระแสไฟประมาณ 150-240 mA เมื่อเชื่อมต่อ WiFi ซึ่งถ้าใช้แบตเตอรี่ 2000mAh จะใช้งานได้เพียง 8-13 ชั่วโมง เท่านั้น

💡 แต่ด้วย Deep Sleep Mode กระแสไฟจะลดลงเหลือเพียง 10-100 µA (0.01-0.1 mA) ทำให้แบตเตอรี่เดิมใช้งานได้ 6-12 เดือน หรือมากกว่านั้น!

สถานการณ์ที่เหมาะกับ Deep Sleep:

  • 🌡️ เซ็นเซอร์วัดอุณหภูมิ/ความชื้น ที่อ่านค่าทุก 5-15 นาที
  • 🌾 โปรเจกต์ Smart Agriculture ที่ต้องการตรวจสอบค่าน้อยครั้ง
  • 📦 ตัวติดตามสินค้า (Asset Tracker) ที่ส่งข้อมูลเป็นระยะ
  • 🏠 Remote Control ที่รอรับสัญญาณจากผู้ใช้
  • 🔔 ระบบแจ้งเตือนที่ทำงานเมื่อเกิดเหตุการณ์เฉพาะ

📊 เข้าใจ ESP32 Sleep Modes

ESP32 มีหลายโหมดการประหยัดพลังงาน แต่ละโหมดเหมาะกับ使用งานที่แตกต่างกัน:

โหมดกระแสไฟเวลาตื่นการใช้งาน
Active (WiFi On)150-240 mA-ทำงานปกติ
Modem Sleep15-30 mA< 1 msCPU ทำงาน, WiFi สลับ
Light Sleep0.8-15 mA< 10 msCPU หยุด, RAM เก็บ
Deep Sleep10-100 µA2-50 msCPU/RAM ปิด, RTC เท่านั้น
Hibernation2.5-5 µA2-50 msทุกอย่างปิด

ℹ️ Deep Sleep คือโหมดที่นิยมที่สุดสำหรับโปรเจกต์แบตเตอรี่ เพราะสมดุลระหว่างกระแสไฟต่ำและความสามารถในการรักษาข้อมูลใน RTC Memory

⚡ การเตรียมฮาร์ดแวร์สำหรับ Low Power

ก่อนเริ่มเขียนโค้ด ต้องเตรียมฮาร์ดแวร์ให้พร้อมก่อน นี่คือสิ่งสำคัญที่หลายคนมองข้าม!

1. การเชื่อมต่อแบตเตอรี่ที่ถูกต้อง

⚠️ อย่าใช้ USB ขณะทดสอบกระแส Deep Sleep! USB จะจ่ายไฟเพิ่มทำให้วัดกระแสไฟไม่ได้ ใช้แบตเตอรี่หรือ Power Supply ภายนอกแทน

วิธีเชื่อมต่อแบตเตอรี่ Li-Ion/Li-Po:

  • ขา BAT: เชื่อมต่อกับขาบวกของแบตเตอรี่ (3.7V-4.2V)
  • ขา GND: เชื่อมต่อกับขาลบของแบตเตอรี่
  • ขา 3V3: ใช้เพื่อจ่ายไฟให้เซ็นเซอร์ (หลีกเลี่ยงถ้าต้องการประหยัดสูงสุด)

2. ตัด LED บนบอร์ด (ตัวเลือก)

หลายบอร์ด ESP32 มี Power LED และ Status LED ที่ใช้กระแส 2-20 mA ซึ่งมากกว่า Deep Sleep เสียอีก!

  • ถอนตัวต้านทาน LED ออก (สำหรับบอร์ดที่มี jumper)
  • หรือใช้โค้ดปิด LED ก่อนเข้า Deep Sleep

3. ใช้ LDO ที่มีประสิทธิภาพสูง

บอร์ดบางอย่างใช้ LDO ที่ใช้กระแสไฟสูง (quiescent current) เลือกบอร์ดที่ใช้:

  • AMS1117: ~5-10 mA (ไม่เหมาะกับแบตเตอรี่)
  • ME6211: ~50-80 µA (ดีกว่า)
  • HT7833: ~5-10 µA (ดีที่สุดสำหรับแบตเตอรี่)

💻 Deep Sleep แบบพื้นฐาน: ตื่นด้วย Timer

เริ่มต้นด้วยตัวอย่างง่ายที่สุด: ESP32 จะหลับด้วย Deep Sleep เป็นเวลาที่กำหนด แล้วตื่นขึ้นมาทำงาน

#include "esp_sleep.h"

// ตั้งค่าเวลานอน (เป็นไมโครวินาที)
// ตัวอย่าง: นอน 60 วินาที
#define SLEEP_DURATION_US 60 * 1000000

RTC_DATA_ATTR int bootCount = 0;  // เก็บค่าใน RTC Memory (ไม่หายเมื่อ Deep Sleep)

void setup() {
  Serial.begin(115200);
  
  // เพิ่มจำนวนครั้งที่บูต
  bootCount++;
  Serial.println("Boot number: " + String(bootCount));
  
  // แสดงสาเหตุการตื่น
  esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause();
  switch(wakeup_reason) {
    case ESP_SLEEP_WAKEUP_TIMER:
      Serial.println("ตื่นเพราะ Timer");
      break;
    case ESP_SLEEP_WAKEUP_EXT0:
      Serial.println("ตื่นเพราะ GPIO (EXT0)");
      break;
    default:
      Serial.println("ไม่ใช่การตื่นจาก Deep Sleep");
      break;
  }
  
  // ทำงานของคุณที่นี่ (อ่านเซ็นเซอร์, ส่งข้อมูล, ฯลฯ)
  Serial.println("กำลังทำงาน...");
  delay(2000);  // จำลองการทำงาน 2 วินาที
  Serial.println("เสร็จสิ้น กำลังเข้า Deep Sleep...");
  
  // ตั้งค่า Timer และเข้า Deep Sleep
  esp_sleep_enable_timer_wakeup(SLEEP_DURATION_US);
  Serial.println("Zzz...");
  Serial.flush();
  
  // เข้า Deep Sleep
  esp_deep_sleep_start();
}

void loop() {
  // ไม่มีอะไรที่นี่ เพราะ Deep Sleep จะรีเซ็ตเมื่อตื่น
}

RTC_DATA_ATTR คือคีย์เวิร์ดสำคัญ! ตัวแปรที่ประกาศด้วยจะเก็บใน RTC Memory และไม่หายเมื่อ Deep Sleep เหมาะสำหรับเก็บ boot count, settings, หรือข้อมูลเล็กๆ

⏰ ตัวเลือกการตื่นจาก Deep Sleep

ESP32 รองรับหลายวิธีในการตื่นจาก Deep Sleep เลือกให้เหมาะกับโปรเจกต์ของคุณ:

1. Timer Wake-up (ตื่นตามเวลา)

เหมาะสำหรับเซ็นเซอร์ที่อ่านค่าเป็นระยะ เช่น อุณหภูมิทุก 10 นาที

esp_sleep_enable_timer_wakeup(60 * 1000000); // 60 วินาที

2. EXT0 Wake-up (ตื่นด้วย GPIO 1 ขา)

เหมาะสำหรับปุ่มกด, เซ็นเซอร์ PIR, สวิตช์แม่เหล็ก

esp_sleep_enable_ext0_wakeup(GPIO_NUM_4, 1); // ขา 4, ตื่นเมื่อ HIGH

⚠️ รองรับเพียง 1 ขา และต้องเป็น RTC IO pin เท่านั้น (0, 2, 4, 12-15, 25-27, 32-39)

3. EXT1 Wake-up (ตื่นด้วย GPIO หลายขา)

เหมาะสำหรับหลายเซ็นเซอร์ ตื่นเมื่อขาใดขาหนึ่ง ACTIVE

uint64_t mask = (1ULL << GPIO_NUM_4) | (1ULL << GPIO_NUM_5);
esp_sleep_enable_ext1_wakeup(mask, ESP_EXT1_WAKEUP_ANY_HIGH);

4. Touch Wake-up (ตื่นด้วย Touch Sensor)

เหมาะสำหรับปุ่มสัมผัส, แผงควบคุมแบบ Touch

esp_sleep_enable_touchpad_wakeup();

5. ULP Co-processor (ตื่นเมื่อเงื่อนไขตรง)

เหมาะสำหรับตรวจสอบเซ็นเซอร์โดยไม่ต้องตื่น CPU ประหยัดสุด!

esp_sleep_enable_ulp_wakeup();

🚀 เทคนิคขั้นสูง: ประหยัดไฟสุดๆ

หลังจากใช้ Deep Sleep แล้ว เรายังสามารถลดกระแสไฟได้อีกด้วยเทคนิคเหล่านี้:

1. ปิด WiFi และ Bluetooth ทันทีที่ไม่ใช้

// ปิด WiFi
WiFi.mode(WIFI_OFF);
btStop();  // ปิด Bluetooth

// หรือใช้วิธีล้างค่า WiFi
esp_wifi_stop();
esp_wifi_deinit();
esp_bt_controller_disable();
esp_bt_controller_deinit();

2. ปิด Peripherals ที่ไม่ใช้

// ปิด ADC, DAC, Sensor ที่ไม่ใช้
adc_power_off();  // ปิด ADC
dac_output_disable(DAC_CHANNEL_1);
dac_output_disable(DAC_CHANNEL_2);

// ลดความถี่ CPU (สำหรับ Light Sleep)
setCpuFrequencyMhz(80);  // ลดจาก 240 MHz เป็น 80 MHz

3. ใช้ ULP Co-processor แทน CPU

ULP (Ultra Low Power) Co-processor สามารถทำงานแบบง่ายๆ ได้โดยใช้กระแสเพียง ~10-150 µA เหมาะสำหรับ:

  • อ่านค่าเซ็นเซอร์ ADC เป็นระยะ
  • ตรวจสอบ Touch Pad
  • เปรียบเทียบค่าและตัดสินใจตื่น CPU เมื่อจำเป็น

💡 ตัวอย่าง: ULP สามารถอ่านค่าอุณหภูมิทุก 10 นาที และตื่น CPU เมื่อเกิน 40°C เท่านั้น ทำให้ประหยัดแบตเตอรี่ได้มาก!

4. ปิดเซ็นเซอร์ด้วย MOSFET

หลายเซ็นเซอร์ใช้กระแสไฟมากเวลา Standby ใช้ MOSFET ตัดไฟเมื่อไม่ใช้:

// ก่อนเข้า Deep Sleep
digitalWrite(SENSOR_POWER_PIN, LOW);  // ปิดเซ็นเซอร์
esp_deep_sleep_start();

// เมื่อตื่น
digitalWrite(SENSOR_POWER_PIN, HIGH);  // เปิดเซ็นเซอร์
delay(100);  // รอให้เซ็นเซอร์พร้อม
// อ่านค่าเซ็นเซอร์...

🧮 คำนวณอายุการใช้งานแบตเตอรี่

มาคำนวณกันว่าแบตเตอรี่จะใช้งานได้นานแค่ไหน:

สูตรคำนวณ:

Battery Life (hours) = Battery Capacity (mAh) / Average Current (mA)

ตัวอย่าง 1: ไม่ใช้ Deep Sleep

  • 📊 แบตเตอรี่: 2000 mAh (แบตเตอรี่ 18650)
  • ⚡ กระแสเฉลี่ย: 150 mA (WiFi เปิดตลอด)
  • 🕐 อายุการใช้งาน: 2000 / 150 = 13.3 ชั่วโมง

ตัวอย่าง 2: ใช้ Deep Sleep ดีๆ

📊 สถานการณ์:

  • แบตเตอรี่: 2000 mAh
  • ตื่นทำงาน: 10 วินาที ทุก 10 นาที (100 mA ขณะตื่น)
  • Deep Sleep: 9 นาที 50 วินาที (50 µA)

🧮 คำนวณ:

  • กระแสเฉลี่ย = (10s × 100mA + 590s × 0.05mA) / 600s
  • กระแสเฉลี่ย = (1000 + 29.5) / 600 = 1.72 mA
  • อายุการใช้งาน = 2000 / 1.72 = 1,163 ชั่วโมง ≈ 48 วัน

⚠️ ข้อควรระวัง: นี่คือคำนวณทางทฤษฎี ในความเป็นจริงต้องคิดแบตเตอรี่เสื่อม (ประมาณ 80% capacity), self-discharge, และอุณหภูมิ

🔧 ปัญหาที่พบบ่อยและวิธีแก้ไข

❌ ปัญหา: Deep Sleep ใช้กระแสไฟ 10-20 mA (เยอะเกินไป)

สาเหตุ: LDO ใช้กระแสสูง, อุปกรณ์ต่อพ่วงใช้ไฟเยอะ

วิธีแก้:

  • ตรวจสอบว่าถอน USB แล้ว
  • ปิด LED บนบอร์ด
  • ตรวจสอบว่าเซ็นเซอร์ปิดอยู่จริง
  • เปลี่ยนบอร์ดที่ใช้ LDO ประหยัดไฟ

❌ ปัญหา: ESP32 ไม่ยอมตื่นจาก Deep Sleep

สาเหตุ: ตั้งเวลาผิด, ใช้ขาที่ไม่รองรับ, แบตเตอรี่หมด

วิธีแก้:

  • ตรวจสอบว่าใช้ RTC IO pin (สำหรับ EXT0/EXT1)
  • ตรวจสอบแรงดันแบตเตอรี่ (ต่ำกว่า 2.3V อาจตื่นไม่ได้)
  • ใช้ Serial Monitor เพื่อ Debug

❌ ปัญหา: WiFi เชื่อมต่อไม่ได้หลังตื่น

สาเหตุ: WiFi state ไม่ได้รักษาไว้ใน Deep Sleep

วิธีแก้:

  • ต้องเชื่อมต่อ WiFi ใหม่ทุกครั้งที่ตื่น
  • ใช้ WiFi.persistent(false) เพื่อประหยัด Flash
  • พิจารณาใช้ Light Sleep แทนถ้าต้องการรักษา WiFi

❌ ปัญหา: ข้อมูลหายเมื่อตื่น

สาเหตุ: ตัวแปรปกติจะรีเซ็ตเมื่อ Deep Sleep

วิธีแก้:

  • ใช้ RTC_DATA_ATTR สำหรับตัวแปรที่ต้องเก็บ
  • ใช้ Preferences.h (SPIFFS) สำหรับข้อมูลขนาดใหญ่

🌍 โปรเจกต์จริง: เครื่องวัดอุณหภูมิไร้สาย

มาดูตัวอย่างโปรเจกต์จริงที่ใช้ Deep Sleep สร้างเครื่องวัดอุณหภูมิที่ส่งข้อมูลไปยัง CynoIoT Platform:

#include <WiFi.h>
#include <HTTPClient.h>
#include "esp_sleep.h"
#include "DHT.h"

// WiFi credentials
const char* ssid = "your_SSID";
const char* password = "your_PASSWORD";

// CynoIoT API endpoint
const char* apiUrl = "https://api.cynoiot.com/sensor/data";

// Sensor config
#define DHTPIN 4
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

// Deep sleep config
#define SLEEP_INTERVAL_MS 10 * 60 * 1000  // 10 นาที

// RTC memory variables
RTC_DATA_ATTR int bootCount = 0;
RTC_DATA_ATTR float lastTemp = 0;
RTC_DATA_ATTR float lastHum = 0;

void setup() {
  Serial.begin(115200);
  bootCount++;
  
  Serial.println("=== Boot #" + String(bootCount) + " ===");
  
  // อ่านค่าเซ็นเซอร์
  dht.begin();
  float temp = dht.readTemperature();
  float hum = dht.readHumidity();
  
  if (isnan(temp) || isnan(hum)) {
    Serial.println("Failed to read from DHT sensor!");
    temp = lastTemp;
    hum = lastHum;
  } else {
    lastTemp = temp;
    lastHum = hum;
  }
  
  Serial.printf("Temperature: %.2f°C\n", temp);
  Serial.printf("Humidity: %.2f%%\n", hum);
  
  // เชื่อมต่อ WiFi
  Serial.print("Connecting to WiFi...");
  WiFi.begin(ssid, password);
  
  unsigned long startAttempt = millis();
  while (WiFi.status() != WL_CONNECTED && 
         millis() - startAttempt < 20000) {
    delay(500);
    Serial.print(".");
  }
  
  if (WiFi.status() == WL_CONNECTED) {
    Serial.println(" connected!");
    Serial.printf("IP: %s\n", WiFi.localIP().toString().c_str());
    
    // ส่งข้อมูลไป CynoIoT
    sendToCynoIoT(temp, hum);
    
    // ปิด WiFi
    WiFi.disconnect(true);
    WiFi.mode(WIFI_OFF);
  } else {
    Serial.println(" failed! Will retry next time.");
  }
  
  // เตรียมเข้า Deep Sleep
  Serial.printf("Entering deep sleep for %d ms...\n", SLEEP_INTERVAL_MS);
  Serial.flush();
  
  esp_sleep_enable_timer_wakeup(SLEEP_INTERVAL_MS * 1000);
  esp_deep_sleep_start();
}

void loop() {
  // Nothing here - deep sleep resets on wake
}

void sendToCynoIoT(float temp, float hum) {
  HTTPClient http;
  http.begin(apiUrl);
  http.addHeader("Content-Type", "application/json");
  
  // สร้าง JSON payload
  String payload = "{\"temperature\":" + String(temp) + 
                    ",\"humidity\":" + String(hum) + 
                    ",\"device_id\":\"esp32_temp_sensor\"}";
  
  Serial.print("Sending data to CynoIoT...");
  int httpCode = http.POST(payload);
  
  if (httpCode > 0) {
    Serial.printf(" success! Code: %d\n", httpCode);
    String response = http.getString();
    Serial.println("Response: " + response);
  } else {
    Serial.printf(" failed! Error: %s\n", http.errorToString(httpCode).c_str());
  }
  
  http.end();
}

📊 ผลลัพธ์: ด้วยแบตเตอรี่ 2000 mAh, โปรเจกต์นี้สามารถทำงานได้ 4-6 เดือน โดยไม่ต้องเปลี่ยนแบตเตอรี่!

🎯 สรุป

Deep Sleep ลดกระแสไฟจาก 150 mA เหลือ 10-100 µA ทำให้อายุแบตเตอรี่ยาวขึ้น 100-1000 เท่า

เลือก Wake-up Source ให้เหมาะกับโปรเจกต์: Timer, GPIO, Touch, หรือ ULP

ปิด WiFi, Bluetooth, และเซ็นเซอร์ที่ไม่ใช้ ทันที เพื่อประหยัดพลังงาน

ใช้ RTC_DATA_ATTR เพื่อรักษาข้อมูลข้ามรอบ Deep Sleep

คำนวณอายุแบตเตอรี่ก่อนทำโปรเจกต์จริง เพื่อตั้งค่าคาดหวังที่เป็นจริง

📚 อ่านเพิ่มเติม