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