This shows you the differences between two versions of the page.
patr:laboratoare:10 [2021/10/22 17:46] 127.0.0.1 external edit |
patr:laboratoare:10 [2022/01/13 14:00] (current) alexandru.ionita99 |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ===== Laboratorul 10. ===== | + | ===== Laboratorul 10 - Semafoare FreeRTOS ===== |
+ | |||
+ | |||
+ | ==== Introducere ==== | ||
+ | FreeRTOS conține un API specializat în crearea și apelarea semafoarelor, denumit **Semaphore API**. După cum ați observat în cadrul laboratorului de C POSIX cu același subiect, semafoarele și mutexurile pot fi utilizate pentru sincronizarea task-urilor, accesul la resurse partajate, dar și alte tipuri de semnalizări (similar cu rolul semafoarelor fizice :) ). \\ | ||
+ | |||
+ | FreeRTOS utilizează următoarele tipuri de semafoare, pe care le vom detalia în continuare: | ||
+ | * Semafoare binare | ||
+ | * Semafoare generalizate | ||
+ | * Mutexuri | ||
+ | |||
+ | În cadrul acestui laborator, vom discuta despre semafoarele binare și cele generalizate, urmând ca în următorul să fie prezentate mutexurile. | ||
+ | |||
+ | Toate tipurile de semafore, similar altor elemente din FreeRTOS, sunt referite cu ajutorul **handle-urilor**. În plus, pentru a le utiliza, este necesară declararea bilbiotecii **semphr.h**, alături de clasica **Arduino_FreeRTOS.h**. | ||
+ | |||
+ | <code c> | ||
+ | // Include biblioteca FreeRTOS | ||
+ | #include <Arduino_FreeRTOS.h> | ||
+ | |||
+ | // Include biblioteca pentru semafoare | ||
+ | #include <semphr.h> | ||
+ | |||
+ | // Declară o variabilă globală de tipul SemaphoreHandle_t | ||
+ | SemaphoreHandle_t semafor; | ||
+ | </code> | ||
+ | |||
+ | În [[https://www.freertos.org/fr-content-src/uploads/2018/07/FreeRTOS_Reference_Manual_V10.0.0.pdf|Documentația oficială FreeRTOS]], API-ul corespunzător este prezentat începând cu pagina 208, împreună cu exemple de utilizare pentru fiecare funcție. | ||
+ | |||
+ | ==== Declarare ==== | ||
+ | |||
+ | === Semafoare binare === | ||
+ | |||
+ | O situație în care semafoarele binare se pretează este sincronizarea a două task-uri. De exemplu, un task mai rapid poate fi blocat la un semafor până când un task mai lent ajunge într-un punct în care îl deblochează. \\ | ||
+ | |||
+ | Diferențele dintre mutexuri și semafoarele binare vor fi prezentate în cadrul laboratorului viitor. Momentan, ne vom orienta atenția către crearea semafoarelor binare. | ||
+ | |||
+ | Pentru a crea un semafor binar, este utilizată funcția ** xSemaphoreCreateBinary() **. Aceasta alocă spațiu în heap pentru semaforul binar și îl creează, cu starea inițială este "blocat". Dacă valoarea întoarsă este NULL, nu există suficientă memorie disponibilă. \\ | ||
+ | |||
+ | ** Exemplu: ** | ||
+ | <code c> | ||
+ | SemaphoreHandle_t xSemaphore; | ||
+ | void vATask( void * pvParameters ) | ||
+ | { | ||
+ | /* Încearcă crearea unui semafor. */ | ||
+ | xSemaphore = xSemaphoreCreateBinary(); | ||
+ | if( xSemaphore == NULL ) | ||
+ | { | ||
+ | /* Nu există spațiu suficient în memorie pentru a crea semaforul */ | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | /* Semaforul poate fi acum utilizat. Apelarea xSemaphoreTake() va eșua până la apelarea xSemaphoreGive(). */ | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | === Semafoare generalizate === | ||
+ | |||
+ | Semafoarele generalizate pot avea orice valoare ≥ 0. Când valoarea sa este 0, semaforul este blocat. Pentru a crea un semafor generalizat, este utilizată funcția **xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount )**. Primul argument reprezintă valoarea maximă a semaforului, iar al doilea argument definește valoare inițială a acestuia. | ||
+ | |||
+ | **Exemplu** | ||
+ | <code c> | ||
+ | void vATask( void * pvParameters ) | ||
+ | { | ||
+ | SemaphoreHandle_t xSemaphore; // Declarare handle | ||
+ | |||
+ | xSemaphore = xSemaphoreCreateCounting( 10, 0 ); // Creare semafor generalizat cu valoare inițială 0 și valoarea maximă 10 | ||
+ | if( xSemaphore != NULL ) | ||
+ | { | ||
+ | /* Semaforul a fost creat cu succces*/ | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | În exemplul de mai sus, handle-ul a fost declarat în interiorul unui task și nu sub formă de variabilă globală. | ||
+ | |||
+ | |||
+ | |||
+ | ==== Utilizare ==== | ||
+ | |||
+ | Următoarele funcții sunt de interes: | ||
+ | * Pentru a afla valoarea unui semafor, este utilizată funcția **UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore )** | ||
+ | * Pentru a crește valoarea unui semafor, este utilizată funcția **BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore )** | ||
+ | * Pentru a scădea valoarea unui semafor, este utilizată funcția **BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait)**. Al doilea parametru specifică timpul maxim pe care un task îl poate petrece așteptând deblocarea semaforului. După depășirea acestui timp, taksul își continuă execuția | ||
+ | * Pentru a șterge un semafor, este utilizată funcția **void vSemaphoreDelete( SemaphoreHandle_t xSemaphore )** | ||
+ | |||
+ | <note tip>Funcțiile **Give** și **Take** întorc două valori posibile: **pdPASS** dacă operația a fost realizată cu succes sau **pdFAIL** dacă nu.</note> | ||