ในการทำงานบางประเภทบนระบบฝังตัว เช่น การสุ่มสัญญาณ การอิมพลิเมนต์ตัวควบคุมเชิงเส้น สิ่งสำคัญที่ต้องคำนึงถึงคือคาบเวลาของการประมวลผลที่จะต้องมีความแม่นยำและสามารถกำหนดได้ในโปรแกรม วิธีการง่ายสุดคือการใช้คำสั่ง delay() เพื่อหน่วงเวลา แต่จะไม่ได้รวมเวลาการคำนวณอัลกอริทึมเข้าไปด้วย ซึ่งจะมีความคลาดเคลื่อนสูงโดยเฉพาะสำหรับระบบที่ต้องการคาบเวลาการทำงานสั้นมาก ในบทความนี้รวบรวมวิธีการกำหนดคาบเวลาสำหรับ ESP8266 โดยอาศัยไทเมอร์หรือการอ่านค่าฐานเวลาจากระบบ สำหรับตัวประมวลผล ESP32 จะมีไลบรารี FreeRTOS ช่วยให้การกำหนดทาสก์รายคาบทำได้ง่ายและเป็นระบบ
การใช้ไทเมอร์แบบซอฟต์แวร์
อธิบายโดยสังเขป ไทเมอร์แบบซอฟต์แวร์ (software timer) คือการใช้ไทเมอร์ของตัวประมวลผลในลักษณะที่มีส่วนของโปรแกรมห่อหุ้มอยู่อีกชั้นหนึ่ง อาศัยฐานเวลาจากฮาร์ดแวร์เป็นตัวกำหนดความละเอียด นิยมเรียกว่า “ติ๊ก” เปรียบได้กับเข็มวินาทีของนาฬิกา ดังนั้นการกำหนดค่าคาบเวลาจะกระทำกับซอฟต์แวร์โดยไม่ได้เปลี่ยนแปลงคาบเวลาของฮาร์ดแวร์ไทเมอร์แต่อย่างใด
วิธีที่ 1
ตัวอย่างในหนังสือ
"ระบบควบคุมและอินเทอร์เน็ตเชื่อมต่อสรรพสิ่ง" ผู้เขียนได้ใช้คำสั่งสำหรับสร้าง ซอฟต์แวร์ไทเมอร์ ซึ่งเป็นวิธีหนึ่งในการกำหนดให้อัลกอริทึมทำงานทุกครั้งที่เกิดอินเทอร์รัพท์ ในที่นี้จะแสดงคำสั่งที่ใช้อีกครั้งหนึ่งสำหรับอ้างอิง
หมายเหตุ : การใช้วิธีนี้ต้องเพิ่มคำสั่งนี้ที่ต้นโปรแกรม
extern "C" {
#include "user_interface.h"
}
นิยามแฮนเดิลของไทเมอร์ที่ส่วนบนของโปรแกรม
os_timer_t myTimer;
กำหนดคาบเวลาที่ต้องการ เช่น 80 มิลลิวินาที
float T = 0.08;
ในฟังก์ชัน setup() ใช้คำสั่งดังนี้เพื่อตั้งคาบเวลาและฟังก์ชันตอบสนองอินเทอร์รัพท์
os_timer_setfn(&myTimer, timerCallback, NULL);
os_timer_arm(&myTimer, 1000*T, true);
สังเกตว่าการกำหนดคาบเวลาจะมีหน่วยเป็นมิลลิวินาที อัลกอริทึมที่เรียกทำงานทุกครั้งที่เกิดอินเทอร์รัพท์ถูกเขียนไว้ในฟังก์ชัน timerCallback()
void timerCallback(void *pArg) {
// implement periodic algorithm here
}
วิธีที่ 2
อีกวิธีหนึ่งในการใช้ไทเมอร์แบบซอฟต์แวร์คืออาศัยไลบรารี Ticker ซึ่งใช้งานค่อนข้างสะดวก เริ่มโดยเรียกไลบรารีที่ส่วนบนของโปรแกรม
#include <Ticker.h>
นิยามออปเจ็คแบบ Ticker และตัวแปรคาบเวลา
Ticker msticker;
int T_ms = 80; // milliseconds
หลังจากนั้นใน setup() กำหนดฟังก์ชันรายคาบและคาบเวลาโดยคำสั่งดังนี้
msticker.attach_ms(T_ms, timerCallback);
โดยในที่นี้ฟังก์ชันรายคาบคือ timerCallback() ที่นิยามเป็นแบบ void
void timerCallback() {
// implement your periodic algorithm here
}
หมายเหตุ : หากต้องการกำหนดคาบเวลาหน่วยเป็นวินาที สามารถใช้ msticker.attach() แทน
การใช้ไทเมอร์แบบฮาร์ดแวร์
วิธีการนี้จะโปรแกรมไทเมอร์ที่เป็นฮาร์ดแวร์บน ESP8266 โดยตรง ซึ่งจะมีไทเมอร์ 0 และ 1 แต่ ESP8266 จะใช้ไทเมอร์ 0 สำหรับการเชื่อมต่อ WiFi ดังนั้นไม่ควรใช้ไทเมอร์นี้ ตัวเลือกที่เหลือคือ timer 1
ข้อดีของการใช้ไทเมอร์แบบฮาร์ดแวร์ คือสามารถกำหนดความละเอียดได้เป็นหน่วยไมโครวินาที ตัวอย่างการตั้งค่าในฟังก์ชัน setup()
timer1_attachInterrupt(timerCallback);
timer1_isr_init();
timer1_enable(TIM_DIV16, TIM_EDGE, TIM_LOOP);
timer1_write(ticks);
ความสัมพันธ์ของ ticks กับตัวหารคือ
// TIM_DIV1 = 0, //80MHz (80 ticks/us - 104857.588 us max)
// TIM_DIV16 = 1, //5MHz (5 ticks/us - 1677721.4 us max)
// TIM_DIV256 = 3 //312.5Khz (1 tick = 3.2us - 26843542.4 us max)
อัลกอริทึมที่เรียกใช้เขียนไว้ใน timerCallback() ที่นิยามดังนี้
void ICACHE_RAM_ATTR timerCallback(void) {
// implement your periodic algorithm here
}
การตรวจสอบเวลาปัจจุบันจาก ESP8266
นับตั้งแต่จ่ายไฟเลี้ยงให้อุปกรณ์ ESP8266 จะมีฐานเวลาของตัวเองที่เพิ่มขึ้นเรื่อยๆ โดยอ่านค่าได้ตลอดเวลาทั้งแบบหน่วยเป็นไมโครวินาทีและมิลลิวินาที ดังนั้นสามารถใช้วิธีอ่านค่าเวลาและสร้างเงื่อนไขในการประมวลผลอัลกอริทึมต่อเมื่อค่าเวลานับจากการรันครั้งสุดท้ายเท่ากับหรือมากกว่าคาบเวลาที่ตั้งไว้ ในกรณีนี้อัลกอริทึมสามารถใส่ไว้ในฟังก์ชัน loop()
ตัวอย่างการตั้งค่าคาบเวลาเท่ากับ 80 มิลลิวินาที นิยามตัวแปร
unsigned long newmillis = 0, lastmillis=0;
unsigned long T_ms = 80;
ใน loop() ใช้เงื่อนไขดังนี้
newmillis = millis();
if (newmillis-lastmillis > T_ms) {
lastmillis = newmillis;
periodic_function();
}
โดยอัลอกริทึมรายคาบเขียนไว้ใน periodic_function() หากต้องการคาบเวลาหน่วยเป็นไมโครวินาที สามารถใช้ micros() โดยโครงสร้างของโปรแกรมจะไม่ต่างกัน
หมายเหตุ : ในตัวอย่างนี้ไม่ได้เขียนป้องกันกรณีเกิด overflow
periodic_blinks.zip : ตัวอย่างโปรแกรมสำหรับการตั้งค่ารายคาบวิธีต่างๆ ผลที่ได้คือ LED บนบอร์ดของ NodeMCU V2 จะกระพริบด้วยคาบเวลา 80 มิลลิวินาที
No comments:
Post a Comment