,
El ESP32 NodeMCU se basa en el microprocesador de doble núcleo Xtensa LX6 de 32 bits que ejecuta el sistema operativo FreeRTOS. Cuando se utiliza el IDE de Arduino, el programa se ejecuta por defecto en el núcleo 1. Para la multitarea, es interesante utilizar todos los recursos del microprocesador. En este tutorial veremos cómo ejecutar tareas en ambos núcleos
Existe una librería FreeRTOS compatible con los microcontroladores Arduino con arquitectura AVR (Uno, Nano, Mega, etc.).
Material
- NodeMCU ESP32
- Cable USB A Macho
Descripción del sistema operativo FreeRTOS
FreeRTOS es un sistema operativo en tiempo real ligero y de código abierto. Por lo tanto, se adapta perfectamente a los problemas de gestión de tareas en función del tiempo o de ocurrencia de eventos. Espressif ha integrado el sistema operativo en las últimas versiones del SDK. Por lo tanto, es posible utilizar la funcionalidad de este sistema operativo para explotar el potencial de los dos núcleos del NodeMCU ESP32 con el IDE de Arduino.
Código
En este código, crearemos varias tareas a las que asignaremos una función que se ejecutará cuando la tarea sea llamada.
Creación de la tarea asignada a un núcleo
xTaskCreatePinnedToCore(
task1Func, /* Task function. */
"Task1", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
10, /* priority of the task */
&Task1, /* Task handle to keep track of created task */
0); /* pin task to core 0 */
Definición del bucle infinito que se ejecutará cuando se llame a la tarea
void task1Func( void * pvParameters ){
for(;;){
// place code here
}
}
Cabe destacar que la función delay() (o vsTaskDelay) permite bloquear la tarea y pasar a la siguiente con mayor prioridad.
TaskHandle_t Task1; TaskHandle_t Task2; TaskHandle_t Task3; unsigned long previousTime,previousTime1,previousTime2,previousTime3; void setup() { Serial.begin(115200); //create a task on core 0 that will be execute task1Func() with priority 10 xTaskCreatePinnedToCore( task1Func, /* Task function. */ "Task1", /* name of task. */ 10000, /* Stack size of task */ NULL, /* parameter of the task */ 10, /* priority of the task */ &Task1, /* Task handle to keep track of created task */ 0); /* pin task to core 0 */ delay(500); //create a task on core 1 that will be execute task2Func() with priority 9 xTaskCreatePinnedToCore( task2Func, /* Task function. */ "Task2", /* name of task. */ 10000, /* Stack size of task */ NULL, /* parameter of the task */ 9, /* priority of the task */ &Task2, /* Task handle to keep track of created task */ 1); /* pin task to core 1 */ delay(500); xTaskCreatePinnedToCore(task3Func, "Task3", 10000, NULL, 8, &Task3, 0); } void task1Func( void * pvParameters ){ for(;;){ Serial.printf("%s running on core %d (priorite %d) - %dms\n", "Task1", xPortGetCoreID(), uxTaskPriorityGet( NULL ),millis()-previousTime1); previousTime1=millis(); delay(200);//vTaskDelay( pdMS_TO_TICKS( 200 ) ); } } void task2Func( void * pvParameters ){ for(;;){ Serial.printf("%s running on core %d (priorite %d) - %dms\n", "Task2", xPortGetCoreID(), uxTaskPriorityGet( NULL ),millis()-previousTime2); previousTime2=millis(); delay(600); //vTaskDelay( pdMS_TO_TICKS( 600 ) ); } } void task3Func( void *pvParameters ) { for( ;; ) { Serial.printf("%s running on core %d (priorite %d) - %dms\n", "Task3", xPortGetCoreID(), uxTaskPriorityGet( NULL ),millis()-previousTime3); previousTime3=millis(); delay(100); //vTaskDelay( pdMS_TO_TICKS( 100 ) ); } } void loop() { Serial.printf("%s running on core %d (priorite %d) - %dms\n", "loop()", xPortGetCoreID(), uxTaskPriorityGet( NULL ),millis()-previousTime); previousTime=millis(); delay(500); }
Hay varias funciones para crear características más avanzadas, como la sincronización y la comunicación entre tareas. Consulte la documentación.
Algunas características a recordar:
- xTaskCreate() para crear una tarea
- xTaskCreatePinnedToCore() para crear una tarea en un núcleo determinado
- vTaskDelayUntil() para activar una tarea periódicamente
- vTaskDelay() bloquea una tarea durante un cierto número de ticks de reloj (utiliza pdMS_TO_TICKS para convertir una duración en un número de ticks)
- vTaskPrioritySet() cambia la prioridad de una tarea
- vTaskDelete() para eliminar una tarea
Resultado
Una vez iniciado el programa, se observa que las tareas se desarrollan de forma ordenada.