- Com funciona RTOS?
- Termes d'ús freqüent a RTOS
- Instal·lació de la biblioteca Arduino FreeRTOS
- Esquema de connexions
- Exemple Arduino FreeRTOS: creació de tasques FreeRTOS a Arduino IDE
- Implementació de tasques FreeRTOS a IDE Arduino
El sistema operatiu present als dispositius incrustats s’anomena RTOS (sistema operatiu en temps real). Als dispositius incrustats, les tasques en temps real són fonamentals, on el temps juga un paper molt important. Les tasques en temps real són determinants del temps: el temps de resposta a qualsevol esdeveniment sempre és constant, de manera que es pot garantir que qualsevol esdeveniment concret es produirà en un moment fix. RTOS està dissenyat per executar aplicacions amb un temps molt precís i un alt grau de fiabilitat. RTOS també ajuda en la tasca múltiple amb un sol nucli.
Ja hem tractat un tutorial sobre com utilitzar RTOS en sistemes incrustats on podeu obtenir més informació sobre RTOS, la diferència entre sistemes operatius d’ús general i RTOS, diferents tipus de RTOS, etc.
En aquest tutorial, començarem amb FreeRTOS. FreeRTOS és una classe de RTOS per a dispositius incrustats prou petita per funcionar amb microcontroladors de 8/16 bits, tot i que el seu ús no es limita a aquests microcontroladors. És un codi completament obert i el seu codi està disponible a github. Si coneixem alguns conceptes bàsics de RTOS, és molt fàcil utilitzar FreeRTOS perquè té API ben documentades que es poden utilitzar directament al codi sense conèixer la part de fons de la codificació. Podeu trobar la documentació completa de FreeRTOS aquí.
Com que FreeRTOS pot funcionar amb MCU de 8 bits, també es pot executar a la placa Arduino Uno. Només hem de descarregar la biblioteca FreeRTOS i després començar a implementar el codi mitjançant API. Aquest tutorial està pensat per a un principiant complet, a continuació es detallen els temes que tractarem en aquest tutorial Arduino FreeRTOS:
- Com funciona RTOS
- Alguns termes d'ús freqüent a RTOS
- Instal·lació de FreeRTOS a Arduino IDE
- Com crear tasques de FreeRTOS amb un exemple

Com funciona RTOS?
Abans de començar a treballar amb RTOS, vegem què és una tasca. La tasca és un fragment de codi que es pot programar a la CPU per executar-lo. Per tant, si voleu realitzar alguna tasca, s’hauria de programar amb retard del nucli o amb interrupcions. Aquest treball el fa Scheduler present al nucli. En un processador de nucli únic, el planificador ajuda les tasques a executar-se en un segment de temps concret, però sembla que s’executen diferents tasques simultàniament. Cada tasca s'executa segons la prioritat que se li dóna.
Ara, vegem què passa al nucli RTOS si volem crear una tasca perquè el LED parpellegi amb un interval d’un segon i posem aquesta tasca en la màxima prioritat.

A part de la tasca LED, hi haurà una tasca més creada pel nucli, que es coneix com a tasca inactiva.. La tasca inactiva es crea quan no hi ha cap tasca disponible per a l'execució. Aquesta tasca sempre s'executa amb la prioritat més baixa, és a dir, 0. Si analitzem el gràfic de temps indicat anteriorment, es pot veure que l’execució comença amb una tasca LED i s’executa durant un temps especificat i, durant el temps restant, la tasca inactiva s’executa fins que es produeix una interrupció de tick. A continuació, el nucli decideix quina tasca s'ha d'executar segons la prioritat de la tasca i el temps total transcorregut de la tasca LED. Quan s'ha completat 1 segon, el nucli torna a escollir la tasca principal perquè s'executi perquè té una prioritat més alta que la tasca inactiva, també podem dir que la tasca LED preveu la tasca inactiva. Si hi ha més de dues tasques amb la mateixa prioritat, s'executaran de manera circular durant un temps especificat.
A sota del diagrama d'estats, ja que mostra el canvi de la tasca que no s'executa a l'estat d'execució.

Totes les tasques de nova creació passen a l'estat Llest (part de l'estat de no execució). Si la tasca creada (Tasca 1) té la màxima prioritat que altres tasques, es mourà a l'estat d'execució. Si aquesta tasca en execució és anterior a l'altra, tornarà a l'estat llest de nou. En cas contrari, si la tasca 1 es bloqueja mitjançant l'API de bloqueig, la CPU no participarà amb aquesta tasca fins al temps d'espera definit per l'usuari.
Si la tasca 1 es suspèn en estat d'execució mitjançant API de suspensió, la tasca 1 passarà a l'estat de suspensió i no tornarà a estar disponible per al planificador. Si repreneu la tasca 1 en estat suspès, tornarà a l'estat preparat, tal com podeu veure al diagrama de blocs.
Aquesta és la idea bàsica de com s’executen les tasques i canvien els seus estats. En aquest tutorial, implementarem dues tasques a Arduino Uno mitjançant l'API FreeRTOS.
Termes d'ús freqüent a RTOS
1. Tasca: és un fragment de codi que es pot programar a la CPU per executar-lo.
2. Planificador: s’encarrega de seleccionar una tasca de la llista d’estats preparats a l’estat d’execució. Els programadors sovint s’implementen de manera que mantenen ocupats tots els recursos informàtics (com en l’equilibri de càrrega).
3. Prevenció: és el fet d’interrompre temporalment una tasca que ja s’està executant amb la intenció d’eliminar-la de l’estat de funcionament sense la seva cooperació.
4. canvi de context: En preferència basada en la prioritat, el programador compara la prioritat de les tasques que s'executen amb una prioritat de la llista de tasques disposada a cada systick interrupció. Si hi ha alguna tasca a la llista la prioritat de la qual sigui superior a la tasca en execució, es produirà el canvi de context. Bàsicament, en aquest procés es guarden continguts de diferents tasques a la seva respectiva memòria de pila.
5. Tipus de polítiques de programació:
- Planificació preventiva: en aquest tipus de planificació, les tasques s’executen amb un segment de temps igual sense tenir en compte les prioritats.
- Prioritari basat en prioritats : la primera tasca s'executarà.
- Programació cooperativa: el canvi de context només es produirà amb la cooperació de tasques en execució. La tasca s'executarà contínuament fins que es cridi el rendiment de la tasca.
6. Objectes del nucli: per a la senyalització de la tasca per realitzar una mica de treball, s’utilitza el procés de sincronització. Per realitzar aquest procés s’utilitzen objectes del nucli. Alguns objectes del nucli són Esdeveniments, Semàfors, Cues, Mutex, Bústies, etc. Veurem com utilitzar aquests objectes en els propers tutorials.
De la discussió anterior, tenim algunes idees bàsiques sobre el concepte RTOS i ara podem implementar el projecte FreeRTOS a Arduino. Per tant, comencem instal·lant les biblioteques FreeRTOS a Arduino IDE.
Instal·lació de la biblioteca Arduino FreeRTOS
1. Obriu Arduino IDE i aneu a Sketch -> Inclou biblioteca -> Gestiona biblioteques . Cerqueu FreeRTOS i instal·leu la biblioteca com es mostra a continuació.

Podeu descarregar la biblioteca des de github i afegir el fitxer.zip a Sketch-> Inclou biblioteca -> Afegir fitxer .zip .
Ara, reinicieu l'IDE Arduino. Aquesta biblioteca proporciona alguns exemples de codi, que també es poden trobar a Fitxer -> Exemples -> FreeRTOS com es mostra a continuació.

Aquí escriurem el codi des de zero per entendre el funcionament, més endavant podeu comprovar els exemples de codis i utilitzar-los.
Esquema de connexions
A continuació es mostra el diagrama de circuits per crear tasques LED intermitents mitjançant FreeRTOS a Arduino:

Exemple Arduino FreeRTOS: creació de tasques FreeRTOS a Arduino IDE
Vegem una estructura bàsica per escriure un projecte FreeRTOS.
1. Primer, incloeu el fitxer de capçalera Arduino FreeRTOS com a
#incloure
2. Doneu el prototip de funció de totes les funcions que esteu escrivint per a l'execució, que s'escriu com
void Task1 (void * pvParameters); void Task2 (void * pvParameters); .. ….
3. Ara, a la funció void setup () , creeu tasques i inicieu el planificador de tasques.
Per crear tasques, es crida l' API xTaskCreate () a la funció de configuració amb certs paràmetres / arguments.
xTaskCreate (TaskFunction_t pvTaskCode, const char * const pcName, uint16_t usStackDepth, void * pvParameters, UBaseType_t uxPriority, TaskHandle_t * pxCreatedTask);
Hi ha 6 arguments que s’han de passar mentre es crea una tasca. Vegem quins són aquests arguments
- pvTaskCode: és simplement un punter cap a la funció que implementa la tasca (en efecte, només el nom de la funció).
- pcName: un nom descriptiu per a la tasca. FreeRTOS no l’utilitza. S'inclou exclusivament amb finalitats de depuració.
- usStackDepth: cada tasca té la seva pròpia pila única que el nucli assigna a la tasca quan es crea la tasca. El valor especifica el nombre de paraules que pot contenir la pila, no el nombre de bytes. Per exemple, si la pila té 32 bits d'amplada i usStackDepth es passa com a 100, s'assignaran 400 bytes d'espai de pila (100 * 4 bytes) a la memòria RAM. Utilitzeu-ho amb prudència perquè Arduino Uno només té 2Kbytes de RAM.
- pvParameters: paràmetre d'entrada de tasca (pot ser NUL).
- uxPriority: Prioritat de la tasca (0 és la prioritat més baixa).
- pxCreatedTask: es pot utilitzar per passar un identificador a la tasca que s'està creant. Aquest controlador es pot utilitzar per fer referència a la tasca en les trucades a l'API que, per exemple, canvien la prioritat de la tasca o suprimeixen la tasca (pot ser NUL).
Exemple de creació de tasques
xTaskCreate (tasca1, "tasca1", 128, NULL, 1, NULL); xTaskCreate (tasca2, "tasca2", 128, NULL, 2, NULL);
Aquí, Task2 té una prioritat més alta i, per tant, s’executa primer.
4. Després de crear la tasca, inicieu el planificador en una configuració buida mitjançant vTaskStartScheduler (); API.
5. La funció Bucle buit () romandrà buida, ja que no volem executar cap tasca manualment i infinitament. Com que l'execució de tasques ara la gestiona Scheduler.
6. Ara, hem d'implementar funcions de tasca i escriure la lògica que voleu executar dins d'aquestes funcions. El nom de la funció ha de ser el mateix que el primer argument de l' API xTaskCreate () .
void task1 (void * pvParameters) { while (1) { .. ..//your logic } }
7. La majoria del codi necessita una funció de retard per aturar la tasca en execució, però a RTOS no es recomana utilitzar la funció Delay () ja que atura la CPU i, per tant, RTOS també deixa de funcionar. Així doncs, FreeRTOS té una API del nucli per bloquejar la tasca durant un temps concret.
vTaskDelay (const TickType_t xTicksToDelay);
Aquesta API es pot utilitzar amb finalitats de retard. Aquesta API retarda una tasca per a un nombre determinat de paparres. El temps real durant el qual la tasca es manté bloquejada depèn de la taxa de tick. El portTICK_PERIOD_MS constant es pot utilitzar per calcular en temps real a partir de la taxa de tick.
Això vol dir que si voleu un retard de 200 ms, només cal que escriviu aquesta línia
vTaskDelay (200 / portTICK_PERIOD_MS);
Per tant, per a aquest tutorial, utilitzarem aquestes API FreeRTOS per implementar tres tasques.
API que s'han d'utilitzar:
- xTaskCreate ();
- vTaskStartScheduler ();
- vTaskDelay ();
Tasca que cal crear per a aquest tutorial:
- El LED parpelleja al pin digital 8 amb una freqüència de 200 ms
- El LED parpelleja al pin digital 7 amb una freqüència de 300 ms
- Imprimiu números en monitor sèrie amb una freqüència de 500 ms.
Implementació de tasques FreeRTOS a IDE Arduino
1. A partir de l'explicació de l'estructura bàsica anterior, incloeu el fitxer de capçalera Arduino FreeRTOS. A continuació, feu prototips de funció. Com que tenim tres tasques, feu tres funcions i els seus prototips.
#include void TaskBlink1 (void * pvParameters); void TaskBlink2 (void * pvParameters); void Taskprint (void * pvParameters);
2. A la funció void setup () , inicialitzeu la comunicació serial a 9600 bits per segon i creeu les tres tasques mitjançant l' API xTaskCreate () . Inicialment, definiu les prioritats de totes les tasques com a '1' i inicieu el planificador.
configuració nul·la () { Serial.begin (9600); xTaskCreate (TaskBlink1, "Task1", 128, NULL, 1, NULL); xTaskCreate (TaskBlink2, "Task2", 128, NULL, 1, NULL); xTaskCreate (Taskprint, "Task3", 128, NULL, 1, NULL); vTaskStartScheduler (); }
3. Ara, implementeu les tres funcions tal com es mostra a continuació per al parpelleig del LED de la tasca 1.
void TaskBlink1 (void * pvParameters) { pinMode (8, OUTPUT); while (1) { digitalWrite (8, HIGH); vTaskDelay (200 / portTICK_PERIOD_MS); digitalWrite (8, BAIX); vTaskDelay (200 / portTICK_PERIOD_MS); } }
De la mateixa manera, implementeu la funció TaskBlink2. La funció Task3 s'escriurà com a
void Taskprint (void * pvParameters) { int counter = 0; while (1) { comptador ++; Serial.println (comptador); vTaskDelay (500 / portTICK_PERIOD_MS); } }
Això és. Hem completat amb èxit un projecte FreeRTOS Arduino per a Arduino Uno. Podeu trobar el codi complet juntament amb un vídeo al final d’aquest tutorial.
Finalment, connecteu dos LED al pin digital 7 i 8 i pengeu el codi a la vostra placa Arduino i obriu el monitor sèrie. Veureu que un comptador s’executa un cop a 500 ms amb el nom de la tasca, tal com es mostra a continuació.


A més, observeu els LED, que parpellegen a diferents intervals de temps. Proveu de jugar amb l'argument de prioritat a la funció xTaskCreate . Canvieu el número i observeu el comportament del monitor sèrie i dels LED.
Ara podeu entendre els dos primers exemples de codis en què es creen tasques de lectura analògica i lectura digital. D’aquesta manera, podeu fer més projectes avançats utilitzant només les API Arduino Uno i FreeRTOS.
