RTOS چیست؟
هر وقت کلمهی “سیستمعامل” را میشنویم ناخودآگاه به یاد سیستمعاملهای لینوکس، مک، ویندوز، بیاسدی و دیگر سیستمعاملهای آشنا میافتیم!
کار اصلی یک سیستمعامل مدیریت منابع و ایجاد هماهنگی بین اجزاء یک سیستم و برنامهها است. در سیستمعاملهای رایج، مدیریت منابع سیستم بین برنامههای در حال اجرا تقسیم میشود و تمرکز بر ایجاد تعادل بین برنامهها است. این دسته از سیستمعاملها برای اجراشدن نیاز به سختافزار قوی و میزان حافظه زیادی دارند که پیادهسازی آنها را بر روی سیستمهای مبتنی بر میکروکنترلر غیرممکن میکند. اما نگران نباشید! سیستمعاملهای دیگری وجود دارند که برای کار بر روی میکروکنترلرها طراحی و ساختهشدهاند. ممکن است فکر کنید که “با محدودیت موجود در ساختار یک میکروکنترلر، چه منابعی وجود دارد که به مدیریت نیاز دارد؟ حجم برنامهها و تعداد سختافزارهای در دسترس اینقدر محدود است که نیاز به مدیریت خاصی ندارد.” در پاسخ به این سؤال باید عنوان کنم که یکی از اساسیترین و کلیدیترین منابع موجود در هر سیستمی، زمان است! شما در طراحی هر سیستمی نیاز دارید که بهصورت صحیح زمان را مدیریت کنید. اگر بعد از اعمال ورودیها، سیستم در زمان مناسب قادر به ارائه خروجی نباشد، به این سیستم نمیتوان به چشم یک سیستم کاربردی نگاه کرد. بهعنوانمثال خودرویی تمام هوشمند را فرض کنید که با سرعت ۶۰ کیلومتر بر ساعت در حال حرکت است و مانعی را شناسایی میکند. اگر نتواند بهموقع بعد از شناسایی مانع عکسالعمل نشان داده و خودرو را متوقف کند، خودرو با مانع برخورد کرده و باعث ایجاد خسارت خواهد شد. پس همانطور که مشاهده میکنید مدیریت زمان، مخصوصاً در سیستمهای کنترلی از اهمیت بسیار بالایی برخوردار است. مدیریت زمان با اتکا به سیستم سنتی Super Loop شاید برای برنامههای ساده و کوچک عملی باشد؛ ولی عملاً در برنامههای پیچیده غیرممکن خواهد بود. مثلاً برای پیادهسازی یک خلبان خودکار یا سیستمهای پزشکی که زمان اهمیت بالایی دارد نمیتوان از Super Loop برای کنترل برنامه استفاده کرد و سیستم بهسرعت دچار خطا خواهد شد. برای رفع این مشکل، سیستمعاملهایی خاص طراحیشدهاند که مدیریت زمان را به بهترین نحو ممکن انجام میدهند. این دستهی خاص از سیستمعاملها real-time operating system نام دارند که بهاختصار RTOS خوانده میشوند. همانطور که از نام این سیستمعاملها بر میآید، تخصص آنها در مدیریت زمان است.
RTOS چگونه زمان را مدیریت میکند؟
در سیستمهای مبتنی بر RTOS، هر وظیفه (Task) به شکل یک Super Loop مجزا و ایزوله (به لحاظ فضای حافظه) از بقیه وظیفهها در نظر گرفته میشود و میتوان با توجه به اهمیت وظیفهی مربوطه، آنها را دستهبندی کرد. بهعنوانمثال فرض کنید قصد داریم سیستم راننده خودکار را پیادهسازی کنیم. برای شروع سیستم ما سه وظیفه اساسی خواهد داشت: تشخیص مانع، رانندگی کردن و پخش موزیک! اگر همهی وظایف محوله به سیستم در یک اولویت قرار گیرند، قطعاً سیستم بهدرستی کار نخواهد کرد؛ چراکه هنگام پخش موزیک فراموش میکند که جاده را اسکن کرده و موانع را تشخیص دهد. اما بهراحتی میتوان اولویتها را تغییر داد: یعنی تشخیص موانع بالاترین اولویت را داشته باشد. بعدازآن رانندگی و در آخر پخش موزیک! قطعاً همه ترجیح میدهند که سالم از ماشین خود پیاده شوند تا اینکه یک موزیک را بدون اختلال گوش کرده باشند!
با توجه به تصویر فوق، وظیفه قرمز (Task 1) بالاترین اولویت را دارا خواهد بود؛ یعنی تشخیص موانع. بعدازآن رانندگی است که بارنگ آبی (Task 2) مشخصشده و در آخر پخش موزیک که بارنگ سبز (Task 3) نشان دادهشده است. همانطور که در تصویر مشاهده میکنید در طول زمان اول لازم است جاده برای تشخیص موانع اسکن شود و بعدازآن سیستم به رانندگی بپردازد و اگر زمان باقی ماند، موزیک پخش کند. برای همین است که Task3 دارای زمان یکسانی برای اجرا نیست!
از کدام RTOS استفاده کنم؟
امروزه انواع بسیار زیادی از RTOS ها در دسترس هستند؛ از RTOS های تجاری که توسط شرکتهای بزرگ، طراحی و پیادهسازی شدهاند تا RTOS های رایگان و متنبازی که توسط هزاران برنامهنویس در سراسر جهان توسعه یافتهاند. با توجه به این میزان تنوع در انتخاب، قطعاً باید معیارهای زیر را برای انتخاب درست در نظر گرفت که در ادامه دچار مشکل نشویم:
- محدودیتهای سختافزار
- نوع کار تعریفشده
- میزان حساسیت آن
در خصوص معیار اول، قطعاً شما نمیتوانید RTOS ای که برای هستههای ARM پایهریزی شده است را بر روی AVR استفاده کنید و یا برعکس. همچنین هر سیستمعاملی برای راهاندازی نیاز به یک حداقل Ram و حافظه برنامه خواهد داشت که باید آن را در نظر گرفت. بهعنوان نمونه شما نمیتوانید از ucLinux بر روی AVR بهره ببرید چراکه برای اجرای این سیستمعامل نیاز به چند ده مگابایت رم دارید؛ درصورتیکه بالاترین میزان حافظه در AVR چند ده کیلوبایت است.
مسئله مهم بعد میزان حساسیت کار است. میزان حساسیت کار سیستمی که خط تولید یک کارخانه را کنترل کند، چندان بالا نیست و میتوان از یک RTOS معمولی هم استفاده کرد. ولی اگر قصد طراحی سیستمی داشته باشید که خلبان خودکار یک وسیله پرنده باشد، قطعاً باید از RTOS خاص، با مدیریت دقیق زمان و ضریب اطمینان بسیار بالا استفاده کنید(برای مشاهده لیست RTOS های موجود میتوانید به سایت osrtos مراجعه کنید).
ما در این مقاله قصد داریم که نحوه راهاندازی و کانفیگ یکی از پرطرفدارترین RTOS های موجود را آموزش دهیم: FREE RTOS؛ که علاوه بر رایگان بودن متنباز هم هست و بهصورت خیلی ساده طراحیشده که قابلیت پشتیبانی از ۳۱ نوع میکروکنترلر متفاوت را دارا باشد. پس بهترین گزینه برای خیلی از پروژهها، این RTOS است.
نصب FREE RTOS بر روی آردوینو
برای شروع کار با FreeRTOS باید کتابخانههای لازم را بر روی ادیتور آردوینو نصب کنیم. جهت نصب ابتدا به منوی Sketch رفته و از زیر منوی Include Library گزینه Library Manager را انتخاب کنید.
بعدازآن از پنجره بازشده، واژه Free Rtos را جستجو کرده و سپس با فشردن کلید Install آن را نصب کنید.
چگونه با FREE RTOS یک پروژه ایجاد کنیم؟
ابتدا به منوی Sketch رفته و پس از آن از زیرمنوی Include Library گزینه FreeRtos را انتخاب میکنیم.
پس از انتخاب گزینه مربوطه، هدر Arduino_FreeRTOS.h به پروژه اضافه خواهد شد. دقت کنید که نصب سیستمعامل نیاز به فضای کافی دارد و در صورت نبود فضای کافی، با خطای کامپایلر هنگام کامپایل مواجه خواهید شد. با توجه به جدول زیر میتوانید فضای موردنیاز جهت FreeRTOS و مقدار حافظه موردنیاز وقتیکه از FreeRTOS استفاده نمیکنید را در بردهای مختلف مشاهده کنید.
// Device: loop() -> FreeRTOS | Additional Program Storage // Uno: 444 -> 7340 | 21% // Goldilocks: 502 -> 7408 | 6% // Leonardo: 3624 -> 10508 | 24% // Yun: 3618 -> 10502 | 24% // Mega: 656 -> 24108 | 9%
همانطور که مشخص است بر روی آردوینو Uno در حالت بدون سیستمعامل، بدون هیچ برنامهای ۴۴۴ بایت از حافظه کد اشغال خواهد شد و بعد از نصب سیستمعامل ۷۳۴۰ بایت که یعنی سیستمعامل فقط ۲۱ درصد از فضای برنامه را اشغال کرده است.
چگونگی شروع برنامه نویسی با Free Rtos
در برنامهی زیر ما سعی کردهایم که سادهترین برنامه ممکن را با استفاده از Free RTOS بنویسیم . درواقع کار برنامه این است که دو LED متصل به پورت های ۱۲ و ۱۳ را با سرعت متفاوتی به چشمک زدن وادار کند. برای این کار ما دو تسک ایجاد کردیم که یکی LED متصل به پورت ۱۲ و دیگری LED متصل به پورت ۱۳ را کنترل میکند.
#include <Arduino_FreeRTOS.h> // define two tasks for Blink void TaskBlink_One( void *pvParameters ); void TaskBlink_Two( void *pvParameters ); // the setup function runs once when you press reset or power the board void setup() { // Now set up two tasks to run independently. xTaskCreate( TaskBlink_One , (const portCHAR *)"Blink One" // A name just for humans , 128 // Stack size , NULL , 2 // priority , NULL ); xTaskCreate( TaskBlink_Two , (const portCHAR *) "Blink Two" , 128 // This stack size can be checked & adjusted by reading Highwater , NULL , 1 // priority , NULL ); } void loop() { // Empty. Things are done in Tasks. } /*--------------------------------------------------*/ /*---------------------- Tasks ---------------------*/ /*--------------------------------------------------*/ void TaskBlink_One(void *pvParameters) // This is a task. { (void) pvParameters; // initialize digital pin 13 as an output. pinMode(13, OUTPUT); for (;;) // A Task shall never return or exit. { digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level) vTaskDelay( 150 / portTICK_PERIOD_MS ); // wait for 150 Mili second digitalWrite(13, LOW); // turn the LED off by making the voltage LOW vTaskDelay( 150 / portTICK_PERIOD_MS ); // wait for 150 Mili second } } void TaskBlink_Two(void *pvParameters) // This is a task. { (void) pvParameters; // initialize digital pin 13 as an output. pinMode(12, OUTPUT); for (;;) // A Task shall never return or exit. { digitalWrite(12, HIGH); // turn the LED on (HIGH is the voltage level) vTaskDelay( 1000/ portTICK_PERIOD_MS ); // wait for one second digitalWrite(12, LOW); // turn the LED off by making the voltage LOW vTaskDelay( 1000/ portTICK_PERIOD_MS ); // wait for one second } }
منبع: سیسوگ