#include <Arduino.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/semphr.h>
#include <freertos/queue.h>
#include <freertos/event_groups.h>
#include <freertos/timers.h>
// Definição dos pinos
#define LED_SALA 23
#define LED_ALARME 22
#define LED_AR_CONDICIONADO 21
#define LED_IRRIGACAO 19
#define LED_NOTIFICACAO 18
#define LED_ELETRODOMESTICO 5
#define BOTAO_PANICO 17
#define BOTAO_TEMPERATURA 16
#define BOTAO_IRRIGACAO_MANUAL 4
// Handles para tarefas
TaskHandle_t taskIluminacaoHandle = NULL;
TaskHandle_t taskSegurancaHandle = NULL;
TaskHandle_t taskTemperaturaHandle = NULL;
TaskHandle_t taskIrrigacaoHandle = NULL;
TaskHandle_t taskNotificacoesHandle = NULL;
TaskHandle_t taskEletrodomesticosHandle = NULL;
// Mutex para acesso compartilhado ao sensor de temperatura simulado
SemaphoreHandle_t xMutexTemperatura;
// Semáforo Binário para ativação do alarme
SemaphoreHandle_t xAlarmeAtivado;
// Semáforo Contador para limite de eletrodomésticos ligados
SemaphoreHandle_t xEletrodomesticosSemaphore;
// Fila para comandos de irrigação
QueueHandle_t xFilaIrrigacao;
// Grupo de eventos para notificações do sistema
EventGroupHandle_t xEventGroupSistema;
// Temporizador para verificação periódica do sistema
TimerHandle_t xTimerSistema;
// Bits do grupo de eventos
#define WIFI_CONECTADO (1 << 0)
#define ALARME_DISPARADO (1 << 1)
#define TEMPERATURA_ALTA (1 << 2)
// Variáveis globais
float temperaturaAtual = 22.5; // Temperatura simulada
void IRAM_ATTR botaoPanicoISR(void* arg) {
static BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(xAlarmeAtivado, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken == pdTRUE) portYIELD_FROM_ISR();
debounce(BOTAO_PANICO);
}
// ISR do botão de temperatura
void IRAM_ATTR botaoTemperaturaISR(void* arg) {
if (xSemaphoreTakeFromISR(xMutexTemperatura, NULL) == pdTRUE) {
temperaturaAtual += 2.0; // Aumenta temperatura simulada
xSemaphoreGiveFromISR(xMutexTemperatura, NULL);
}
debounce(BOTAO_TEMPERATURA);
}
// ISR do botão de irrigação manual
void IRAM_ATTR botaoIrrigacaoISR(void* arg) {
int minutosIrrigacao = 1; // 1 minuto de irrigação manual
xQueueSendFromISR(xFilaIrrigacao, &minutosIrrigacao, NULL);
debounce(BOTAO_IRRIGACAO_MANUAL);
}
void setup() {
Serial.begin(115200);
// Configuração dos pinos
pinMode(LED_SALA, OUTPUT);
pinMode(LED_ALARME, OUTPUT);
pinMode(LED_AR_CONDICIONADO, OUTPUT);
pinMode(LED_IRRIGACAO, OUTPUT);
pinMode(LED_NOTIFICACAO, OUTPUT);
pinMode(LED_ELETRODOMESTICO, OUTPUT);
pinMode(BOTAO_PANICO, INPUT_PULLUP);
pinMode(BOTAO_TEMPERATURA, INPUT_PULLUP);
pinMode(BOTAO_IRRIGACAO_MANUAL, INPUT_PULLUP);
// Inicialização dos recursos FreeRTOS
xMutexTemperatura = xSemaphoreCreateMutex();
xAlarmeAtivado = xSemaphoreCreateBinary();
xEletrodomesticosSemaphore = xSemaphoreCreateCounting(3, 3); // Máximo 3 eletrodomésticos
xFilaIrrigacao = xQueueCreate(5, sizeof(int)); // Fila de minutos de irrigação
xEventGroupSistema = xEventGroupCreate();
// Temporizador de verificação do sistema (1 segundo)
xTimerSistema = xTimerCreate(
"TimerSistema",
pdMS_TO_TICKS(1000),
pdTRUE,
(void*)0,
timerSistemaCallback);
xTimerStart(xTimerSistema, 0);
// Configuração das interrupções dos botões
attachInterruptArg(BOTAO_PANICO, botaoPanicoISR, NULL, FALLING);
attachInterruptArg(BOTAO_TEMPERATURA, botaoTemperaturaISR, NULL, FALLING);
attachInterruptArg(BOTAO_IRRIGACAO_MANUAL, botaoIrrigacaoISR, NULL, FALLING);
// Criação das tarefas
xTaskCreatePinnedToCore(
taskIluminacao, // Função da tarefa
"Iluminacao", // Nome da tarefa
2048, // Tamanho da pilha
NULL, // Parâmetros
1, // Prioridade
&taskIluminacaoHandle,
0 // Núcleo
);
xTaskCreatePinnedToCore(
taskSeguranca,
"Seguranca",
2048,
NULL,
3, // Prioridade mais alta para segurança
&taskSegurancaHandle,
0
);
xTaskCreatePinnedToCore(
taskTemperatura,
"Temperatura",
2048,
NULL,
2,
&taskTemperaturaHandle,
0
);
xTaskCreatePinnedToCore(
taskIrrigacao,
"Irrigacao",
2048,
NULL,
1,
&taskIrrigacaoHandle,
0
);
xTaskCreatePinnedToCore(
taskNotificacoes,
"Notificacoes",
2048,
NULL,
2,
&taskNotificacoesHandle,
1
);
xTaskCreatePinnedToCore(
taskEletrodomesticos,
"Eletrodomesticos",
2048,
NULL,
1,
&taskEletrodomesticosHandle,
1
);
// Simula conexão WiFi após 3 segundos
xTaskCreate(
taskConectarWiFi,
"ConectarWiFi",
1024,
NULL,
1,
NULL
);
}
void loop() {
// Nada aqui - tudo é tratado pelas tarefas
delay(10);
}
// Tarefa 1: Controle de Iluminação da Sala
void taskIluminacao(void *pvParameters) {
bool luzLigada = false;
while(1) {
// Simula sensor de luminosidade (noite/dia)
int horaSimulada = (xTaskGetTickCount() / 1000) % 24; // 0-23
if (horaSimulada >= 18 || horaSimulada <= 6) { // Noite
if (!luzLigada) {
digitalWrite(LED_SALA, HIGH);
luzLigada = true;
Serial.println("Iluminação: Luz da sala ligada (noite)");
}
} else { // Dia
if (luzLigada) {
digitalWrite(LED_SALA, LOW);
luzLigada = false;
Serial.println("Iluminação: Luz da sala desligada (dia)");
}
}
vTaskDelay(pdMS_TO_TICKS(5000)); // Verifica a cada 5 segundos
}
}
// Tarefa 2: Sistema de Segurança e Alarme
void taskSeguranca(void *pvParameters) {
bool alarmeAtivo = false;
while(1) {
// Verifica se o semáforo de alarme foi ativado (pelo botão de pânico)
if (xSemaphoreTake(xAlarmeAtivado, 0) == pdTRUE) {
alarmeAtivo = true;
xEventGroupSetBits(xEventGroupSistema, ALARME_DISPARADO);
Serial.println("Segurança: Alarme disparado!");
}
// Comportamento do alarme
if (alarmeAtivo) {
for (int i = 0; i < 10; i++) { // Alarme por 5 segundos (10 x 500ms)
digitalWrite(LED_ALARME, !digitalRead(LED_ALARME));
vTaskDelay(pdMS_TO_TICKS(500));
}
alarmeAtivo = false;
xEventGroupClearBits(xEventGroupSistema, ALARME_DISPARADO);
Serial.println("Segurança: Alarme desativado");
}
vTaskDelay(pdMS_TO_TICKS(100)); // Verifica frequentemente
}
}
// Tarefa 3: Controle de Temperatura e Ar Condicionado
void taskTemperatura(void *pvParameters) {
float temperaturaDesejada = 22.0;
while(1) {
// Atualiza temperatura simulada (com mutex)
if (xSemaphoreTake(xMutexTemperatura, portMAX_DELAY) == pdTRUE) {
// Variação aleatória de temperatura
temperaturaAtual += (random(-10, 11) / 10.0);
// Limites de temperatura
if (temperaturaAtual < 15) temperaturaAtual = 15;
if (temperaturaAtual > 35) temperaturaAtual = 35;
xSemaphoreGive(xMutexTemperatura);
}
// Controle do ar condicionado
if (temperaturaAtual > temperaturaDesejada + 1.0) {
digitalWrite(LED_AR_CONDICIONADO, HIGH);
if (temperaturaAtual > 28) {
xEventGroupSetBits(xEventGroupSistema, TEMPERATURA_ALTA);
}
} else if (temperaturaAtual < temperaturaDesejada - 1.0) {
digitalWrite(LED_AR_CONDICIONADO, LOW);
xEventGroupClearBits(xEventGroupSistema, TEMPERATURA_ALTA);
}
Serial.printf("Temperatura: Atual %.1f°C, Desejada %.1f°C\n", temperaturaAtual, temperaturaDesejada);
vTaskDelay(pdMS_TO_TICKS(3000)); // Verifica a cada 3 segundos
}
}
// Tarefa 4: Sistema de Irrigação do Jardim
void taskIrrigacao(void *pvParameters) {
int minutosIrrigacao;
while(1) {
// Recebe comandos da fila (0 = desliga, 1-5 = minutos de irrigação)
if (xQueueReceive(xFilaIrrigacao, &minutosIrrigacao, portMAX_DELAY) == pdPASS) {
if (minutosIrrigacao > 0) {
Serial.printf("Irrigação: Iniciando por %d minutos\n", minutosIrrigacao);
digitalWrite(LED_IRRIGACAO, HIGH);
// Contagem regressiva do tempo de irrigação
for (int i = 0; i < minutosIrrigacao; i++) {
vTaskDelay(pdMS_TO_TICKS(60000)); // 1 minuto
Serial.printf("Irrigação: %d minuto(s) restante(s)\n", minutosIrrigacao - i - 1);
}
digitalWrite(LED_IRRIGACAO, LOW);
Serial.println("Irrigação: Concluída");
}
}
}
}
// Tarefa 5: Sistema de Notificações
void taskNotificacoes(void *pvParameters) {
EventBits_t bitsEventos;
while(1) {
// Espera por eventos no grupo de eventos
bitsEventos = xEventGroupWaitBits(
xEventGroupSistema,
WIFI_CONECTADO | ALARME_DISPARADO | TEMPERATURA_ALTA,
pdTRUE, // Limpa os bits após leitura
pdFALSE, // Não espera por todos os bits
portMAX_DELAY);
// Processa os eventos recebidos
if (bitsEventos & WIFI_CONECTADO) {
Serial.println("Notificação: WiFi conectado");
piscarLED(LED_NOTIFICACAO, 2, 200);
}
if (bitsEventos & ALARME_DISPARADO) {
Serial.println("Notificação: Alarme disparado!");
piscarLED(LED_NOTIFICACAO, 5, 200);
}
if (bitsEventos & TEMPERATURA_ALTA) {
Serial.println("Notificação: Temperatura muito alta!");
piscarLED(LED_NOTIFICACAO, 3, 500);
}
}
}
// Tarefa 6: Controle de Eletrodomésticos
void taskEletrodomesticos(void *pvParameters) {
uint32_t notificacao;
while(1) {
// Espera por notificações (número de vezes para ligar/desligar)
notificacao = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
// Tenta adquirir um token do semáforo de contagem
if (xSemaphoreTake(xEletrodomesticosSemaphore, 0) == pdTRUE) {
Serial.printf("Eletrodomésticos: Ligando dispositivo (Total ligados: %d)\n",
3 - uxSemaphoreGetCount(xEletrodomesticosSemaphore));
digitalWrite(LED_ELETRODOMESTICO, HIGH);
vTaskDelay(pdMS_TO_TICKS(notificacao * 1000)); // Mantém ligado por N segundos
digitalWrite(LED_ELETRODOMESTICO, LOW);
xSemaphoreGive(xEletrodomesticosSemaphore);
Serial.printf("Eletrodomésticos: Desligando dispositivo (Total ligados: %d)\n",
3 - uxSemaphoreGetCount(xEletrodomesticosSemaphore));
} else {
Serial.println("Eletrodomésticos: Limite de dispositivos atingido!");
piscarLED(LED_NOTIFICACAO, 3, 100); // Notifica limite atingido
}
}
}
// Tarefa auxiliar: Simula conexão WiFi
void taskConectarWiFi(void *pvParameters) {
vTaskDelay(pdMS_TO_TICKS(3000)); // Espera 3 segundos
xEventGroupSetBits(xEventGroupSistema, WIFI_CONECTADO);
Serial.println("WiFi: Conectado à rede");
vTaskDelete(NULL); // Auto-deleta após concluir
}
// Callback do temporizador do sistema
void timerSistemaCallback(TimerHandle_t xTimer) {
// Rotina de irrigação automática (2 minutos às 6h e 18h simuladas)
int horaSimulada = (xTaskGetTickCount() / 1000) % 24;
if (horaSimulada == 6 || horaSimulada == 18) {
int minutosIrrigacao = 2;
xQueueSend(xFilaIrrigacao, &minutosIrrigacao, 0);
}
// Atualização periódica do status
static int contador = 0;
Serial.printf("Sistema: Operação normal [%d]\n", contador++);
}
// Função auxiliar para debounce
void debounce(int pino) {
static unsigned long ultimoTempo = 0;
unsigned long tempoAtual = millis();
if (tempoAtual - ultimoTempo > 300) {
ultimoTempo = tempoAtual;
} else {
return;
}
}
// Função auxiliar para piscar LED
void piscarLED(int led, int vezes, int intervalo) {
for (int i = 0; i < vezes; i++) {
digitalWrite(led, HIGH);
vTaskDelay(pdMS_TO_TICKS(intervalo));
digitalWrite(led, LOW);
vTaskDelay(pdMS_TO_TICKS(intervalo));
}
}