- Изтриване на задача в FreeRTOS Arduino
- Каква е опашката в FreeRTOS?
- Създаване на опашка в FreeRTOS
- Електрическа схема
- Внедряване на FreeRTOS Queue в Arduino IDE
В предишния урок въведохме FreeRTOS в Arduino Uno и създадохме задача за мигащия светодиод. Сега, в този урок, ще се потопим повече в предварителните концепции на RTOS API и ще научим за комуникацията между различни задачи. Тук също така научаваме за Queue за прехвърляне на данни от една задача в друга и демонстрираме работата на API на опашката, като свързваме 16x2 LCD и LDR с Arduino Uno.
Преди да обсъдим опашките, нека видим още един FreeRTOS API, който е полезен при изтриването на задачите, когато приключи с възложената работа. Понякога задачата трябва да бъде изтрита, за да освободи разпределената памет. В продължение на предишния урок ще използваме функцията vTaskDelete () API в същия код, за да изтрием една от задачите. Задача може да използва функцията API на vTaskDelete (), за да се изтрие или друга задача.
За да използвате този API, трябва да конфигурирате файла FreeRTOSConfig.h . Този файл се използва за приспособяване на FreeRTOS според приложението. Използва се за промяна на алгоритмите за планиране и много други параметри. Файлът може да бъде намерен в Arduino Directory, който обикновено е достъпен в папката Documents на вашия компютър. В моя случай той е достъпен в \ Documents \ Arduino \ libraries \ FreeRTOS \ src, както е показано по-долу.
Сега отворете файла чрез произволен текстов редактор и да търсите за #define INCLUDE_vTaskDelete и се уверете, че стойността му е "1" (1 средства дават възможност и 0 означава забраните). По подразбиране е 1, но проверява за него.
Ще използваме този конфигурационен файл често в следващите уроци за задаване на параметрите.
Сега да видим как да изтриете задача.
Изтриване на задача в FreeRTOS Arduino
За да изтрием задача, трябва да използваме функцията API vTaskDelete (). Необходим е само един аргумент.
vTaskDelete (TaskHandle_t pxTaskToDelete);
pxTaskToDelete: Трябва да се изтрие манипулаторът на задачата. Това е същото като 6 -ти аргумент на xTaskCreate () API. В предишния урок този аргумент е зададен като NULL, но можете да предадете адреса на съдържанието на задачата, като използвате произволно име. Нека кажем, ако искате да зададете манипулатор на задача за Task2, който е деклариран като
TaskHandle_t any_name; Пример: TaskHandle_t xTask2Handle;
Сега, в vTaskCreate () API зададе 6 -ти аргумент като
xTaskCreate (TaskBlink2, "task2", 128, NULL, 1, & xTask2Handle);
Съдържанието на тази задача вече може да бъде достъпно с помощта на дръжката, дадена от вас.
Също така задача може да се изтрие, като предаде NULL вместо валиден манипулатор на задачата.
Ако искаме да изтрием Задача 3 от самата задача 3, трябва да напишете vTaskDelete (NULL); във функцията Task3, но ако искате да изтриете задача 3 от задача 2, напишете vTaskDelete (xTask3Handle); във функцията task2.
В предишния урок код, за да изтриете Task2 от самата task2 , просто добавете vTaskDelete (NULL); в void функция TaskBlink2 (void * pvParameters) . Тогава горната функция ще изглежда така
void TaskBlink2 (void * pvParameters) { Serial.println („Task2 работи и е на път да изтрие“); vTaskDelete (NULL); pinMode (7, ИЗХОД); докато (1) { digitalWrite (7, HIGH); vTaskDelay (300 / портTICK_PERIOD_MS); digitalWrite (7, LOW); vTaskDelay (300 / portTICK_PERIOD_MS); } }
Сега качете кода и наблюдавайте светодиодите и серийния монитор. Ще видите, че вторият светодиод не мига сега и task2 се изтрива, след като срещнете API за изтриване.
Така че този API може да се използва за спиране на изпълнението на конкретната задача.
Сега да започнем с опашката.
Каква е опашката в FreeRTOS?
Опашката е структурата на данните, която може да съдържа крайния брой елементи с фиксиран размер и се управлява в схемата FIFO (First-in First-out). Опашките осигуряват механизъм за комуникация задача към задача, задача към прекъсване и прекъсване до задача.
Максималният брой елементи, които опашката може да събере, се нарича нейната „дължина“. Както дължината, така и размерът на всеки елемент се задават при създаването на опашката.
Пример за това как опашката се използва за трансфер на данни е илюстриран добре в документацията на FreeRTOS, която можете да намерите тук. Можете лесно да разберете дадения пример.
След като разберем Опашките, нека се опитаме да разберем процеса на създаване на опашка и да се опитаме да го приложим в нашия FreeRTOS код.
Създаване на опашка в FreeRTOS
Първо опишете изявлението за проблема, което трябва да бъде внедрено с помощта на опашката FreeRTOS и Arduino Uno.
Искаме да отпечатаме стойността на LDR сензора на 16 * 2 LCD. Така че има две задачи сега
- Задача1 получава аналогови стойности на LDR.
- Task2 отпечатва аналоговата стойност на LCD.
И така, тук опашката играе своята роля, защото за изпращане на данните, генерирани от task1 до task2. В task1 ще изпратим аналогова стойност към опашката, а в task2 ще я получим от опашката.
Има три функции за работа с опашки
- Създаване на опашка
- Изпращане на данни към опашката
- Получаване на данни от опашката
За създаване на опашка използвайте API на функцията xQueueCreate (). Необходими са два аргумента.
xQueueCreate (UBaseType_t uxQueueLength, UBaseType_t uxItemSize);
uxQueueLength: Максималният брой елементи, които опашката, която се създава, може да съдържа едновременно.
uxItemSize: Размерът в байтове на всеки елемент от данни, който може да се съхранява в опашката.
Ако тази функция връща NULL, опашката не се създава поради недостатъчна памет и ако връща стойност, различна от NULL, опашката се създава успешно. Съхранявайте тази върната стойност в променлива, за да я използвате като манипулатор за достъп до опашката, както е показано по-долу.
QueueHandle_t опашка1; queue1 = xQueueCreate (4, sizeof (int));
Това ще създаде опашка от 4 елемента в паметта на купчина с размер int (2 байта от всеки блок) и ще съхрани връщаната стойност в променливата за обработка queue1 .
2. Изпращане на данни на опашка в FreeRTOS
За да изпрати стойностите на опашката, FreeRTOS има 2 варианта на API за тази цел.
- xQueueSendToBack (): Използва се за изпращане на данни към гърба (опашката) на опашката.
- xQueueSendToFront (): Използва се за изпращане на данни отпред (главата) на опашка.
Сега , xQueueSend () е еквивалентна на, и точно същата като, xQueueSendToBack ().
Всички тези API имат 3 аргумента.
xQueueSendToBack (QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait);
xQueue: Манипулаторът на опашката, към която се изпращат (записват) данните. Тази променлива е същата като използваната за съхраняване на връщаната стойност на API на xQueueCreate.
pvItemToQueue: указател към данните, които трябва да бъдат копирани в опашката.
xTicksToWait: Максималният период от време, в който задачата трябва да остане в блокирано състояние, за да изчака пространството да стане налично в опашката.
Задаването на xTicksToWait на portMAX_DELAY ще накара задачата да чака безкрайно (без изчакване), при условие че INCLUDE_vTaskSuspend е зададено на 1 във FreeRTOSConfig.h, иначе можете да използвате макроса pdMS_TO_TICKS (), за да преобразувате време, посочено в милисекунди, във време, посочено в тикове.
3. Получаване на данни от опашката във FreeRTOS
За получаване (четене) на елемент от опашка се използва xQueueReceive (). Полученият елемент се отстранява от опашката.
Този API също взема три аргумента.
xQueueReceive (QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait);
Първият и третият аргумент са същите като изпращането на API. Само вторият аргумент е различен.
const pvBuffer: указател към паметта, в която ще бъдат копирани получените данни.
Надявам се, че сте разбрали трите API. Сега ще внедрим тези API в Arduino IDE и ще се опитаме да разрешим изявлението за проблема, което описахме по-горе.
Електрическа схема
Ето как изглежда на борда:
Внедряване на FreeRTOS Queue в Arduino IDE
Нека започнем да пишем код за нашето приложение.
1. Първо отворете Arduino IDE и включете заглавния файл Arduino_FreeRTOS.h . Сега, ако се използва някакъв обект на ядрото като опашка, включете заглавния файл от него. Тъй като използваме 16 * 2 LCD, включете и библиотеката за него.
#include #include
2. Инициализирайте манипулатора на опашката, за да съхраните съдържанието на опашката. Освен това инициализирайте номера на LCD щифтове.
QueueHandle_t queue_1; LCD LiquidCrystal (7, 8, 9, 10, 11, 12);
3. При настройка за невалидни () инициализирайте LCD и серийния монитор с 9600 скорости на предаване. Създайте опашка и две задачи, като използвате съответните API. Тук ще създадем опашка с размер 4 с цял тип. Създайте задача с равни приоритети и по-късно опитайте да играете с този номер. И накрая, стартирайте планировчика, както е показано по-долу.
void setup () { Serial.begin (9600); lcd.begin (16, 2); опашка_1 = xQueueCreate (4, sizeof (int)); if (queue_1 == NULL) { Serial.println ("Опашката не може да бъде създадена"); } xTaskCreate (TaskDisplay, "Display_task", 128, NULL, 1, NULL); xTaskCreate (TaskLDR, "LDR_task", 128, NULL, 1, NULL); vTaskStartScheduler (); }
4. Сега направете две функции TaskDisplay и TaskLDR . Във функцията TaskLDR прочетете аналогов пин A0 в променлива, тъй като имаме LDR, свързан към A0 пина на Arduino UNO. Сега изпратете стойността, съхранена в променливата, като я предадете в API на xQueueSend и изпратете задачата за блокиране на състоянието след 1 секунда, като използвате API на vTaskDelay (), както е показано по-долу.
void TaskLDR (void * pvParameters) { int current_intensity; докато (1) { Serial.println ("Задача1"); current_intensity = analogRead (A0); Serial.println (текуща_интензивност); xQueueSend (опашка_1, & текуща_интензивност, портMAX_DELAY); vTaskDelay (1000 / портTICK_PERIOD_MS); } }
5. По същия начин направете функция за TaskDisplay и получете стойностите в променлива, която се предава на функцията xQueueReceive . Също така, xQueueReceive () връща pdPASS, ако данните могат да бъдат получени успешно от опашката и връща errQUEUE_EMPTY, ако опашката е празна.
Сега покажете стойностите на LCD с помощта на функцията lcd.print () .
void TaskDisplay (void * pvParameters) { int интензивност = 0; докато (1) { Serial.println ("Задача2"); ако (xQueueReceive (опашка_1, & интензивност, портMAX_DELAY) == pdPASS) { lcd.clear (); lcd.setCursor (0, 0); lcd.print ("Интензивност:"); lcd.setCursor (11, 0); lcd.print (интензивност); } } }
Това е. Завършихме кодиращата част от изпълнението на опашката. Пълен код с работещо видео можете да намерите в края.
Сега свържете LCD и LDR с Arduino UNO според схемата за качване на кода. Отворете серийния монитор и наблюдавайте задачите. Ще видите, че задачите се превключват и стойностите на LDR се променят в зависимост от интензивността на светлината.
ЗАБЕЛЕЖКА: Повечето библиотеки, създадени за различни сензори, не се поддържат от ядрото FreeRTOS поради внедряване на функцията за забавяне в библиотеките. Delay кара процесора да спре напълно, следователно ядрото на FreeRTOS също спира да работи и кодът няма да се изпълнява допълнително и започва да се държи неправилно. И така, трябва да направим библиотеките без забавяне за работа с FreeRTOS.