Uma parte do curso de IOT que
estou desenvolvendo. É o que mostro hoje para vocês: uma aula sobre Multitask,
ou seja, sobre como ser profissional programando “multitarefas”. Adianto que dá
para fazer isso com o ESP32 e também com o Arduino, embora com menor
velocidade. Então, vamos aprender a programar tasks utilizando FreeRTOS, em um
exemplo que utiliza os 2 cores do ESP32.
PROGRAMAÇÃO MULTICORE
Introdução
O ESP32 é dual core, ou seja,
possui 2 cores que são definidos como core 0 e core 1.
Quando executamos o código na
Arduino IDE, o core 0 inicialmente não possui processos definidos enquanto o
core 1 possui os processos das funções setup e loop.
Para saber em qual core o
código está sendo executado existe a função xPortGetCoreID().
Basta chamar essa função
dentro do escopo da função desejada. Você pode usar o
Serial.println(xPortGetCoreID()); e ver no monitor serial o número indicado,
que corresponde ao core 0 ou 1.
Caso o Serial.println
estivesse em uma task iniciada no core 0, então o número 0 seria exibido.
No próximo slide veremos como
iniciar uma task.
Criando uma task
Para criar tarefas que serão
executadas para sempre (loop infinito), o código utilizado é o seguinte:
Para tarefas que são temporárias, ou seja, serão executadas só uma vez, é necessário criar um manipulador de tarefa. Conforme o código abaixo.
Encerrando uma task
Abaixo temos um exemplo de
iniciação e encerramento de uma task temporária
Visualizando o monitor serial:
Watchdog timer tasks
Todas as tasks são
automaticamente vigiadas por um watchdog e temos que resetar este contador
chamando a função esp_task_wdt_reset.
Watchdog
É possível desabilitar esse
watchdog, porém você deve entender que o seu projeto estará sujeito a possíveis
problemas de travamento.
Desabilitando o Watchdog timer
(core 0):
Parâmetros
Mostraremos um exemplo de como
passar uma variável por parâmetro. É possível passar também uma struct ou até
mesmo um objeto por exemplo.
MULTITASK - EXEMPLO
Recursos usados
- ESPWROOM-32 DevKit de 38 pinos
- Led verde
- Led vermelho
- 2 Resistores 220 ohm ou 330 ohm
- Jumpers
- Protoboard
Montagem
CÓDIGO
Fluxograma
Funcionamento
Neste nosso exemplo estamos
utilizando duas tasks no core 0 e também o loop no core 1.
A task 1 (taskLedVerde) é encarregada
de piscar o led verde a cada 100 ms.
A task 2 (taskLedVermelho) é
encarregada de piscar o led vermelho a cada 1000 ms.
O loop é encarregado de
reiniciar o ESP 10 segundos após a sua inicialização.?
A saída no monitor serial é feita de acordo com a imagem abaixo, é a função loop que exibe estas mensagens.
A saída no monitor serial é feita de acordo com a imagem abaixo, é a função loop que exibe estas mensagens.
Código
Declarações e Variáveis
// Biblioteca com as funções de watchdog #include "esp_task_wdt.h" // Pinos dos leds const int ledVerde = 32, ledVermelho = 33; // Segundos que serão contados para reiniciar o ESP, a partir do momento que ele iniciar const int secondsRestart = 10; // Variável auxiliar usada na função loop int auxSeconds = -1; // Variável que guarda o valor de "millis()" ao iniciar o ESP int startMillis;
Setup
void setup()
{
// Habilitamos o watchdog com timeout de 15 segundos
esp_task_wdt_init(15, true);
// Setamos os pinos dos leds como saída
pinMode(ledVerde, OUTPUT);
pinMode(ledVermelho, OUTPUT);
// Iniciamos a serial com velocidade de 115200
Serial.begin(115200);
// Pulamos uma linha ao iniciar/reiniciar o ESP para separar o lixo de memória do primeiro Serial.println
Serial.println();
// Deixamos os leds apagados indicando a reiniciação do ESP, caso contrário não é possível ver os leds "parando" no momento em que o ESP é reiniciado
digitalWrite(ledVerde, LOW);
digitalWrite(ledVermelho, LOW);
// Exibimos que o esp irá iniciar em 3 segundos
Serial.println("Starting in 3 seconds...");
// Aguardamos 3 segundos
// Iniciamos uma task para o led verde
xTaskCreatePinnedToCore( taskLedVerde, // Função que implementa a tarefa
"taskLedVerde", // Nome da tarefa
10000, // Número de palavras a serem alocadas na pilha (stack)
NULL, // Parâmetro de entrada para a tarefa
1, // Prioridade da tarefa
NULL, // Referência para a tarefa
0 // Núcleo em que a task rodará (0 ou 1)
);
// Iniciamos uma task para o led vermelho
xTaskCreatePinnedToCore(taskLedVermelho, "taskLedVermelho", 10000, NULL, 1, NULL, 0);
// Atribuímos o valor de millis para nossa variável de referência que será usada no contador de tempo
startMillis = millis();
}
TaskLedVerde
// Task que pisca o led verde a cada 100ms
void taskLedVerde(void *p)
{
esp_task_wdt_add(NULL);
// Loop infinito
while(true)
{
esp_task_wdt_reset();
// Mudamos de estado do led
digitalWrite(ledVerde, !digitalRead(ledVerde));
// Aguardamos 100ms
delay(100);
}
}
TaskLedVermelho
// Task que pisca o led vermelho a cada 1000ms
void taskLedVermelho(void *p)
{
esp_task_wdt_add(NULL);
// Loop infinito
while(true)
{
esp_task_wdt_reset();
// Invertemos o estado do led e aguardamos 1 segundo, piscando o led
digitalWrite(ledVermelho, !digitalRead(ledVermelho));
delay(1000);
}
}
Loop
// O loop será responsável por contar o tempo decorrido e caso este tempo ultrapassar os segundos definidos pela variável "secondsRestart" o ESP será reiniciado
void loop()
{
// Variável que recebe o tempo decorrido em segundos
int seconds = (millis() - startMillis)/1000;
// Caso o tempo ultrapassou os segundos definidos pela variável "secondsRestart"
if(seconds >= secondsRestart)
{
// Exibimos reiniciando
Serial.println("\t\t\tRestarting...");
// Reiniciamos o ESP
ESP.restart();
}
// Exibimos de segundo em segundo o tempo restante para o ESP reiniciar
if(seconds != auxSeconds)
{
// Exibimos na serial os segundos restantes
Serial.println("Seconds remaining to restart: "+String(secondsRestart-seconds));
// Atribuímos para a variável auxiliar o valor de "seconds"
auxSeconds = seconds;
}
}























2 Comentários
Olá. Quando o curso será lançado ? Tenho grande interesse na área de programação para RTOS e venho acompanhando seu canal a um bom tempo, parabéns pela iniciativa !!!
ResponderExcluirgostaria tb de participar. wbhenriques@gmail.com
ResponderExcluir