- RTOS ทำงานอย่างไร
- คำศัพท์ที่ใช้บ่อยใน RTOS
- การติดตั้ง Arduino FreeRTOS Library
- แผนภูมิวงจรรวม
- Arduino FreeRTOS ตัวอย่าง - การสร้างงาน FreeRTOS ใน Arduino IDE
- การติดตั้งงาน FreeRTOS ใน Arduino IDE
ระบบปฏิบัติการปัจจุบันภายในอุปกรณ์ฝังตัวที่เรียกว่าRTOS (Real-Time Operating System) ในอุปกรณ์ฝังตัวงานแบบเรียลไทม์เป็นสิ่งสำคัญที่เวลามีบทบาทสำคัญมาก งานแบบเรียลไทม์เป็นตัวกำหนดเวลาหมายถึงเวลาตอบสนองต่อเหตุการณ์ใด ๆ จะคงที่เสมอดังนั้นจึงสามารถรับประกันได้ว่าเหตุการณ์ใด ๆ จะเกิดขึ้นในเวลาที่กำหนด RTOS ได้รับการออกแบบมาเพื่อเรียกใช้แอปพลิเคชันที่มีการจับเวลาที่แม่นยำและมีความน่าเชื่อถือสูง RTOS ยังช่วยในการทำงานหลายอย่างด้วยแกนเดียว
เราได้กล่าวถึงบทช่วยสอนเกี่ยวกับวิธีใช้ RTOS ในระบบฝังตัวซึ่งคุณสามารถทราบข้อมูลเพิ่มเติมเกี่ยวกับ RTOS ความแตกต่างระหว่างระบบปฏิบัติการทั่วไปและ RTOS RTOS ประเภทต่างๆเป็นต้น
ในการกวดวิชานี้เราจะเริ่มต้นด้วยFreeRTOSFreeRTOS เป็นคลาสของ RTOS สำหรับอุปกรณ์ฝังตัวซึ่งมีขนาดเล็กพอที่จะทำงานบนไมโครคอนโทรลเลอร์ 8/16 บิตแม้ว่าการใช้งานจะไม่ จำกัด เฉพาะไมโครคอนโทรลเลอร์เหล่านี้ มันเป็นโอเพ่นซอร์สที่สมบูรณ์และมีรหัสอยู่ใน github หากเราทราบแนวคิดพื้นฐานของ RTOS แล้วการใช้ FreeRTOS นั้นง่ายมากเนื่องจากมี API ที่มีเอกสารอย่างดีซึ่งสามารถใช้โดยตรงในโค้ดโดยไม่ทราบถึงส่วนแบ็กเอนด์ของการเข้ารหัส สามารถดูเอกสาร FreeRTOS ฉบับสมบูรณ์ได้ที่นี่
เนื่องจาก FreeRTOS สามารถทำงานบน MCU 8 บิตจึงสามารถรันบนบอร์ด Arduino Uno ได้ เราต้องดาวน์โหลดไลบรารี FreeRTOS จากนั้นเริ่มติดตั้งโค้ดโดยใช้ API บทช่วยสอนนี้มีไว้สำหรับผู้เริ่มต้นที่สมบูรณ์ด้านล่างนี้เป็นหัวข้อที่เราจะกล่าวถึงในบทช่วยสอน Arduino FreeRTOSนี้:
- RTOS ทำงานอย่างไร
- คำศัพท์ที่ใช้บ่อยใน RTOS
- การติดตั้ง FreeRTOS ใน Arduino IDE
- วิธีสร้าง FreeRTOS Tasks พร้อมตัวอย่าง
RTOS ทำงานอย่างไร
ก่อนเริ่มด้วย RTOS มาดูกันว่า Task คืออะไร Task คือโค้ดส่วนหนึ่งที่สามารถกำหนดตารางเวลาบน CPU เพื่อดำเนินการได้ ดังนั้นหากคุณต้องการทำงานบางอย่างก็ควรกำหนดเวลาโดยใช้เคอร์เนลดีเลย์หรือใช้อินเทอร์รัปต์ งานนี้ทำโดย Scheduler ที่มีอยู่ในเคอร์เนล ในโปรเซสเซอร์ single-core ตัวกำหนดตารางเวลาช่วยให้งานดำเนินการในช่วงเวลาหนึ่ง ๆ แต่ดูเหมือนว่างานต่างๆจะดำเนินการพร้อมกัน ทุกงานดำเนินไปตามลำดับความสำคัญที่กำหนดไว้
ตอนนี้เรามาดูกันว่าจะเกิดอะไรขึ้นในเคอร์เนล RTOS หากเราต้องการสร้างงานสำหรับ LED กะพริบโดยมีช่วงเวลาหนึ่งวินาทีและกำหนดให้งานนี้มีลำดับความสำคัญสูงสุด
นอกเหนือจากงาน LED แล้วยังมีอีกหนึ่งงานที่เคอร์เนลสร้างขึ้นซึ่งเรียกว่างานที่ไม่ได้ใช้งาน. งานที่ไม่ได้ใช้งานถูกสร้างขึ้นเมื่อไม่มีงานให้ดำเนินการ งานนี้จะทำงานบนลำดับความสำคัญต่ำสุดคือลำดับความสำคัญ 0 เสมอ หากเราวิเคราะห์กราฟเวลาที่ระบุข้างต้นจะเห็นได้ว่าการดำเนินการเริ่มต้นด้วยงาน LED และจะทำงานตามเวลาที่กำหนดจากนั้นในช่วงเวลาที่เหลืองานที่ไม่ได้ใช้งานจะทำงานจนกว่าจะมีการขัดจังหวะการทำเครื่องหมาย จากนั้นเคอร์เนลจะตัดสินใจว่างานใดจะต้องดำเนินการตามลำดับความสำคัญของงานและเวลาที่ผ่านไปทั้งหมดของงาน LED เมื่อเสร็จสิ้น 1 วินาทีเคอร์เนลจะเลือกงานนำอีกครั้งเพื่อดำเนินการเนื่องจากมีลำดับความสำคัญสูงกว่างานที่ไม่ได้ใช้งานเราสามารถพูดได้ว่างาน LED จะป้องกันงานที่ไม่ได้ใช้งาน หากมีงานมากกว่าสองงานที่มีลำดับความสำคัญเท่ากันงานเหล่านั้นจะดำเนินการแบบปัดเศษตามเวลาที่กำหนด
ด้านล่างแผนภาพสถานะจะแสดงการเปลี่ยนงานที่ไม่ได้ทำงานเป็นสถานะกำลังทำงาน
งานที่สร้างขึ้นใหม่ทั้งหมดจะอยู่ในสถานะพร้อม (ส่วนหนึ่งของสถานะไม่ทำงาน) หากงานที่สร้างขึ้น (Task1) มีลำดับความสำคัญสูงสุดกว่างานอื่น ๆ งานนั้นจะย้ายไปที่สถานะกำลังทำงาน หากงานที่กำลังรันอยู่นี้ถูกแย่งชิงโดยงานอื่นงานนั้นจะกลับไปสู่สถานะพร้อมอีกครั้ง หาก Task1 ถูกบล็อกโดยใช้ API การบล็อก CPU จะไม่เข้าร่วมกับงานนี้จนกว่าจะหมดเวลาที่กำหนดโดยผู้ใช้
หาก Task1 ถูกระงับในสถานะการทำงานโดยใช้ Suspend APIs Task1 จะเข้าสู่สถานะ Suspended และจะไม่พร้อมใช้งานสำหรับตัวกำหนดตารางเวลาอีก หากคุณกลับมาใช้งาน Task1 ต่อในสถานะที่ถูกระงับมันจะกลับสู่สถานะพร้อมดังที่คุณเห็นในแผนภาพบล็อก
นี่คือความคิดพื้นฐานของวิธีการเรียกใช้งานและเปลี่ยนสถานะของพวกเขาในบทช่วยสอนนี้เราจะใช้งานสองอย่างใน Arduino Uno โดยใช้ FreeRTOS API
คำศัพท์ที่ใช้บ่อยใน RTOS
1. งาน:เป็นส่วนหนึ่งของรหัสที่กำหนดเวลาบน CPU เพื่อดำเนินการได้
2. เครื่องมือจัดกำหนดการ:มีหน้าที่ในการเลือกงานจากรายการสถานะพร้อมเป็นสถานะกำลังทำงาน ตัวกำหนดเวลามักจะถูกนำมาใช้เพื่อให้ทรัพยากรคอมพิวเตอร์ทั้งหมดไม่ว่าง (เช่นเดียวกับการจัดสรรภาระงาน)
3. ใบจอง:เป็นการขัดขวางงานที่กำลังดำเนินการอยู่ชั่วคราวโดยมีเจตนาที่จะลบออกจากสถานะที่กำลังดำเนินการอยู่
4. การสลับบริบท:ในใบจองตามลำดับความสำคัญตัวกำหนดตารางเวลาจะเปรียบเทียบลำดับความสำคัญของงานที่กำลังรันกับลำดับความสำคัญของรายการงานที่พร้อมใช้งานในทุกการขัดจังหวะของ systick หากมีงานใดในรายการที่มีลำดับความสำคัญสูงกว่างานที่รันอยู่การสลับบริบทจะเกิดขึ้น โดยทั่วไปในกระบวนการนี้เนื้อหาของงานต่าง ๆ จะถูกบันทึกไว้ในหน่วยความจำสแต็กตามลำดับ
5. ประเภทของนโยบายการจัดกำหนดการ:
- การจัดกำหนดการล่วงหน้า:ในการจัดกำหนดการประเภทนี้งานจะทำงานโดยแบ่งเวลาเท่ากันโดยไม่คำนึงถึงลำดับความสำคัญ
- Preemptive ตามลำดับความสำคัญ:งานที่มีลำดับความสำคัญสูงจะทำงานก่อน
- การจัดตารางเวลาความร่วมมือ: การสลับบริบทจะเกิดขึ้นเฉพาะกับความร่วมมือในการทำงาน งานจะทำงานอย่างต่อเนื่องจนกว่าจะมีการเรียกผลตอบแทนของงาน
6. เคอร์เนลออบเจ็กต์: สำหรับการส่งสัญญาณงานเพื่อทำงานบางอย่างจะใช้กระบวนการซิงโครไนซ์ ในการดำเนินการกระบวนการนี้จะใช้วัตถุเคอร์เนล เคอร์เนลออบเจ็กต์บางอย่าง ได้แก่ เหตุการณ์, เซมาโฟเรส, คิว, มิวเท็กซ์, เมลบ็อกซ์เป็นต้นเราจะดูวิธีใช้อ็อบเจกต์เหล่านี้ในบทช่วยสอนที่กำลังจะมาถึง
จากการสนทนาข้างต้นเรามีแนวคิดพื้นฐานเกี่ยวกับแนวคิด RTOS และตอนนี้เราสามารถใช้โครงการ FreeRTOS ใน Arduino ได้แล้ว ดังนั้นขอเริ่มต้นโดยการติดตั้งห้องสมุด FreeRTOS ใน Arduino IDE
การติดตั้ง Arduino FreeRTOS Library
1. เปิด Arduino IDE และไปที่ ร่าง -> รวม Library -> จัดการห้องสมุด ค้นหา FreeRTOS และติดตั้งไลบรารีดังที่แสดงด้านล่าง
คุณสามารถดาวน์โหลดไลบรารีจาก github และเพิ่มไฟล์. zip ใน Sketch-> รวมไลบรารี -> เพิ่ม ไฟล์ . zip
ตอนนี้รีสตาร์ท Arduino IDE ไลบรารีนี้มีโค้ดตัวอย่างบางส่วนซึ่งสามารถพบได้ใน ไฟล์ -> ตัวอย่าง -> FreeRTOS ดังที่แสดงด้านล่าง
ที่นี่เราจะเขียนโค้ดตั้งแต่เริ่มต้นเพื่อทำความเข้าใจการทำงานหลังจากนั้นคุณสามารถตรวจสอบโค้ดตัวอย่างและใช้งานได้
แผนภูมิวงจรรวม
ด้านล่างนี้เป็นแผนภาพวงจรสำหรับสร้างงานกะพริบ LED โดยใช้ FreeRTOS บน Arduino:
Arduino FreeRTOS ตัวอย่าง - การสร้างงาน FreeRTOS ใน Arduino IDE
มาดูโครงสร้างพื้นฐานในการเขียนโครงการ FreeRTOS
1. ขั้นแรกรวมไฟล์ส่วนหัว Arduino FreeRTOS เป็น
# รวม
2. ให้ฟังก์ชันต้นแบบของฟังก์ชันทั้งหมดที่คุณกำลังเขียนเพื่อดำเนินการซึ่งเขียนเป็น
โมฆะ Task1 (โมฆะ * pvParameters); โมฆะ Task2 (โมฆะ * pvParameters); .. ….
3. ตอนนี้ในฟังก์ชัน void setup () ให้สร้างงานและเริ่มตัวกำหนดตารางเวลางาน
สำหรับการสร้างงาน xTaskCreate () API ถูกเรียกในฟังก์ชัน การตั้งค่า พร้อมพารามิเตอร์ / อาร์กิวเมนต์บางอย่าง
xTaskCreate (TaskFunction_t pvTaskCode, const char * const pcName, uint16_t usStackDepth, void * pvParameters, UBaseType_t uxPriority, TaskHandle_t * pxCreatedTask);
มีข้อโต้แย้ง 6 ข้อที่ควรส่งผ่านขณะสร้างงานใด ๆ มาดูกันว่าข้อโต้แย้งเหล่านี้คืออะไร
- pvTaskCode:เป็นเพียงตัวชี้ไปยังฟังก์ชันที่ดำเนินการตามภารกิจ (มีผลเฉพาะชื่อของฟังก์ชัน)
- pcName:ชื่อที่สื่อความหมายสำหรับงาน FreeRTOS ไม่ได้ใช้ รวมไว้เพื่อวัตถุประสงค์ในการดีบักเท่านั้น
- usStackDepth:แต่ละงานมีสแต็กเฉพาะของตัวเองที่เคอร์เนลจัดสรรให้กับงานเมื่องานถูกสร้างขึ้น ค่านี้ระบุจำนวนคำที่สแต็กสามารถเก็บได้ไม่ใช่จำนวนไบต์ ตัวอย่างเช่นหากสแต็กมีความกว้าง 32 บิตและ usStackDepth ถูกส่งผ่านเป็น 100 ดังนั้นพื้นที่สแต็ก 400 ไบต์จะถูกจัดสรร (100 * 4 ไบต์) ใน RAM ใช้สิ่งนี้อย่างชาญฉลาดเพราะ Arduino Uno มี RAM เพียง 2Kbytes
- pvParameters:พารามิเตอร์อินพุตงาน (สามารถเป็น NULL)
- uxPriority:ลำดับความสำคัญของงาน (0 คือลำดับความสำคัญต่ำสุด)
- pxCreatedTask:สามารถใช้เพื่อส่งหมายเลขอ้างอิงไปยังงานที่สร้างขึ้น จากนั้นสามารถใช้แฮนเดิลนี้เพื่ออ้างอิงงานในการเรียก API เช่นเปลี่ยนลำดับความสำคัญของงานหรือลบงาน (อาจเป็น NULL)
ตัวอย่างการสร้างงาน
xTaskCreate (task1, "task1", 128, NULL, 1, NULL); xTaskCreate (งาน 2, "task2", 128, NULL, 2, NULL);
ที่นี่ Task2 มีลำดับความสำคัญสูงกว่าและดำเนินการก่อน
4. หลังจากสร้างงานแล้วให้เริ่มตัวกำหนดตารางเวลาในการตั้งค่าโมฆะโดยใช้vTaskStartScheduler (); API
5. ฟังก์ชัน Void loop () จะยังคงว่างเปล่าเนื่องจากเราไม่ต้องการเรียกใช้งานใด ๆ ด้วยตนเองและไม่สิ้นสุด เนื่องจากขณะนี้การเรียกใช้งานถูกจัดการโดย Scheduler
6. ตอนนี้เราต้องใช้ฟังก์ชันงานและเขียนตรรกะที่คุณต้องการดำเนินการภายในฟังก์ชันเหล่านี้ ชื่อฟังก์ชันควรเหมือนกับอาร์กิวเมนต์แรกของ xTaskCreate () API
เป็นโมฆะ task1 (โมฆะ * pvParameters) { while (1) { .. ..// ตรรกะของคุณ } }
7. โค้ดส่วนใหญ่ต้องการฟังก์ชันดีเลย์เพื่อหยุดงานที่กำลังทำงานอยู่ แต่ใน RTOS ไม่แนะนำให้ใช้ฟังก์ชัน Delay () เนื่องจากจะหยุดทำงานของ CPU และด้วยเหตุนี้ RTOS ก็หยุดทำงานเช่นกัน ดังนั้น FreeRTOS จึงมี kernel API เพื่อบล็อกงานในช่วงเวลาหนึ่ง
vTaskDelay (const TickType_t xTicksToDelay);
API นี้สามารถใช้เพื่อวัตถุประสงค์ในการหน่วงเวลา API นี้หน่วงเวลางานสำหรับจำนวนเห็บที่กำหนด เวลาจริงที่งานยังคงถูกบล็อกจะขึ้นอยู่กับอัตราติ๊ก สามารถใช้ พอร์ต TICK_PERIOD_MS คงที่เพื่อคำนวณแบบเรียลไทม์จากอัตราติ๊ก
ซึ่งหมายความว่าหากคุณต้องการความล่าช้า 200ms ให้เขียนบรรทัดนี้
vTaskDelay (200 / portTICK_PERIOD_MS);
ดังนั้นสำหรับบทช่วยสอนนี้เราจะใช้FreeRTOS APIเหล่านี้เพื่อใช้งานสามอย่าง
API ที่จะใช้:
- xTaskCreate ();
- vTaskStartScheduler ();
- vTaskDelay ();
งานที่จะสร้างสำหรับบทช่วยสอนนี้:
- LED กะพริบที่ Digital pin 8 ด้วยความถี่ 200ms
- LED กะพริบที่ Digital pin 7 ด้วยความถี่ 300ms
- พิมพ์หมายเลขในจอภาพอนุกรมด้วยความถี่ 500ms
การติดตั้งงาน FreeRTOS ใน Arduino IDE
1. จากคำอธิบายโครงสร้างพื้นฐานข้างต้นให้รวมไฟล์ส่วนหัว Arduino FreeRTOS จากนั้นสร้างต้นแบบฟังก์ชัน เนื่องจากเรามีงานสามอย่างดังนั้นให้สร้างฟังก์ชันสามอย่างและเป็นต้นแบบ
# รวม โมฆะ TaskBlink1 (โมฆะ * pvParameters); โมฆะ TaskBlink2 (โมฆะ * pvParameters); โมฆะ Taskprint (โมฆะ * pvParameters);
2. ในฟังก์ชัน void setup () เริ่มต้นการสื่อสารแบบอนุกรมที่ 9600 บิตต่อวินาทีและสร้างทั้งสามงานโดยใช้ xTaskCreate () API เริ่มแรกจัดลำดับความสำคัญของงานทั้งหมดเป็น '1' และเริ่มตัวกำหนดตารางเวลา
การตั้งค่าเป็นโมฆะ () { Serial.begin (9600); xTaskCreate (TaskBlink1, "Task1", 128, NULL, 1, NULL); xTaskCreate (TaskBlink2, "Task2", 128, NULL, 1, NULL); xTaskCreate (Taskprint, "Task3", 128, NULL, 1, NULL); vTaskStartScheduler (); }
3. ตอนนี้ใช้ทั้งสามฟังก์ชั่นที่แสดงด้านล่างสำหรับพริบ LED task1
โมฆะ TaskBlink1 (โมฆะ * pvParameters) { pinMode (8, OUTPUT); ในขณะที่ (1) { digitalWrite (8, สูง); vTaskDelay (200 / portTICK_PERIOD_MS); digitalWrite (8, ต่ำ); vTaskDelay (200 / portTICK_PERIOD_MS); } }
ในทำนองเดียวกันการใช้ฟังก์ชั่น TaskBlink2 ฟังก์ชัน Task3จะเขียนเป็น
โมฆะ Taskprint (โมฆะ * pvParameters) { int counter = 0; ในขณะที่ (1) {ตัว นับ ++; Serial.println (ตัวนับ); vTaskDelay (500 / portTICK_PERIOD_MS); } }
แค่นั้นแหละ. เราได้ทำโครงการFreeRTOS Arduinoสำหรับ Arduino Uno สำเร็จแล้ว คุณสามารถค้นหาโค้ดแบบเต็มพร้อมกับวิดีโอในตอนท้ายของบทช่วยสอนนี้
สุดท้ายเชื่อมต่อ LED สองดวงที่พินดิจิทัล 7 และ 8 แล้วอัปโหลดรหัสบนบอร์ด Arduino ของคุณและเปิดจอภาพอนุกรม คุณจะเห็นตัวนับทำงานหนึ่งครั้งใน 500 มิลลิวินาทีพร้อมชื่องานดังที่แสดงด้านล่าง
นอกจากนี้ให้สังเกตไฟ LED ที่กะพริบในช่วงเวลาที่ต่างกัน พยายามเล่นกับอาร์กิวเมนต์ลำดับความสำคัญในฟังก์ชัน xTaskCreate เปลี่ยนหมายเลขและสังเกตลักษณะการทำงานของมอนิเตอร์แบบอนุกรมและ LED
ตอนนี้คุณสามารถเข้าใจรหัสตัวอย่างสองตัวแรกที่สร้างงานการอ่านแบบอะนาล็อกและการอ่านแบบดิจิทัล ด้วยวิธีนี้คุณสามารถสร้างโปรเจ็กต์ขั้นสูงได้มากขึ้นโดยใช้ Arduino Uno และ FreeRTOS API