[TH] Ticker Class : esp8266 Timer interrupt

บทความนี้กล่าวถึงการใช้ Ticker กับไมโครคอนโทรลเลอร์ ESP8266 เพื่อสร้างการขัดจังหวะจากสัญญาณนาฬิกา แทนการหน่วงเวลาด้วย delay() ทำให้ระยะเวลาที่ต้องเสียจากการวนรอบด้วย delay() ถูกใช้ไปทำอย่างอื่น และสร้างประสิทธิภาพต่อซอฟต์แวร์ที่พัฒนา

การใช้งาน Ticker

Ticker เป็นไลบรารีของ esp8266 ที่พัฒนามาตั้งแต่ปี ค.ศ. 2014 โดย Ivan Grokhotkov ซึ่งเป็นการเปิดความสามารถของเฟรมเวิร์ก Arduino ให้เข้าถึงการใช้ os_timer เพื่อตั้งเวลาให้เรียกฟังก์ชัน callback ที่กำหนดไว้เมื่อครบระยะเวลาที่ต้องการ โดยการใช้งานต้องเรียกใช้ไฟล์ส่วนหัว Ticker.h ดังนี้

#include <Ticker.h>

เมื่อนำเข้าไฟล์ส่วนหัว Ticker เรียบร้อย ขั้นตอนต่อไปคือสร้างวัตถุประเภทตัวตั้งเวลาที่สร้างจากคลาส Ticker ดังนี้

Ticker วัตถุ;

การใช้งานวัตถุที่เป็นตัวตั้งเวลาจะต้องกำหนดระยะเวลาของการตั้งเวลาในหน่วยวินาที (ใช้ข้อมูลแบบตัวเลขทศนิยม) และระบุฟังก์ชันที่จะถูกเรียกใช้เมื่อครบระยะเวลาที่กำหนดดังรูปแบบต่อไปนี้

วัตถุ.attach( เวลาหน่วยวินาที, ฟังก์ชันเรียกกลับ)

หรือถ้าต้องการตั้งค่าเป็นหน่วยมิลลิวินาทีให้เปลี่ยนการใช้งานเป็นฟังก์ชัน attach_ms() แทน attach() ดังรูปแบบต่อไปนี้

วัตถุ.attach_ms( เวลาหน่วยมิลลิวินาที, ฟังก์ชันเรียกกลับ )

สำหรับการเรียกฟังก์ชันที่กำหนดแบบเพียงครั้งเดียวสามารถเปลี่ยนเป็นใช้ once() หรือ once_ms() ตามรูปแบบการใช้งานดังนี้

วัตถุ.once( เวลาในหน่วยวินาที, ฟังก์ชันเรียกกลับ )
วัตถุ.once_ms( เวลาในหน่วยมิลลินาที, ฟังก์ชันเรียกกลับ )

ถ้าต้องการตรวจสอบสถานะการทำงานของวัตถุตั้งเวลาที่สร้างไว้ให้ใช้คำสั่ง active() ในการตรวจสอบสถานะดังนี้ และได้คำตอบเป็น true หรือ false

สถานะ = วัตถุ.active()

ในกรณีที่ใช้ attach() หรือ attach_ms() และต้องการหยุดการเรียกซ้ำสามารถทำได้ด้วยการยกเลิกการผนวกฟังก์ชันเข้ากับตัวตั้งเวลาด้วยคำสั่ง detach() ดังนี้

วัตถุ.detach()

นอกจากนี้ กรณีที่ต้องการสร้างพารามิเตอร์ส่งไปให้ฟังก์ชันตอบกลับต้องใช้ std::bind() เป็นตัวช่วย เช่นตัวอย่างต่อไปนี้

void func( int id ) {
    Serial.println( id );
}
...
วัตถุ.attach_ms(500, std::bind( func, 10 ));
...

ตัวอย่างโปรแกรม

จากโค้ดตัวอย่างด้านล่างนี้เป็นการใช้วิธีหน่วงเวลาของคำสั่ง delay() เพื่อสั่งให้หลอดแอลอีดีบนบอร์ด NodeMCU ติดและดับสลับกันทุก 500ms (โดยประมาณ)

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);    
}

void loop() {
  digitalWrite(LED_BUILTIN, LOW);   
  delay(500);  
  digitalWrite(LED_BUILTIN, HIGH);  
  delay(500);  
}

เมื่อเขียนใหม่ด้วยการใช้ Ticker ซึ่งมีขั้นตอนของการเขียน 3 ส่วนหลัก คือ ส่วนของการสร้างวัตถุตั้งเวลาทำงานประเภท Ticker การสร้างฟังก์ชันตอบสนอง และการผนวกฟังก์ชันเข้ากับวัตถุตั้งเวลาทำงาน ดังโค้ดต่อไปนี้

#include <Ticker.h>

Ticker tm500ms;

void  myToggle() {
  int state = digitalRead(LED_BUILTIN);  // get the current state of GPIO1 pin
  digitalWrite(LED_BUILTIN, !state);     // set pin to the opposite state
}

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  tm500ms.attach(0.5, myToggle);
}

void loop() {
}

เมื่อสังเกตหลักการทำงานของทั้ง 2 โปรแกรมจะพบว่า โปรแกรมแรกนั้นสั่งเปิด (หรือปิด) แล้วหน่วงเวลาไป 500 มิลลิวินาที หลังจากนั้น สั่งปิด (หรือเปิด) แล้วหน่วงเวลาอีก 500 มิลลิวินาที จึงทำให้เวลาที่ใช้ไปจริง ๆ เกิน 1 วินาที แต่ในโปรแกรมที่ 2 เมื่อใช้ Ticker จะเกิดการทำงานทุก 500 มิลลิวินาที หมายความว่าเมื่อครบเวลาที่ตั้งไว้โปรแกรมจะทำการอ่านสถานะของขา LED_BUILTIN และกลับค่าเพื่อส่งผลให้หลอดสลับการติดหรือดับ แล้วสิ้นสุดการทำงาน และเมื่อครบ 500 มิลลิวินาทีอีกครั้งจะทำการสลับผลการติดหรือดับอีกครั้ง ดังนั้น การเขียนในแบบที่ 2 มีผลให้ 1 วินาที หรือใกล้เคียง 1 วินาทีจะเกิดการติดและดับ 1 วงรอบ ส่งผลให้ในเวลาที่เหลืออยู่นั้นสามารถเขียนโปรแกรมให้ทำงานอื่นได้ เพราะเมื่อครบเวลาที่ตั้งไว้จะหยุดงานที่ทำอยู่และกลับไปตอบสนองการสั่งเปิด/ปิด แต่ในวิธีแรกนั้นต้องเสียเวลาในการ delay()

สรุป

จากบทความนี้จะพบว่า Ticker รองรับการทำงานในเรื่องของการตั้งเวลา โดยรองรับทั้งการตั้งเวลาให้ทำทุกเวลาที่กำหนด และสามารถยกเลิกการทำงานในภายหลังได้ กับตั้งเวลาเพื่อให้เรียกใช้งานเพียงครั้งเดียว ซึ่งเมื่อนำไปประยุกต์กับการใช้งานในลักษณะของการตั้งเวลาให้ไมโครคอนโทรลเลอร์เก็บค่าจาก DHT11 ในทุก 1 นาที จะทำให้สามารถเก็บฐานข้อมูลอุณหภูมิและความชื้นที่ละเอียดเป็นทุก 1 นาทีได้ด้วย หรือประยุกต์เป็นตัวนาฬิกาได้เช่นกันซึ่งทั้งหมดนี้ขึ้นอยู่กับประสบการ์และการนำไปประยุกต์ใช้ สุดท้ายขอให้สนุกกับการเขียนโปรแกรมครับ

แหล่งอ้างอิง

  1. Github: esp8266/Arduino/Libraries/Ticker

(C) 2020-2021, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ

ปรับปรุงเมื่อ 2021-08-12, 2021-11-22