เนื้อหาในบทความ
บทนำ: Sleep Modes คืออะไร?
Arduino ใช้พลังงานสูงเมื่อทำงานปกติประมาณ 20-50 mA ที่ 5V ซึ่งหมายความว่าแบตเตอรี่ 9V แบบปกติจะหมดภายในไม่กี่ชั่วโมง แต่ด้วย Sleep Modes เราสามารถลดกำลังไฟลงเหลือเพียง 0.1-5 mA หรือน้อยกว่านั้น
💡 ทำไมต้องใช้ Sleep Modes?
- ✓ ยืดอายุการใช้งานแบตเตอรี่จากวันเดียวเป็นหลายเดือน
- ✓ เหมาะสำหรับโปรเจกต์ Sensor Node ที่ต้องส่งข้อมูลน้อย
- ✓ ประหยัดค่าไฟในโปรเจกต์ขนาดใหญ่
- ✓ ลดความร้อนที่เกิดจากการทำงานต่อเนื่อง
Arduino รุ่นที่รองรับ Sleep Modes
Arduino ส่วนใหญ่ใช้ชิพ ATmega328P ซึ่งรองรับ Sleep Modes หลายรูปแบบ:
- Arduino Uno/Nano - ATmega328P (รองรับครบทุก mode)
- Arduino Pro Mini - ATmega328P (เหมาะกับโปรเจกต์ประหยัดไฟ)
- Arduino Mega - ATmega2560 (รองรับครบทุก mode)
ประเภทของ Sleep Modes บน ATmega328P
| Sleep Mode | กำลังไฟ | Wake-up Time | ฟีเจอร์ที่ใช้งานได้ |
|---|---|---|---|
| IDLE | ~15 mA | 6 ครั้งนาฬิกา | CPU หยุดทำงาน, ตัวต่อต่อ (peripherals) ทำงานต่อ |
| ADC NOISE REDUCTION | ~7 mA | 6 ครั้งนาฬิกา | CPU + ADC หยุดทำงาน |
| POWER SAVE | ~1.5 mA | 2 ครั้งนาฬิกา | Timer 2 ทำงาน |
| POWER DOWN | ~0.1 mA | 1,000 ครั้งนาฬิกา | External interrupt และ Watchdog เท่านั้น |
⚠️ หมายเหตุสำคัญ
ค่ากำลังไฟข้างต้นเป็นค่าโดยประมาณ ค่าจริงขึ้นอยู่กับอุปกรณ์ต่อพ่วง อุณหภูมิ และเงื่อนไขการใช้งาน แนะนำให้วัดค่าจริงจากโปรเจกต์ของคุณ
อุปกรณ์ที่ต้องใช้
🎯 อุปกรณ์หลัก
- • Arduino Uno/Nano/Pro Mini
- • USB Cable สำหรับ Upload
- • แหล่งจ่ายไฟ (Battery/Adapter)
- • Breadboard และ Jumper wires
⚡ อุปกรณ์เสริม (ตามโปรเจกต์)
- • Real-time Clock (DS3231)
- • Temperature Sensor (DHT11/22)
- • Motion Sensor (PIR)
- • Push button สำหรับ Wake-up
1. Idle Mode: พื้นฐาน
Idle Mode เป็น Sleep Mode ที่ใช้งานง่ายที่สุด CPU จะหยุดทำงาน แต่ peripherals ทั้งหมดยังทำงานต่อไป เหมาะสำหรับการรอสัญญาณจาก sensor หรือการรับส่งข้อมูลผ่าน Serial
ตัวอย่างโค้ด Idle Mode
// Arduino Idle Mode Example
// ตัวอย่างการใช้งาน Idle Mode เพื่อประหยัดพลังงาน
#include <avr/sleep.h> // Library สำหรับ Sleep Mode
void setup() {
Serial.begin(9600);
pinMode(LED_BUILTIN, OUTPUT);
Serial.println("Arduino Idle Mode Example");
Serial.println("CPU จะหยุดทำงานแต่ Serial ยังใช้งานได้");
}
void loop() {
// กระพริบ LED เพื่อแสดงว่ากำลังทำงาน
digitalWrite(LED_BUILTIN, HIGH);
delay(100);
digitalWrite(LED_BUILTIN, LOW);
Serial.println("เข้าสู่ Idle Mode...");
delay(100); // รอให้ Serial ส่งข้อมูลเสร็จก่อน
// เข้าสู่ Idle Mode
set_sleep_mode(SLEEP_MODE_IDLE); // ตั้งค่าเป็น Idle Mode
sleep_mode(); // เข้าสู่ Sleep Mode
// เมื่อ Wake-up โค้ดจะทำงานต่อจากตรงนี้
Serial.println("ตื่นจาก Idle Mode!");
delay(2000); // ทำงานปกติ 2 วินาที
}💡 เมื่อไหร่ควรใช้ Idle Mode?
- • ต้องการรับส่งข้อมูล Serial/UART
- • รอสัญญาณจาก Timer หรือ Counter
- • ใช้งาน ADC แบบต่อเนื่อง
- • ต้องการ Wake-up ได้เร็วๆ
2. Power Save Mode: ประหยัดไฟขั้นต่อ
Power Save Mode จะปิดการทำงานของ CPU และ peripherals ส่วนใหญ่ แต่ยังคง Timer 2 ไว้ทำงาน ทำให้กำลังไฟลดลงเหลือ ~1.5 mA เหมาะสำหรับโปรเจกต์ที่ต้องการตื่นด้วย Timer
ตัวอย่างโค้ด Power Save Mode
// Arduino Power Save Mode Example
// ใช้งาน Timer 2 เพื่อตื่นจาก Sleep ทุกๆ 1 วินาที
#include <avr/sleep.h>
volatile bool wakeUp = false; // Flag สำหรับตรวจสอบ Wake-up
// Timer 2 Interrupt Service Routine
ISR(TIMER2_COMPA_vect) {
wakeUp = true; // ตั้งค่า flag เมื่อตื่น
}
void setup() {
Serial.begin(9600);
// ตั้งค่า Timer 2 สำหรับ CTC mode
TCCR2A = (1 << WGM21); // CTC mode
TCCR2B = (1 << CS22) | (1 << CS21) | (1 << CS20); // Prescaler 1024
OCR2A = 0x7C; // 124 (เพื่อให้ได้ ~1 วินาที)
TIMSK2 = (1 << OCIE2A); // เปิดใช้งาน Timer 2 Compare Match A Interrupt
Serial.println("Arduino Power Save Mode Example");
Serial.println("ตื่นทุกๆ 1 วินาทีด้วย Timer 2");
}
void loop() {
if (wakeUp) {
Serial.println("ตื่นจาก Power Save Mode!");
wakeUp = false;
// ทำงานที่ต้องการ
digitalWrite(LED_BUILTIN, HIGH);
delay(100);
digitalWrite(LED_BUILTIN, LOW);
}
// เข้าสู่ Power Save Mode
set_sleep_mode(SLEEP_MODE_PWR_SAVE);
sleep_enable();
sleep_mode(); // เข้าสู่ Sleep Mode
sleep_disable(); // ปิดใช้งาน Sleep Mode เมื่อตื่น
}3. Power Down Mode: สุดคุ้ม
Power Down Mode เป็น Mode ที่ประหยัดไฟมากที่สุด กำลังไฟลดเหลือเพียง ~0.1 mA แต่ต้องใช้ External Interrupt หรือ Watchdog Timer เท่านั้นในการตื่น
ตัวอย่างโค้ด Power Down Mode ด้วย Button
// Arduino Power Down Mode Example
// ตื่นจาก Sleep ด้วยการกดปุ่ม (Pin 2 หรือ 3 เท่านั้น)
#include <avr/sleep.h>
const int buttonPin = 2; // ต้องใช้ Interrupt Pin (2 หรือ 3)
const int ledPin = LED_BUILTIN;
volatile bool wakeUp = false;
void wakeUpFunction() {
// ฟังก์ชันนี้จะถูกเรียกเมื่อมีการกดปุ่ม
wakeUp = true;
// หมายเหตุ: ใน ISR ควรทำงานน้อยๆ เท่านั้น
}
void setup() {
Serial.begin(9600);
pinMode(buttonPin, INPUT_PULLUP); // ตั้งค่าเป็น Input พร้อม Pull-up
pinMode(ledPin, OUTPUT);
// ตั้งค่า Interrupt สำหรับ Wake-up
attachInterrupt(digitalPinToInterrupt(buttonPin), wakeUpFunction, FALLING);
Serial.println("Arduino Power Down Mode Example");
Serial.println("กดปุ่มที่ Pin 2 เพื่อตื่น");
}
void loop() {
if (wakeUp) {
// รอสัญญาณจากปุ่ม (debounce)
delay(50);
wakeUp = false;
Serial.println("ตื่นจาก Power Down Mode!");
// กระพริบ LED 3 ครั้ง
for (int i = 0; i < 3; i++) {
digitalWrite(ledPin, HIGH);
delay(200);
digitalWrite(ledPin, LOW);
delay(200);
}
Serial.println("กลับเข้า Sleep Mode...");
delay(1000); // รอให้ Serial ส่งข้อมูลเสร็จ
}
// เข้าสู่ Power Down Mode
Serial.println("กำลังเข้าสู่ Power Down Mode...");
delay(100); // รอให้ Serial ส่งข้อมูลเสร็จ
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_mode(); // เข้าสู่ Sleep Mode (จะหยุดที่นี่จนกว่าจะตื่น)
sleep_disable(); // โค้ดจะทำงานต่อเมื่อตื่นแล้ว
}ตัวอย่างโค้ด Power Down Mode ด้วย Watchdog
// Arduino Power Down Mode ด้วย Watchdog Timer
// ตื่นทุกๆ 8 วินาทีอัตโนมัติ
#include <avr/sleep.h>
#include <avr/wdt.h> // Watchdog Timer Library
volatile bool wakeUp = false;
// Watchdog Interrupt Service Routine
ISR(WDT_vect) {
wakeUp = true; // ตั้งค่า flag เมื่อ Watchdog หมดเวลา
}
void setupWatchdog() {
// ปิดการใช้งาน interrupts
cli();
// ตั้งค่า Watchdog
wdt_reset(); // Reset Watchdog
// ตั้งค่า WDTCSR (Watchdog Timer Control Register)
// WDIE: Watchdog Interrupt Enable
// WDP3, WDP2, WDP1, WDP0: Prescaler bits
// ตั้งค่าให้ตื่นทุกๆ 8 วินาที
WDTCSR |= (1 << WDCE) | (1 << WDE); // เปลี่ยนค่า WDTCSR
WDTCSR = (1 << WDIE) | (1 << WDP3) | (1 << WDP0); // 8 วินาที
// เปิดใช้งาน interrupts
sei();
}
void setup() {
Serial.begin(9600);
pinMode(LED_BUILTIN, OUTPUT);
setupWatchdog(); // ตั้งค่า Watchdog
Serial.println("Arduino Power Down Mode ด้วย Watchdog");
Serial.println("ตื่นทุกๆ 8 วินาที");
}
void loop() {
if (wakeUp) {
wakeUp = false;
Serial.println("ตื่นจาก Power Down Mode! (8 วินาทีผ่านไป)");
// กระพริบ LED
digitalWrite(LED_BUILTIN, HIGH);
delay(100);
digitalWrite(LED_BUILTIN, LOW);
delay(1000); // รอให้ Serial ส่งข้อมูลเสร็จ
}
// เข้าสู่ Power Down Mode
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_mode(); // เข้าสู่ Sleep Mode
sleep_disable(); // โค้ดจะทำงานต่อเมื่อตื่นแล้ว
}💡 ค่าเวลาของ Watchdog Timer
| WDP3 | WDP2 | WDP1 | WDP0 | เวลา |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 16 ms |
| 0 | 0 | 0 | 1 | 32 ms |
| 0 | 0 | 1 | 0 | 64 ms |
| 0 | 0 | 1 | 1 | 0.125 s |
| 0 | 1 | 0 | 0 | 0.25 s |
| 0 | 1 | 0 | 1 | 0.5 s |
| 0 | 1 | 1 | 0 | 1 s |
| 0 | 1 | 1 | 1 | 2 s |
| 1 | 0 | 0 | 0 | 4 s |
| 1 | 0 | 0 | 1 | 8 s |
วิธีการตื่นจาก Sleep Modes
แต่ละ Sleep Mode มีวิธีการตื่นที่แตกต่างกัน:
⚡ External Interrupt
ใช้ Pin 2 หรือ 3 (INT0 หรือ INT1) ตื่นเมื่อมีการกดปุ่มหรือสัญญาณภายนอก
- • LOW: ตื่นเมื่อ Pin เป็น LOW
- • HIGH: ตื่นเมื่อ Pin เป็น HIGH
- • FALLING: ตื่นเมื่อ HIGH→LOW
- • RISING: ตื่นเมื่อ LOW→HIGH
⏰ Watchdog Timer
ใช้ Watchdog Timer ภายในชิพ ตั้งเวลาได้ 16ms - 8 วินาที
- • ใช้งานได้ทุก Sleep Mode
- • ไม่ต้องต่อวงจรภายนอก
- • ประหยัดพื้นที่บอร์ด
- • ค่าเวลาจำกัด (สูงสุด 8 วิ)
⏱️ Timer Interrupt
ใช้ Timer 2 (Power Save Mode) หรือ Timer 0/1 (Idle Mode)
- • ตั้งเวลาได้แม่นยำ
- • ใช้งานได้เฉพาะบาง Mode
- • ตั้งค่าซับซ้อนกว่า
- • เหมาะกับการตั้งเวลาแม่นยำ
📡 Hardware Events
ตื่นเมื่อมีเหตุการณ์ฮาร์ดแวร์เฉพาะ
- • Serial data received
- • I2C address match
- • SPI transfer complete
- • ADC conversion complete
เทคนิคขั้นสูง: ประหยัดไฟสุดๆ
1. ปิด Peripherals ที่ไม่ใช้งาน
// ปิด Peripherals ที่ไม่ใช้เพื่อลดกำลังไฟ
void setup() {
// ปิด ADC
ADCSRA = 0; // ปิด ADC (ประหยัด ~0.2 mA)
// ปิด Serial
Serial.end(); // ปิด Serial หากไม่ได้ใช้
// ปิด Timer ที่ไม่ได้ใช้
TIMSK0 = 0; // ปิด Timer 0
TIMSK1 = 0; // ปิด Timer 1
TIMSK2 = 0; // ปิด Timer 2
// ปิด TWI (I2C)
power_twi_disable();
// ปิด SPI
power_spi_disable();
// ปิด USART
power_usart0_disable();
}2. ลดค่า Clock Speed
// ลดค่า Clock Speed เพื่อประหยัดไฟ
// ค่าเริ่มต้น: 16 MHz, ~10 mA
// ลดเหลือ: 1 MHz, ~1 mA
#include <avr/power.h>
void setup() {
// ปิด Prescaler เพื่อลด Clock Speed
clock_prescale_set(clock_div_16); // 16 MHz / 16 = 1 MHz
// หรือใช้วิธีนี้:
// CLKPR = (1 << CLKPCE); // เปิดใช้งาน Prescaler Change
// CLKPR = (1 << CLKPS2); // ตั้งค่าเป็น /16
// หมายเหตุ: Serial จะไม่ทำงานถ้าลดค่าเกินไป
Serial.begin(9600); // อาจต้องใช้ค่าที่ต่ำกว่า
}3. ใช้ Low Dropout Regulator (LDO)
Arduino Uno/Nano ใช้ Linear Regulator ที่กินไฟ ~5 mA แม้ Arduino จะ Sleep แนะนำให้ใช้:
- Arduino Pro Mini 3.3V - ไม่มี Regulator บนบอร์ด
- Barebone ATmega328P - ต่อ Regulator ภายนอกที่ดีกว่า
- Step-Up/Step-Down Converter - มีประสิทธิภาพสูงกว่า
4. ตัด LED บนบอร์ด
// ตัด LED บนบอร์ด (Pin 13)
// LED บน Arduino Uno กินไฟ ~3-5 mA
// วิธีที่ 1: ใช้โค้ด (ยังมีกระแสไหลผ่านตัวต้านทานเล็กน้อย)
void setup() {
pinMode(LED_BUILTIN, INPUT); // ตั้งเป็น Input เพื่อปิด LED
}
// วิธีที่ 2: ตัดตัวต้านทานทางกายภาพ (ถ้าจำเป็นต้องประหยัดสุดๆ)
// ใช้หั่นแหล็งตัดตัวต้านทานที่ต่อกับ LED บนบอร์ด
// หรือใช้ Arduino Pro Mini ที่ไม่มี LED บนบอร์ดเปรียบเทียบ Power Consumption ระหว่าง Modes
| สภาพการทำงาน | กำลังไฟ | อายุแบตเตอรี่ (9V) | อายุแบตเตอรี่ (2x AA) |
|---|---|---|---|
| Active (Normal) | ~20 mA | ~5 ชั่วโมง | ~20 ชั่วโมง |
| Idle Mode | ~15 mA | ~7 ชั่วโมง | ~25 ชั่วโมง |
| Power Save Mode | ~1.5 mA | ~3 วัน | ~10 วัน |
| Power Down Mode | ~0.1 mA | ~45 วัน | ~150 วัน |
| Power Down + ปิด LED | ~0.05 mA | ~90 วัน | ~300 วัน |
💡 เคล็ดลับ: การคำนวณอายุแบตเตอรี่
สูตร: อายุแบตเตอรี่ (ชั่วโมง) = ความจุแบตเตอรี่ (mAh) / กำลังไฟ (mA)
ตัวอย่าง: แบตเตอรี่ 9V 500mAh / 0.1 mA = 5,000 ชั่วโมง ≈ 208 วัน
ปัญหาที่พบบ่อยและวิธีแก้ไข
❌ Arduino ไม่ตื่นจาก Sleep Mode
สาเหตุ:
- • ต่อปุ่มที่ไม่ใช่ Interrupt Pin (ต้องใช้ 2 หรือ 3)
- • ไม่ได้ตั้งค่า Watchdog Timer ให้ถูกต้อง
- • ใช้ Sleep Mode ที่ไม่รองรับวิธีตื่นที่เลือก
วิธีแก้: ตรวจสอบ Interrupt Pin, ลองใช้ Watchdog Timer แทน
⚠️ Serial Monitor ไม่ทำงานใน Sleep Mode
สาเหตุ:
- • ส่งข้อมูล Serial ก่อน Sleep ไม่ทัน
- • Serial buffer ยังไม่ได้ส่งข้อมูลเสร็จ
วิธีแก้: เพิ่ม delay(100) ก่อนเข้า Sleep Mode
🔋 กินไฟมากกว่าที่ควร
สาเหตุ:
- • ยังคง LED บนบอร์ดเปิดอยู่
- • ไม่ได้ปิด Peripherals ที่ไม่ใช้
- • ใช้ Arduino Uno (มี Regulator กินไฟ)
วิธีแก้: ตัด LED, ปิด Peripherals, ใช้ Pro Mini แทน Uno
⏰ Wake-up ไม่ตรงเวลา
สาเหตุ:
- • Watchdog Timer มีค่าความคลาดเคลื่อน
- • Crystal oscillator มีค่าความคลาดเคลื่อน
วิธีแก้: ใช้ RTC Module (DS3231) สำหรับความแม่นยำสูง
สรุป
Arduino Sleep Modes เป็นเครื่องมือที่ทรงพลังสำหรับการประหยัดพลังงาน สามารถยืดอายุการใช้งานแบตเตอรี่จากชั่วโมงเป็นเดือนได้อย่างง่ายดาย โดยเฉพาะ Power Down Mode ที่ลดกำลังไฟลงเหลือเพียง 0.1 mA
🎯 เลือก Sleep Mode อย่างไร?
- Idle Mode: ใช้เมื่อต้องการ Serial/Timer/ADC ทำงานต่อ
- Power Save Mode: ใช้เมื่อต้องการตั้งเวลาด้วย Timer 2
- Power Down Mode: ใช้เมื่อต้องการประหยัดไฟสุดๆ ตื่นด้วย Interrupt/Watchdog
ถัดไป: โปรเจกต์ที่เกี่ยวข้อง
- ESP32 Deep Sleep Guide - ประหยัดไฟขั้นสูงกับ ESP32
- สร้าง Sensor Node ประหยัดไฟ ESP32 - โปรเจกต์จริง
- ระบบติดตามสุขภาพพืช - ประยุกต์ใช้ Sleep Mode