กลับไปหน้ารวมไฟล์
esp-32-elapsed-timer-alerting-framework-0e4593.md

title: "Mastering ESP32 Timer Interrupts: ระบบจัดการเวลาอัจฉริยะ (ETA Framework)" description: "เจาะลึกการใช้งาน Hardware Timer ของ ESP32 เพื่อสร้างระบบจัดการ Task แบบขนานผ่าน Elapsed Timer Alerts (ETA) ที่มีความแม่นยำสูง"

บทนำ: ก้าวข้ามขีดจำกัดของ delay() ด้วย Hardware Timers

ในการเขียนโปรแกรมบน ESP32 ปัญหาที่วิศวกรระบบฝังตัวมักพบเจอคือการจัดการเหตุการณ์หลายอย่างที่ต้องเกิดขึ้นในเวลาที่ต่างกัน (Multi-tasking) หากเราใช้ฟังก์ชัน delay() โปรแกรมจะหยุดชะงักและไม่สามารถตอบสนองต่อเหตุการณ์อื่นได้ทันท่วงที

บทความนี้จะนำเสนอ ETA Framework (Elapsed Timer Alerts) ซึ่งเป็นโครงสร้างการเขียนโปรแกรมที่ใช้ประโยชน์จาก Timer Interrupts ของ ESP32 โดยตรง ช่วยให้คุณสามารถสร้าง "ตัวตั้งเวลา" ได้หลายตัวพร้อมกัน (Multiple Timers) ไม่ว่าจะเป็นแบบทำงานครั้งเดียว (One-off) หรือทำงานซ้ำ (Recurring) โดยไม่รบกวนการทำงานหลักของโปรแกรม

แนวคิดของ ETA Framework

หัวใจสำคัญของ Framework นี้คือการนิยามเงื่อนไขการแจ้งเตือนเมื่อเวลาผ่านไป ซึ่งเราเรียกว่า Elapsed Timer Alert (ETA) โดยแต่ละ ETA จะประกอบด้วย:

  1. Type: ประเภทของ Timer (ทำงานครั้งเดียว หรือ ทำงานวนลูป)
  2. Alert ID: รหัสประจำตัวที่ไม่ซ้ำกัน (ID 0-65535) เพื่อใช้ในการแยกแยะว่า Task ไหนทำงานเสร็จแล้ว
  3. Countdown (ms): ระยะเวลาถอยหลังในหน่วยมิลลิวินาที

เจาะลึกวิศวกรรม: ESP32 Hardware Timers (Example 1)

ESP32 มี Hardware Timers ทั้งหมด 4 ตัว (Timer 0 ถึง 3) ซึ่งเป็นตัวนับแบบ 64-bit ที่มีความแม่นยำสูง ในตัวอย่างแรก (Example 1) เราจะกำหนดให้ Timer 0 ทำงานที่ความถี่ 1,000Hz หรือทุกๆ 1 มิลลิวินาที

หลักการทำงานในเชิงลึก:

  • Prescaler: สัญญาณนาฬิกาของ ESP32 อยู่ที่ 80MHz เราใช้ Prescaler ขนาด 80 เพื่อหารความถี่ลงมาให้เหลือ 1MHz (1 ล้านครั้งต่อวินาที)
  • Alarm: เมื่อตัวนับ (Counter) นับครบ 1,000 ครั้ง มันจะสร้างสัญญาณ Interrupt ขึ้นมา 1 ครั้ง (เท่ากับ 1ms พอดี)
  • ISR (Interrupt Service Routine): เมื่อเกิด Interrupt โปรแกรมจะกระโดดไปทำงานในฟังก์ชันพิเศษที่เก็บไว้ใน IRAM_ATTR เพื่อความรวดเร็ว หน้าที่ของมันใน Framework นี้คือการเพิ่มค่าตัวแปรนับเวลา (Interrupt Count)

โครงสร้างหลักของ ETA Framework (Example 2)

Framework นี้ถูกออกแบบมาให้ทำงานแบบ Asynchronous หมายความว่าตัว Interrupt จะทำหน้าที่นับเวลาอย่างเดียว ส่วนการตัดสินใจหรือ Logic หนักๆ จะถูกยกมาทำใน loop() หลัก เพื่อไม่ให้เครื่องค้าง (WDT Reset)

ขั้นตอนการทำงาน (Pseudo Code):

 main loop {  
   ตรวจสอบจำนวน Interrupt ที่ค้างอยู่;  
   while (มี Interrupt ที่ยังไม่ได้จัดการ) { 
     update_ETAs(); // ลดค่า countdown ของทุก Timer ลง 1ms 
     while (มี ETA ที่ถึงกำหนดเวลา) {  
       switch (ETA Alert ID) {  
         case heart_beat:  
           กะพริบไฟ LED;  
         case sensor_read_id:  
           อ่านค่าจากเซนเซอร์;  
         ...  
       }  
     }  
   }  
   ทำงานส่วนอื่นๆ (เช่น เชื่อมต่อ Wi-Fi หรือประมวลผลข้อมูล);  
 }  

การกำหนดจำนวน Timer

คุณสามารถกำหนดจำนวน Timer สูงสุดที่ระบบจะจัดการได้ผ่าน Macro #define max_ETAs เพื่อให้ระบบจัดสรรหน่วยความจำได้อย่างมีประสิทธิภาพ


การใช้งานฟังก์ชันหลักใน Framework

1. การสร้าง Timer (create_ETA)

ฟังก์ชันนี้ใช้สร้างภารกิจที่ต้องการตั้งเวลา มีพารามิเตอร์ 3 ส่วน:

  • ETA_type: one_off_ETA (ทำครั้งเดียวแล้วลบออก) หรือ recurring_ETA (ทำซ้ำต่อเนื่อง)
  • ETA_alert_id: ID ของงาน (0 - 65535)
  • ETA_interval: เวลาที่ต้องการ (ms)

ตัวอย่างการสร้าง:

if(create_ETA(recurring_ETA, 102, 500) == ETA_inserted) {
    // สร้าง Timer สำหรับส่งข้อมูลทุก 500ms สำเร็จ!
}

2. การลบ Timer (delete_ETA)

เราสามารถสั่งยกเลิกการตั้งเวลาได้ทันทีผ่าน delete_ETA(type, id) ซึ่งมีประโยชน์มากในกรณีที่ต้องการหยุด Task บางอย่างตามเงื่อนไขที่กำหนด

3. การแสดงสถานะ (print_ETAs)

สำหรับการ Debugging ฟังก์ชันนี้จะพิมพ์ตาราง Timer ทั้งหมดออกมาทาง Serial Monitor (115200 baud) เพื่อตรวจสอบว่าค่า Countdown และ Interval ของแต่ละ ID ยังทำงานถูกต้องหรือไม่


กรณีศึกษา: ระบบควบคุมสภาพแวดล้อมอัจฉริยะ (Example 3)

เพื่อให้เห็นภาพการใช้งานจริง Example 3 จำลองระบบดูแลโรงเรือน (Greenhouse Control) ซึ่งต้องจัดการ Task ที่มีความถี่ต่างกันอย่างสิ้นเชิง:

  • Heartbeat (500ms): กะพริบไฟ LED เพื่อบอกว่าระบบยังไม่ค้าง
  • Sensor Sampling (2 seconds): อ่านค่าอุณหภูมิและความชื้น
  • Soil Moisture Check (30 seconds): ตรวจสอบความชื้นในดิน (ซึ่งไม่ต้องตรวจบ่อยเท่าอุณหภูมิ)
  • Stats Report (1 minute): สรุปผลการทำงานผ่าน Serial Port

ด้วย ETA Framework เราสามารถนิยามสิ่งเหล่านี้ได้ง่ายๆ ในรูปแบบ Array:

unsigned int my_ETA_data[max_ETAs][3] = {
    {recurring_ETA, heart_beat_id, 500},
    {recurring_ETA, sensor_read_id, 2000},
    {recurring_ETA, soil_moisture_id, 30000},
    {recurring_ETA, stats_report_id, 60000}
};

ข้อมูลสนับสนุนด้านเวลา (Time Macros)

Framework เตรียมค่าคงที่เพื่อช่วยให้ Code อ่านง่ายขึ้น (Self-documenting code):

  • one_day : 86,400,000 ms
  • one_hour : 3,600,000 ms
  • one_minute : 60,000 ms
  • one_second : 1,000 ms

คุณสามารถใช้ค่าเหล่านี้ได้ทันที เช่น create_ETA(one_off_ETA, 5, 2 * one_hour); เพื่อตั้งเวลาอีก 2 ชั่วโมงข้างหน้า


บทสรุปจากมุมมองวิศวกร

การใช้งาน ESP32 Timer Interrupts ผ่าน ETA Framework ช่วยเปลี่ยนจากการเขียนโปรแกรมแบบ "รอคอย" (Blocking) มาเป็นการเขียนโปรแกรมแบบ "ตอบสนองต่อเหตุการณ์" (Event-Driven) อย่างเต็มตัว

ระบบนี้มีความยืดหยุ่นสูง (Scalability) และช่วยลดภาระการคำนวณในส่วนของ ISR ให้เหลือน้อยที่สุด ทำให้ ESP32 ของคุณทำงานได้เสถียร ไม่ติดขัด และสามารถรองรับโปรเจค IoT ที่ซับซ้อนได้อย่างมืออาชีพ

หากต้องการนำไปใช้กับบอร์ดตระกูล Arduino (AVR) คุณเพียงแค่เปลี่ยนส่วนการตั้งค่า Register ของ Timer ให้ตรงกับสถาปัตยกรรมนั้นๆ (เช่นการใช้ AVR Timer Interrupts Calculator) แต่โครงสร้างตรรกะของ ETA Framework ยังคงสามารถใช้งานร่วมกันได้ทันที

ข้อมูล Frontmatter ดั้งเดิม

title: "ESP 32 Elapsed Timer Alerting Framework"
description: "A totally flexible and general timer interrupt framework for designing solutions needing one or many individual elapsing and separate timers"
author: "ronbentley1"
category: ""
tags:
  - "etas"
  - "esp 32"
  - "alerting"
  - "timers"
  - "interrupts"
views: 1452
likes: 0
price: 2450
difficulty: "Intermediate"
components:
  - "1x ESP32S"
tools: []
apps:
  - "1x Arduino IDE"
downloadableFiles:
  - "https://projects.arduinocontent.cc/1ed87cdf-35cb-4167-933a-7f1745167f87.ino"
  - "https://projects.arduinocontent.cc/c23cbc08-47fb-4f98-b288-751799d75ea3.ino"
  - "https://projects.arduinocontent.cc/1ed87cdf-35cb-4167-933a-7f1745167f87.ino"
documentationLinks: []
passwordHash: "87328bc21168104cabebc8079173f7f6ff20911fa0fc0928495665e57d182d05"
encryptedPayload: "U2FsdGVkX1+owfScJPPlvxV1KJE4ucksEVYf7lojdAhIVoPiv/qW9k7xgso/55NFhID7i+fUw54cqn9BPepewC/BL5oJpuAABfjKzEFcZ5A="
seoDescription: "A flexible ESP 32 Timer interrupt framework for managing multiple separate elapsing timers in Arduino projects."
videoLinks: []
heroImage: "https://cdn.jsdelivr.net/gh/bigboxthailand/arduino-assets@main/images/projects/esp-32-elapsed-timer-alerting-framework-0e4593_cover.jpg"
lang: "en"