Tutoriale Arduino FreeRTOS
Tutoriale Arduino FreeRTOS
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.
Î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:
Î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.
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.
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.
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.
#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
..
….
Pentru crearea unei sarcini, API-ul xTaskCreate() este apelat în funcția setup cu anumite
parametrii/argumente.
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(task2,"task2",128,NULL,2,NULL);
Aici, Task2 are o prioritate mai mare și, prin urmare, se execută primul.
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()
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.
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
Așa că pentru acest tutorial, vom folosi aceste API-uri FreeRTOS pentru a implementa trei sarcini.
1. xTaskCreate();
2. vTaskStartScheduler();
3. vTaskDelay();
Sarcina care trebuie creată pentru acest tutorial:
#include <Arduino_FreeRTOS.h>
void setup() {
[Link](9600);
xTaskCreate(TaskBlink1,"Task1",128,NULL,1,NULL);
xTaskCreate(TaskBlink2,"Task2 ",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.
pinMode(8, OUTPUT);
while(1)
digitalWrite(8, ÎNALT);
digitalWrite(8, LOW);
int contador = 0;
în timp ce(1)
counter++;
[Link](counter);
vTaskDelay( 500 / portTICK_PERIOD_MS );
Î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.
Pentru a șterge o sarcină, trebuie să folosim funcția API vTaskDelete(). Aceasta ia doar un singur
argument.
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;
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.
Î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
vTaskDelete(NULL);
pinMode(7, OUTPUT);
while(1)
digitalWrite(7, ÎNALT);
vTaskDelay( 300 / portTICK_PERIOD_MS );
digitalWrite(7, LOW);
Așadar, această API poate fi utilizată pentru a opri executarea sarcinii respective.
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.
Vrem să imprimăm valoarea senzorului LDR pe un LCD de 16*2. Așadar, există două sarcini.
acum
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.
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().
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.
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
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;
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));
vTaskStartScheduler();
int intensitate_curentă;
while(1) {
[Link]("Task1");
intensitate_curentă = analogRead(A0);
[Link](current_intensity);
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ă.
int intensity = 0;
în timp ce(1) {
[Link]("Task2");
[Link]();
[Link](0, 0);
[Link]("Intensitate:");
[Link](11, 0);
[Link](intensitate);
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, ¤t_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.
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).
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
Pentru a utiliza orice obiect de kernel, trebuie mai întâi să-l creăm. Pentru a crea un semafor binar,
usevSemaphoreCreateBinary().
sema_v = xSemaphoreCreateBinary();
Furnizând un semafor:
Pentru a oferi un semafor, există două versiuni - una pentru întrerupere și alta pentru
sarcină normală.
Pentru a lua un semafor, utilizați funcția API xSemaphoreTake(). Această API acceptă două
parametrii.
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.
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ă.
#include <Arduino_FreeRTOS.h>
#include <semphr.h>
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);
interruptSemaphore = xSemaphoreCreateBinary();
timp_de_bătaie_de_lungime = 150;
void debounceInterrupt() {
interruptHandler();
microsecunde_ultime = microsecunde();
}
void handlerDeInterruptie() {
xSemaphoreGiveFromISR(interruptSemaphore, NULL);
(void) pvParameters;
pinMode(8, OUTPUT);
while(1) {
digitalWrite(8, !digitalRead(8));
(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);
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.
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.
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.
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.
SemaphoreHandle_t mutex_v;
mutex_v = xSemaphoreCreateMutex();
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.
#include <Arduino_FreeRTOS.h>
#include <semphr.h>
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();
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.
while(1) {
xSemaphoreTake(mutex_v, portMAX_DELAY);
[Link]("Salut de la Task1");
xSemaphoreGive(mutex_v);
vTaskDelay(pdMS_TO_TICKS(1000));
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();
18
void loop() {}
19
20
void handlerDeInterupere() {
21
xSemaphoreGiveFromISR(interruptSemaphore, NULL);
22 }
23
25 {
26 (void) pvParameters;
pinMode(8, OUTPUT);
27
pentru (;;) {
28
dacă (xSemaphoreTake(interruptSemaphore, portMAX_DELAY) == pdPASS) {
29
digitalWrite(8, !digitalRead(8));
30
}
31
}
32
}
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() {
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();
59 }
60 xTaskCreate(Task1, "Task1", 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
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);
}
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);
}
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
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
Împărț irea timpului este baza execuț iei Procesele sunt executate pe baza de
1
procese în sistemul de operare ordinea priorităț ii lor
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
Tipuri de RTOS
Putem categoriza sistemele de operare în timp real în trei părți principale, și anume
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:
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.
. 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.
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
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ă”.
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
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:
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.