Manual
do
Maker
.
com
Esse foi sem sombra de dúvidas o desafio mais fácil até agora. Quem usa task, provavelmente precisou em algum momento usar um TaskHandle para interagir com o processamento paralelo. Se não leu o Desafio Maker 05, dê uma lida rapidinho pelo menos pra saber qual era o tema.
Normalmente passamos NULL como parâmetro do manipulador, ao criar uma task. Se feito desse modo, não há como controlar a task "externamente" ao processo assíncrono da thread. Porém o TaskHandle nos dá alguns controle sobre as tasks, como pausar, retomar e excluir, além de pegar seu status.
Como o desafio propõe o controle sem aferir qual task está em execução através do status das threads, como saber para qual das 4 tasks enviar o suspend? Simples (mas dispendioso); criar um array com os manipuladores e incrementar um indexador e cada passagem de task.
Veja uma task declarada:
void task1(void *pvParameters){
vTaskDelay(pdMS_TO_TICKS(10000)); //aqui seria solenoide do leite
xTaskCreatePinnedToCore(task2,"task2",10000,NULL,0,&tasks[1],0);
idx+=1;
vTaskDelete(NULL);
}
Usei o delay para representar o processamento da task, mas obviamente deveria ser a função millis() em um caso de uso real, tal qual exemplifico na função loop(), mas adiante.
Quando a task termina seu trabalho, ela inicia o próximo processo, incrementa o indexador que é referência para manipulação da task e então se exclui.
Repare que a task1 usa o idx 0, e assim sucessivamente. Quando a task4 termina seu trabalho, coloca o idx em 0 novamente antes de se excluir.
Na função loop() eu usei a serial invés de botão, porque estou com preguiça de fazer solda e wiring, mas quem está lendo esse artigo já deve estar muuuuito habituado com GPIO e digitalRead(). Então, se for recebido 0, utiliza-se vTaskSuspend(tasks[idx]), onde tasks é um array com os TaskHandle e idx é o indexador da tarefa. Desse modo, não precisamos verificar o status de cada uma das tasks antes de suspendê-la, basta apontar diretamente para seu manipulador conforme o idx. O código do desafio ficou assim:
#include <Wire.h>
#include <WiFi.h>
TaskHandle_t t_task1;
TaskHandle_t t_task2;
TaskHandle_t t_task3;
TaskHandle_t t_task4;
TaskHandle_t tasks[4] = {t_task1,t_task2,t_task3,t_task4};
unsigned char idx = 0;
unsigned char onOff = 1;
unsigned long int timeout = millis();
void task1(void *pvParameters){
vTaskDelay(pdMS_TO_TICKS(10000)); //aqui seria solenoide do leite
xTaskCreatePinnedToCore(task2,"task2",10000,NULL,0,&tasks[1],0);
idx+=1;
vTaskDelete(NULL);
}
void task2(void *pvParameters){
vTaskDelay(pdMS_TO_TICKS(12000)); //aqui seria solenoide do leite
xTaskCreatePinnedToCore(task3,"task3",10000,NULL,0,&tasks[2],0);
idx+=1;
vTaskDelete(NULL);
}
void task3(void *pvParameters){
vTaskDelay(pdMS_TO_TICKS(30000)); //aqui seria solenoide do leite
xTaskCreatePinnedToCore(task4,"task4",10000,NULL,0,&tasks[3],0);
idx+=1;
vTaskDelete(NULL);
}
void task4(void *pvParameters){
vTaskDelay(pdMS_TO_TICKS(30000)); //aqui seria solenoide do leite
xTaskCreatePinnedToCore(task1,"task1",10000,NULL,0,&tasks[0],0);
idx=0;
vTaskDelete(NULL);
}
void setup() {
Serial.begin(115200);
while (!Serial);
xTaskCreatePinnedToCore(task1,"task1",10000,NULL,0,&tasks[0],0);
}
void loop() {
if (Serial.available()){
onOff = Serial.read()-48;a
if (onOff == 1){
if (eTaskGetState(&tasks[idx]) == 0){
vTaskResume(tasks[idx]);
}
}
else{
vTaskSuspend(tasks[idx]);
Serial.println("1");
}
Serial.print("resposta: ");
Serial.println(onOff);
}
if ((millis()-timeout) > 1000){
timeout = millis();
if (onOff == 1){
Serial.println(idx);
}
}
}
Dá pra fazer com Arduino se usar RTOS, apesar do desempenho ser bastante ruim.
Se precisar de mais referências (e tiver habilidade com inglês), a documentação oficial do ESP32 é bastante auxiliadora. Aliás, foi de lá que estudei e aprendi a usar o ESP32.
E aí? Conseguiu resolver? Gostou do resultado?
Até o próximo desafio!
Inscreva-se no nosso canal Manual do Maker no YouTube.
Também estamos no Instagram.
Autor do blog "Do bit Ao Byte / Manual do Maker".
Viciado em embarcados desde 2006.
LinuxUser 158.760, desde 1997.