- Brisanje naloge v FreeRTOS Arduino
- Kakšna je čakalna vrsta v FreeRTOS?
- Ustvarjanje čakalne vrste v FreeRTOS
- Shema vezja
- Izvajanje čakalne vrste FreeRTOS v Arduino IDE
V prejšnji vadnici smo v Arduino Uno predstavili FreeRTOS in ustvarili nalogo za utripajočo LED. Zdaj se bomo v tej vadnici podrobneje poglobili v koncepte RTOS API-jev in spoznali komunikacijo med različnimi nalogami. Tu se naučimo tudi o čakalni vrsti za prenos podatkov iz ene naloge v drugo in predstavimo delovanje API-jev čakalne vrste s povezovanjem 16x2 LCD in LDR z Arduino Uno.
Preden se pogovorimo o čakalnih vrstah, si oglejmo še en API FreeRTOS, ki je koristen pri brisanju opravil, ko je končano z dodeljenim delom. Včasih je treba nalogo izbrisati, da sprostite dodeljeni pomnilnik. V nadaljevanju prejšnje vadnice bomo v isti kodi uporabili funkcijo API vTaskDelete () v isti kodi za brisanje ene od nalog. Opravilo lahko s pomočjo funkcije vTaskDelete () API izbriše sebe ali katero koli drugo nalogo.
Če želite uporabljati ta API, morate konfigurirati datoteko FreeRTOSConfig.h . Ta datoteka se uporablja za prilagajanje FreeRTOS glede na aplikacijo. Uporablja se za spreminjanje algoritmov razporejanja in mnogih drugih parametrov. Datoteko lahko najdete v imeniku Arduino, ki je običajno na voljo v mapi Dokumenti v računalniku. V mojem primeru je na voljo v \ Documents \ Arduino \ libraries \ FreeRTOS \ src, kot je prikazano spodaj.
Zdaj, odprite datoteko z uporabo katerega koli urejevalnikom besedila in iskanje po #define INCLUDE_vTaskDelete in poskrbite, da je njegova vrednost "1" (1 pomeni omogočiti in 0 pomeni onemogočanje). Privzeto je 1, vendar ga preverja.
To nastavitveno datoteko bomo pogosto uporabljali v naslednjih vadnicah za nastavitev parametrov.
Zdaj pa poglejmo, kako izbrisati nalogo.
Brisanje naloge v FreeRTOS Arduino
Če želite izbrisati nalogo, moramo uporabiti funkcijo vTaskDelete () API. Potreben je samo en argument.
vTaskDelete (TaskHandle_t pxTaskToDelete);
pxTaskToDelete: Izbrisati morate ročaj naloge. To je isto kot 6 th argument xTaskCreate () API. V prejšnji vadnici je ta argument nastavljen na NULL, vendar lahko naslov vsebine naloge posredujete s katerim koli imenom. Recimo, če želite nastaviti ročico naloge za Task2, ki je deklarirana kot
TaskHandle_t poljubno_ime; Primer: TaskHandle_t xTask2Handle;
Zdaj, v vTaskCreate () API nastaviti 6 th argumenta kot
xTaskCreate (TaskBlink2, "task2", 128, NULL, 1 in & xTask2Handle);
Do vsebine te naloge je zdaj mogoče dostopati z ročico, ki ste jo dali.
Prav tako se opravilo lahko izbriše tako, da namesto veljavnega ročaja opravila posreduje NULL.
Če želimo izbrisati opravilo 3 iz samega opravila 3, morate napisati vTaskDelete (NULL); znotraj funkcije Task3, če pa želite izbrisati opravilo 3 iz opravila 2, potem napišite vTaskDelete (xTask3Handle); znotraj funkcije task2.
V prejšnji kodi vadnice, če želite izbrisati Task2 iz same task2, preprosto dodajte vTaskDelete (NULL); v void funkciji TaskBlink2 (void * pvParameters) . Potem bo zgornja funkcija videti tako
void TaskBlink2 (void * pvParameters) { Serial.println (»Task2 se izvaja in bo kmalu izbrisan«); vTaskDelete (NULL); pinMode (7, IZHOD); while (1) { digitalWrite (7, HIGH); vTaskDelay (300 / portTICK_PERIOD_MS); digitalWrite (7, LOW); vTaskDelay (300 / portTICK_PERIOD_MS); } }
Zdaj naložite kodo in opazujte LED in serijski monitor. Videli boste, da druga LED dioda zdaj ne utripa in task2 po izbrisu API za brisanje izbriše.
Tako lahko ta API uporabimo za ustavitev izvajanja določene naloge.
Zdaj pa začnimo s čakalno vrsto.
Kakšna je čakalna vrsta v FreeRTOS?
Čakalna vrsta je podatkovna struktura, ki lahko vsebuje končno število elementov s fiksno velikostjo in deluje v shemi FIFO (First-in First-out). Čakalne vrste zagotavljajo komunikacijski mehanizem opravilo do naloge, prekinitev naloge in prekinitev do naloge.
Največje število elementov, ki jih lahko vsebuje čakalna vrsta, se imenuje njegova »dolžina«. Dolžina in velikost vsakega elementa se nastavita, ko se ustvari vrsta.
Primer uporabe vrste za prenos podatkov je dobro prikazan v dokumentaciji FreeRTOS, ki jo najdete tukaj. Navedeni primer lahko enostavno razumete.
Po razumevanju čakalnih vrst poskusimo razumeti postopek ustvarjanja čakalne vrste in ga poskusimo implementirati v našo kodo FreeRTOS.
Ustvarjanje čakalne vrste v FreeRTOS
Najprej opišite stavek o težavi, ki naj se izvede s pomočjo čakalne vrste FreeRTOS in Arduino Uno.
Vrednost senzorja LDR želimo natisniti na LCD 16 * 2. Torej sta zdaj dve nalogi
- Naloga 1 je pridobivanje analognih vrednosti LDR.
- Task2 tiska analogno vrednost na LCD.
Torej, tu ima čakalna vrsta svojo vlogo, ker za pošiljanje podatkov, ki jih ustvari task1, v task2. V task1 bomo poslali analogno vrednost v čakalno vrsto, v task2 pa jo bomo prejeli iz čakalne vrste.
Obstajajo tri funkcije za delo s čakalnimi vrstami
- Ustvarjanje čakalne vrste
- Pošiljanje podatkov v čakalno vrsto
- Prejemanje podatkov iz čakalne vrste
Za ustvarjanje čakalne vrste uporabite API funkcije xQueueCreate (). Potrebna sta dva argumenta.
xQueueCreate (UBaseType_t uxQueueLength, UBaseType_t uxItemSize);
uxQueueLength: največje število elementov, ki jih lahko ustvari čakalna vrsta, ki je ustvarjena hkrati.
uxItemSize: Velikost v bajtih vsakega podatkovnega elementa, ki ga je mogoče shraniti v čakalno vrsto.
Če ta funkcija vrne NULL, vrsta ni ustvarjena zaradi premajhnega pomnilnika in če vrne vrednost, ki ni NULL, je čakalna vrsta uspešno ustvarjena. To vrnjeno vrednost shranite v spremenljivko, da jo uporabite kot ročico za dostop do čakalne vrste, kot je prikazano spodaj.
QueueHandle_t čakalna vrsta1; queue1 = xQueueCreate (4, sizeof (int));
To bo ustvarilo čakalno vrsto elementov v pomnilniku kopice velikosti int (2 bajta vsakega bloka) in shranilo povratno vrednost v spremenljivko ročaja queue1 .
2. Pošiljanje podatkov v čakalno vrsto v FreeRTOS
Za pošiljanje vrednosti v čakalno vrsto ima FreeRTOS v ta namen 2 različici API-ja.
- xQueueSendToBack (): Uporablja se za pošiljanje podatkov na zadnji (rep) čakalne vrste.
- xQueueSendToFront (): Uporablja se za pošiljanje podatkov na sprednji del (glavo) čakalne vrste.
Zdaj je xQueueSend () enakovreden xQueueSendToBack () in popolnoma enak njemu.
Vsi ti API-ji imajo 3 argumente.
xQueueSendToBack (QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait);
xQueue: Ročaj čakalne vrste, v katero se pošiljajo (zapisujejo) podatki. Ta spremenljivka je enaka kot pri shranjevanju povratne vrednosti API-ja xQueueCreate.
pvItemToQueue: Kazalec na podatke, ki jih želite kopirati v čakalno vrsto.
xTicksToWait: Najdaljši čas, ko mora naloga ostati v blokiranem stanju, da počaka, da bo prostor na voljo v čakalni vrsti.
Če xTicksToWait nastavite na portMAX_DELAY, bo naloga opravila čakala neomejeno dolgo (brez časovne omejitve), pod pogojem, da je INCLUDE_vTaskSuspend nastavljen na 1 v FreeRTOSConfig.h, sicer pa lahko uporabite makro pdMS_TO_TICKS () za pretvorbo časa, določenega v milisekundah, v čas, določen s tiki.
3. Prejemanje podatkov iz čakalne vrste v FreeRTOS
Za sprejem (branje) predmeta iz čakalne vrste se uporablja xQueueReceive (). Prejeti element je odstranjen iz čakalne vrste.
Ta API vsebuje tudi tri argumente.
xQueueReceive (QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait);
Prvi in tretji argument sta enaka pošiljanju API-ja. Le drugi argument je drugačen.
const pvBuffer: Kazalec na pomnilnik, v katerega bodo kopirani prejeti podatki.
Upam, da ste razumeli tri API-je. Zdaj bomo te API-je implementirali v Arduino IDE in poskušali rešiti zgoraj opisano težavo.
Shema vezja
Takole izgleda na plošči:
Izvajanje čakalne vrste FreeRTOS v Arduino IDE
Začnimo pisati kodo za našo aplikacijo.
1. Najprej odprite Arduino IDE in vključite glavo Arduino_FreeRTOS.h . Zdaj, če je uporabljen kateri koli objekt jedra, kot je čakalna vrsta, vključite njegovo glavo. Ker uporabljamo LCD 16 * 2, vključite knjižnico tudi zanj.
#include #include
2. Inicializirajte ročaj čakalne vrste, da shranite vsebino čakalne vrste. Inicializirajte tudi številke pinov LCD.
QueueHandle_t čakalna vrsta_1; LCD LiquidCrystal (7, 8, 9, 10, 11, 12);
3. V void setup () inicializirajte LCD in serijski monitor s hitrostjo 9600 baud. Ustvarite čakalno vrsto in dve nalogi z uporabo ustreznih API-jev. Tu bomo ustvarili vrsto velikosti 4 s celoštevilskim tipom. Ustvarite nalogo z enakimi prioritetami in se kasneje poskusite igrati s to številko. Na koncu zaženite načrtovalnik, kot je prikazano spodaj.
void setup () { Serial.begin (9600); lcd.begin (16, 2); queue_1 = xQueueCreate (4, sizeof (int)); if (queue_1 == NULL) { Serial.println ("Čakalne vrste ni mogoče ustvariti"); } xTaskCreate (TaskDisplay, "Display_task", 128, NULL, 1, NULL); xTaskCreate (TaskLDR, "LDR_task", 128, NULL, 1, NULL); vTaskStartScheduler (); }
4. Zdaj naredite dve funkciji TaskDisplay in TaskLDR . V funkciji TaskLDR preberite analogni pin A0 v spremenljivki, saj imamo LDR priključen na pin A0 Arduino UNO. Zdaj pošljite vrednost, shranjeno v spremenljivki, tako da jo posredujete v xQueueSend API in po 1 sekundi z API-jem vTaskDelay () pošljete nalogo za blokiranje stanja, kot je prikazano spodaj.
void TaskLDR (void * pvParameters) { int current_intensity; while (1) { Serial.println ("Task1"); trenutna_intenzivnost = analogRead (A0); Serial.println (trenutna_intenzivnost); xQueueSend (čakalna vrsta_1 in trenutna_intenzivnost, vrataMAX_DELAY); vTaskDelay (1000 / portTICK_PERIOD_MS); } }
5. Podobno naredite funkcijo za TaskDisplay in prejmite vrednosti v spremenljivki, ki je posredovana funkciji xQueueReceive . Tudi xQueueReceive () vrne pdPASS, če je podatke mogoče uspešno prejeti iz čakalne vrste in vrne errQUEUE_EMPTY, če je vrsta prazna.
Zdaj prikažite vrednosti na LCD-ju s funkcijo lcd.print () .
void TaskDisplay (void * pvParameters) { int intenziteta = 0; while (1) { Serial.println ("Task2"); if (xQueueReceive (queue_1, & intenzivnost, portMAX_DELAY) == pdPASS) { lcd.clear (); lcd.setCursor (0, 0); lcd.print ("Intenzivnost:"); lcd.setCursor (11, 0); lcd.print (intenzivnost); } } }
To je to. Končali smo s kodirnim delom izvedbe čakalne vrste. Celotno kodo z delujočim videom najdete na koncu.
Zdaj povežite LCD in LDR z Arduino UNO v skladu s shemo vezja, naložite kodo. Odprite serijski monitor in opazujte naloge. Videli boste, da se naloge preklapljajo in vrednosti LDR spreminjajo glede na jakost svetlobe.
OPOMBA: Večina knjižnic, izdelanih za različne senzorje, jedro FreeRTOS ne podpira zaradi zakasnitve izvajanja funkcije v knjižnicah. Zaradi zakasnitve se CPU popolnoma ustavi, zato tudi jedro FreeRTOS preneha delovati in koda se ne bo več izvajala, zato se začne neprimerno obnašati. Torej moramo knjižnicam omogočiti, da delajo z FreeRTOS brez odlašanja.