0% au considerat acest document util (0 voturi)
4 vizualizări49 pagini

Tutoriale Arduino FreeRTOS

Acest document oferă o prezentare generală a creării de sarcini FreeRTOS în Arduino IDE pentru a face un LED să clipească. Se discută despre concepte cheie ale RTOS, cum ar fi sarcinile, programarea și preempția. Apoi, se explică cum să instalați biblioteca FreeRTOS în Arduino IDE, să creați sarcini folosind xTaskCreate() și să porniți programatorul. Este furnizată o schemă exemplu pentru a face un LED să clipească. Documentul demonstrează scrierea funcțiilor de sarcină și utilizarea vTaskDelay() în loc de delay() pentru temporizare.

Tradus de

ScribdTranslations
Drepturi de autor
© All Rights Reserved
Respectăm cu strictețe drepturile privind conținutul. Dacă suspectați că acesta este conținutul dumneavoastră, reclamați-l aici.
Formate disponibile
Descărcați ca PDF, TXT sau citiți online pe Scribd
0% au considerat acest document util (0 voturi)
4 vizualizări49 pagini

Tutoriale Arduino FreeRTOS

Acest document oferă o prezentare generală a creării de sarcini FreeRTOS în Arduino IDE pentru a face un LED să clipească. Se discută despre concepte cheie ale RTOS, cum ar fi sarcinile, programarea și preempția. Apoi, se explică cum să instalați biblioteca FreeRTOS în Arduino IDE, să creați sarcini folosind xTaskCreate() și să porniți programatorul. Este furnizată o schemă exemplu pentru a face un LED să clipească. Documentul demonstrează scrierea funcțiilor de sarcină și utilizarea vTaskDelay() în loc de delay() pentru temporizare.

Tradus de

ScribdTranslations
Drepturi de autor
© All Rights Reserved
Respectăm cu strictețe drepturile privind conținutul. Dacă suspectați că acesta este conținutul dumneavoastră, reclamați-l aici.
Formate disponibile
Descărcați ca PDF, TXT sau citiți online pe Scribd

Tutorial Arduino FreeRTOS 1 - Crearea

o sarcină FreeRTOS pentru a clipească LED-ul în

Arduino Uno
INCORPORAT
PrinRishabh Jain26 mar 20200

Fre
eRTOS sarcină pentru a clipi LED-ul în Arduino UNO
Sistemul de operare prezent în dispozitivele integrate se numește RTOS (Sistem de operare în timp real)
Sistem). În dispozitivele încorporate, sarcinile în timp real sunt critice unde timpul joacă un rol foarte important.
rol important. Sarcinile în timp real sunt deterministe în timp, ceea ce înseamnă că timpul de răspuns la orice
evenimentul este întotdeauna constant astfel încât să se poată garanta că orice eveniment particular va avea loc
la o oră fixă. RTOS este proiectat să ruleze aplicații cu o temporalitate foarte precisă și o înaltă
grad de fiabilitate. RTOS ajută, de asemenea, în multitasking cu un singur nucleu.

Am acoperit deja un tutorial desprecum se utilizează RTOS în sistemele încorporateunde ești


poate ști mai multe despre RTOS, diferența între sistemele de operare de uz general și RTOS,
diferite tipuri de RTOS, etc.

În acest tutorial, vom începe cu FreeRTOS. FreeRTOS este o clasă de RTOS pentru
dispozitive încorporate care sunt suficient de mici pentru a fi rulate pe microcontrolere de 8/16 biți,
deși utilizarea sa nu este limitată la aceste microcontrolere. Este complet open-source
și codul său este disponibil pegithubDacă știm câteva concepte de bază ale RTOS, atunci este
foarte ușor de utilizat FreeRTOS deoarece are API-uri bine documentate care pot fi utilizate direct
folosit în cod fără a cunoaște partea de backend a codării. CompletFreeRTOS
documentație poate fi găsit aici.
Deoarece FreeRTOS poate rula pe un MCU de 8 biți, acesta poate fi rulat și pe placa Arduino Uno. Noi
trebuie să descărcați biblioteca FreeRTOS și apoi să începeți să implementați codul folosind
APIs. Acest tutorial este destinat unui începător complet, mai jos sunt subiectele pe care le vom aborda
în acest tutorial Arduino FreeRTOS:

1. Cum funcționează RTOS


2. Câteva termeni folosiți frecvent în RTOS
3. Instalarea FreeRTOS în Arduino IDE
4. Cum să creați sarcini FreeRTOS cu exemplu

Cum funcționează un RTOS?

Înainte de a începe lucrul cu RTOS, să vedem ce este o Sarcină. O Sarcină este un fragment de cod care
este programabil pe CPU pentru a fi executat. Așa că, dacă doriți să efectuați o sarcină, atunci este
ar trebui să fie programat folosind întârzierea nucleului sau folosindinterrupții Această lucrare este realizată de
Scheduler prezent în kernel. Într-un procesor cu un singur nucleu, schedulerul ajută sarcinile să
se execută într-o fereastră de timp particulară, dar pare că sarcini diferite se execută
simultan. Fiecare sarcină se desfășoară conform priorității acordate acesteia.

Acum, să vedem ce se întâmplă în nucleul RTOS dacă dorim să creăm o sarcină pentru LED.
clipește cu un interval de o secundă și pune această sarcină pe cea mai înaltă prioritate.
Pe lângă sarcina LED, va mai fi încă o sarcină care este creată de nucleu, aceasta este
cunoscut sub numele de sarcină inactivă. Sarcina inactivă este creată atunci când nu există nicio sarcină disponibilă pentru execuție.
Această sarcină rulează întotdeauna cu cea mai mică prioritate, adică prioritate 0. Dacă analizăm graficul temporizării
având în vedere cele de mai sus, se poate observa că execuția începe cu o sarcină LED și rulează pentru o
timpul specificat, apoi pentru timpul rămas, sarcina inactivă rulează până când apare un întrerupător de tick.
Apoi, kernelul decide care sarcină trebuie executată în funcție de prioritatea sarcinii
și timpul total scurs al sarcinii LED. Când se finalizează 1 secundă, nucleul alege
sarcina LED trebuie executată din nou, deoarece are o prioritate mai mare decât sarcina inactivă, putem
de asemenea, spune că sarcina LED preia controlul asupra sarcinii idle. Dacă există mai mult de două sarcini cu
prioritatea aceea, atunci vor rula într-un mod rotativ pentru o perioadă specificată.

Mai jos este diagrama de stare, așa cum arată comutarea sarcinii care nu rulează în
stare de funcț ionare.
Fiecare sarcină nou creată se află în starea Pregătită (parte a stării nerecunoscute). Dacă sarcina creată
task (Task1) are cea mai mare prioritate față de alte sarcini, atunci va trece în starea de execuție. Dacă
această sarcină de rulare este întreruptă de cealaltă sarcină, apoi va reveni din nou în starea de pregătire.
În caz contrar, dacă task1 este blocat prin utilizarea unei API blocate, atunci CPU-ul nu va fi implicat în această sarcină
până la expirarea definită de utilizator.

Dacă Task1 este suspendat în starea de rulare folosind API-urile Suspend, atunci Task1 va merge la
Stare suspendată și nu este disponibilă din nou pentru planificator. Dacă reiei Task1 în
starea suspendată, apoi se va întoarce la starea de pregătire, după cum puteți vedea în bloc
diagramă.
Aceasta este ideea de bază despre cum rulează sarcinile și își schimbă stările. În acest tutorial, noi
va implementa două sarcini în Arduino Uno folosind API-ul FreeRTOS.

Termeni folosiți frecvent în RTOS


1. Sarcină: Este un fragment de cod care poate fi programat pe CPU pentru a fi executat.

2. Planificator: Este responsabil pentru selectarea unei sarcini din lista de stare pregătită pentru a fi executată.
state. Planificatorii sunt adesea implementați astfel încât să mențină toate resursele computerului ocupate (căci
în echilibrarea sarcinii).

3. Preemptie: Este actul de a întrerupe temporar o sarcină care este deja în execuție cu
intenția de a-l elimina din starea de funcționare fără cooperarea sa.

4. Schimbarea contextului: În preempția bazată pe prioritate, planificatorul compară prioritatea


de a rula sarcini cu o prioritate a listei de sarcini gata la fiecare întrerupere a sistemului. Dacă există vreo
o sarcină din listă a cărei prioritate este mai mare decât sarcina în execuție, atunci are loc o comutare a contextului.
În esență, în acest proces, conținuturile diferitelor sarcini sunt salvate în stiva lor respectivă.
memorie.

5. Tipuri de politici de programare:

1. Programare Preemptivă: În acest tip de programare, sarcinile se execută cu timp egal


felie fără a lua în considerare prioritățile.
2. Preemptiv pe bază de prioritate: Sarcina cu prioritate mare va rula prima.
3. Programare cooperativă: Comutarea contextului va avea loc doar cu co-
funcționarea sarcinilor de execuție. Sarcina va rula continuu până când se va apela yield-ul sarcinii.
6. Obiecte Kernel: Pentru semnalizarea sarcinii de a efectua o muncă, sincronizarea
se utilizează. Pentru a efectua acest proces, se folosesc obiecte Kernel. Unele obiecte Kernel
sunt Evenimente, Semafore, Cozi, Mutex, Cutii poștale etc. Vom vedea cum să le folosim
obiecte în tutorialele viitoare.

Din discuția de mai sus, am obținut câteva idei de bază despre conceptul de RTOS și
Acum putem implementa proiectul FreeRTOS în Arduino. Așadar, să începem cu
instalarea bibliotecilor FreeRTOS în Arduino IDE.

Instalarea bibliotecii Arduino FreeRTOS


1. Deschide Arduino IDE și mergi la Sketch -> Include Library -> Manage Libraries.
Caută FreeRTOS și instalează biblioteca așa cum este arătat mai jos.

Puteți descărca biblioteca de pe github și adăugați fișierul .zip în Sketch -> Include
Bibliotecă -> Adaugă fiș ier .zip.

Acum, reporniți Arduino IDE. Această bibliotecă furnizează unele exemple de cod, de asemenea, care pot fi
găsit inFile -> Exemple -> FreeRTOS aș a cum este prezentat mai jos.
Aici vom scrie codul de la zero pentru a înțelege funcționarea, mai târziu poți verifica.
exemplul codurilor și folosiți-le.

Diagramă de circuit
Mai jos este diagrama circuitului pentru crearea sarcinii LED intermitent folosind FreeRTOS pe Arduino:
Exemplu Arduino FreeRTOS - Crearea sarcinilor FreeRTOS în
Arduino IDE
Să vedem o structură de bază pentru a scrie un proiect FreeRTOS.

1. În primul rând, include fișierul de antet Arduino FreeRTOS ca

#include <Arduino_FreeRTOS.h>

2. Oferiți prototipul funcției pentru toate funcțiile pe care le scrieți pentru execuție care este
scris ca

void Task1( void *pvParameters );

void Task2( void *pvParameters );

..

….

3. Acum, în funcția void setup(), creați sarcini și începeți planificatorul de sarcini.

Pentru crearea unei sarcini, API-ul xTaskCreate() este apelat în funcția setup cu anumite
parametrii/argumente.

xTaskCreate( Funcț iaTask_t codTaskPv const caracter * const numePC uint16_t


adâncimeaStiveiUs void *pvParameters, UBaseType_t prioritateUX TaskHandle_t
*pxCreatedTask );
Există 6 argumente care ar trebui să fie trecute în momentul creării unui task. Să vedem ce
aceste argumente sunt

1. Este pur ș i simplu un indicator către funcț ia care implementează sarcina (în
efect, doar numele funcției).
2. Un nume descriptiv pentru sarcină. Acesta nu este utilizat de FreeRTOS. Este
inclus doar în scopuri de depanare.
3. Fiecare sarcină are propriul său stivă unică care este alocată de kernel
la sarcină atunci când sarcina este creată. Valoarea specifică numărul de cuvinte pe care le
stiva poate reține, nu numărul de octeți. De exemplu, dacă stiva are lățimea de 32 de biți
anduStackDepth este trecut ca 100, apoi 400 de bytes de spațiu pe stivă vor fi
alocat (100 * 4 octeți) în RAM. Folosește acest lucru cu înțelepciune, deoarece Arduino Uno are doar
2 Kbytes de RAM.
4. pvParameters: Parametru de intrare al sarcinii (poate fi NULL).
5. Prioritatea sarcinii (0 este cea mai scăzută prioritate).
6. Poate fi folosit pentru a transmite un handle către sarcina care este creată.
Această mândră poate fi folosită pentru a face referire la sarcină în apelurile API care, de exemplu,
schimba prioritatea sarcinii sau șterge sarcina (poate fi NULL).
Exemplu de creare a unei sarcini

xTaskCreate(task1, "task1", 128, NULL, 1, NULL);

xTaskCreate(task2,"task2",128,NULL,2,NULL);

Aici, Task2 are o prioritate mai mare și, prin urmare, se execută primul.

4. După crearea sarcinii, porniți programatorul în a void setup


folosind vTaskStartScheduler(); API.

Funcția void loop() va rămâne goală, deoarece nu dorim să executăm nicio sarcină manual.
în mod infinit. Pentru că executarea sarcinilor este acum gestionată de Scheduler.

6. Acum, trebuie să implementăm funcțiile de sarcină și să scriem logica pe care vrem să o executăm
în interiorul acestor funcții. Numele funcției ar trebui să fie același cu primul argument
API ofxTaskCreate()

void task1(void *pvParameters)

while(1) {

..

..//logica ta

}
7. Cea mai mare parte a codului are nevoie de o funcție de întârziere pentru a opri sarcina în execuție, dar în RTOS nu este nevoie.
s-a sugerat utilizarea funcției Delay() deoarece oprește CPU-ul și, prin urmare, RTOS-ul se oprește de asemenea
Deci, FreeRTOS are o API de nucleu pentru a bloca sarcina pentru o perioadă specifică de timp.

vTaskDelay( const TickType_t xTicksToDelay );

Această API poate fi utilizată în scopuri de întârziere. Această API întârzie o sarcină pentru un număr dat de
ticitii. Timpul efectiv pentru care sarcina rămâne blocată depinde de rata de tic.
constantport TICK_PERIOD_MScan poate fi folosit pentru a calcula în timp real din rata de ticks.

Asta înseamnă că, dacă dorești o întârziere de 200ms, pur și simplu scrii această linie

vTaskDelay( 200 / portTICK_PERIOD_MS );

Așa că pentru acest tutorial, vom folosi aceste API-uri FreeRTOS pentru a implementa trei sarcini.

APIs care trebuie folosite:

1. xTaskCreate();
2. vTaskStartScheduler();
3. vTaskDelay();
Sarcina care trebuie creată pentru acest tutorial:

1. LED clipește la pinul digital 8 cu o frecvență de 200ms


2. LED-ul clipește la pinul digital 7 cu o frecvență de 300 ms
3. Imprimă numere pe monitorul serial cu o frecvență de 500 ms.

Implementarea sarcinilor FreeRTOS în Arduino IDE


1. Din explicația de mai sus a structurii de bază, includeți antetul Arduino FreeRTOS
fișier. Apoi creați prototipuri de funcții. Având în vedere că avem trei sarcini, creați trei funcții
și prototipurile sale.

#include <Arduino_FreeRTOS.h>

void TaskBlink1( void *pvParameters );

void TaskBlink2( void *pvParameters );

void Taskprint( void *pvParameters );

2. În funcția setup() învoid, inițializează comunicația serială la 9600 biți pe secundă și


creați toate cele trei sarcini folosind API-ul xTaskCreate(). Inițial, faceți prioritățile tuturor sarcinilor
ca '1' și pornește programatorul.

void setup() {

[Link](9600);
xTaskCreate(TaskBlink1,"Task1",128,NULL,1,NULL);

xTaskCreate(TaskBlink2,"Task2 ",128,NULL,1,NULL);

xTaskCreate(Taskprint, "Task3", 128, NULL, 1, NULL);

vTaskStartScheduler();

3. Acum, implementează cele trei funcții așa cum este arătat mai jos pentru sarcina 1 LED clipire.

void TaskBlink1(void *pvParameters)

pinMode(8, OUTPUT);

while(1)

digitalWrite(8, ÎNALT);

vTaskDelay( 200 / portTICK_PERIOD_MS );

digitalWrite(8, LOW);

vTaskDelay( 200 / portTICK_PERIOD_MS );

În mod similar, funcția implementTaskBlink2. Funcția Task3 va fi scrisă ca

void Taskprint(void *pvParameters)

int contador = 0;

în timp ce(1)

counter++;

[Link](counter);
vTaskDelay( 500 / portTICK_PERIOD_MS );

Asta e. Am finalizat cu succes un proiect FreeRTOS pentru Arduino.


Uno. Puteți găsi codul complet împreună cu un videoclip la sfârșitul acestui tutorial.

În cele din urmă, conectați două LED-uri la pinul digital 7 și 8 și încărcați codul pe Arduino dvs.
conectați placa și deschideți monitorul Serial. Veți vedea un contor care funcționează o dată la 500ms cu
numele sarcinii este afișat mai jos.

De asemenea, observă LED-urile, ele clipocește la intervale de timp diferite. Încercă să te joci cu
argumentul de prioritate în funcția xTaskCreate. Schimbați numărul și observați
comportamentul pe monitorul serial și LED-uri.

Acum, poți înțelege primele două exemple de cod în care se citește analogic și digital
sarcinile citite sunt create. În acest fel, poți realiza proiecte mai avansate folosind doar
Arduino Uno și API-urile FreeRTOS.

Cod
#include <Arduino_FreeRTOS.h>
void TaskBlink1( void *pvParameters );
void TaskBlink2( void *pvParameters );
void Taskprint( void *pvParameters );
void setup() {
// initialize comunicarea serială la 9600 biți pe secundă:
[Link](9600);
xTaskCreate(
TaskBlink1
task1
, 128
, NULL
, 1
, NULL );
xTaskCreate(
TaskBlink2
task2
, 128
, NULL
, 1
, NULL );
xTaskCreate(
Taskprint
task3
128
, NULL
1
, NULL );
vTaskStartScheduler();
}
void loop()
{
}
void TaskBlink1(void *pvParameters) {
pinMode(8, OUTPUT);
în timp ce(1)
{
[Link]("Task1");
digitalWrite(8, ÎNALT);
vTaskDelay( 200 / portTICK_PERIOD_MS );
digitalWrite(8, LOW);
vTaskDelay( 200 / portTICK_PERIOD_MS );
}
}
void TaskBlink2(void *pvParameters)
{
pinMode(7, OUTPUT);
while(1)
{
[Link]("Task2");
digitalWrite(7, HIGH);
vTaskDelay( 300 / portTICK_PERIOD_MS );
digitalWrite(7, LOW);
vTaskDelay( 300 / portTICK_PERIOD_MS );
}
}
void Taskprint(void *pvParameters) {
int counter = 0;
while(1)
{
counter++;
[Link](counter);
vTaskDelay(500 / portTICK_PERIOD_MS); }
}

Video
#include <Arduino_FreeRTOS.h>
void TaskBlink1( void *pvParameters );
void TaskBlink2( void *pvParameters );
void Taskprint( void *pvParameters );
void setup() {
// inițializează comunicația serială la 9600 biți pe secundă:
[Link](9600);
xTaskCreate(
TaskBlink1
task1
, 128
, NULL
, 1
, NULL );
xTaskCreate(
TaskBlink2
task2
, 128
, NULL
1
, NULL );
xTaskCreate(
Taskprint
task3
, 128
, NULL
, 1
, NULL );
vTaskStartScheduler();
}
void loop()
{
}
void TaskBlink1(void *pvParameters) {
pinMode(8, OUTPUT);
while(1)
{
[Link]("Task1");
digitalWrite(8, ÎNALT);
vTaskDelay( 200 / portTICK_PERIOD_MS );
digitalWrite(8, LOW);
vTaskDelay( 200 / portTICK_PERIOD_MS );
}
}
void TaskBlink2(void *pvParameters)
{
pinMode(7, OUTPUT);
while(1)
{
[Link]("Task2");
digitalWrite(7, HIGH);
vTaskDelay( 300 / portTICK_PERIOD_MS );
digitalWrite(7, LOW);
vTaskDelay( 300 / portTICK_PERIOD_MS );
}
}
void Taskprint(void *pvParameters) {
int counter = 0;
while(1)
{
counter++;
[Link](counter);
vTaskDelay(500 / portTICK_PERIOD_MS); }
}

PARTEA 2
Arduino FreeRTOS Tutorial 2 - Folosind
Cozi în Arduino FreeRTOS
ÎNCORPORAT
DeRishabh Jain06 Apr 20200
Arduino FreeRTOS folosind cozi
În tutorialul anterior, am introdusFreeRTOS în Arduino Uno și a creat o sarcină pentru
LED-ul care clipește Acum, în acest tutorial, ne vom adânci mai mult în conceptele avansate ale RTOS
APIs și învățăm despre comunicarea între diferite sarcini. Aici învățăm, de asemenea, despre
Coada pentru transferul datelor de la o sarcină la alta și a demonstra funcționarea acesteia
coada API-urilor prin interfaț area LCD 16x2 ș i LDR cu Arduino Uno.

Înainte de a discuta despre Cozi, să vedem încă o API FreeRTOS care este utilă în
ștergerea sarcinilor când este terminată cu munca asignată. Uneori, sarcina are nevoie de
a fi șters pentru a elibera memoria alocată. În continuareatutorial anterior, vom
folosiț i funcț ia API usevTaskDelete() în acelaș i cod pentru a ș terge una dintre sarcini. O sarcină poate
folosiț i funcț ia API vTaskDelete() pentru a se ș terge pe sine sau orice altă sarcină.

Pentru a folosi această API, trebuie să configurezi fișierul FreeRTOSConfig.h. Acest fișier este folosit pentru
adaptează FreeRTOS în funcție de aplicație. Este folosit pentru a schimba planificarea
algoritmi și multe alte parametrii. Fișierul poate fi găsit în directorul Arduino
care este în general disponibil în folderul Documente al PC-ului tău. În cazul meu, este
disponibil în\Documents\Arduino\libraries\FreeRTOS\src așa cum este afișat mai jos.
Acum, deschide acest fișier folosind orice editor de text și caută după #define
INCLUDE_vTaskDelete ș i asiguraț i-vă că valoarea sa este '1' (1 înseamnă activat ș i 0 înseamnă
dezactivat). Este 1 în mod implicit, dar verifică pentru acesta.

Vom folosi frecvent acest fișier de configurare în următoarele tutoriale pentru a seta parametrii.

Acum, să vedem cum se șterge o sarcină.


Ștergerea unei sarcini în FreeRTOS Arduino

Pentru a șterge o sarcină, trebuie să folosim funcția API vTaskDelete(). Aceasta ia doar un singur
argument.

vTaskDelete( TaskHandle_t pxTaskDeSters );

pxTaskToDelete: Este manerul sarcinii care urmează să fie ș ters. Este acelaș i ca
6 th argumentul funcției xTaskCreate() API. Întutorial anterior, acest argument este setat ca NULL
dar poți pasa adresa conținutului sarcinii folosind orice nume. Să zicem că dacă
vrei să setezi manevra de sarcină pentru Task2, care este declarat ca

TaskHandle_t orice_nume;

Exemplu: TaskHandle_t xTask2Handle;

Acum, în API-ul vTaskCreate() setează al 6-lea


th argument ca

xTaskCreate(TaskBlink2, "task2", 128, NULL, 1, &xTask2Handle);

Conținutul acestei sarcini poate fi acum accesat folosind mânerele furnizate de tine.

De asemenea, o sarcină poate să se ștergă singură prin trecerea NULL în locul unui maner de sarcină valid.

Dacă dorim să ștergem Task 3 din task 3 însuși, trebuie să


scrieTaskDelete( NULL ); în interiorul funcției Task3 dar dacă vrei să ștergi taskul 3
din task 2, apoi scrie TaskDelete(xTask3Handle); în interiorul funcț iei task2.

În codul tutorial anterior, pentru a șterge Task2 din task2 în sine, doar
adauga TaskDelete (NULL); în funcția void TaskBlink2(void *pvParameters). Apoi,
funcția de mai sus va arăta astfel

void TaskBlink2(void *pvParameters)

[Link]("Task2 rulează ș i este pe cale să ș teargă");

vTaskDelete(NULL);

pinMode(7, OUTPUT);

while(1)

digitalWrite(7, ÎNALT);
vTaskDelay( 300 / portTICK_PERIOD_MS );

digitalWrite(7, LOW);

vTaskDelay( 300 / portTICK_PERIOD_MS );

Acum, încarcă codul și observă LED-urile și monitorul serial. Vei vedea că


al doilea LED nu mai clipește acum și task2 a fost șters după întâlnirea cu API-ul de ștergere.

Așadar, această API poate fi utilizată pentru a opri executarea sarcinii respective.

Acum, să începem cu coada.

Ce este coada în FreeRTOS?


Coada este structura de date care poate conține un număr finit de elemente de dimensiune fixă și ea
este operat în schema FIFO (Primul venit, primul servit). Cozile oferă o legătură între sarcini,
mecanism de comunicare de tip întrerupere și întrerupere-la-sarcină.

Numărul maxim de elemente pe care o coadă îl poate conține se numește "lungime". Atât lungimea
iar dimensiunea fiecărui element este stabilită atunci când coada este creată.

Un exemplu de cum este folosită coada pentru transferul de date este ilustrat bine în FreeRTOS
documentația care poate figăsit aiciPuteți înțelege cu ușurință exemplul dat.
După ce am înțeles cozile, să încercăm să înțelegem procesul de creare a unei cozi
și încearcă să-l implementezi în codul nostru FreeRTOS.

Crearea unei cozi în FreeRTOS


În primul rând, descrie enunțul problemei care trebuie implementat cu ajutorul
Coada FreeRTOS și Arduino Uno.

Vrem să imprimăm valoarea senzorului LDR pe un LCD de 16*2. Așadar, există două sarcini.
acum

1. Task1 obține valori analogice de la LDR.


2. Task2 afișează valoarea analogică pe LCD.
Așadar, aici coada își joacă rolul pentru că trebuie să trimită datele generate de task1 către task2. În
task1, vom trimite valoarea analogică în coadă și în task2, o vom primi de la
coada.

Există trei funcții pentru a lucra cu cozi

1. Crearea unei cozi


2. Trimiterea datelor în coadă
3. Receivând date din coadă
1. Crearea unei Cozi
Pentru a crea o coadă, utilizați funcția API xQueueCreate(). Aceasta ia două argumente.

xQueueCreate(UBaseType_t uxQueueLength, UBaseType_t uxItemSize);

Numărul maxim de elemente pe care coada creată le poate deț ine


în orice moment.

Mărimea în octeț i a fiecărui element de date care poate fi stocat în coadă.

Dacă această funcție returnează NULL, atunci coada nu este creată din cauza memoriei insuficiente
și dacă returnează o valoare non-NULL, coada este creată cu succes. Stocați acest return
valoare unei variabile pentru a o folosi ca un mâner pentru a accesa coada, așa cum este arătat mai jos.

QueueHandle_t coada1;

queue1 = xQueueCreate(4,sizeof(int));

Aceasta va crea o coadă de 4 elemente în memoria heap de dimensiune int (2 biți pentru fiecare bloc)
și stochează valoarea de returnare în variabila thequeue1handle.

2. Trimiterea datelor în coadă în FreeRTOS

Pentru a trimite valorile în coadă, FreeRTOS are 2 variante de API pentru acest scop.

1. xQueueSendToBack(): Folosit pentru a trimite date către spatele (coada) unei cozi.
2. xQueueSendToFront(): Folosit pentru a trimite date la începutul (capul) unei cozi.
Acum, xQueueSend() este echivalent cu, și exact la fel ca, xQueueSendToBack().

Toate aceste API-uri iau 3 argumente.

xQueueSendToBack( QueueHandle_t xQueue, const niciunul * pvItemToQueue, TickType_t


xTicksToWait );

xQueue: Manea coada la care sunt trimise (scrise) datele. Această variabilă
este la fel ca cel folosit pentru a stoca valoarea de returnare a API-ului xQueueCreate.

pvItemToQueue: Un pointer către datele care trebuie copiate în coadă.

Timpul maxim în care sarcina ar trebui să rămână în blocat


starea de a aștepta să devină disponibil spațiul în coadă.
Setarea xTicksToWait la portMAX_DELAY va cauza ca sarcina să aș tepte la nesfârș it (fără
timpul de a expira), cu condiția ca INCLUDE_vTaskSuspend să fie setat la 1 în FreeRTOSConfig.h
poți folosi macropdMS_TO_TICKS() pentru a converti un timp specificat în milisecunde
într-un timp specificat în ticuri.

3. Primirea datelor din coadă în FreeRTOS


Pentru a primi (citi) un element dintr-o coadă, se folosește xQueueReceive(). Elementul care este
recepționat este eliminat din coadă.

Această API ia de asemenea trei argumente.

xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t


xTicksToWait );

Primul și al treilea argument sunt aceleași ca trimiterea API-ului. Doar al doilea argument este
diferit.

const pvBuffer: Un pointer către memoria în care vor fi copiate datele primite.

Sper că ai înțeles cele trei API-uri. Acum, vom implementa aceste API-uri în Arduino
IDE și încearcă să rezolvi problema pe care am descris-o mai sus.

Diagrama de circuit

Așa arată pe placa de testare:


Implementarea Queue-ului FreeRTOS în Arduino IDE
Să începem să scriem cod pentru aplicația noastră.

1. Mai întâi, deschide Arduino IDE și include fișierul de antet Arduino_FreeRTOS.h. Acum, dacă vreun
Un obiect kernel de tip coadă este folosit, apoi includeți fișierul header corespunzător. Deoarece folosim 16*2
LCD, așa că includeți și biblioteca pentru acesta.

#include <Arduino_FreeRTOS.h>

#include <queue.h>

#include <LiquidCrystal.h>

2. Inițializează un mâner de coadă pentru a stoca conținutul cozii. De asemenea, inițializează pinul LCD
numere.

QueueHandle_t queue_1;

LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

3. În funcția setup(), inițializează LCD-ul și monitorul serial cu o rată de 9600 baud. Creează o coadă.
și două sarcini folosind API-urile respective. Aici vom crea o coadă de dimensiune 4 cu
tip întreg. Creează o sarcină cu priorități egale și mai târziu încearcă să te joci cu acest număr.
În cele din urmă, porniți planificatorul așa cum este arătat mai jos.
void setup() {

[Link](9600);

[Link](16, 2);

xQueueCreate(4, sizeof(int));

dacă (queue_1 == NULL) {

Queue nu poate fi creat

xTaskCreate(TaskDisplay, "Display_task", 128, NULL, 1, NULL);

xTaskCreate(TaskLDR, "LDR_task", 128, NULL, 1, NULL);

vTaskStartScheduler();

4. Acum, creează două funcții TaskDisplay și TaskLDR. În funcția TaskLDR, citește


pinul analog A0 într-o variabilă, deoarece avem LDR conectat la pinul A0 al Arduino UNO.
Acum trimite valoarea stocată în variabilă prin trecerea acesteia în API-ul thexQueueSend.
trimite sarcina la blocare a stării după 1 secundă folosind API-ul vTaskDelay() așa cum este prezentat mai jos.

void TaskLDR(void * pvParameters) {

int intensitate_curentă;

while(1) {

[Link]("Task1");

intensitate_curentă = analogRead(A0);

[Link](current_intensity);

xQueueSend(queue_1, &current_intensity, portMAX_DELAY);

vTaskDelay( 1000 / portTICK_PERIOD_MS );

5. În mod similar, faceți o funcție pentruTaskDisplayși primiți valorile într-o variabilă care este
transmis funcției xQueueReceive. De asemenea, xQueueReceive() returnează pdPASS dacă
datele pot fi primite cu succes din coadă și returnează ERR_QUEUE_EMPTY dacă a
coada este goală.

Acum, afișați valorile pe LCD folosind funcția [Link]() .

void TaskDisplay(void * pvParameters) {

int intensity = 0;

în timp ce(1) {

[Link]("Task2");

dacă (xQueueReceive(queue_1, &intensity, portMAX_DELAY) == pdPASS) {

[Link]();

[Link](0, 0);

[Link]("Intensitate:");

[Link](11, 0);

[Link](intensitate);

Asta e tot. Am terminat partea de codare a implementării cozii. Cod complet


cu un videoclip funtional care poate fi gasit la sfarsit.

Acum, conectează LCD-ul și LDR-ul la Arduino UNO conform schemei electrice


încarcă codul. Deschide monitorul serial și observă sarcinile. Vei vedea sarcinile sunt
valorile comutării și ale LDR-ului se schimbă în funcție de intensitatea luminii.
NOTĂ: Cele mai multe biblioteci create pentru diferite senzori nu sunt suportate de
Nucleul FreeRTOS din cauza implementării funcției de întârziere în biblioteci. Întârzierea face
CPU-ul se oprește complet, prin urmare, nucleul FreeRTOS încetează de asemenea să funcționeze și codul
nu va executa mai departe și începe să se comporte necorespunzător. Deci, trebuie să facem bibliotecile
fără întârzieri pentru a lucra cu FreeRTOS.

Cod
#include <Arduino_FreeRTOS.h>
#include <queue.h>
#include <LiquidCrystal.h>
QueueHandle_t queue_1;
LiquidCrystal lcd(7, 8, 9, 10, 11, 12); // RST E D4 D5 D6 D7
void setup() {
[Link](9600);
[Link](16, 2);
queue_1 = xQueueCreate(5, sizeof(int));
dacă (queue_1 == NULL) {
[Link]("Coada nu poate fi creată");
}
xTaskCreate(TaskDisplay, "Display_task", 128, NULL, 1, NULL);
xTaskCreate(TaskLDR, "LDR_task", 128, NULL, 1, NULL);
vTaskStartScheduler();
}
void loop() {
}
void TaskDisplay(void * pvParameters) {
int intensitate = 0;
while(1) {
[Link]("TaskDisplay");
dacă (xQueueReceive(queue_1, &intensity, portMAX_DELAY) == pdPASS) {
[Link]();
[Link](0, 0);
[Link]("Intensitate:");
[Link](11, 0);
[Link](intensitate);
}
}
}
void TaskLDR(void * pvParameters) {
int intensitate_curentă;
while(1) {
[Link]("TaskLDR");
current_intensity = analogRead(A0);
[Link](intensitatea_curentă);
xQueueSend(queue_1, &current_intensity, portMAX_DELAY);
vTaskDelay( 1000 / portTICK_PERIOD_MS );
}
}

Video

PARTEA 3
Tutorial Arduino FreeRTOS 3 - Folosind
Semafor și Mutex în FreeRTOS
cu Arduino
ÎNCORPORAT
PrinRishabh Jain09 Apr 20200
Semafor ș i Mutex în FreeRTOS cu Arduino
În tutorialele anterioare, am abordatnoțiunile de bază ale FreeRTOS cu Arduino și
theObiect de kernel coadă în FreeRTOS ArduinoAcum, în acest al treilea tutorial FreeRTOS, noi
vei învăța mai multe despre FreeRTOS și API-urile sale avansate, care te pot ajuta să înțelegi
platforma de multitasking mai profund.

Semaforul ș i Mutexul (Excludere mutuală) sunt obiectele de kernel care sunt folosite pentru
sincronizare, gestionarea resurselor și protejarea resurselor împotriva corupției. În
în prima jumătate a acestui tutorial, vom vedea ideea din spatele Semaphore, cum și unde să o folosim
În a doua jumătate, vom continua cu Mutex.

Ce este semaforul?
În tutorialele anterioare, am discutat despre prioritățile sarcinilor și am aflat de asemenea că un
o sarcină de prioritate mai mare o împiedică pe cea de prioritate mai mică, așa că în timp ce se execută sarcina de prioritate înaltă
ar putea exista o posibilitate ca corupția datelor să apară în sarcinile de prioritate mai mică deoarece
nu a fost executat încă și datele vin continuu la această sarcină de la un senzor care
cauzează pierderi de date și defecțiuni ale întregii aplicații.
Deci, există o necesitate de a proteja resursele de pierderea datelor ș i aici Semaphore joacă un rol.
rol important.
Semaforul este un mecanism de semnalizare în care o sarcină într-o stare de așteptare este semnalizată de
o altă sarcină de executat. Cu alte cuvinte, când o sarcină1 își finalizează munca, atunci va
afișează un steag sau crește un steag cu 1 și apoi acest steag este primit de o altă sarcină (sarčina2)
arată că poate să-și îndeplinească munca acum. Când task2 își va termina munca, atunci steagul va
fi redus cu 1.
Deci, în esență, este un mecanism de „Dă” și „Primește” și semaforul este o variabilă întreagă.
care este folosit pentru a sincroniza accesul la resurse.

Tipuri de Semafor în FreeRTOS:

Semaforul este de două tipuri.

1. Semafor binar
2. Semaphore de numărare
1. Semafor binar: Are două valori întregi 0 și 1. Este oarecum similar cu
Coada de lungime 1. De exemplu, avem două sarcini, task1 și task2. Task1 trimite date.
pentru task2, astfel că task2 verifică continuu elementul din coadă; dacă există 1, atunci poate citi
date în caz contrar trebuie să aștepte până devine 1. După preluarea datelor, task2 decrementează
coada și fă-l 0. Asta înseamnă că task1 poate trimite din nou datele către task2.

Din exemplul de mai sus, se poate spune că semaforul binar este folosit pentru
sincronizarea între sarcini sau între sarcini și întreruperi.

2. Semafor de numărare: are valori mai mari decât 0 ș i poate fi considerat un coadă de
lungime mai mare de 1. Acest semafor este utilizat pentru numărarea evenimentelor. În acest scenariu de utilizare,
un handler de evenimente va 'oferi' un semafor de fiecare dată când apare un eveniment (incrementând
valoarea de contor a semaforului), iar o sarcină de manipulare va 'lua' un semafor de fiecare dată când acesta
procesează un eveniment (decrementând valoarea contorului semaforului).

Valoarea numărului este, așadar, diferența dintre numărul de evenimente care au


s-a întâmplat și numărul care a fost procesat.

Acum, să vedem cum să folosim Semaphore în codul nostru FreeRTOS.

Cum să folosești Semaphore în FreeRTOS?

FreeRTOS suportă diferite API-uri pentru crearea unei semafor, obținerea unei semafor și
dând un semafor.

Acum, pot exista două tipuri de API-uri pentru același obiect kernel. Dacă trebuie să oferim
semafor dintr-un ISR, atunci API-ul normal de semafor nu poate fi folosit. Ar trebui să folosești
API-uri protejate de întreruperi.

În acest tutorial, vom folosi semafor binar deoarece este uș or de înț eles ș i
implementați. Deoarece funcționalitatea de întrerupere este utilizată aici, trebuie să folosiți protecție împotriva întreruperilor

APIs în funcția ISR. Când spunem sincronizarea unei sarcini cu o întrerupere, ea


înseamnă punerea sarcinii în starea de rulare imediat după ISR.

Crearea unui semafor:

Pentru a utiliza orice obiect de kernel, trebuie mai întâi să-l creăm. Pentru a crea un semafor binar,
usevSemaphoreCreateBinary().

Această API nu ia niciun parametru și returnează o variabilă de tip


SemaphoreHandle_t. O variabilă globală numită sema_vis creată pentru a stoca
semafor.
SemaphoreHandle_t sema_v;

sema_v = xSemaphoreCreateBinary();

Furnizând un semafor:

Pentru a oferi un semafor, există două versiuni - una pentru întrerupere și alta pentru
sarcină normală.

1. xSemaphoreGive(): Această API ia doar un argument, care este variabila


numele semaforului, cum ar fi sema_v, așa cum s-a dat mai sus la crearea unui semafor. Poate
fii apelat din orice sarcină normală pe care dorești să o sincronizezi.
2. xSemaphoreGiveFromISR(): Aceasta este varianta API protejată de întrerupere a
xSemaphoreGive(). Când avem nevoie să sincronizăm un ISR și o sarcină normală, atunci
xSemaphoreGiveFromISR() ar trebui folosit din funcția ISR.
Folosind un semafor:

Pentru a lua un semafor, utilizați funcția API xSemaphoreTake(). Această API acceptă două
parametrii.

xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait );

xSemaphore:Numele semaforului care trebuie preluat în cazul nostru sema_v.

Aceasta este cantitatea maximă de timp în care sarcina va aș tepta în Stare Blocat
stare pentru ca semaforul să devină disponibil. În proiectul nostru, vom
setxTicksToWaittoportMAX_DELAY pentru a face ca task_1 să aș tepte la infinit în Blocată
așteptați până când sema_v este disponibil.

Acum, să folosim aceste API-uri și să scriem un cod pentru a efectua anumite sarcini.

Aici este un buton și două LED-uri sunt interfețate. Butonul va acționa ca un


buton de întrerupere care este atașat la pinul 2 al Arduino Uno. Când acest buton este apăsat
va fi generat un întrerupător și un LED conectat la pinul 8 va fi aprins
și când îl apesi din nou, va fi OPRIT.

Așadar, când butonul este apăsat, xSemaphoreGiveFromISR() va fi apelată din funcția ISR.
funcția andxSemaphoreTake() va fi apelată din funcția TaskLED.
Pentru a face sistemul să arate ca având multitasking, conectați alte LED-uri cu pinul 7 care va fi în
stare de clipire constantă.

Explicația codului semafor


Hai să începem să scriem cod deschizând IDE-ul Arduino
1. În primul rând, include fișierul de antet Arduino_FreeRTOS.h. Acum, dacă se folosește orice obiect al nucleului
ca un semafor de coadă, trebuie inclus și un fișier de antet pentru acesta.

#include <Arduino_FreeRTOS.h>
#include <semphr.h>

2. Declară o variabilă de tip SemaphoreHandle_t pentru a stoca valorile semaforului.

SemaphoreHandle_t semaforInterrupț ie;

3. În funcția void setup(), creați două sarcini (TaskLED și TaskBlink) folosind API-ul xTaskCreate()
și apoi creează un semafor folosind xSemaphoreCreateBinary(). Creează o sarcină cu egal
priorități și apoi încearcă să te joci cu acest număr. De asemenea, configurează pinul 2 ca intrare și
activează rezistorul de pull-up intern și atașează pinul de întrerupere. În cele din urmă, pornește
programatorul așa cum este arătat mai jos.

void setup() {

pinMode(2, INPUT_PULLUP);

xTaskCreate(TaskLed, "Led", 128, NULL, 0, NULL);

xTaskCreate(TaskBlink, "LedBlink", 128, NULL, 0, NULL);

interruptSemaphore = xSemaphoreCreateBinary();

dacă (semaforulDeInterrupț ie != NULL) {

ataș eazăInterrupț ie(digitalPinToInterrupt(2), debounceInterrupt, LOW);

4. Acum, implementați funcția ISR. Creați o funcție și numiți-o la fel ca și


al doilea argument al funcției attachInterrupt(). Pentru a face ca întreruperea să funcționeze corect, trebuie să
trebuie să elimin problema de debouncing a butonului folosind funcția millis sau micros
și de ajustare the debouncing timp. De la acesta funcție
funcția callinterruptHandler() așa cum este arătat mai jos.

timp_de_bătaie_de_lungime = 150;

volatile unsigned long last_micros;

void debounceInterrupt() {

dacă((long)(micros() - last_micros) >= debouncing_time * 1000) {

interruptHandler();

microsecunde_ultime = microsecunde();
}

Funcția IninterruptHandler(), apel pentru API-ul callxSemaphoreGiveFromISR().

void handlerDeInterruptie() {

xSemaphoreGiveFromISR(interruptSemaphore, NULL);

Această funcție va oferi un semafor pentru TaskLed pentru a aprinde LED-ul.

5. Creează o funcție TaskLed și în interiorul buclei while, apelează API-ul xSemaphoreTake()


și verifică dacă semaforul a fost preluat cu succes sau nu. Dacă este egal cu pdPASS (adică 1)
apoi fă LED-ul să se comute așa cum este arătat mai jos.

void TaskLed(void *pvParameters)

(void) pvParameters;

pinMode(8, OUTPUT);

while(1) {

dacă (xSemaphoreTake(interruptSemaphore, portMAX_DELAY) == pdPASS) {

digitalWrite(8, !digitalRead(8));

6. De asemenea, creați o funcție pentru a clipi un alt LED conectat la pinul 7.

void TaskLed1(void *pvParameters)

(void) pvParameters;

pinMode(7, OUTPUT);
în timp ce(1) {

digitalWrite(7, RIDICAT);

vTaskDelay(200 / portTICK_PERIOD_MS);

digitalWrite(7, LOW);

vTaskDelay(200 / portTICK_PERIOD_MS);

7. Funcția loop goală va rămâne goală. Nu uita asta.

void loop() {}

Asta e, codul complet poate fi găsit la sfârșitul acestui tutorial. Acum, încarcă acest cod
și conectați LED-urile și butonul cu Arduino UNO conform circuitului
diagramă.

Diagrama de circuit

După încărcarea codului, veți vedea un LED care clipește după 200 ms și când
butonul este apăsat, imediat a doua LED va străluci așa cum este arătat în videoclipul dat la
sfârșitul.
În acest fel, semaforele pot fi folosite în FreeRTOS cu Arduino acolo unde este nevoie.
transmite datele de la o sarcină la alta fără nicio pierdere.

Acum, să vedem ce este Mutex și cum să-l utilizăm în FreeRTOS.

Ce este un Mutex?
După cum s-a explicat mai sus, semaforul este un mecanism de semnalizare, în mod similar, Mutex-ul este o blocare.
mecanism spre deosebire de semafor care are funcții separate pentru incrementare și
decrement dar în Mutex, funcția ia și dă în sine. Este o tehnică pentru a evita
corupția resurselor partajate.

Pentru a proteja resursa partajată, se atribuie un card de token (mutex) resursei.


Cine are acest card poate accesa celălalt resursă. Ceilalți ar trebui să aștepte până când cardul
întors. În acest fel, doar o resursă poate accesa sarcina, iar celelalte așteaptă rândul lor.
șansă.

Să înțelegem Mutex în FreeRTOS cu ajutorul unui exemplu.

Aici avem trei sarcini, una pentru imprimarea datelor pe LCD, a doua pentru trimiterea datelor LDR.
pentru sarcina LCD și ultima sarcină pentru trimiterea datelor de temperatură pe LCD. Așa că aici sunt două sarcini
partajând aceeași resursă, adică LCD. Dacă sarcina LDR și sarcina de temperatură trimit date
simultan, atunci unul dintre date poate fi corupt sau pierdut.
Așadar, pentru a proteja împotriva pierderii de date, trebuie să blocăm resursa LCD pentru task1 până când acesta este finalizat.
sarcina de afișare. Apoi, sarcina LCD se va debloca și apoi sarcina2 își poate desfășura munca.

Puteți observa funcționarea Mutex-ului și semafoarelor în diagrama de mai jos.


Cum se folosește Mutex în FreeRTOS?

Mutexurile sunt folosite în același mod ca și semafoarele. În primul rând, creează-l, apoi oferă-l și
folosește API-urile respective.

Crearea unui Mutex:


Pentru a crea un mutex, utiliza ț i API-ul xSemaphoreCreateMutex(). A ș a cum sugerează numele său
Mutex este un tip de semafor binar. Ele sunt utilizate în contexte și scopuri diferite.
Un semafor binar este folosit pentru a sincroniza sarcinile, în timp ce Mutex este folosit pentru a proteja un.
resursă partajată.

Această API nu ia niciun argument și returnează o variabilă de


typeSemaphoreHandle_t. Dacă the mutex nu poate fii
creat,xSemaphoreCreateMutex()return NULL.

SemaphoreHandle_t mutex_v;

mutex_v = xSemaphoreCreateMutex();

Obț inerea unui mutex:

Când o sarcină dorește să acceseze o resursă, va lua un Mutex prin


utilizând API-ul xSemaphoreTake(). Este același lucru cu un semafor binar. De asemenea, ia două
parametrii.
xSemaphore:Numele Mutex-ului care trebuie preluat în cazul nostru mutex_v.

Aceasta este cea mai mare perioadă de timp în care sarcina va aș tepta în Stare Blocat
starea pentru ca Mutex-ul să devină disponibil. În proiectul nostru, vom
setxTicksToWaittoportMAX_DELAY pentru a face task_1 să aș tepte indefinit în Blocked
stare până la mutex_vis disponibil.

Oferind un Mutex:
După accesarea resursei partajate, sarcina ar trebui să restituie Mutexul astfel încât altele
sarcinile pot accesa API-ul [Link]() care este folosit pentru a da înapoi Mutex-ul.

Funcția xSemaphoreGive() ia doar un argument, care este Mutex-ul care trebuie oferit.
în cazul nostru mutex_v.

Folosind API-urile de mai sus, să implementăm Mutex în codul FreeRTOS folosind Arduino
IDE.

Explicația codului Mutex


Aici, scopul acestei părți este de a folosi un monitor serial ca resursă comună și două
diferite sarcini pentru a accesa monitorul serial pentru a imprima un mesaj.

1. Fișierele de antet vor rămâne aceleași ca un semafor.

#include <Arduino_FreeRTOS.h>

#include <semphr.h>

2. Declară o variabilă de tip SemaphoreHandle_t pentru a stoca valorile Mutex.

SemaphoreHandle_t mutex_v;

3. În void setup(), ini ț ializează monitorul serial cu o rată de 9600 baud ș i creează două
tare(Task1 și Task2) folosind API-ul xTaskCreate(). Apoi, crează un Mutex
folosind xSemaphoreCreateMutex(). Creează o sarcină cu priorități egale și mai târziu încearcă să
joacă-te cu acest număr.

void setup() {

[Link](9600);

mutex_v = xSemaphoreCreateMutex();

dacă (mutex_v == NULL) {

Mutex nu poate fi creat

xTaskCreate(Task1, "Task 1", 128, NULL, 1, NULL);

xTaskCreate(Task2, "Task 2", 128, NULL, 1, NULL);

4. Acum, fă funcții de sarcină pentru Sarcina1 și Sarcina2. Într-o buclă de așteptare a funcției de sarcină, înainte de
pentru a imprima un mesaj pe monitorul serial, trebuie să luăm un Mutex
folosind xSemaphoreTake() apoi tipăriți mesajul și apoi returnați Mutex-ul
folosind xSemaphoreGive(). Apoi dă niște întârziere.

void Task1(void *pvParameters) {

while(1) {

xSemaphoreTake(mutex_v, portMAX_DELAY);

[Link]("Salut de la Task1");

xSemaphoreGive(mutex_v);

vTaskDelay(pdMS_TO_TICKS(1000));

În mod similar, implementează funcț ia Task2 cu o întârziere de 500ms.

5. Funcția loop() va rămâne goală.

Acum, încarcă acest cod pe Arduino UNO și deschide monitorul serial.

Veți vedea mesaje tipărite din task1 și task2.

Pentru a testa funcționarea Mutex, pur și simplu comentați xSemaphoreGive(mutex_v); din orice sarcină.
Poți observa că programul se blochează la ultima mesaj de tip print.
Aceasta este modul în care semaforul și mutexul pot fi implementate în FreeRTOS cu Arduino. Pentru
mai multe informații despre Semaphore și Mutex, puteți vizita site-ul oficial documentație de
FreeRTOS.

Codurile complete și videoclipul pentru Semaphore și Mutes sunt date mai jos.

Cod
1 COD pentru Semafor:

2
#include <Arduino_FreeRTOS.h>
3
#include <semphr.h>
4
long timp_de_debounce = 150;
5
volatile unsigned long last_micros;
6

7
SemaphoreHandle_t interruptSemaphore;
8

9
void setup() {
10
pinMode(2, INPUT_PULLUP);
11
xTaskCreate(TaskLed, "Led", 128, NULL, 0, NULL);
12 xTaskCreate(TaskBlink, "LedBlink", 128, NULL, 0, NULL );

13 interruptSemaphore = xSemaphoreCreateBinary();

dacă (semaforInterupere != NULL) {


14
ataș ează întreruperea(digitalPinToInterrupt(2), debounceInterrupt, LOW);
15
}
16
}
17

18
void loop() {}
19

20
void handlerDeInterupere() {

21
xSemaphoreGiveFromISR(interruptSemaphore, NULL);

22 }

23

24 void TaskLed(void *pvParameters)

25 {

26 (void) pvParameters;

pinMode(8, OUTPUT);
27
pentru (;;) {
28
dacă (xSemaphoreTake(interruptSemaphore, portMAX_DELAY) == pdPASS) {
29
digitalWrite(8, !digitalRead(8));
30
}
31
}
32
}

33 void TaskBlink(void *pvParameters)

34 {

35 (void) pvParameters;
36 pinMode(7, OUTPUT);

37 pentru (;;) {

digitalWrite(7, ÎNALT);
38
vTaskDelay(200 / portTICK_PERIOD_MS);
39
digitalWrite(7, LOW);
40
vTaskDelay(200 / portTICK_PERIOD_MS);
41
}
42
}

43
void debounceInterrupt() {

44 dacă((long)(micros() - last_micros) >= debouncing_time * 1000) {

45 interruptHandler();

46 ultima_micros = micros();

47 }

}
48

49
COD pentru Mutex:
50
#include <Arduino_FreeRTOS.h>
51
#include <semphr.h>
52

53
SemaphoreHandle_t mutex_v;
54
void setup() {
55
[Link](9600);

56
mutex_v = xSemaphoreCreateMutex();

57 dacă (mutex_v == NULL) {

58 Mutexul nu poate fi creat

59 }
60 xTaskCreate(Task1, "Task1", 128, NULL, 1, NULL);

61 xTaskCreate(Task2, "Task2", 128, NULL, 1, NULL);

}
62

63
void Task1(void *pvParameters) {
64
while(1) {
65
xSemaphoreTake(mutex_v, portMAX_DELAY);
66
Salut din Task1
67
xSemaphoreGive(mutex_v);
68
vTaskDelay(pdMS_TO_TICKS(1000));

69 }

70 }

71

72 void Task2(void *pvParameters) {

73 în timp ce(1) {

xSemaphoreTake(mutex_v, portMAX_DELAY);
74
Salut din Task2
75
xSemaphoreGive(mutex_v);
76
vTaskDelay(pdMS_TO_TICKS(500));
77
}
78
}
79

80
void loop() {

81 }

82

83
84

85

86

87

88

Video
COD pentru Semafor:

#include <Arduino_FreeRTOS.h>
#include <semphr.h>
lung debouncing_time = 150;
volatil lung nesemnat ultimii_micros

SemaphoreHandle_t semaforDeInterupere;

void setup() {
pinMode(2, INPUT_PULLUP);
xTaskCreate(TaskLed, "Led", 128, NULL, 0, NULL);
xTaskCreate(TaskBlink, "LedBlink", 128, NULL, 0, NULL);
interruptSemaphore = xSemaphoreCreateBinary();
dacă (interruptSemaphore != NULL) {
ataș eazăInterrupț ie(digitalPinToInterrupț ie(2), debounceInterrupț ie, LOW);
}
}

fără loop() {}

vid interruptHandler() {
xSemaphoreGiveFromISR(interruptSemaphore, NULL);
}

gol TaskLed(void *pvParameters)


{
(void) pvParameters;
pinMode(8, OUTPUT);
pentru (;;) {
dacă (xSemaphoreTake(interruptSemaphore, portMAX_DELAY) == pdPASS) {
digitalWrite(8, !digitalRead(8));
}
}
}
gol TaskBlink(void *pvParameters)
{
(void) pvParameters;
setPinMode(7, IESIRE);
pentru (;;) {
digitalWrite(7, ÎNALT);
vTaskDelay(200 / portTICK_PERIOD_MS);
digitalWrite(7, LOW);
vTaskDelay(200 / portTICK_PERIOD_MS);
}
}
void debounceInterrupt() {
dacă ((long)(micros() - last_micros) >= debouncing_time * 1000) {
interruptHandler();
ultimii_micros = micros();
}
}

COD pentru Mutex:


#include <Arduino_FreeRTOS.h>
#include <semphr.h>

SemaphoreHandle_t mutex_v;
void setup() {
[Link](9600);
mutex_v = xSemaphoreCreateMutex();
dacă (mutex_v == NULL) {
Mutexul nu poate fi creat
}
xTaskCreate(Task1, "Task1", 128, NULL, 1, NULL);
xTaskCreate(Task2, "Task2", 128, NULL, 1, NULL);
}

gol Task1(void *pvParameters) {


while(1) {
xSemaphoreTake(mutex_v, portMAX_DELAY);
[Link]("Bună de la Task1");
xSemaphoreGive(mutex_v);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}

void Task2(void *pvParameters) {


while(1) {
xSemaphoreTake(mutex_v, portMAX_DELAY);
Salut din Task2
xSemaphoreGive(mutex_v);
vTaskDelay(pdMS_TO_TICKS(500));
}
}

tuș ă loop() {
}

Tutorial
Înțelegerea sistemelor de operare în timp real
Sistem (RTOS) și cum să-l folosești pentru
următorul tău design încorporat
INCORPORAT
DeSunakshi29 augusta 20190

Înț elegerea Realului


Sistem de operare în timp real (RTOS)

Sistemele integrate au o gamă largă de aplicații în toate dispozitivele electronice din jur.
noi, un exemplu evident este mini laptopul pe care îl purtăm cu noi tot timpul, da, eu
mă refer la telefoanele noastre mobile.

Ori de câte orisistem încorporatcând intră în scenă, este întotdeauna o combinație de hardware
ca microcontrolere sau microprocesoare și software precum un firmware sau un sistem de operare
sistem. Un Sistem de Operare formează baza tuturor dispozitivelor electronice și
gestionează atât hardware-ul, cât și software-ul din orice dispozitiv electronic. Termenul
sistemul de operare nu se limitează doar la Unix și Windows pentru computere, ci poate de asemenea
extinde la microcontrolere. Un astfel de sistem de operare care poate rula pe microcontrolere
se nume ș te sistem de operare în timp real. Aici vom învă ț a despre RTOS
și aplicațiile sistemului de operare în timp real.

Ce este RTOS?
Sistemul de operare în timp real, cunoscut popular sub numele de RTOS, oferă controlerului capacitatea
a răspunde la input și a finaliza sarcini într-o perioadă specifică de timp, în funcție de prioritate.
La prima vedere, un RTOS ar putea părea ca orice alt program încorporat sau
firmware, dar este construit pe arhitectura unui sistem de operare. Prin urmare, ca orice
sistemul de operare RTOS poate permite mai multor programe să se execute simultan
suportă multiplexarea. Aș a cum ș tim, nucleul unui procesor sau al unui controler poate doar
executa o singură instrucțiune la un moment dat, dar RTOS-ul are ceva numit
programatorul care decide ce instrucțiune să execute primul și astfel execută
instrucțiuni ale mai multor programe una după alta. Tehnic, un RTOS creează doar
o iluzie a multitasking-ului prin executarea instrucțiunilor paralele una câte una.

Acest lucru face ca RTOS să fie potrivit pentru diverse aplicații în lumea reală. În RTOS pentru orice intrare
de fiecare dată când o logică a fost evaluată, care oferă rezultatul corespunzător. Această logică este
măsurat pe baza nu doar a creativității logice, ci și a duratei de timp
în care sarcina specifică a fost îndeplinită. Dacă un sistem eșuează în îndeplinirea sarcinii în acel
durata specifică de timp este cunoscută sub numele de eșec al sistemului.

De ce RTOS??
. Disponibilitatea driverelor: Există mulți drivere disponibili în cadrul RTOS, care
ne permite să le folosim direct pentru diverse aplicații.
. Fi ș iere programate: RTOS se ocupă de programare, a ș a că în loc să ne concentrăm pe
orice sistem de programare putem să ne concentrăm pur și simplu pe dezvoltarea aplicației. De exemplu,
fișierele de programare a sarcinilor sunt folosite pentru a defini anumite acțiuni ori de câte ori există un set de condiții

RTOS folosește anumite algoritmi avansați pentru programare, de obicei în execuție,


stările pregătite și blocate care, în timp ce rulează RTOS, mențin o atenție mai mare asupra dezvoltării
aplicație mai degrabă decât programare.
. Flexibilitatea de a adăuga caracteristici: În cadrul RTOS, chiar dacă eș ti dispus să adaugi noi
funcționalități, poți să le adaugi pur și simplu fără a deranja funcționalitățile existente

Diferen ț a dintre sistemul de operare în timp real ș i


Sistem de operare
Există diverse diferențe între sistemul de operare în timp real și sistemul de operare
sisteme precum Windows, Linux etc. Să le analizăm pe rând cu ajutorul
format de tabel:

nr. crt. Sistem Realtme

Împărț irea timpului este baza execuț iei Procesele sunt executate pe baza de
1
procese în sistemul de operare ordinea priorităț ii lor

Sistemul de operare acț ionează ca o interfaț ă


Sistemul Realtme este conceput pentru a avea
2 între hardware ș i software de
executie pentru problemele reale ale lumii
un sistem

Gestionarea memoriei nu este o problemă critică Gestionarea memoriei este dificilă deoarece se bazează pe
3 când vine vorba de executare de problema de memorie în timp real este alocată
sistem de operare care în sine este critic
Aplicaț ii: Birou, Centre de date, Aplicaț ii: Controlul aeronavelor sau nuclear
4
Sistem pentru acasă etc reactor

Exemple : Microsoft Windows


5 Exemple: Vx Works, QNX, Windows CE
Linux, OS

Tipuri de RTOS
Putem categoriza sistemele de operare în timp real în trei părți principale, și anume

1. Sistem de operare în timp real rigid


2. Sistem de operare în timp real moale
3. Sistem de operare în timp real firm
Sistem de operare în timp real strict

Să începem să înțelegem acest tip de sistem de operare folosind un exemplu, live


un exemplu este sistemul de control al zborului. În cadrul sistemului de control al zborului, orice sarcină este dată
de către pilot, sub formă de input, aceasta ar trebui să fie efectuată la timp. În timp real strict
Sistem de operare, eșecurile sistemului pot fi tolerate. Caracteristicile RTOS-ului rigid sunt:

. A efectua sarcinile la timp


. Neîndeplinirea termenului limită este fatală
. Timp de răspuns garantat în cel mai rău caz
. Poate duce la eșecul sistemului
2. Sistem de operare în timp real soft

Cel mai simplu exemplu de utilizare a RTOS-ului soft este baza de date online, deoarece în cadrul RTOS-ului soft
parametrul care ne îngrijorează mai mult este viteza. Prin urmare, caracteristicile RTOS-ului moale sunt:

. Sarcinile ar trebui îndeplinite cât mai repede posibil


. Finalizarea târzie a sarcinilor este nedorită, dar nu este fatală
. Există o posibilitate de degradare a performanței
. Nu poate duce la eșecul sistemului
Sistem de operare în timp real ferm

Brațul robotic folosit pentru a lua obiecte poate fi considerat printre unul dintre
exemplu de RTOS firm. Aici, în cadrul acestei firme RTOS, chiar dacă procesul este întârziat, este
tolerat.

Beneficiile utilizării Free RTOS

Următoarele sunt avantajele utilizării RTOS în aplicațiile dvs.

. Fără probleme cu firewall-ul


. Lățime de bandă mică pentru performanță îmbunătățită
. Securitate și confidențialitate îmbunătățite
. Costuri reduse, datorită reducerii componentelor hardware și software utilizate pentru
dezvoltare
Câteva probleme majore legate de RTOS
Acum, în ciuda faptului că are multe avantaje pentru RTOS în aplicațiile din lumea reală, are
există și diverse dezavantaje. Unele dintre problemele legate de acesta sunt discutate aici.

. Interrupterele sunt de obicei folosite în programe pentru a opri programul în execuție pentru a devia
fluxul către o altă parte importantă a codului. Aici, în cadrul RTOS, deoarece rapid
timpul de răspuns este necesar; se recomandă ca întreruperile să fie dezactivate pentru
un timp minim posibil.
. Deoarece, nucleul ar trebui să răspundă și la diferite evenimente, este necesar să
să aibă o dimensiune mai mică a nucleului astfel încât să se potrivească corect în ROM
. Funcțiile sofisticate ale RTOS-ului ar trebui eliminate, deoarece nu există un concept de așa.
o astfel de memorie virtuală în cadrul ei.

Cum să foloseș ti RTOS

Acum că știi ce este un RTOS și unde îl poți folosi, pentru a începe cu


RTOS, în mod normal, trebuie să folosești dezvoltarea Tornado sau FreeRTOS
mediu. Să aruncăm o privire scurtă asupra acestor două medii de dezvoltare.

Tornado – VxWorks
Tornado este un mediu integrat pentru a dezvolta sisteme încorporate legate de timp real
aplicații RTOS pe sistemul țintă. Tornado constă din trei elemente de bază
care sunt enumerate mai jos.

VxWorks

2) Instrumente de construire a aplicațiilor (compilator și programe asociate)

3) Mediu de dezvoltare integrat, care poate gestiona, depana și monitoriza


Aplicație VxWorks
Sfâșiat
mediu de dezvoltare ado

VxWorks este un sistem de operare în timp real conectat la reț ea. Pentru a începe cu VxWorks, ar trebui să
am un kit de dezvoltare (țintă) împreună cu o stație de lucru. Aici, kitul de dezvoltare este
numai gazda sau componenta țintă care comunică cu serverul țintă pe
stația de lucru. Obiectivul aici conectează uneltele tornado, cum ar fi shelland
debagatorul. Prin urmare, folosind VxWorks, vom configura și construi sistemele în timp ce
Tornado ne oferă o interfa ț ă grafică de utilizator ș i instrumente de linie de comandă pentru
configurare și construire.

Un punct foarte important care intră în discuție aici este că, în timpul instalării tornado în cadrul
direcția de instalare a sistemului dumneavoastră ar trebui să folosească următoarele căi:
installDir/target. De exemplu, dacă doriți să vă stocați tornada în C:\tornado pe un
gazda windows calea completă ar trebui să fie identificată în acest caz ca
installDir/target/h/vxworks.h.

Aici, nu vom discuta în detaliu despre caracteristicile Vx works (vom lăsa asta
pentru următorul tutorial) dar vom discuta cum poate fi realizată dezvoltarea folosind C++ în cadrul
Vxworks folosind WindRiver GNU. WindRiver GNU ne ajută să oferim o interfață grafică
analiză privind întreruperea implicată în timpul execuției, precum și utilizarea memoriei
raport.
De exemplu, opinia enunțată mai sus despre WindRiver explică procesorul asociat.
numărul împreună cu prioritatea sarcinilor (tLowPri și tHighPri). Starea de inactivitate adică linie de culoare verde
a declarat perioada de timp în care procesorul nu se află în stare de funcționare, care este observată
să fie după fiecare câteva secunde. t1, t7, t8 și t9 nu sunt altceva decât diferitele procesoare
utilizat. Aici, selectăm doar procesorul t7.

Prin urmare, acest Windriver este capabil să invoce atât VxWorks cât și modulul de aplicație.
subrutine. Puteți lansa aplicația Windriver fie din lansarea tornado
bara de unelte (-> butonul i) mai târziu faceți clic pe meniu și apoi faceți clic pe shell. În cele din urmă, din
în linia de comandă, tastați „>windsh server țintă”.

Acum, pentru a programa folosind C++, este important să includem INCLUDE_CPLUS_DEMANGLER


component, acest demangler component permite simbolurilor țintă ale shell-ului să returneze uman
forme lizibile ale numelui simbolurilor C++. Înainte de a descărca modulul C++ în Vxworks
țintă, urmează procesul cunoscut sub numele de munching. Aici, munching se referă la un gazdă suplimentară
pas de procesare.

Compilati sursa aplicației C++ și obțineți, de exemplu, fișierul [Link]. Apoi, rulați-l.
a ronțăi .o și a compila fișierul ctdt.c generat. În plus, leagă aplicația cu
ctdt.o pentru a genera modul descărcabil, [Link] în VxWorks. Ieșirea după
executarea acestui VxWorks va fi un fișier make care va fi utilizat pe un anumit țintă.

Free RTOS

În general, atunci când începem cu RTOS, preferăm în general Vx Works RTOS. Dar,
hai să avem o discuție scurtă despre Free RTOS, care poate fi folosită de asemenea
pentru începători să parcurgă conceptul de sistem de operare în timp real. Free RTOS este
dezvoltat de Richard Barry și echipa FreeRTOS, de asemenea, este deținut de Real time
ingineri ltd, dar este gratuit de utilizat și poate fi descărcat cu ușurință făcând clic pe link
sub

Descarcă gratuit ROTS


Cea mai recentă versiune a Free RTOS utilizată la momentul redactării acestui articol este versiunea 10, menționată ca
FreeRTOS V10.

Cel mai mare avantaj al Free RTOS-ului, care îl face superior în comparație cu celelalte
RTOS este comportamentul său independent de platformă în termeni de hardware, adică codul C care
vom folosi pentru a executa un sistem de operare care poate rula pe diferite platforme având
o arhitectură diferită. Prin urmare, indiferent dacă folosiți 8051
microcontrolersau unele recenteMicrocontroler ARMcodul pe care l-ai scris împreună cu
procesul de execuție va fi similar pentru ambele.

Există multe alte beneficii ale utilizării Free RTOS în comparație cu VxWorks și alte RTOS.
unele instrumente de operare. Unele dintre ele pot fi menționate astfel:

Oferă testare mai ușoară


2. Promovează conceptul de reutilizare a codului
3. Timp de inactivitate mai redus

4. Ușoară întreținere
5. Abstract de informații de temporizare
De asemenea, basicKernel, unde Kernel se referă la componenta centrală a unui sistem de operare
sistemul care este prezent în RTOS-ul gratuit îl face accesibil pentru utilizare în diverse
aplicații. Deoarece este ușor să atașați module extinse la sistemele de operare pentru a obține
mai multe aplicații, RTOS gratuit devine mai puternic.

Unul dintre exemplele de utilizare a Free RTOS poate fi explicat prin utilizarea conceptului de
combinând Free RTOS cu Nabto. Nabto este un dispozitiv web gratuit folosit pentru a transfera
informații de la dispozitiv către browser.

Prin urmare, combinarea Free RTOS cu Nabto face ca acesta să fie un mic fragment de cod C, deoarece ...
explicat în figura a. În zilele noastreInternetul de Lucruri (IOT)este în tendințe și fiecare IOT
dispozitivul la care vom avea acces are o adresă URL unică pe internet și tehnologia
permite conexiuni punct la punct sigure și extrem de cu lățime de bandă redusă. În absența
conectivitate la internet această combinație poate fi utilă. Prin urmare, free RTOS este popular
alegere când vine vorba de implementarea IoT.

S-ar putea să vă placă și