- איך עובד RTOS?
- מונחים נפוצים ב- RTOS
- התקנת ספריית Arduino FreeRTOS
- תרשים מעגל
- דוגמה ל- Arduino FreeRTOS- יצירת משימות FreeRTOS ב- Arduino IDE
- יישום משימות FreeRTOS ב- Arduino IDE
מערכת ההפעלה הקיימת בתוך המכשירים המשובצים נקראת RTOS (מערכת הפעלה בזמן אמת). במכשירים משובצים, משימות בזמן אמת הן קריטיות כאשר העיתוי ממלא תפקיד חשוב מאוד. משימות בזמן אמת הן זמן דטרמיניסטי פירושו שזמן התגובה לכל אירוע הוא תמיד קבוע, כך שניתן להבטיח שכל אירוע מסוים יתרחש בזמן קבוע. RTOS נועד להריץ יישומים בתזמון מדויק מאוד ובמידה גבוהה של אמינות. RTOS מסייע גם בריבוי משימות עם ליבה אחת.
כבר סקרנו הדרכה כיצד להשתמש ב- RTOS במערכות משובצות בהן תוכלו לדעת יותר על RTOS, ההבדל בין מערכת הפעלה כללית ל- RTOS, סוגים שונים של RTOS וכו '.
במדריך זה נתחיל ב- FreeRTOS. FreeRTOS הוא סוג של RTOS למכשירים משובצים שהוא קטן מספיק להפעלה במיקרו-בקרים 8/16 סיביות, אם כי השימוש בו אינו מוגבל למיקרו-בקרים אלה. זהו קוד פתוח לחלוטין והקוד שלו זמין ב- github. אם אנו מכירים כמה מושגים בסיסיים של RTOS, קל מאוד להשתמש ב- FreeRTOS מכיוון שיש לו ממשקי API מתועדים היטב שניתן להשתמש בהם ישירות בקוד מבלי לדעת את החלק האחורי של הקידוד. תיעוד FreeRTOS מלא ניתן למצוא כאן.
כמו FreeRTOS יכול לרוץ על 8-bit MCU כך זה יכול להיות מופעל גם על לוח Arduino Uno. עלינו פשוט להוריד את ספריית FreeRTOS ואז להתחיל ליישם את הקוד באמצעות ממשקי API. הדרכה זו מיועדת למתחילים שלמים, להלן הנושאים שנעסוק בהדרכה זו של Arduino FreeRTOS:
- איך עובד RTOS
- כמה מונחים בשימוש תכוף ב- RTOS
- התקנת FreeRTOS ב- Arduino IDE
- כיצד ליצור משימות FreeRTOS לדוגמא
איך עובד RTOS?
לפני שמתחילים בעבודה עם RTOS, בואו נראה מהי משימה. משימה היא פיסת קוד שניתן לתזמן על המעבד לביצוע. לכן, אם ברצונך לבצע משימה כלשהי, יש לתזמן אותה באמצעות עיכוב ליבה או באמצעות הפרעות. עבודה זו נעשית על ידי מתזמן שנמצא בגרעין. במעבד ליבה יחידה, מתזמן עוזר למשימות לבצע בפרוסת זמן מסוימת אך נראה שמשימות שונות מבוצעות בו זמנית. כל משימה פועלת על פי העדיפות שניתנה לה.
עכשיו, בואו נראה מה קורה בגרעין RTOS אם אנחנו רוצים ליצור משימה עבור מהבהב LED עם מרווח של שנייה ולשים משימה זו בעדיפות הגבוהה ביותר.
מלבד משימת ה- LED, תהיה עוד משימה אחת אשר נוצרת על ידי הליבה, היא ידועה כמשימה סרק. משימת הסרק נוצרת כאשר אין משימה זמינה לביצוע. משימה זו פועלת תמיד בעדיפות הנמוכה ביותר כלומר 0 עדיפות. אם אנו מנתחים את גרף התזמון שניתן לעיל, ניתן לראות כי הביצוע מתחיל במשימת LED והיא פועלת למשך זמן מוגדר ואז למשך הזמן הנותר, משימת הסרק פועלת עד שמתרחשת הפרעה בסימון. ואז הליבה מחליטה איזו משימה יש לבצע על פי עדיפות המשימה והזמן הכולל שחלף של משימת ה- LED. כאשר שנייה אחת הושלמה, הליבה בוחרת שוב את המשימה המובילה לביצוע מכיוון שיש לה עדיפות גבוהה יותר ממשימת הסרק, אנו יכולים גם לומר כי משימת ה- LED מקדימה את משימת הסרק. אם יש יותר משתי משימות עם אותה עדיפות אז הן יפעלו בצורה של רובין למשך זמן מוגדר.
מתחת לתרשים המצב כפי שהוא מראה את המעבר של המשימה שאינה פועלת למצב פועל.
כל משימה שנוצרה לאחרונה עוברת למצב מוכן (חלק ממצב שאינו פועל). אם למשימה שנוצרה (Task1) יש עדיפות גבוהה יותר ממשימות אחרות, היא תעבור למצב פועל. אם משימה ריצה זו מונעת מראש את המשימה האחרת, היא תחזור שוב למצב המוכן. אחרת אם משימה 1 נחסמת באמצעות חסימת ממשק API, אז המעבד לא יעסוק במשימה זו עד לפסק הזמן שהגדיר המשתמש.
אם משימה 1 מושעה במצב פועל באמצעות ממשקי API מושעים, משימה 1 תעבור למצב מושעה והיא לא תהיה זמינה לתזמון שוב. אם תחדש את משימת 1 במצב מושעה, היא תחזור למצב מוכן כפי שניתן לראות בתרשים הבלוקים.
זהו הרעיון הבסיסי כיצד משימות פועלות ומשנות את מצבן. במדריך זה נבצע שתי משימות ב- Arduino Uno באמצעות FreeRTOS API.
מונחים נפוצים ב- RTOS
1. משימה: זו חתיכת קוד שניתן לתזמן על המעבד לביצוע.
2. מתזמן: הוא אחראי לבחירת משימה מרשימת המצב המוכן למצב הריצה. מתזמנים מיושמים לעיתים קרובות כך שהם מעסיקים את כל משאבי המחשב (כמו באיזון עומסים).
3. פדיון: זהו פעולה של הפרעה זמנית של משימה שכבר מבצעת במטרה להוציא אותה מהמדינה הפועלת ללא שיתוף פעולה שלה.
4. החלפת הקשר: בקדימה מבוססת עדיפות, מתזמן משווה את העדיפות של ריצת משימות עם עדיפות של רשימת משימות מוכנה בכל הפרעת סיסטיק . אם יש משימה כלשהי ברשימה שעדיפותה גבוהה יותר מפעילת משימה, מתרחש החלפת הקשר. בעיקרון, בתהליך זה תוכן של משימות שונות נשמר בזיכרון הערימה שלהם.
5. סוגי מדיניות תזמון:
- תזמון מניעתי: בתזמון מסוג זה, המשימות פועלות עם פרוסת זמן שווה מבלי להתחשב בסדרי העדיפויות.
- עדיפות מבוססת עדיפות: משימת עדיפות גבוהה תפעל תחילה.
- תזמון שיתופי פעולה: החלפת הקשר יקרה רק בשיתוף פעולה של משימות הפעלה. המשימה תפעל ברציפות עד לביצוע המשימות.
6. אובייקטים ליבה: לצורך איתות המשימה לביצוע עבודה כלשהי, נעשה שימוש בתהליך הסנכרון. לביצוע תהליך זה משתמשים באובייקטים של ליבה. כמה אובייקטים מהליבה הם אירועים, סמפורים, תורים, Mutex, תיבות דואר וכו '. נראה כיצד להשתמש באובייקטים אלה בהדרכות הקרובות.
מהדיון לעיל יש לנו כמה רעיונות בסיסיים לגבי מושג RTOS וכעת נוכל ליישם את פרויקט FreeRTOS בארדואינו. אז בואו נתחיל בהתקנת ספריות FreeRTOS ב- Arduino IDE.
התקנת ספריית Arduino FreeRTOS
1. פתח את Arduino IDE ועבור אל סקיצה -> כלול ספרייה -> נהל ספריות . חפש FreeRTOS והתקן את הספרייה כמוצג להלן.
אתה יכול להוריד את הספרייה מ- github ולהוסיף את קובץ ה- zip ב- Sketch-> Include Library -> הוסף קובץ zip .
כעת, הפעל מחדש את ה- IDE של ארדואינו. ספרייה זו מספקת קוד לדוגמא כלשהו, גם אותו ניתן למצוא בקובץ -> דוגמאות -> FreeRTOS כפי שמוצג להלן.
כאן נכתוב את הקוד מאפס כדי להבין את העבודה, בהמשך תוכלו לבדוק את הקודים לדוגמא ולהשתמש בהם.
תרשים מעגל
להלן תרשים המעגל ליצירת משימת LED מהבהבת באמצעות FreeRTOS ב- Arduino:
דוגמה ל- Arduino FreeRTOS- יצירת משימות FreeRTOS ב- Arduino IDE
בואו נראה מבנה בסיסי לכתיבת פרויקט FreeRTOS.
1. ראשית, כלול את קובץ הכותרת של Arduino FreeRTOS כ-
#לִכלוֹל
2. תן את אב הטיפוס של הפונקציה של כל הפונקציות שאתה כותב לביצוע שנכתב כ
בטלה משימה 1 (בטל * pvParameters); בטל משימה 2 (בטל * pvParameters); .. ….
3. עכשיו, בפונקציה setup () ריק , צור משימות והפעל את מתזמן המשימות.
ליצירת משימה, API ל- xTaskCreate () נקרא בפונקציית ההתקנה עם פרמטרים / ארגומנטים מסוימים.
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 בתים) בזיכרון. השתמש בזה בחוכמה מכיוון ש- Arduino Uno מכיל זיכרון RAM בלבד של 2 קילו-בייט.
- pvParameters: פרמטר קלט משימה (יכול להיות NULL).
- uxPriority: עדיפות המשימה (0 היא העדיפות הנמוכה ביותר).
- pxCreatedTask: בעזרתו ניתן להעביר ידית למשימה שנוצרת. לאחר מכן ניתן להשתמש בידית זו כדי להפנות את המשימה בשיחות API, למשל, לשנות את עדיפות המשימה או למחוק את המשימה (יכולה להיות NULL).
דוגמה ליצירת משימות
xTaskCreate (task1, "task1", 128, NULL, 1, NULL); xTaskCreate (task2, "task2", 128, NULL, 2, NULL);
כאן, ל- Task2 יש עדיפות גבוהה יותר ולכן היא מבוצעת תחילה.
4. לאחר יצירת המשימה, הפעל את מתזמן ההתקנה הריק באמצעות vTaskStartScheduler (); ממשק API.
5. פונקציית Void loop () תישאר ריקה מכיוון שאיננו רוצים להפעיל שום משימה באופן ידני ואינסופי. מכיוון שביצוע המשימות מטופל כעת על ידי מתזמן.
6. כעת עלינו ליישם פונקציות משימות ולכתוב את הלוגיקה שברצונך לבצע בתוך פונקציות אלה. שם הפונקציה צריך להיות זהה לארגומנט הראשון של ה- API של xTaskCreate () .
void task1 (void * pvParameters) { while (1) { .. ..// ההיגיון שלך } }
7. רוב הקוד זקוק לפונקציית עיכוב בכדי לעצור את משימת ההפעלה אך ב- RTOS לא מומלץ להשתמש בפונקציה Delay () מכיוון שהוא מפסיק את המעבד ומכאן שגם RTOS מפסיק לעבוד. אז ל- FreeRTOS יש ממשק API ליבה לחסימת המשימה לזמן מסוים.
vTaskDelay (const TickType_t xTicksToDelay);
ניתן להשתמש בממשק API זה למטרות עיכוב. ממשק API זה מעכב משימה למספר תיקים מסוים. הזמן שבו המשימה נשארת חסומה בפועל תלוי בשיעור הסימון. ניתן להשתמש בנמל הקבוע TICK_PERIOD_MS לחישוב זמן אמת משיעור הסימון.
זה אומר שאם אתה רוצה עיכוב של 200 ms, פשוט כתוב את השורה הזו
vTaskDelay (200 / portTICK_PERIOD_MS);
אז לצורך הדרכה זו, נשתמש בממשקי ה- API האלה של FreeRTOS ליישום שלוש משימות.
ממשקי API לשימוש:
- xTaskCreate ();
- vTaskStartScheduler ();
- vTaskDelay ();
משימה שתיווצר עבור הדרכה זו:
- מהבהב LED בסיכה דיגיטלית 8 בתדר 200ms
- מהבהב LED בסיכה דיגיטלית 7 בתדר 300ms
- הדפס מספרים בצג סדרתי בתדירות של 500ms.
יישום משימות FreeRTOS ב- Arduino IDE
1. מההסבר המבני הבסיסי שלעיל, כלול את קובץ הכותרת של Arduino FreeRTOS. ואז הכינו אבות טיפוס לפונקציה. מכיוון שיש לנו שלוש משימות, אז בצע שלוש פונקציות וזה אבות טיפוס.
#include void TaskBlink1 (void * pvParameters); בטל TaskBlink2 (בטל * pvParameters); בטל משימה בטל (חלל * pvParameters);
2. בפונקציית ההתקנה הריקה () , אתחל תקשורת טורית ב 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. כעת, יישם את כל שלוש הפונקציות כפי שמוצג להלן עבור מהבהב נורית המשימות 1.
בטל TaskBlink1 (חלל * pvParameters) { pinMode (8, OUTPUT); בעוד (1) { digitalWrite (8, HIGH); vTaskDelay (200 / portTICK_PERIOD_MS); digitalWrite (8, LOW); vTaskDelay (200 / portTICK_PERIOD_MS); } }
באופן דומה, יישם את הפונקציה TaskBlink2. פונקציית Task3 תיכתב כ-
void Task Task (void * pvParameters) { int counter = 0; ואילו (1) { counter ++; Serial.println (מונה); vTaskDelay (500 / portTICK_PERIOD_MS); } }
זהו זה. סיימנו בהצלחה פרויקט FreeRTOS Arduino עבור Arduino Uno. תוכל למצוא קוד מלא יחד עם סרטון בסוף הדרכה זו.
לבסוף, חבר שני נוריות לסיכה הדיגיטלית 7 ו- 8 והעלה את הקוד בלוח Arduino שלך ופתח את הצג הסידורי. תראה שדלפק פועל פעם אחת ב 500ms עם שם המשימה כמוצג להלן.
כמו כן, התבונן בנוריות הנוריות, הן מהבהבות במרווחי זמן שונים. נסה לשחק עם טיעון העדיפות בפונקציה xTaskCreate . שנה את המספר וראה את ההתנהגות בצג סדרתי ובנורות LED.
כעת תוכלו להבין את שני הקודים לדוגמא הראשונים שבהם נוצרות משימות קריאה אנלוגיות ומשימות קריאה דיגיטליות. בדרך זו, תוכל לבצע פרויקטים מקדימים נוספים באמצעות ממשקי API בלבד של Arduino Uno ו- FreeRTOS.