ด้วยคุณสมบัติของ ESP32 ที่เหมาะสำหรับทำอุปกรณ์ IoT ทั้งทำเป็น Node ต่าง ๆ และทำเป็น Gateway สำหรับการนำ ESP32 ไปทำเป็น Node มักจะมีปัญหาหนึ่งซึ่งเป็นปัญหาสำคัญของผู้พัฒนา คือ ปัญหาการใช้พลังงาน การสร้าง Node ส่วนใหญ่มักจะใช้แบตเตอรี่เป็นพลังงาน เพื่อให้ Node สามารถทำงานได้ แต่ด้วยคุณสมบัติของ ESP32 ที่เมื่อมีการใช้งาน WiFi จะใช้พลังงานไฟฟ้าจำนวนมาก เมื่อมีการใช้งานอย่างต่อเนื่องจะทำให้สิ้นเปลืองพลังงานมาก และทำให้แบตเตอรี่หมดอย่างรวดเร็ว ดังนั้น การสร้าง Node ของ ESP32 จึงควรคำนึงถึงการประหยัดพลังงานเป็นสำคัญ การประหยัดพลังงานที่ง่ายที่สุดคือการปิดใช้งานระบบต่าง ๆ ทั้ง WiFi และ CPU ทำให้ประหยัดพลังงานลงไปได้ สำหรับ ESP32 ได้เตรียมฟังก์ชั่นต่าง ๆ ไว้ให้ใช้งานแล้ว โดยถูกเรียกรวม ๆ ว่า Deep Sleep
โหมดการใช้งาน Deep Sleep จะแบ่งได้ตามวิธีการ “ปลุกให้ตื่น” โดยสามารถแบ่งลักษณะการปลุกให้ตื่นได้ 2 แบบ ดังนี้
หมายถึง การทำให้ ESP32 กลับมาเริ่มทำงานใหม่ด้วยการกระตุ้นจากภายนอก แบ่งการกระตุ้นได้ 2 แบบ คือ
ใช้เซ็นเซอร์สัมผัส – เหมาะสำหรับการใช้นิ้วสัมผัสโดยตรงเพื่อให้ ESP32 สามารถกลับมาทำงานได้
เปลี่ยนสถานะ GPIO – ใช้เมื่อต้องการให้อุปกรณ์อื่นกระตุ้นทำให้เกิดการตื่นขึ้นมา เช่น การใช้งานเซ็นเซอร์ต่าง ๆ เพื่อกระตุ้นให้เกิดการส่งข้อมูลทันที
หมายถึง การใช้วงจรไฟฟ้าภายใน ESP32 เป็นตัวกระตุ้น แล้วทำให้ ESP32 ตื่นขึ้นมา มักจะหมายถึงการปลุกให้ตื่นตามเวลาด้วย RTC โดยปกติแม้ส่วนวงจรอื่น ๆ ของ ESP32 จะถูกปิดการทำงาน แต่ส่วนของ RTC จะยังนับ และจดจำค่าเวลาต่อไปเรื่อย ๆ ตราบใดที่ยังมีการจ่ายพลังงานไฟฟ้าเลี้ยงอยู่ตลอด เพื่อรอการดึงค่าเวลาออกมาใช้งาน
ในส่วนของฟังก์ชั่นที่เกี่ยวข้องกับ Deep Sleep มีด้วยกันดังนี้
จะใช้ฟังก์ชั่น esp_deep_sleep_start(); มีรูปแบบการใช้งานดังนี้
void esp_deep_sleep_start();
ไม่มีค่าพารามิเตอร์ และไม่มีค่าที่ส่งกลับ จะใช้ก็ต่อเมื่อมีการตั้งค่าลักษณะการตื่นเรียบร้อยแล้วเท่านั้น กรณีที่เรียกใช้ฟังก์ชั่นนี้แล้วไม่ได้กำหนดลักษณะการตื่น จะต้องกดปุ่ม Reset เท่านั้น จึงจะทำให้ ESP32 กลับขึ้นทำงานอีกครั้ง
ฟังก์ชั่นกำหนดการตื่นด้วยการเปลี่ยนสถานะ GPIO ฟังก์ชั่น esp_deep_sleep_enable_ext0_wakeup(); จะใช้สำหรับกำหนด GPIO ที่ต้องการให้ ESP32 ตื่นขึ้นมาเมื่อมีการเปลี่ยนสถานะของ GPIO ซึ่งมีรูปแบบการใช้งานดังนี้
void esp_deep_sleep_enable_ext0_wakeup(gpio_num_t gpio_num, int level);
มีรายละเอียดของค่าพารามิเตอร์ดังนี้
(gpio_num_t) gpio_num – หมายเลขขา GPIO ที่ต้องการกำหนดใช้กระตุ้นให้ ESP32 ตื่นขึ้นมา
(int) สถานะของลอจิกที่ทำให้ ESP32 ตื่นขึ้นมา
และไม่มีค่าที่ส่งกลับ
ฟังก์ชั่นกำหนดการตื่นด้วยเซ็นเซอร์สัมผัส ใช้ฟังก์ชั่น esp_deep_sleep_enable_touchpad_wakeup(); กำหนด โดยมีรูปแบบการใช้งานดังนี้
void esp_deep_sleep_enable_touchpad_wakeup();
ไม่มีค่าพารามิเตอร์ และไม่มีค่าที่ส่งกลับ สำหรับการกำหนดช่องของเซ็นเซอร์ที่ใช้ จะกำหนดผ่านฟังก์ชั่น touchAttachInterrupt(); ซึ่งผู้เขียนแนะนำให้ดูตัวอย่างจะเข้าใจมากขึ้น
ฟังก์ชั่นกำหนดการตื่นตามเวลา ใช้ฟังก์ชั่น esp_deep_sleep_enable_timer_wakeup(); ในการกำหนด ซึ่งจะมีรูปแบบการใช้งานดังนี้
void esp_deep_sleep_enable_timer_wakeup(uint64_t time_in_us);
มีค่าพารามิเตอร์จำนวน 1 ตัว ซึ่งมีรายละเอียดดังนี้
(uint64_t) time_in_us – ค่าเวลาที่ต้องการให้อยู่ในโหมด Deep Sleep โดยมีหน่วยเป็นไมโครวินาที
และไม่มีค่าที่ส่งกลับมา
หลังจากการใช้ Deep Sleep จะมีการตัดการจ่ายไฟเลี้ยงในส่วนของแรมที่เชื่อมต่ออยู่กับ CPU ด้วย ทำให้ข้อมูลที่อยู่ในแรมนั้นถูกล้างออกจนหมด แต่จะมีข้อยกเว้นสำหรับแรมของวงจรส่วน RTC ที่ยังคงมีไฟเลี้ยงอยู่เสมอ ทำให้เราสามารถนำข้อมูลบางส่วนไปเก็บไว้บนแรมของ RTC ได้ แม้มีการใช้ Deep Sleep กี่ครั้ง ข้อมูลก็ยังคงถูกเก็บรักษาไว้เหมือนเดิม
การสร้างตัวแปรที่จะเก็บข้อมูลไว้บนแรมของ RTC สามารถทำได้โดยประกาศตัวแปรในรูปแบบดังต่อไปนี้
RTC_DATA_ATTR ชนิดตัวแปร ชื่อตัวแปร;
หรือ
RTC_DATA_ATTR ชนิดตัวแปร ชื่อตัวแปร = ค่าที่ต้องการเซ็ต;
ทั้งนี้ตัวแปรที่เก็บไว้บนแรมของ RTC สามารถนำมาอ่าน เขียนได้ตามปกติ การประกาศควรประกาศให้มีขอบเขตใช้งานแบบโกลบอล
ในการทดลอง จะสมมุติหน้าที่การทำงานของ Node ต่าง ๆ ที่จะกำหนดให้มีการตื่นที่แตกต่างกันออกไป ตามสถานะการที่สมมุติขึ้นมาดังนี้
การแสดงผลมักใช้จอแสดงผลที่มีการใช้พลังงานไฟฟ้ามาก ดังนั้นการใช้งาน Deep Sleep จึงเหมาะมากที่จะนำมาใช้งานกับ Node ประเภทนี้ โดยหลักการทำงานคือจะจำลองการแสดงผลบางอย่างนาน 30 วินาที แล้วจึงปิดหน้าจอไป จากนั้นจึงเข้าสู่โหมด Deep Sleep สำหรับการตื่น ให้ใช้วิธีการสัมผัสไปในจุดที่กำหนดขึ้นมา ซึ่งรวม ๆ จะเขียนโค้ดโปรแกรมส่วนของ Deep Sleep ได้ดังนี้
void setup() {
touchAttachInterrupt(T3, [](){ }, 40); // กำหนดใช้เซ็นเซอร์สำผัสช่อง T3 และให้มีค่าเกิน 40 จึงเกิดอินเตอร์รัพท์
esp_deep_sleep_enable_touchpad_wakeup(); // กำหนดการตื่นด้วยเซ็นเซอร์สัมผัส
// โค้ดโปรแกรมอื่น ๆ ที่จะใช้แสดงผลไปที่จอ
//
//
}
void loop() {
if (millis() > 30 * 1000) { // ถ้าครบ 30 วินาที
esp_deep_sleep_start(); // เข้าสู่โหมด Deep Sleep
}
// คำสั่งอื่น ๆ ในลูป
}
view rawESP32DeepSleepDisplay.ino hosted with ❤ by GitHub
ให้สังเกตว่า ในโค้ดโปรแกรมผู้เขียนได้กำหนดขาที่จะให้ตื่นขึ้นมาไว้ที่ช่อง ??? ดังนั้นหากนำไปใช้งานจริงจะต้องมีการต่อสายขึ้นมา และทำจุดให้สัมผัสไว้ด้วย
Node ส่งค่าอุณหภูมิ
สำหรับ Node นี้ ผู้เขียนจะให้ Node มีการส่งค่าอุณหภูมิขึ้นระบบ MQTT ทุก ๆ 10 นาที หลักการคือ หลังจากการเชื่อมต่อ WiFi ได้แล้ว จะมีการส่งข้อมูลไปทันที จากนั้นจึงเข้าสู่โหมด Deep Sleep เป็นเวลา 10 นาที แล้วจึงกำหนดให้ตื่นขึ้นมา ดังนั้นในตัวอย่างนี้จะกำหนดให้ตื่นโดยใช้เหตุการณ์ภายใน นั้นก็คือการใช้ RTC ภายในเพื่อจับเวลาการ Deep Sleep นั่นเอง
ตัวอย่างของโค้ดของ Node นี้ในส่วนของ Deep Sleep จึงมีดังนี้
void setup() {
// โค้ดโปรแกรมอื่น ๆ ใช้ส่งข้อมูลไปยัง MQTT
//
//
esp_deep_sleep_enable_timer_wakeup(10 * 60 * 1000 * 1000); // กำหนดให้ตื่นเมื่อครบ 10 นาทีข้างหน้า
esp_deep_sleep_start(); // เริ่มเข้าสู่โหมด Deep Sleep
}
void loop() {
}
view rawESP32DeepSleepTimer.ino hosted with ❤ by GitHub
เซ็นเซอร์ส่วนใหญ่แล้ว จะมีการทำงานแบบดิจิตอล คือเมื่อมีการตรวจจับสัญญาณบางอย่างได้ จะใช้ค่าเป็น 0 หรือให้ค่าเป็น 1 แต่กรณีที่นำไปใช้กับ Node ต่าง ๆ มักจะเป็นการตรวจจับสภาพแวดล้อมในพื้นที่นั้น ๆ เช่น การใช้เซ็นเซอร์น้ำฝนเพื่อตรวจจับว่ามีฝนตกหรือไม่ หรือการใช้งาน PIR เพื่อตรวจจับผู้บุกรุก การสร้าง Node ขึ้นมาแล้วใช้ Deep Sleep จึงสำคัญมาก เพราะหากมีการเปิดใช้งาน ESP32 อยู่เสมอเพื่ออ่านสถานะลอจิกอยู่ตลอดเวลา จะทำให้ใช้พลังงานมาก ดังนั้น การใช้งาน Deep Sleep แล้วทำให้ตื่นขึ้นมาด้วยวิธีการเปลี่ยนสถานะ GPIO ก็จะทำให้ประหยัดพลังงานไปได้มาก
จากเหตุผลที่ได้อธิบายไปแล้ว ทำให้โค้ดส่วนของ Deep Sleep มีดังนี้
void setup() {
// โค้ดโปรแกรมอื่น ๆ ใช้ส่งข้อมูลไปยัง MQTT
//
//
esp_deep_sleep_enable_ext0_wakeup((gpio_num_t)33, HIGH); // กำหนดขาที่ต่อกับเซ็นเซอร์ และกำหนด Active เป็น HIGH
esp_deep_sleep_start(); // เริ่มเข้าสู่โหมด Deep Sleep
}
void loop() {
}
view rawESP32DeepSleepSensor.ino hosted with ❤ by GitHub
ในการทดลองวัดอัตราการใช้พลังงานของ ESP32 ผู้เขียนได้ใช้บอร์ด NodeMCU-32S และดิจิตอลมิเตอร์ 2 ตัว ต่างยีห้อกัน โดยตัวหนึ่งทำหน้าที่วัดแรงดันไฟฟ้าที่จ่ายให้กับ ESP32 (แรงดัน 3.3V) และอีกตัวหนึ่งทำหน้าที่วัดการจ่ายกระแสไฟฟ้าเข้าหัว MicroUSB จากการวัดค่าทั้ง 2 นี้ เมื่อนำมาคูณกันจะได้เป็นค่าของพลังงานไฟฟ้า