เคยไหมครับ เขียนโปรเจกต์ ESP32 อยู่ดี ๆ แล้วเจอคำว่า Interrupt โผล่มาในตัวอย่างโค้ด แต่ไม่แน่ใจว่ามันจำเป็นจริงไหม? หลายคนรีบใช้เพราะคิดว่ามันดูโปร แต่พอใช้ผิดจุด โค้ดยุ่งกว่าเดิม แถมระบบยังงงอีกต่างหาก
บทความนี้จะพาคุณเข้าใจว่า ESP32 Interrupt คืออะไร ใช้ตอนไหนถึงคุ้ม ใช้ตอนไหนไม่จำเป็น และมีตัวอย่างแบบภาษาคนทำโปรเจกต์จริง เพื่อให้คุณตัดสินใจได้ว่าโปรเจกต์ของคุณควรใช้ Interrupt หรือใช้แค่ loop() กับ millis() ก็พอแล้ว
- ถ้าคุณยังใหม่กับบอร์ดนี้ แนะนำเริ่มจากบทความ ESP32 คืออะไร ก่อน แล้วค่อยกลับมาอ่านเรื่อง Interrupt ต่อ
- และถ้ายังไม่คุ้นกับขา input/output แนะนำดู ESP32 Pinout DevKit V1 ควบคู่กัน
สารบัญ
- Interrupt คืออะไรแบบภาษาคนทำโปรเจกต์
- ESP32 Interrupt ทำงานยังไง
- ESP32 Interrupt ใช้งานตอนไหน
- งานแบบไหนไม่จำเป็นต้องใช้ Interrupt
- ตัวอย่างการใช้ attachInterrupt() บน ESP32
- ข้อควรระวังเวลาเขียน ISR บน ESP32
- Interrupt กับ Polling ต่างกันยังไง
- ตัวอย่างโปรเจกต์จริงที่ควรใช้ Interrupt
- สรุป ESP32 Interrupt สำหรับมือใหม่
- FAQ คำถามที่คนเริ่มต้นมักสงสัย

Interrupt คืออะไรแบบภาษาคนทำโปรเจกต์
Interrupt คือการขัดจังหวะให้ ESP32 ไปทำงานสำคัญทันที
ถ้าอธิบายแบบง่ายมาก ๆ Interrupt คือกลไกที่บอก ESP32 ว่า“หยุดงานที่กำลังทำไว้ก่อน แล้วรีบมาดูเหตุการณ์นี้เดี๋ยวนี้”สมมติว่า ESP32 กำลังอ่านค่าเซนเซอร์ทุก ๆ รอบใน
loop() แต่จู่ ๆ มีปุ่มฉุกเฉินถูกกด หรือมีพัลส์จาก flow sensor เข้ามาเร็วมาก ถ้ารอให้ loop() วิ่งมาเช็กเอง บางครั้งอาจช้าไปหรือพลาดเหตุการณ์นั้นได้ตรงนี้แหละครับที่ Interrupt มีประโยชน์ เพราะมันช่วยให้ ESP32 ตอบสนองกับเหตุการณ์สำคัญได้ทันทีถ้าไม่ใช้ Interrupt ระบบจะทำงานแบบไหน
ถ้าไม่ใช้ Interrupt โปรแกรมส่วนใหญ่จะทำงานแบบ Polling คือเช็กไปเรื่อย ๆ ในloop() เช่น- เช็กว่าปุ่มถูกกดหรือยัง
- เช็กว่า sensor เปลี่ยนค่าหรือยัง
- เช็กว่า input เป็น HIGH หรือ LOW
ทำไมมือใหม่ควรรู้เรื่องนี้ตั้งแต่เริ่มทำโปรเจกต์
เพราะมือใหม่มักเจอ 2 แบบครับ
- แบบแรก: ไม่ใช้ Interrupt ทั้งที่งานควรใช้ ทำให้ระบบพลาด event
- แบบสอง: ใช้ Interrupt กับทุกอย่าง จนโค้ดซับซ้อนเกินจำเป็น
ถ้าคุณเข้าใจหลักตั้งแต่ต้น คุณจะเลือกเครื่องมือได้ถูกว่า งานนี้ควรใช้ loop(), millis() หรือ Interrupt
ESP32 Interrupt ทำงานยังไง

CPU กำลังทำงานอยู่ แล้วเกิด event แทรกเข้ามา
ลองนึกภาพว่า ESP32 กำลังทำงานตามปกติอยู่ใน loop() เช่น อ่านค่า sensor, อัปเดตจอ, ส่งข้อมูล WiFi
เมื่อมีเหตุการณ์ที่เรากำหนดไว้เกิดขึ้น เช่น
- ขา GPIO เปลี่ยนจาก LOW เป็น HIGH
- ขา GPIO เปลี่ยนจาก HIGH เป็น LOW
- มีสัญญาณพัลส์เข้ามา
ESP32 จะกระโดดไปทำฟังก์ชันพิเศษตัวหนึ่งทันที ฟังก์ชันนั้นเรียกว่า ISR
ISR คืออะไร และหน้าที่จริงของมันคืออะไร
ISR ย่อมาจาก Interrupt Service Routine เป็นฟังก์ชันที่ถูกเรียกตอนเกิด Interrupt
หน้าที่ของ ISR ไม่ใช่ทำทุกอย่างให้เสร็จในนั้น แต่ควรทำแค่เรื่องสั้น ๆ เช่น
- ตั้ง flag ว่าเกิด event แล้ว
- นับจำนวนพัลส์เพิ่ม 1
- จำเวลาที่เกิด event
แนวคิดสำคัญ: ISR ควรสั้น เร็ว และไม่หนัก
RISING, FALLING, CHANGE ต่างกันยังไง
เวลาผูก Interrupt กับ GPIO เรามักกำหนดโหมดประมาณนี้
- RISING = ทำงานเมื่อสัญญาณเปลี่ยนจาก LOW ไป HIGH
- FALLING = ทำงานเมื่อสัญญาณเปลี่ยนจาก HIGH ไป LOW
- CHANGE = ทำงานทุกครั้งที่มีการเปลี่ยนทั้งขึ้นและลง
ตัวอย่างเช่น ถ้าคุณต่อปุ่มแบบกดแล้วดึงลง LOW อาจเลือกใช้ FALLING เพื่อให้ Interrupt ทำงานตอนกดปุ่ม
ESP32 Interrupt ใช้งานตอนไหน
ใช้กับปุ่มกดหรือสวิตช์ที่ต้องตอบสนองไว
ถ้าคุณมีปุ่มกดที่มีความสำคัญ เช่น
- ปุ่มหยุดมอเตอร์
- ปุ่มฉุกเฉิน
- ปุ่มเริ่ม/หยุดโหมดการทำงาน
การใช้ Interrupt จะช่วยให้ระบบตอบสนองได้เร็ว โดยไม่ต้องรอให้ loop วิ่งมาเช็ก
ใช้กับการนับพัลส์ เช่น flow sensor หรือ encoder
งานแบบนี้เหมาะมาก เพราะสัญญาณอาจมาเร็วและถี่ เช่น
- นับพัลส์จาก water flow sensor
- นับรอบจาก rotary encoder
- นับจำนวนวัตถุผ่าน sensor
ถ้าคุณใช้แต่ loop แล้วในระบบมีงานอื่นทำเยอะ เช่น WiFi, จอ, web server ก็มีโอกาสพลาดพัลส์ได้
ใช้จับเหตุการณ์สั้น ๆ ที่ loop() อาจพลาด
บาง event อยู่ไม่นาน เช่น สัญญาณขอบขึ้นขอบลงเร็ว ๆ ถ้า loop ของคุณหมุนไม่เร็วพอ มันอาจมองไม่ทัน แต่ Interrupt ถูกออกแบบมาเพื่อเรื่องนี้โดยตรง
ใช้กับงาน event-driven มากกว่างานอ่านค่าเป็นรอบ
ถ้างานของคุณคือ “รอให้มีเหตุการณ์เกิด แล้วค่อยตอบสนอง” แบบนี้ Interrupt เหมาะมาก
แต่ถ้างานของคุณคือ “อ่านค่าทุก 1 วินาที” หรือ “เช็กทุก 5 วินาที” แบบนี้มักไม่จำเป็นต้องใช้ Interrupt
งานแบบไหนไม่จำเป็นต้องใช้ Interrupt
งานอ่านค่า sensor ช้า ๆ เช่นอุณหภูมิและความชื้น
เซนเซอร์หลายตัวไม่ได้เปลี่ยนเร็วขนาดต้องใช้ Interrupt เช่น
- DHT11 / DHT22
- อุณหภูมิห้อง
- ความชื้นอากาศ
- ค่าแสงทั่วไป
อ่านเป็นรอบด้วย millis() ก็เพียงพอและดูแลง่ายกว่า
งานที่ใช้ millis() ก็พอแล้ว
ถ้าคุณแค่อยากให้ระบบทำงานหลายอย่างโดยไม่ใช้ delay() การใช้ millis() จะเหมาะกว่าในหลายเคส เช่น
- อ่าน sensor ทุก 2 วินาที
- กระพริบ LED ทุก 500 ms
- เช็กปุ่มทุกไม่กี่ ms
มือใหม่หลายคนข้าม millis() ไปหา Interrupt เลย ทั้งที่จริงแล้วปัญหาหลายอย่างแก้ได้ง่ายกว่าด้วยโค้ด non-blocking ปกติ
ถ้างานของคุณแค่อ่านค่าเป็นรอบ ๆ การใช้ millis() แบบ non-blocking มักง่ายกว่าและดูแลง่ายกว่า
ใช้ Interrupt ผิดที่ โค้ดจะยุ่งโดยไม่จำเป็น
นี่คือสิ่งที่เจอจริงบ่อยมากครับ บางโปรเจกต์ใช้ Interrupt กับทุก input ทั้งที่ไม่จำเป็น สุดท้าย
- ดีบักยาก
- โค้ดอ่านยาก
- เกิดบั๊กแปลก ๆ
- ระบบไม่เสถียร
สรุปง่าย ๆ: อย่าใช้ Interrupt เพราะมันดูเท่ ใช้เมื่อมันช่วยแก้ปัญหาจริง
ตัวอย่างการใช้ attachInterrupt() บน ESP32
โครงสร้างคำสั่ง attachInterrupt()
ตัวอย่างพื้นฐานบน ESP32 จะหน้าตาประมาณนี้
attachInterrupt(digitalPinToInterrupt(pin), isrFunction, mode);ความหมายคือ
pin= ขาที่ต้องการจับเหตุการณ์isrFunction= ฟังก์ชัน ISR ที่จะให้ทำงานmode= รูปแบบการเปลี่ยนสัญญาณ เช่น RISING, FALLING, CHANGE
ตัวอย่างนับจำนวนครั้งที่กดปุ่ม
const int buttonPin = 18;
volatile int pressCount = 0;
void IRAM_ATTR handleButtonPress() {
pressCount++;
}
void setup() {
Serial.begin(115200);
pinMode(buttonPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(buttonPin), handleButtonPress, FALLING);
}
void loop() {
static int lastCount = 0;
if (pressCount != lastCount) {
lastCount = pressCount;
Serial.print("Button pressed: ");
Serial.println(pressCount);
}
}โค้ดนี้ทำงานแบบนี้
- เมื่อกดปุ่ม ขาเปลี่ยนสถานะ
- Interrupt ทำงานทันที
- ISR เพิ่มค่า
pressCount - ใน
loop()ค่อยเอาค่านั้นมาแสดงผล
นี่คือรูปแบบที่ดีสำหรับมือใหม่ เพราะ ISR ทำงานสั้น ๆ ส่วนงานแสดงผลไปทำใน loop แทน
ทำไมต้องใช้ volatile กับตัวแปรบางตัว
ตัวแปรที่ถูกแก้ไขใน ISR และถูกอ่านใน loop() ควรประกาศเป็น volatile เพื่อบอกคอมไพเลอร์ว่า
“ค่านี้อาจเปลี่ยนเมื่อไรก็ได้จากภายนอก flow ปกติของโปรแกรม”
ถ้าไม่ใส่ บางครั้งคอมไพเลอร์อาจ optimize จนเกิดผลลัพธ์แปลก ๆ ได้
ข้อควรระวังเวลาเขียน ISR บน ESP32
ISR ต้องสั้นและไว
หลักจำง่ายมากครับ
ISR เอาไว้ “รับรู้” ว่าเกิด event ไม่ได้เอาไว้ “จัดการทุกอย่าง”
ให้ทำแค่
- ตั้ง flag
- เพิ่มตัวนับ
- เก็บ timestamp
แล้วค่อยให้ loop() หรือ task อื่นมาจัดการงานหนักต่อ
ไม่ควรใช้ delay() หรือโค้ดหนักใน ISR
สิ่งที่ไม่ควรยัดใส่ ISR เช่น
delay()- โค้ดยาว ๆ
- การสื่อสารที่กินเวลา
- งานคำนวณหนัก
- การจัดการ logic ใหญ่ทั้งระบบ
เพราะจะทำให้ระบบตอบสนองช้าลง หรือมีปัญหาแปลก ๆ ตามมา
ระวัง debounce จากปุ่มกด
ปุ่มกดจริงมักไม่ได้เปลี่ยนสถานะนิ่ง ๆ ครั้งเดียว แต่มันอาจเด้งหลายรอบในช่วงเวลาสั้นมาก ทำให้กดครั้งเดียวแต่ interrupt วิ่งหลายครั้ง
วิธีรับมือ เช่น
- ใช้ debounce ด้วย software
- ใช้เวลาเช็กห่างกัน เช่นไม่นับซ้ำใน 30-50 ms
- ใช้วงจรช่วยกรองสัญญาณ ถ้าจำเป็น
ตัวอย่างแนวคิดแบบง่าย
volatile unsigned long lastInterruptTime = 0;
volatile int pressCount = 0;
void IRAM_ATTR handleButtonPress() {
unsigned long now = millis();
if (now - lastInterruptTime > 50) {
pressCount++;
lastInterruptTime = now;
}
}หมายเหตุ: ตัวอย่างนี้ช่วยให้เห็นภาพเรื่อง debounce แต่ในงานจริงควรออกแบบให้เหมาะกับข้อจำกัดของ ISR และระบบที่ใช้
อย่าใส่ทุกอย่างลงใน interrupt
หลายคนเริ่มต้นแล้วทำแบบนี้
- กดปุ่ม → ISR เปิดรีเลย์
- ส่ง WiFi
- อัปเดตจอ
- บันทึกข้อมูล
- เช็ก sensor ต่ออีกหลายตัว
แบบนี้เสี่ยงพังครับ วิธีที่ดีกว่าคือให้ ISR แค่แจ้งว่า “เกิด event แล้ว” แล้วไปจัดการต่อใน flow หลัก

Interrupt กับ Polling ต่างกันยังไง
Polling เหมาะกับงานแบบไหน
Polling เหมาะกับงานที่
- ไม่ต้องตอบสนองเร็วมาก
- อ่านค่าเป็นช่วง ๆ ได้
- logic ไม่ซับซ้อน
- ต้องการโค้ดที่เข้าใจง่าย
ตัวอย่างเช่น อ่านอุณหภูมิทุก 2 วินาที หรือเช็กสถานะน้ำในถังทุก 500 ms
Interrupt เหมาะกับงานแบบไหน
Interrupt เหมาะกับงานที่
- event เกิดเร็ว
- event สั้น
- ห้ามพลาดสัญญาณ
- ต้องตอบสนองไว
เช่น นับพัลส์ flow sensor, ปุ่มหยุดฉุกเฉิน, encoder, reed switch บางประเภท

วิธีเลือกให้เหมาะกับโปรเจกต์จริง
| สถานการณ์ | เหมาะกับ | เหตุผล |
|---|---|---|
| อ่านค่าอุณหภูมิทุก 2 วินาที | Polling / millis() | ไม่ใช่ event เร็ว |
| นับพัลส์จาก flow sensor | Interrupt | พัลส์อาจมาถี่และสั้น |
| ปุ่มเมนูทั่วไป | Polling | เขียนง่าย ดูแลง่าย |
| ปุ่มหยุดฉุกเฉิน | Interrupt | ต้องตอบสนองไว |
ตัวอย่างโปรเจกต์จริงที่ควรใช้ Interrupt
ปุ่มหยุดฉุกเฉิน
ถ้าระบบของคุณควบคุมมอเตอร์ ปั๊ม หรืออุปกรณ์ที่มีความเสี่ยง การใช้ Interrupt กับปุ่มหยุดฉุกเฉินช่วยให้ระบบตอบสนองเร็วขึ้นกว่าการรอ loop
ระบบวัดการไหลของน้ำ
ในงาน Smart Farm หรือระบบจ่ายน้ำอัตโนมัติ flow sensor มักส่งพัลส์ออกมาตามอัตราการไหล ถ้าไม่นับพัลส์ให้ทัน ปริมาณน้ำที่คำนวณได้จะคลาดเคลื่อน
ระบบนับรอบมอเตอร์
ถ้าคุณใช้ sensor ตรวจรอบ เช่น Hall sensor หรือ encoder การใช้ Interrupt จะช่วยให้นับรอบได้แม่นขึ้น โดยเฉพาะตอนความเร็วสูง
ระบบตรวจจับการเปิดปิดประตู
งานแบบ reed switch หรือ magnetic switch ก็เหมาะ เพราะมันเป็น event ชัดเจนว่าเปิดหรือปิดเมื่อไร แล้วค่อยให้ระบบไปทำต่อ เช่น แจ้งเตือนหรือบันทึก log

สรุป ESP32 Interrupt สำหรับมือใหม่
เข้าใจหลักให้ถูกก่อนลงมือเขียนโค้ด
Interrupt คือเครื่องมือสำหรับรับมือกับเหตุการณ์ที่ต้องตอบสนองไวหรือห้ามพลาด ไม่ใช่คำสั่งพิเศษที่ต้องยัดใส่ทุกโปรเจกต์
ใช้เมื่อจำเป็น ไม่ใช่ใช้เพราะดูเท่
ถ้างานของคุณอ่านค่าเป็นรอบ ๆ ใช้ millis() หรือ loop ที่ออกแบบดี ๆ ก็พอ แต่ถ้างานของคุณเป็นพัลส์เร็ว ปุ่มฉุกเฉิน หรือ event สั้น ๆ Interrupt จะช่วยได้มาก
เริ่มจากโปรเจกต์เล็กแล้วค่อยต่อยอด
ถ้าคุณเพิ่งเริ่ม แนะนำให้ลองจาก
- ปุ่มกด + LED
- นับจำนวนพัลส์จาก sensor
- ทดลองเปรียบเทียบ Polling กับ Interrupt
พอเข้าใจหลักแล้วค่อยต่อยอดไปงานจริง เช่น Smart Farm, automation หรือระบบวัดการไหลของน้ำ
สรุปสั้นแบบช่างหน้างาน: ถ้า event มาเร็ว มาไว และพลาดไม่ได้ ใช้ Interrupt ได้เลย แต่ถ้าเป็นงานอ่านค่าเป็นรอบ ใช้ loop หรือ millis() ก่อน จะง่ายและนิ่งกว่าครับ
FAQ คำถามที่คนเริ่มต้นมักสงสัย
ESP32 ทุกขาใช้ Interrupt ได้ไหม
โดยทั่วไป ESP32 รองรับ interrupt ได้หลาย GPIO แต่เวลาใช้งานจริงควรเช็กข้อจำกัดของขาแต่ละขา เช่น ขาที่ใช้ตอน boot หรือขาที่มีหน้าที่พิเศษร่วมอยู่แล้ว
ISR ใส่ Serial.print() ได้ไหม
ไม่แนะนำครับ เพราะ ISR ควรสั้นและไว การพิมพ์ Serial อาจทำให้เกิดพฤติกรรมที่ไม่เสถียรในบางสถานการณ์ ควรตั้ง flag หรือเก็บค่าไว้ แล้วค่อยพิมพ์ใน loop
กดปุ่มครั้งเดียวทำไมค่าขึ้นหลายรอบ
ส่วนใหญ่เกิดจาก debounce ของปุ่มกด สวิตช์จริงมักเด้งหลายครั้งในช่วงเวลาสั้นมาก จึงต้องมีการกรองทั้งด้วย software หรือ hardware
Interrupt ต่างจาก millis() ยังไง
millis() เหมาะกับงานที่ต้องการทำเป็นช่วงเวลาแบบ non-blocking ส่วน Interrupt เหมาะกับงานที่ต้องตอบสนองเมื่อเกิด event ทันที ทั้งสองอย่างไม่ใช่คู่แข่งกัน แต่เป็นเครื่องมือคนละงาน
Smart Farm แบบไหนควรใช้ Interrupt
เช่น งานนับพัลส์ flow sensor, ปุ่มหยุดฉุกเฉิน, sensor ตรวจรอบ หรือ input บางอย่างที่เกิดเร็วและไม่ควรพลาด แต่ sensor ช้า ๆ อย่างอุณหภูมิหรือความชื้นทั่วไป มักไม่จำเป็นต้องใช้



