Manual

do

Maker

.

com

Como controlar tasks com ESP32

Como controlar tasks com ESP32

Bem, o circuito do relógio está pronto, todos os componentes testados e resta apenas colocar suas "vísceras" para dentro de seu corpo. Espero fechar esse projeto em mais um ou dois dias, mas antes de publicar esse artigo, preciso introduzir mais um conceito para que tudo fique claro quando você olhar para o código do relógio. E é sobre como controlar tasks no ESP32.

Não tem ESP32 ainda?

Ora, ora. Ali em cima no menu temos ESP32 entre as categorias. Material para aprendizado não falta e, com certeza, depois que você começar a fazer seus projetos com ele, não quererá mais fazê-lo com ESP8266. Aproveite para pegar um dos diversos modelos em um de nossos parceiros:

Atualmente temos 2 parceiros especializados em ESP32, sendo a Curto e a Saravati. Ambos, com link aí no carrossel do início do artigo.

Tasks

As tasks são como threads, processadas assincronamente graças à arquitetura do processador, que permite a execução de um sistema operacional de tempo real - no caso, uma modificação do FreeRTOS, que suporta os 3 processadores do ESP32. Um deles é o ULP, somente programável em assembly. Os outros 2, livres para uso. A API do Arduino executa as funções setup() e loop() no núcleo 1, enquanto deixa livre o núcleo 0.

Normalmente, escrevo minhas tasks para rodar no núcleo 1, mas nada nos impede de utilizar também o núcleo 0, desde que a prioridade da tarefa seja igual a prioridade das funções principais. O ruim disso é que deve-se tomar o máximo de cuidado para não tomar processamento demasiado, de forma a interromper por tempo prolongado a tarefa principal do núcleo 1, por isso prefiro dedicar todo o trabalho de tarefas ao núcleo 0 e rodar apenas as configurações do setup. Eventualmente, rodar algo em loop().

Tarefa com seleção automática do núcleo

Se rodar uma tarefa sem especificar o núcleo, ela será executada no núcleo de onde foi chamada. Por exemplo, iniciar uma task em setup() fará com que ela seja executada no núcleo 1.

Tarefa com indicação do núcleo a rodar

Se quisermos indicar o núcleo que a tarefa deve rodar, devemos utilizar outra função do ESP-IDF. Nesse artigo veremos as duas chamadas e como controlar tasks com ESP32.

Controlar tasks com ESP32 - prova de conceito

esp32-wemos-dobitaobyte.webp

Para esse teste, utilizo um módulo relé, acionado por uma task que levantará o pino IO12. O módulo está sendo alimentado em 5V, e ele possui um transistor para o acionamento.

vTaskDelete

Esse teste mostra o uso da função vTaskDelete. Não é bem adequado para esse tipo de tarefa porque se ela precisa ser reiniciada com tanta frequência, deve ser feita conforme o segundo exemplo. Mas para a prova de conceito está ótimo!

A primeira task (vHigh) é iniciada a partir do núcleo 1, mas ela é iniciada no núcleo 0. Ela coloca o pino 12 em HIGH, então inicia a segunda task sem apontar o núcleo. Poderia apontar, mas a task é executada a partir do núcleo de onde foi invocada, portanto, é indiferente. Desse modo, elas ficarão se alterando em um blink de 1 segundo, excluindo-se ao final.

#include <Arduino.h>
#include "rom/gpio.h"

TaskHandle_t task_high;
TaskHandle_t task_low;

void vHigh(void *pvParameters);
void vLow(void *pvParameters);

void vHigh(void *pvParameters){
  vTaskDelay(pdMS_TO_TICKS(1000));
  digitalWrite(12,HIGH);
  xTaskCreate(vLow,"vLow",10000,NULL,0,&task_low);
  vTaskDelete(NULL);
}

void vLow(void *pvParameters){
  vTaskDelay(pdMS_TO_TICKS(1000));
  digitalWrite(12,LOW);
  xTaskCreate(vHigh,"vHigh",10000,NULL,0,&task_high);
  vTaskDelete(NULL);
}

void setup(){
  pinMode(12,OUTPUT);
  xTaskCreatePinnedToCore(vHigh,"vHigh",10000,NULL,0,&task_high,0);
}

void loop(){

}

É um blink bruto, mas é só para demonstração do uso do recurso, ok?

vTaskSuspend e vTaskResume

Invés das tarefas se alternarem entre si, poderíamos ter uma task gerente, encarregando-se de fazer a alternância. A vTaskSuspend não exclui a tarefa, apenas a coloca para dormir. Para retomá-la, utiliza-se então a vTaskResume. Para ambas, o parâmetro é o manipulador da tarefa.

#include <Arduino.h>

TaskHandle_t task_high;
TaskHandle_t task_low;

void vHigh(void *pvParameters);
void vLow(void *pvParameters);

void vHigh(void *pvParameters){
  while (true){
    vTaskDelay(pdMS_TO_TICKS(100));
    digitalWrite(12,HIGH);
  }
}

void vLow(void *pvParameters){
  while (true){
    vTaskDelay(pdMS_TO_TICKS(100));
    digitalWrite(12,LOW);
  }
}

void vControl(void *pvParameters){
  xTaskCreate(vLow,"vLow",10000,NULL,0,&task_low);
  vTaskDelay(pdMS_TO_TICKS(110));
  vTaskSuspend(task_low);
  xTaskCreate(vHigh,"vHigh",10000,NULL,0,&task_high);
  while (true){
    vTaskDelay(pdMS_TO_TICKS(1000));
    vTaskSuspend(task_high);
    vTaskResume(task_low);
    vTaskDelay(pdMS_TO_TICKS(1000));
    vTaskSuspend(task_low);
    vTaskResume(task_high);
  }
}

void setup(){
  pinMode(12,OUTPUT);
  xTaskCreatePinnedToCore(vControl,"vControl",10000,NULL,0,NULL,0);
}

void loop(){

}

Como pode ser visto, as tarefas são criadas no gerente. Depois em um loop infinito elas vão se alternando, sendo suspensas e levantadas em intervalos e aí está como controlar tasks com ESP32!

O vídeo demonstrativo e explicativo estarão disponíveis em nosso canal DobitAoByteBrasil no Youtube. Se inscreva, clique no sino para receber notificações e deixe seu like para incentivar novos conteúdos!

 

Revisão: Ricardo Amaral de Andrade

Nome do Autor

Djames Suhanko

Autor do blog "Do bit Ao Byte / Manual do Maker".

Viciado em embarcados desde 2006.
LinuxUser 158.760, desde 1997.