در مجموعه آموزش های سیستم عامل FreeRTOS بر روی آردوینو، قسمت پنجم به یکی از مفاهیم کلیدی و پایه ای می پردازیم. در قسمت پیشین، به مفهوم سمافور پرداختیم. آن طور که از قسمت قبل به خاطر داریم، سمافور یکی از ابزارهای کلیدی جهت جلوگیری از تداخل در زمان همزمانی دسترسی به یک منبع مشترک توسط دو یا چندین Task است. تا پیش از این، مثال هایی که دیدیم همگی مربوط به اجرای مستقل Task ها بودند. گاهی نیاز است تا چندین Task اطلاعات خود را به Task دیگر ارسال کنند. به عنوان مثال دو Task وظیفه خواندن مقدار از ورودی آنالوگ و ارسال آن به Task دیگر دارند. در اینجا از مفهومی به نام صف استفاده می گردد. در این آموزش قصد بررسی مفهوم Queue صف را داریم. پس از بررسی مفهوم صف، به نحوه تبادل داده بین Task ها از این طریق خواهیم پرداخت. در نهایت با ارایه مثالی، نحوه انتقال داده بین دو Task از طریق صف را خواهیم آموخت. بنابراین در ادامه آموزش با مرجع تخصصی آردوینو به زبان فارسی، دیجی اسپارک، همراه باشید.
تعریف مفهوم Queue صف
یکی از مهم ترین ساختارهای داده در علوم رایانه، Queue صف است. مفهوم صف یکی از مفاهیم پایه ای در علوم رایانه محسوب می شود، به طوریکه در بسیاری از برنامه ها و حتی سیستم عامل از این مفهوم جهت پیاده سازی روش های تبادل داده، استفاده می شود. یک صف در سیستم کامپیوتری، دقیقا همان مفهوم صف در عالم واقع است. به عنوان مثال یک صف نانوایی را در نظر بگیرید. در این صف، افرادی که زودتر حاضر شده باشند، زودتر نان خود را دریافت کرده و از صف خارج می شوند.
در یک سیستم کامپیوتری نیز مفهوم Queue صف دقیقا مثل صف نانوایی است. پروسه های مختلفی جهت سرویس گرفتن در صف قرار می گیرند. به عنوان مثال در یک صف دیجیتالی، تعدادی پرینتر جهت دریافت فرمان از یک رایانه وارد صف می شوند. پس از ورودی به صف، سیستم عامل بر اساس ترتیب ورود، داده ها را به پرینترها ارسال می کند. سیستم عامل نیز یکی یکی به پرینترها داده ها را ارسال می کند. پس از دریافت داده توسط هر پرینتر، داده ها چاپ خواهند شد. برای پیاده سازی صف در یک برنامه، روش های مختلفی وجود دارد. یکی از ساده ترین و در دسترس ترین روش ها، استفاده از آرایه هاست. به کمک آرایه می توان به سادگی یک صف از داده ها تشکیل داد.
از دیگر روش های کلیدی جهت پیاده سازی Queue صف، استفاده از ساختار یا struct است. به کمک این مفهوم می توان در فرمی ساده تر با دسترسی سریع و راحت تر، اقدام به پیاده سازی صف نمود. به عنوان مثال تعریف زیر را در نظر بگیرید.
struct pinRead { int pin; int value; };
در تعریف فوق، می توان مقادیر مختلفی را به دو متغیر pin و value اختصاص داد. با اختصاص این مقادیر، می توان یک صف ایجاد نمود. به عنوان مثال برای متغیر pin مقادیری را به آن نسبت دهیم. سپس مقادیری را هم به متغیر value نسبت خواهیم داد. در این صورت یک صف با دو متغیر به ازای هر المان، یکی برای pin و دیگری برای value ایجاد خواهد گردید.
تبادل داده بین Task ها از طریق Queue صف
پس از آشنایی با مفهوم صف، نوبت به بررسی مفهومی مهم و کلیدی دیگری می رسد. در این قسمت قصد داریم تا به برسی تبادل داده بین Task های مختلف از طریق صف بپردازیم. یکی از قابلیت های کلیدی و کاربردی سیستم عامل FreeRTOS، توانایی مدیریت تبادل داده بین Task ها از طریق صف است. در این ساختار تعدادی از Task ها به صورت ارسال کننده و Task دیگری می تواند به عنوان گیرنده تعریف شود؛ سپس Task های ارسال کننده داده های خود را درون صف قرار می دهند. در سمت دیگر Task گیرنده آن هرا دریافت می کند. این مورد را می توان دقیقا مانند فرودگاه ها و سیستم های دریافت و کنترل چمدان ها دانست.
مطابق تصویر فوق Task های فرستنده داده های خود را در Queue صف قرار می دهند. سپس Task گیرنده داده ها را دریافت و نمایش می دهد. این فرایند به صورت خودکار توسط FreeRTOS مدیریت می شود. در قسمت بعد به دستورات این ویژگی می پردازیم.
دستورات Queue صف در سیستم عامل FreeRTOS
پس از آشنایی با مفهوم صف و کاربرد آن در سیستم عامل، نوبت به بررسی دستورات آن در FreeRTOS می رسد. برای استفاده از امکانات صف، نخست می بایست کتابخانه آن را به شیوه زیر فراخوانی کنیم.
#include <queue.h>
پس از این مرحله، می بایست از کلاس کتابخانه صف، یک شی تعریف شود.
QueueHandle_t structQueue;
توجه داشته باشید که در این جا ما از struct جهت ساخت صف استفاده می کنیم. به همین جهت به ایجاد یک ساختار مطابق دستور زیر خواهیم پرداخت.
struct pinRead { int pin; int value; };
پس از این مرحله، به کمک تابع زیر می بایست صف را در سیستم عامل تعریف کنیم.
QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength,UBaseType_t uxItemSize )
در تابع فوق، ورودی نخست تعداد آیتم های صف و ورودی دوم اندازه صف را از لحاظ اشغال حجم داده ها تعیین می کند. در این جا این تابع به صورت زیر تعریف می گردد.
structQueue = xQueueCreate(10, sizeof(struct pinRead) );
جهت ارسال داده درون Task ها از تابع xQueueSend استفاده می شود. این تابع در سطح سیستم عامل به شکل زیر تعریف می گردد.
BaseType_t xQueueSend( QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait );
در تابع فوق، ورودی ها از سمت چپ به راست به ترتیب زیر تعریف می گردند.
- شی تعریف شده از کلاس صف
- مقداری که قرار است در صف قرار بگیرد
- مدت زمان انتظار جهت خالی شدن صف برای قرار گرفتن داده جدید
در ادامه نیز، Task دیگری که وظیفه دریافت داده از طریق صف را دارد، داده ها را به شکل زیر دریافت می کند.
BaseType_t xQueueReceive( QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait );
مطابق تابع فوق، ورودی ها از چپ به راست به ترتیب تعریف می گردد.
۱-شی تعریف شده از کلاس صف
۲-مقداری که باید الان خوانده شود.
۳-مدت زمان انتطار برای دریافت داده
اجرای یک نمونه برنامه
پس از آشنایی با توابع و دستورات نوبت به اجرای یک نمونه برنامه می رسد. برای این مورد از منوی File->Examplse->Free RTOS->StructQueue را انتخاب کرده و برنامه نمونه را اجرا نمایید.
لوازم مورد نیاز
لینک خرید انواع برد آردوینو، کلیک کنید
جمع بندی
در مجموعه آموزش های سیستم عامل FreeRTOS بر روی بردهای آردوینو، این قسمت را به یکی از مفاهیم پایه اختصاص دادیم. مفهوم صف یکی از مهم ترین مفاهیم در سیستم های کامپیوتری به شمار می رود. به کمک این مفهوم می توان داده ها را بین Task های مختلف جا به جا نمود. در این آموزش ابتدا به مفهوم صف پرداختیم. سپس در ادامه بتشریح این قابلیت در تبادل داده بین Task ها بررسی گردید. در ادامه با دستورات برنامه نویسی صف در سیستم عامل آشنا شدیم. در نهایت با ارایه مثال، نحوه استفاده از توابع را در برنامه ها آموختیم.
چنانچه در مراحل راه اندازی و انجام این پروژه با مشکل مواجه شدید، بدون هیچ نگرانی در انتهای همین پست، به صورت ثبت نظر سوالتان را مطرح کنید. من در سریعترین زمان ممکن پاسخ رفع مشکل شما را خواهم داد. همچنین اگر ایرادی در کدها و یا مراحل اجرایی وجود دارند میتوانید از همین طریق اطلاع رسانی کنید.
چندین قسمت این آموزشو دیدم. خسته نباشید. اموزنده بود
متشکرم از لطف شما