สวัสดีครับเพื่อน Maker ทุกคน! วันนี้เราจะมาพูดถึงเรื่องสำคัญที่หลายคนที่เริ่มเขียนโปรแกรม Arduino มักจะพลาดไป นั่นคือการใช้งาน delay()
ที่แม้จะดูง่ายและใช้งานสะดวก แต่กลับสร้างปัญหาให้กับโปรแกรมของเราได้มากมาย
ถ้าคุณเคยเขียนโปรแกรม Blink LED หรือโปรเจค Arduino ง่ายๆ คุณคงเคยใช้ delay()
กันมาแล้วแน่นอน แต่เมื่อโปรเจคเริ่มซับซ้อนขึ้น คุณจะพบว่า delay()
เป็นอุปสรรคใหญ่ต่อการพัฒนาโปรแกรมที่มีประสิทธิภาพ
ทำไมต้องหลีกเลี่ยง delay() ใน Arduino?
ปัญหาหลักของ delay():
1. การบล็อกการทำงาน (Blocking)
2. ไม่สามารถทำงานหลายอย่างพร้อมกันได้ ลองนึกภาพว่าคุณต้องการ:
- LED กระพริบทุก 500ms
- อ่านค่าอุณหภูมิทุก 2 วินาที
- ตรวจสอบปุ่มกดตลอดเวลา
- ส่งข้อมูลผ่าน WiFi ทุก 10 วินาที
ด้วย delay()
สิ่งเหล่านี้ทำพร้อมกันไม่ได้!
3. ผลกระทบต่อการตอบสนอง (Responsiveness)
รู้จักกับ millis() และ micros() - ทางออกที่ดีกว่า
millis() คืออะไร?
- ฟังก์ชันที่คืนค่าเวลาเป็นมิลลิวินาที นับตั้งแต่ Arduino เริ่มทำงาน
- ไม่หยุดการทำงานของโปรแกรม (Non-blocking)
- มีความแม่นยำสูงและใช้งานง่าย
micros() คืออะไร?
- คล้าย millis() แต่คืนค่าเป็นไมโครวินาที
- ใช้สำหรับงานที่ต้องการความแม่นยำสูงมาก
- เหมาะสำหรับการวัดเวลาที่สั้นมาก
ตารางเปรียบเทียบ:
ฟังก์ชัน |
หน่วยเวลา |
ความแม่นยำ |
Overflow |
การใช้งาน |
delay() |
มิลลิวินาที |
ปานกลาง |
ไม่มี |
Blocking |
millis() |
มิลลิวินาที |
สูง |
49.7 วัน |
Non-blocking |
micros() |
ไมโครวินาที |
สูงมาก |
71 นาที |
Non-blocking |
ตัวอย่างการเปลี่ยนจาก delay() เป็น millis()
1. Blink LED อย่างง่าย
แบบเก่า (ใช้ delay):
แบบใหม่ (ใช้ millis):
2. ทำงานหลายอย่างพร้อมกัน
3. การใช้ micros() สำหรับความแม่นยำสูง
การจัดการ Overflow ใน millis() และ micros()
Overflow คืออะไร?
millis()
จะ overflow (กลับไปเป็น 0) หลังจาก 49.7 วัน
micros()
จะ overflow หลังจาก 71 นาที
- การคำนวณเวลาอาจผิดพลาดเมื่อเกิด overflow
วิธีแก้ไขปัญหา Overflow:
ทำไมวิธีนี้ใช้ได้แม้เกิด overflow?
- การลบของ unsigned long จะให้ผลลัพธ์ที่ถูกต้องแม้เกิด overflow
- ตัวอย่าง: ถ้า currentMillis = 100, previousMillis = 4294967295 (ก่อน overflow)
- ผลการลบ: 100 - 4294967295 = 101 (ผ่านการ wraparound)
โปรเจคตัวอย่างจริง: ระบบควบคุมอุณหภูมิอัตโนมัติ
ปัญหาที่พบบ่อยและวิธีแก้ไข
1. เวลาไม่แม่นยำ
2. การใช้หน่วยเวลาผิด
3. ลืมจัดการ Overflow
เทคนิคขั้นสูง: สร้าง Timer Class
การประยุกต์ใช้กับ ESP32/ESP8266
สรุปและข้อแนะนำ
ข้อดีของ millis() และ micros():
✅ Non-blocking: ไม่หยุดการทำงานของโปรแกรม
✅ Multitasking: ทำงานหลายอย่างพร้อมกัน
✅ Responsive: ตอบสนองได้ทันที
✅ Accurate: ความแม่นยำสูง
✅ Flexible: ปรับเปลี่ยนได้ง่าย
ข้อเสียของ delay():
❌ Blocking: หยุดการทำงานทั้งหมด
❌ Single-task: ทำได้ครั้งละงาน
❌ Unresponsive: ตอบสนองช้า
❌ Inflexible: ปรับเปลี่ยนยาก
เมื่อไหร่ควรใช้อะไร:
ใช้ millis() เมื่อ:
- ต้องการทำงานหลายอย่างพร้อมกัน
- ต้องการความแม่นยำในการจับเวลา
- ต้องการระบบที่ตอบสนองเร็ว
- เขียนโปรแกรมที่ซับซ้อน
ใช้ micros() เมื่อ:
- ต้องการความแม่นยำสูงมาก (ไมโครวินาที)
- วัดเวลาที่สั้นมาก
- ทำงานกับ sensor ที่ต้องการ timing แม่นยำ
ใช้ delay() ได้เมื่อ:
- โปรแกรมง่ายๆ ที่ทำงานเดียว
- ต้องการ debounce ปุ่มกดสั้นๆ
- สร้าง prototype เร็วๆ
Tips สำหรับการเขียนโปรแกรมที่ดี:
- วางแผนโครงสร้างโปรแกรม - คิดว่างานไหนต้องทำเมื่อไหร่
- ใช้ตัวแปรที่มีความหมาย - เช่น
ledBlinkInterval
แทน interval1
- แยกหน้าที่งาน - สร้างฟังก์ชันแยกสำหรับแต่ละงาน
- ใช้ const สำหรับค่าคงที่ - เช่น
const long interval = 1000;
- คิดถึง overflow - ใช้การลบแทนการบวกเปรียบเทียบ
ทรัพยากรเพิ่มเติม:
หวังว่าบทความนี้จะช่วยให้คุณเข้าใจการใช้ millis()
และ micros()
แทน delay()
และสามารถนำไปประยุกต์ใช้ในโปรเจคของคุณได้นะครับ!
มีคำถามหรือต้องการคำแนะนำเพิ่มเติม สามารถติดต่อ ModuleMore ได้เสมอครับ
Happy Coding! 🚀