#include <LiquidCrystal.h>
#include <DHT.h>
// 1. INCLUIR BIBLIOTECAS DO FREERTOS (conforme imagem)
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/semphr.h> //
const int rs = 19, en = 23, d4 = 18, d5 = 17, d6 = 16, d7 = 15;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
#define DHTPIN 4
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
#define POT_PIN 34
// --- DECLARAÇÃO DOS HANDLES DAS TASKS ---
TaskHandle_t TaskTempHandle;
TaskHandle_t TaskCountHandle;
TaskHandle_t TaskPotHandle;
TaskHandle_t TaskMonitorHandle;
// --- 2. DECLARAÇÃO DO SEMÁFORO (conforme imagem) ---
// Usaremos para proteger o LCD (Recurso Compartilhado)
SemaphoreHandle_t xSemaforoLCD; //
// --- PROTÓTIPOS DAS FUNÇÕES ---
void Task_Temperatura(void *pvParameters);
void Task_Contador(void *pvParameters);
void Task_Potenciometro(void *pvParameters);
void Task_MonitorCore(void *pvParameters);
void setup() {
Serial.begin(115200);
lcd.begin(16, 2);
dht.begin();
pinMode(POT_PIN, INPUT);
// --- 3. CRIAÇÃO DO SEMÁFORO (conforme imagem) ---
if (xSemaforoLCD == NULL) {
xSemaforoLCD = xSemaphoreCreateMutex(); // Cria o mutex
if (xSemaforoLCD != NULL) {
xSemaphoreGive(xSemaforoLCD); // Libera o semáforo para uso inicial
}
} //
lcd.print("COM PROTECAO!"); // Mudamos o texto para indicar que agora tem mutex
delay(1000);
lcd.clear();
// Criação das Tarefas
xTaskCreatePinnedToCore(Task_Temperatura, "TaskTemp", 4096, NULL, 1, &TaskTempHandle, 0);
xTaskCreatePinnedToCore(Task_Contador, "TaskCount", 4096, NULL, 1, &TaskCountHandle, 1);
xTaskCreate(Task_Potenciometro, "TaskPot", 4096, NULL, 2, &TaskPotHandle);
xTaskCreate(Task_MonitorCore, "TaskMonitor", 2048, NULL, 3, &TaskMonitorHandle);
}
void loop() {
vTaskDelete(NULL);
}
// --- TAREFA 1: Temperatura (Protegida por Semáforo) ---
void Task_Temperatura(void *pvParameters) {
for(;;) {
float t = dht.readTemperature();
// --- 4. USO DO SEMÁFORO (conforme imagem) ---
// Tenta pegar o semáforo, espera até 5 ticks se estiver ocupado
if (xSemaphoreTake(xSemaforoLCD, (TickType_t)5) == pdTRUE) { //
// Se entrou aqui, o LCD é "propriedade" desta task agora
lcd.setCursor(0, 0);
lcd.print("Temp: ");
if (isnan(t)) {
lcd.print("Erro");
} else {
lcd.print(t, 1);
lcd.print(" C ");
}
// Devolve o semáforo para as outras tasks usarem
xSemaphoreGive(xSemaforoLCD); //
}
vTaskDelay(500 / portTICK_PERIOD_MS);
}
}
// --- TAREFA 2: Contador (Protegida por Semáforo) ---
void Task_Contador(void *pvParameters) {
int segundos = 0;
for(;;) {
// Tenta pegar o semáforo antes de escrever
if (xSemaphoreTake(xSemaforoLCD, (TickType_t)5) == pdTRUE) { //
lcd.setCursor(0, 1);
lcd.print("Tempo: ");
lcd.print(segundos);
lcd.print("s ");
xSemaphoreGive(xSemaforoLCD); // Libera o LCD
}
segundos++;
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
// --- TAREFA 3: Potenciômetro (Não usa LCD, não precisa travar o Mutex do LCD) ---
void Task_Potenciometro(void *pvParameters) {
for(;;) {
int valor = analogRead(POT_PIN);
// Se você quisesse proteger o Serial, usaria um Mutex aqui também,
// mas o foco principal é o LCD que estava dando erro visual.
Serial.print("[Potenciometro]: ");
Serial.println(valor);
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
// --- TAREFA 4: Monitor ---
void Task_MonitorCore(void *pvParameters) {
for(;;) {
Serial.print("--- [Task Monitor] Rodando no Core: ");
Serial.println(xPortGetCoreID());
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}