¿Quieres sacarle el máximo provecho a tu ESP32 Dual Core con Arduino IDE pero no sabes por dónde empezar? ¡No te preocupes! En este artículo te enseñaremos paso a paso cómo utilizar esta poderosa placa de desarrollo. Desde cómo configurar el entorno de programación hasta cómo aprovechar al máximo sus dos núcleos, ¡descubre todas las posibilidades que te ofrece el ESP32 Dual Core en conjunto con Arduino IDE!
El ESP32 viene con 2 microprocesadores Xtensa LX6 de 32 bits: Core 0 y Core 1. Por lo tanto, es de doble núcleo. Cuando ejecutamos código en Arduino IDE, se ejecuta en Core 1 de forma predeterminada. En esta publicación, le mostraremos cómo ejecutar código en el segundo núcleo del ESP32 mediante la creación de tareas. Puede ejecutar fragmentos de código en ambos núcleos al mismo tiempo y usar su ESP32 para realizar múltiples tareas.
Nota: No es necesario ejecutar doble núcleo para lograr la multitarea.
introducción
El ESP32 viene con 2 microprocesadores Xtensa LX6 de 32 bits, por lo que es de doble núcleo:
- Núcleo 0
- Núcleo 1
Cuando cargamos código al ESP32 usando el IDE de Arduino, simplemente se ejecuta; no tenemos que preocuparnos por qué núcleo está ejecutando el código.
Hay una función que puede utilizar para determinar en qué núcleo se ejecuta el código:
xPortGetCoreID()
Si utiliza esta función en un boceto de Arduino, notará que tanto el configuración() Y Cinta() ejecutándose en Core 1. Pruébelo usted mismo cargando el siguiente boceto en su ESP32.
/*********
Rui Santos
Complete project details at https://randomnerdtutorials.com
*********/
void setup() {
Serial.begin(115200);
Serial.print("setup() running on core ");
Serial.println(xPortGetCoreID());
}
void loop() {
Serial.print("loop() running on core ");
Serial.println(xPortGetCoreID());
}
Abra el monitor en serie con una velocidad de baudios de 115200 y verifique el núcleo que ejecuta el boceto de Arduino.
Crear tareas
El IDE de Arduino es compatible con FreeRTOS para ESP32, un sistema operativo en tiempo real. Esto nos permite ejecutar múltiples tareas en paralelo que se ejecutan de forma independiente una de otra.
Las tareas son fragmentos de código que ejecutan algo. Esto podría ser, por ejemplo, hacer parpadear un LED, enviar una solicitud de red, medir valores de sensores, publicar valores de sensores, etc.
Para asignar fragmentos de código específicos a un núcleo específico, es necesario crear tareas. Al crear una tarea, puedes elegir en qué núcleo se ejecutará y su prioridad. Los valores de prioridad comienzan en 0, siendo 0 la prioridad más baja. El procesador ejecuta primero las tareas de mayor prioridad.
Para crear tareas, debes seguir los siguientes pasos:
1. Cree un identificador de tarea. Un ejemplo para la Tarea 1:
TaskHandle_t Task1;
2. En el configuración() Cree una tarea asignada a un núcleo específico con el xTaskCreatePinnedToCore Función. Esta función toma varios argumentos, incluida la prioridad y el núcleo en el que se debe ejecutar la tarea (el último parámetro).
xTaskCreatePinnedToCore(
Task1code, /* Function to implement the task */
"Task1", /* Name of the task */
10000, /* Stack size in words */
NULL, /* Task input parameter */
0, /* Priority of the task */
&Task1, /* Task handle. */
0); /* Core where the task should run */
3. Después de crear la tarea, debe crear una función que contenga el código para la tarea creada. En este ejemplo necesitas crear: Código de tarea1() Función. Así es como se ve la función de tarea:
Void Task1code( void * parameter) {
for(;;) {
Code for task 1 - infinite loop
(...)
}
}
El para(;;) crea un bucle infinito. Entonces esta función funciona de manera similar a esa. Cinta() Función. Por ejemplo, puedes usarlo como un segundo bucle en tu código.
Durante la ejecución del código, si desea eliminar la tarea creada, puede hacerlo usando el vTaskDelete()Función que acepta el identificador de tarea (Tarea 1) como argumento:
vTaskDelete(Task1);
Veamos cómo funcionan estos conceptos con un ejemplo sencillo.
Crear tareas en diferentes núcleos – ejemplo
Para seguir este ejemplo necesitarás las siguientes piezas:
- Placa ESP32 DOIT DEVKIT V1
- 2x LED de 5 mm
- 2x Resistencia de 330 ohmios
- tablero de circuitos
- Cables de puente
Puedes utilizar los enlaces anteriores o ir directamente MakerAdvisor.com/tools ¡Para encontrar todas las piezas para tus proyectos al mejor precio!
Para crear diferentes tareas que se ejecutan en diferentes núcleos, creamos dos tareas que hacen parpadear LED con diferentes tiempos de retardo. Comience conectando dos LED al ESP32 como se muestra en el siguiente diagrama:
Creamos dos tareas que se ejecutan en diferentes núcleos:
- Task1 se ejecuta en el núcleo 0;
- Task2 se ejecuta en el núcleo 1;
Sube el siguiente boceto a tu ESP32 para hacer parpadear cada LED en un núcleo diferente:
/*********
Rui Santos
Complete project details at https://randomnerdtutorials.com
*********/
TaskHandle_t Task1;
TaskHandle_t Task2;
// LED pins
const int led1 = 2;
const int led2 = 4;
void setup() {
Serial.begin(115200);
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
//create a task that will be executed in the Task1code() function, with priority 1 and executed on core 0
xTaskCreatePinnedToCore(
Task1code, /* Task function. */
"Task1", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&Task1, /* Task handle to keep track of created task */
0); /* pin task to core 0 */
delay(500);
//create a task that will be executed in the Task2code() function, with priority 1 and executed on core 1
xTaskCreatePinnedToCore(
Task2code, /* Task function. */
"Task2", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&Task2, /* Task handle to keep track of created task */
1); /* pin task to core 1 */
delay(500);
}
//Task1code: blinks an LED every 1000 ms
void Task1code( void * pvParameters ){
Serial.print("Task1 running on core ");
Serial.println(xPortGetCoreID());
for(;;){
digitalWrite(led1, HIGH);
delay(1000);
digitalWrite(led1, LOW);
delay(1000);
}
}
//Task2code: blinks an LED every 700 ms
void Task2code( void * pvParameters ){
Serial.print("Task2 running on core ");
Serial.println(xPortGetCoreID());
for(;;){
digitalWrite(led2, HIGH);
delay(700);
digitalWrite(led2, LOW);
delay(700);
}
}
void loop() {
}
Cómo funciona el código
Nota: En el código, creamos dos tareas y asignamos una tarea al núcleo 0 y otra al núcleo 1. Los bocetos de Arduino se ejecutan en el núcleo 1 de forma predeterminada, por lo que puede colocar el código para la Tarea 2 en el Cinta() (no hubo necesidad de crear otra tarea). En este caso, creamos dos tareas diferentes con fines de aprendizaje.
Sin embargo, dependiendo de las necesidades de su proyecto, puede resultar más práctico organizar su código en tareas, como se muestra en este ejemplo.
El código comienza creando un identificador de tarea para Tarea1 y Tarea2 llamado Tarea 1 Y ejercicio 2.
TaskHandle_t Task1;
TaskHandle_t Task2;
Asigne los LED GPIO 2 y GPIO 4:
const int led1 = 2;
const int led2 = 4;
En el configuración()inicialice el monitor serie con una velocidad de baudios de 115200:
Serial.begin(115200);
Declare los LED como salidas:
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
Luego crea la Tarea 1 con eso. xTaskCreatePinnedToCore() Función:
xTaskCreatePinnedToCore(
Task1code, /* Task function. */
"Task1", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&Task1, /* Task handle to keep track of created task */
0); /* pin task to core 0 */
La tarea 1 se implementa con el Código de tarea1() Función. Por lo tanto, necesitamos crear esta función más adelante en el código. Le damos a la tarea prioridad 1 y la fijamos al núcleo 0.
Creamos Task2 usando el mismo método:
xTaskCreatePinnedToCore(
Task2code, /* Task function. */
"Task2", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&Task2, /* Task handle to keep track of created task */
1); /* pin task to core 0 */
Después de crear las tareas, necesitamos crear las funciones que realizan esas tareas.
void Task1code( void * pvParameters ){
Serial.print("Task1 running on core ");
Serial.println(xPortGetCoreID());
for(;;){
digitalWrite(led1, HIGH);
delay(1000);
digitalWrite(led1, LOW);
delay(1000);
}
}
La función para la Tarea1 se llama Código de tarea1() (Puedes llamarlo como quieras). Para fines de depuración, primero imprimimos el núcleo donde se ejecuta la tarea:
Serial.print("Task1 running on core ");
Serial.println(xPortGetCoreID());
Entonces tenemos un bucle infinito similar a este. Cinta() en el boceto de Arduino. En este bucle dejamos que el LED1 parpadee cada segundo.
Con la Tarea2 ocurre lo mismo, pero hacemos parpadear el LED con un tiempo de retardo diferente.
void Task2code( void * pvParameters ){
Serial.print("Task2 running on core ");
Serial.println(xPortGetCoreID());
for(;;){
digitalWrite(led2, HIGH);
delay(700);
digitalWrite(led2, LOW);
delay(700);
}
}
Finalmente, esto Cinta() La función está vacía:
void loop() { }
Nota: como ya se mencionó, el Arduino Cinta() se ejecuta en el núcleo 1. Entonces, en lugar de crear una tarea que se ejecuta en el núcleo 1, puede simplemente poner su código en el Cinta().
demostración
Sube el código a tu ESP32. Asegúrese de haber seleccionado la placa y el puerto COM correctos.
Abra el monitor serie con una velocidad de baudios de 115200. Debería recibir los siguientes mensajes:
Como era de esperar, la Tarea1 se ejecuta en el núcleo 0 mientras que la Tarea2 se ejecuta en el núcleo 1.
En su circuito, un LED debería parpadear cada segundo y el otro cada 700 milisegundos.
Envolver
En total:
- El ESP32 es de doble núcleo;
- Los bocetos de Arduino se ejecutan en Core 1 de forma predeterminada;
- Para usar Core 0, necesitas crear tareas.
- Puedes utilizar el… xTaskCreatePinnedToCore() Función para fijar una tarea específica a un núcleo específico;
- Este método le permite ejecutar dos tareas diferentes de forma independiente y simultánea utilizando los dos núcleos.
En este tutorial proporcionamos un ejemplo sencillo utilizando LED. La idea es utilizar este método en proyectos más avanzados con aplicaciones del mundo real. Por ejemplo, puede resultar útil utilizar un núcleo para ingerir los valores de los sensores y otro para publicar esos valores en un sistema domótico.
Si desea obtener más información sobre ESP32, asegúrese de consultar nuestro curso: Aprenda ESP32 con Arduino IDE.
Introducción
El ESP32 viene con 2 microprocesadores Xtensa de 32 bits LX6: core 0 y core 1, por lo que es de doble núcleo. Por defecto, al ejecutar el código en Arduino IDE, éste se ejecuta en el core 1. En este post te mostraremos cómo ejecutar código en el segundo core del ESP32 creando tareas. Puedes ejecutar fragmentos de código simultáneamente en ambos cores y hacer que tu ESP32 sea multitarea.
Nota: no necesariamente necesitas ejecutar en doble núcleo para lograr multitarea.
Crear Tareas
El Arduino IDE soporta FreeRTOS para el ESP32, que es un sistema operativo en tiempo real. Esto nos permite manejar varias tareas en paralelo que se ejecutan de forma independiente.
Las tareas son fragmentos de código que ejecutan algo. Por ejemplo, puede ser hacer parpadear un LED, realizar una solicitud de red, medir lecturas de sensores, publicar lecturas de sensores, etc…
Para asignar partes específicas del código a un core específico, necesitas crear tareas. Al crear una tarea, puedes elegir en qué core se ejecutará, así como su prioridad.
- Crea un identificador de tarea. Un ejemplo para Task1:
- TaskHandle_t Task1;
- En la función setup(), crea una tarea asignada a un core específico utilizando la función xTaskCreatePinnedToCore.
- Después de crear la tarea, debes crear una función que contenga el código de la tarea creada.
Cómo funciona el código
Como se mencionó anteriormente, Arduino sketches se ejecutan en core 1 por defecto. Por lo tanto, en lugar de crear una tarea para ejecutar en core 1, simplemente puedes escribir tu código dentro de loop().
Sube el código a tu ESP32. Asegúrate de tener seleccionada la placa correcta y el puerto COM.
Abre el Monitor Serial a una velocidad de baudios de 115200. Deberías obtener los siguientes mensajes:
Como era de esperar, Task1 se está ejecutando en el core 0, mientras que Task2 se está ejecutando en el core 1.
En tu circuito, un LED debería estar parpadeando cada segundo, y el otro debería estar parpadeando cada 700 milisegundos.
Conclusión
En resumen:
- El ESP32 es de doble núcleo.
- Los sketches de Arduino se ejecutan en core 1 por defecto.
- Para usar core 0, necesitas crear tareas.
- Puedes usar la función xTaskCreatePinnedToCore() para fijar una tarea específica a un core específico.
En este tutorial hemos proporcionado un ejemplo sencillo con LEDs. La idea es utilizar este método con proyectos más avanzados con aplicaciones del mundo real.
¡Interesante artículo! Me encantaría aprender a sacarle el máximo provecho al ESP32 Dual Core con Arduino IDE. ¡Gracias por compartir la información!