- Mi az a szemafor?
- Hogyan használható a szemafor a FreeRTOS-ban?
- Szemafor kód magyarázat
- Kördiagramm
- Mi az a Mutex?
- Hogyan kell használni a Mutex-et a FreeRTOS-ban?
- Mutex kód magyarázat
Korábbi oktatóprogramokban a FreeRTOS alapjait ismertettük az Arduino-val és a FreeRTOS Arduino Queue kernel objektumával. Most ebben a harmadik FreeRTOS oktatóanyagban többet megtudhatunk a FreeRTOS-ról és annak előzetes API-ról, amelyek mélyebben megismerhetik a többfeladatos platformot.
A szemafor és a Mutex (kölcsönös kizárás) a kernelobjektumok, amelyeket szinkronizálásra, erőforrás-kezelésre és az erőforrások korrupciótól való védelmére használnak. A bemutató első felében meglátjuk a szemafor mögött meghúzódó ötletet, hogyan és hol alkalmazzuk. A második félidőben a Mutexszel folytatjuk.
Mi az a szemafor?
Korábbi oktatóprogramokban megvitattuk a feladatok prioritásait, és megismerhettük azt is, hogy egy magasabb prioritású feladat előre jelez egy alacsonyabb prioritású feladatot, így míg a magas prioritású feladat végrehajtása fennállhat annak a lehetősége, hogy az alacsonyabb prioritású feladatokban adatvesztés történhet még nincs végrehajtva, és az adatok folyamatosan érkeznek ehhez a feladathoz egy érzékelőtől, amely adatvesztést és az egész alkalmazás hibás működését okozza.
Tehát meg kell védeni az erőforrásokat az adatvesztés ellen, és itt a szemafor fontos szerepet játszik.
A szemafor egy olyan jelzési mechanizmus, amelyben egy várakozási állapotban lévő feladatot egy másik feladat jelez végrehajtásra. Más szavakkal, amikor az 1. feladat befejezte a munkáját, akkor egy zászlót mutat, vagy 1-gyel növeli a zászlót, majd ezt a zászlót egy másik feladat (2. feladat) kapja meg, jelezve, hogy képes most elvégezni a munkáját. Amikor a 2. feladat befejezte a munkát, akkor a zászló 1-gyel csökken.
Tehát alapvetően ez egy „Give” és „Take” mechanizmus, a szemafor pedig egy egész változó, amelyet az erőforrásokhoz való hozzáférés szinkronizálására használnak.
A szemafor típusai a FreeRTOS-ban:
A szemafor kétféle.
- Bináris szemafor
- Szemafor számlálása
1. Bináris szemafor: Két egész értéke 0 és 1. Ez némileg hasonlít az 1. hosszúságú sorra. Például két feladatunk van, a task1 és a task2. A Task1 adatokat küld a task2-nek, így a task2 folyamatosan ellenőrzi a várólista elemet, ha van 1, akkor kiolvashatja azokat az adatokat, amelyekre várnia kell, míg 1 lesz. elküldheti az adatokat a task2.
A fenti példából elmondható, hogy a bináris szemafor a feladatok közötti, illetve a feladatok és a megszakítás szinkronizálására szolgál.
2. Szemafor számlálása: 0-nál nagyobb értékekkel rendelkezik, és fel lehet gondolni, hogy az 1-nél hosszabb sor vár. Ebben a felhasználási szcenárióban egy eseménykezelő „ad" egy szemaforot minden esemény bekövetkezésekor (növelve a szemaforszám számértéket), és egy kezelőfeladat "felvesz" egy szemaforot, amikor egy eseményt feldolgoz (csökkenti a szemaforszám értékét).
A számlálás értéke tehát a megtörtént események és a feldolgozott számok közötti különbség.
Most nézzük meg, hogyan kell használni a szemaforot a FreeRTOS kódban.
Hogyan használható a szemafor a FreeRTOS-ban?
A FreeRTOS különböző API-kat támogat egy szemafor létrehozásához, egy szemafor felvételéhez és egy szemafor megadásához.
Kétféle API lehet ugyanarra a kernelobjektumra. Ha szemaforot kell adnunk egy ISR-ből, akkor a normális szemafor API nem használható. Használjon megszakítással védett API-kat.
Ebben az oktatóanyagban bináris szemaforot fogunk használni, mert könnyen érthető és megvalósítható. Mivel itt megszakítási funkciót használnak, megszakítással védett API-kat kell használnia az ISR funkcióban. Amikor azt mondjuk, hogy szinkronizálunk egy feladatot egy megszakítással, ez azt jelenti, hogy a feladatot közvetlenül az ISR után futtatjuk futó állapotba.
Szemafor létrehozása:
Bármely kernelobjektum használatához először létre kell hoznunk. Bináris szemafor létrehozásához használja a vSemaphoreCreateBinary () parancsot.
Ez az API nem vesz fel paramétert, és a SemaphoreHandle_t típusú változót adja vissza. A sema_v globális változó neve létrejön a szemafor tárolására.
SzemaforHandle_t sema_v; sema_v = xSemaphoreCreateBinary ();
Szemafor adása:
A szemafor megadásához két változat létezik - az egyik a megszakításhoz és a másik a normál feladathoz.
- xSemaphoreGive (): Ez az API csak egy argumentumot vesz fel, amely a szemafor változó neve, mint például a fentebb megadott sema_v, miközben egy szemafor létrehozása közben. Bármely normál feladatból meghívható, amelyet szinkronizálni szeretne.
- xSemaphoreGiveFromISR (): Ez az xSemaphoreGive () megszakítással védett API-verziója. Amikor szinkronizálnunk kell egy ISR-t és egy normál feladatot, akkor az xSemaphoreGiveFromISR () -t kell használni az ISR függvényből.
Szemafor felvétele:
Szemafor felvételéhez használja az xSemaphoreTake () API függvényt. Ez az API két paramétert vesz fel.
xSemaphoreTake (SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait);
xSemaphore: Az esetünkben felvehető szemafor neve sema_v.
xTicksToWait: Ez az a maximális idő, amelyre a feladat blokkolt állapotban vár, amíg a szemafor elérhetővé válik. A projektünk szempontjából, akkor xTicksToWait hogy portMAX_DELAY hogy a task_1 várni a végtelenségig Blokkolt állapotban, míg a sema_v elérhető.
Most használjuk ezeket az API-kat, és írjunk egy kódot néhány feladat végrehajtására.
Itt egy nyomógomb és két LED van összekötve. A nyomógomb megszakító gombként fog működni, amely az Arduino Uno 2. tűjéhez csatlakozik. Ha megnyomja ezt a gombot, akkor egy megszakítás keletkezik, és a 8. érintkezőhöz csatlakoztatott LED bekapcsol, és amikor újra megnyomja, akkor kikapcsol.
Tehát, amikor megnyomja a gombot, az xSemaphoreGiveFromISR () az ISR függvényből lesz meghívva, az xSemaphoreTake () függvény pedig a TaskLED függvényből lesz meghívva.
Annak érdekében, hogy a rendszer többfeladatos legyen, csatlakoztasson más LED-eket a 7-es csaphoz, amely mindig villogni fog.
Szemafor kód magyarázat
Kezdjük el írni a kódot az Arduino IDE megnyitásával
1. Először csatolja az Arduino_FreeRTOS.h fejlécfájlt. Most, ha bármely kernelobjektumot használunk, például a sor szemaforát, akkor egy fejléc fájlt is hozzá kell adni.
#include #include
2. Nyújtsa be a SemaphoreHandle_t típusú változót a szemafor értékeinek tárolására.
SzemaforHandle_t megszakításSzemafora;
3. A void setup () alkalmazásban hozzon létre két feladatot (TaskLED és TaskBlink) az xTaskCreate () API használatával, majd hozzon létre egy szemaforot az xSemaphoreCreateBinary () használatával. Hozzon létre egy azonos prioritású feladatot, majd később próbáljon meg játszani ezzel a számmal. Konfigurálja továbbá a 2-es csapot bemenetként, engedélyezze a belső felhúzási ellenállást és csatlakoztassa a megszakító csapot. Végül indítsa el az ütemezőt az alábbiak szerint.
void setup () { pinMode (2, INPUT_PULLUP); xTaskCreate (TaskLed, "Led", 128, NULL, 0, NULL); xTaskCreate (TaskBlink, "LedBlink", 128, NULL, 0, NULL); nutrSemaphore = xSemaphoreCreateBinary (); if ( ruptSemaphore ! = NULL) { attachInterrupt (digitalPinToInterrupt (2), debounceInterrupt, LOW); } }
4. Most hajtsa végre az ISR funkciót. Készítsen egy függvényt, és nevezze el ugyanúgy, mint az attachInterrupt () függvény második argumentumát. A megszakítás megfelelő működése érdekében el kell távolítania a nyomógomb visszadobási problémáját millis vagy micros függvény segítségével és a visszavonási idő beállításával. Ebből a függvényből hívja meg a nutrumpHandler () függvényt az alábbiak szerint.
hosszú debouncing_time = 150; volatilis, aláíratlan hosszú last_micros; void debounceInterrupt () { if ((long) (micros () - last_micros)> = debouncing_time * 1000) { megszakítHandler (); last_micros = micros (); } }
A interruptHandler () függvény, hívja xSemaphoreGiveFromISR () API-t.
érvénytelen megszakításHandler () { xSemaphoreGiveFromISR (megszakításSemaphore, NULL); }
Ez a funkció szemaforot ad a TaskLed-nek a LED bekapcsolásához.
5. Hozzon létre egy TaskLed függvényt, és a while cikluson belül hívja meg az xSemaphoreTake () API-t, és ellenőrizze, hogy a szemafor sikeresen elfoglalt-e vagy sem. Ha megegyezik a pdPASS-szal (azaz 1), akkor a LED-et kapcsolja az alábbiak szerint.
void TaskLed (void * pvParameters) { (void) pvParameters; pinMode (8, OUTPUT); while (1) { if (xSemaphoreTake (nutrSEMaphore, portMAX_DELAY) == pdPASS) { digitalWrite (8,! digitalRead (8)); } } }
6. Ezenkívül hozzon létre egy funkciót a 7. érintkezőhöz csatlakoztatott többi LED villogására.
void TaskLed1 (void * pvParameters) { (void) pvParameters; pinMode (7, OUTPUT); míg (1) { digitalWrite (7, HIGH); vTaskDelay (200 / portTICK_PERIOD_MS); digitalWrite (7, LOW); vTaskDelay (200 / portTICK_PERIOD_MS); } }
7. A void loop funkció üres marad. Ne felejtsd el.
void loop () {}
Ennyi, a teljes kód megtalálható a bemutató végén. Most töltse fel ezt a kódot, és csatlakoztassa a LED-eket és a nyomógombot az Arduino UNO-hoz a kapcsolási rajz szerint.
Kördiagramm
A kód feltöltése után látni fogja, hogy egy LED villog 200 ms után, és amikor megnyomja a gombot, azonnal világítani kezd a második LED, amint azt a végén megadott videó mutatja.
Ily módon a szemaforok használhatók a FreeRTOS-ban az Arduino-val, ahol veszteség nélkül kell átadniuk az adatokat az egyik feladatból a másikba.
Most nézzük meg, mi az a Mutex, és hogyan kell használni a FreeRTOS-t.
Mi az a Mutex?
Amint azt a fentiekben kifejtettük, a szemafor jelzési mechanizmus, hasonlóan a Mutex egy záró mechanizmus, ellentétben a szemaforral, amelynek külön funkciói vannak az inkrementálásra és csökkentésre, de a Mutex-ben a függvény önmagát veszi és adja. Ez egy technika a megosztott erőforrások korrupciójának elkerülésére.
A megosztott erőforrás védelme érdekében az egyik hozzárendel egy tokenkártyát (mutex) az erőforráshoz. Aki rendelkezik ezzel a kártyával, hozzáférhet a másik erőforráshoz. Másoknak meg kell várniuk, amíg a kártya vissza nem tér. Ily módon csak egy erőforrás férhet hozzá a feladathoz, mások pedig várják az esélyüket.
Nézzük megérteni Mutex a FreeRTOS segítségével egy példa.
Itt három feladatunk van: az egyik az adatok nyomtatására az LCD-re, a másik az LDR adatok LCD-re történő küldésére és az utolsó feladat a hőmérsékleti adatok LCD-re történő küldésére. Tehát itt két feladat osztja ugyanazt az erőforrást, azaz az LCD-t. Ha az LDR feladat és a hőmérsékleti feladat egyszerre küld adatokat, akkor az egyik adat sérült vagy elveszhet.
Tehát az adatvesztés védelme érdekében le kell zárnunk az LCD-erőforrást a task1 számára, amíg be nem fejezi a megjelenítési feladatot. Ezután az LCD feladat feloldódik, majd a task2 elvégezheti a munkáját.
Az alábbi ábrán megfigyelheti a Mutex és a szemaforok működését.
Hogyan kell használni a Mutex-et a FreeRTOS-ban?
A Mutexeket ugyanúgy használják, mint a szemaforokat. Először hozza létre, majd adja és vegye a megfelelő API-kat.
Mutex létrehozása:
Mutex létrehozásához használja az xSemaphoreCreateMutex () API-t . Ahogy a neve is sugallja, hogy a Mutex a bináris szemafor típusa. Különböző összefüggésekben és célokban használják őket. A bináris szemafor a feladatok szinkronizálására szolgál, míg a Mutex a megosztott erőforrások védelmére szolgál.
Ez az API nem vesz fel argumentumokat, és a SemaphoreHandle_t típusú változót adja vissza. Ha a mutex nem hozható létre, az xSemaphoreCreateMutex () visszaadja a NULL értéket.
SzemaforHandle_t mutex_v; mutex_v = xSemaphoreCreateMutex ();
Mutex szedése:
Ha egy feladat hozzáférni akar egy erőforráshoz, akkor az xSemaphoreTake () API használatával Mutexet vesz igénybe. Ez megegyezik egy bináris szemaforral. Két paraméterre is szükség van.
xSemaphore: A Mutex neve, amelyet a mi esetünkben kell venni, mutex_v .
xTicksToWait: Ez az a maximális idő, amelyre a feladat Blokkolt állapotban vár, amíg a Mutex elérhetővé válik. A projektünk szempontjából, akkor xTicksToWait hogy portMAX_DELAY hogy a task_1 várni a végtelenségig Blokkolt állapotban, míg a mutex_v elérhető.
Mutex adása:
A megosztott erőforrás elérése után a feladatnak vissza kell adnia a Mutexet, hogy más feladatok is hozzáférhessenek hozzá. Az xSemaphoreGive () API-t használják a Mutex visszaadására.
Az xSemaphoreGive () függvény csak egy argumentumot vesz fel, amely a Mutex, amelyet a miutex_v esetünkben kell megadni.
A fenti API-k segítségével valósítsuk meg a Mutex-et a FreeRTOS-kódban az Arduino IDE használatával.
Mutex kód magyarázat
Itt ennek a résznek az a célja, hogy a soros monitort megosztott erőforrásként használja, és két különböző feladattal érje el a soros monitort egy üzenet kinyomtatásához.
1. A fejlécfájlok ugyanazok maradnak, mint egy szemafor.
#include #include
2. Nyújtsa be a SemaphoreHandle_t típusú változót a Mutex értékeinek tárolására.
SzemaforHandle_t mutex_v;
3. A void setup () alatt inicializálja a soros monitort 9600 baud sebességgel, és az xTaskCreate () API segítségével hozzon létre két feladatot (Task1 és Task2). Ezután hozzon létre egy Mutex-et az xSemaphoreCreateMutex () használatával. Hozzon létre egy feladatot azonos prioritásokkal, majd később próbáljon meg játszani ezzel a számmal.
void setup () { Soros.kezdés (9600); mutex_v = xSemaphoreCreateMutex (); if (mutex_v == NULL) { Serial.println ("A Mutex nem hozható létre"); } xTaskCreate (1. feladat, "1. feladat", 128, NULL, 1, NULL); xTaskCreate (2. feladat, "2. feladat", 128, NULL, 1, NULL); }
4. Most készítsen feladatfüggvényeket a Task1 és a Task2 számára. A feladat függvény rövid időn belül, mielőtt üzenetet nyomtatna a soros monitorra, el kell vennünk egy Mutex-et az xSemaphoreTake () használatával, majd ki kell nyomtatnunk az üzenetet, majd vissza kell adnunk a Mutex- et az xSemaphoreGive () segítségével. Akkor adjon némi késést.
void Task1 (void * pvParameters) { while (1) { xSemaphoreTake (mutex_v, portMAX_DELAY); Serial.println ("Szia 1. feladatból"); xSemaphoreGive (mutex_v); vTaskDelay (pdMS_TO_TICKS (1000)); } }
Hasonlóképpen valósítsa meg a Task2 funkciót 500 ms késéssel.
5. A Void loop () üres marad.
Most töltse fel ezt a kódot az Arduino UNO-ra, és nyissa meg a soros monitort.
Látni fogja, hogy az 1. és a 2. feladat üzenetei nyomtatnak.
A Mutex működésének teszteléséhez tegye a következőket: xSemaphoreGive (mutex_v); bármilyen feladattól. Láthatja, hogy a program lefagy az utolsó nyomtatott üzeneten .
Így valósítható meg a Semaphore és a Mutex a FreeRTOS-ban az Arduino segítségével. A Semaphore-ról és a Mutex-ről további információt a FreeRTOS hivatalos dokumentációjában talál.
Az alábbiakban a szemafor és a némák teljes kódjai és videói találhatók.