#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h" // Biblioteca para Semáforos e Mutexes
#include <stdbool.h> // Variável Bool
#include "driver/gpio.h"
#include "driver/adc.h" // para utilizar o ADC
#define Abertura_da_caixa_dagua GPIO_NUM_17
#define Ligando_bomba GPIO_NUM_18
// cada ESP vai acionar uma dessas entradas
#define Irrigacao_Linha1 GPIO_NUM_16
#define Irrigacao_Linha2 GPIO_NUM_4
#define Irrigacao_Linha3 GPIO_NUM_21
// pino para receber o nível da água
#define Sensor_Nivel_da_caixa GPIO_NUM_14
#define ADC_CHANNEL_POTENCIOMETRO ADC2_CHANNEL_6
static SemaphoreHandle_t Nivel_da_agua_ok_semaphore;
static SemaphoreHandle_t Ligando_a__bomba_ok_semaphore;
// função de mapeamento para o pot
long map_value(long x, long in_min, long in_max, long out_min, long out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
void Ligando_a_Bomba (void *Ligue_a_bomba){
adc2_config_channel_atten(ADC_CHANNEL_POTENCIOMETRO, ADC_ATTEN_DB_11);
int raw_adc_value;
int porcentagem_nivel = 100;
while(1){
esp_err_t ret = adc2_get_raw(ADC_CHANNEL_POTENCIOMETRO, ADC_WIDTH_BIT_12, &raw_adc_value);
if (ret == ESP_OK) {
// Mapeia o valor lido (0-4095) para uma porcentagem (0-100)
porcentagem_nivel = map_value(raw_adc_value, 0, 4095, 0, 100);
printf("Nível: %d%%\n", porcentagem_nivel);
} else {
printf(" Falha ao ler ADC2\n");
}
// --- LÓGICA DE CONTROLE DO SEMÁFORO ---
if (porcentagem_nivel <= 5) {
gpio_set_level(Ligando_bomba,1);
printf("Liagando a bomba d'água...\n");
xSemaphoreTake(Ligando_a__bomba_ok_semaphore, (TickType_t) 0);
//ligar a bomba
} if(porcentagem_nivel = 95){
gpio_set_level(Ligando_bomba,0);
xSemaphoreGive(Ligando_a__bomba_ok_semaphore);
}
// A tarefa roda a cada 1 segundo --- colocar o tempo suficiente para acionar a bomba e encher uma quantidade
//necessária de agua
vTaskDelay(pdMS_TO_TICKS(5000));
}
}
//função para analisar o nível do reservatorio, se estiver abaixo de 5% não aciona a valv da caixa,
//pega o token do semafaro e só entrega depois de utrapassar os 5%
void Nivel_reservatorio(void *Nivel){
adc2_config_channel_atten(ADC_CHANNEL_POTENCIOMETRO, ADC_ATTEN_DB_11);
int raw_adc_value;
int porcentagem_nivel = 100;
while(1){
esp_err_t ret = adc2_get_raw(ADC_CHANNEL_POTENCIOMETRO, ADC_WIDTH_BIT_12, &raw_adc_value);
//teste para saber se deu certo o adc
if (ret == ESP_OK) {
// Mapeia o valor lido (0-4095) para uma porcentagem (0-100)
porcentagem_nivel = map_value(raw_adc_value, 0, 4095, 0, 100);
printf("Nível: %d%%\n", porcentagem_nivel);
} else {
printf(" Falha ao ler ADC2\n");
}
// --- LÓGICA DE CONTROLE DO SEMÁFORO ---
if (porcentagem_nivel <= 5) {
xSemaphoreTake(Nivel_da_agua_ok_semaphore, (TickType_t) 0);
printf("ATENÇÃO: Nível do reservatório baixo! Operação bloqueada, ligue a bomba do reservatório.\n");
//ligar a bomba
} else {
xSemaphoreGive(Nivel_da_agua_ok_semaphore);
}
// A tarefa roda a cada 1 segundo --- colocar o tempo suficiente para acionar a bomba e encher uma quantidade
//necessária de agua
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
// Tarefa para o acionamento da valvula da caixa d'agua, vai acontecer se alguma das linhas forem acionadas
// além disso, se o reservatório estiver acima de 5%, abaixo disso o nível do reservatorio pega o token do semáfaro
// e só entrega quando estiver acima de 5%
void Abertura_da_caixa_Dagua_Task(void *Linha_que_vai_ser_aberta){
//setando o pino da caixa como saida
gpio_reset_pin(Abertura_da_caixa_dagua);
gpio_set_direction(Abertura_da_caixa_dagua, GPIO_MODE_OUTPUT);
// Entradas com pull-down (para ler SINAL ALTO quando pressionado)
gpio_config_t Botaoacionado;
Botaoacionado.intr_type = GPIO_INTR_DISABLE; // Sem interrupções
Botaoacionado.mode = GPIO_MODE_INPUT;
Botaoacionado.pin_bit_mask = (1ULL<<Irrigacao_Linha1) | (1ULL<<Irrigacao_Linha2) | (1ULL<<Irrigacao_Linha3);
Botaoacionado.pull_down_en = 1; // Habilita PULL-DOWN
Botaoacionado.pull_up_en = 0;
gpio_config(&Botaoacionado);
printf("Inicializando a abertura da válvula da caixa d'água...\n");
//bool Abrindo = ((Linha_de_Irrigacao *)Linha_que_vai_ser_aberta)-> Preciso_Que_Abra_A_Caixa_Dagua;
while (1) {
if(gpio_get_level(Irrigacao_Linha1) == 1 || gpio_get_level(Irrigacao_Linha2) == 1 || gpio_get_level(Irrigacao_Linha3) == 1){
if(xSemaphoreTake(Nivel_da_agua_ok_semaphore, portMAX_DELAY) == pdTRUE){
gpio_set_level(Abertura_da_caixa_dagua,1);
printf("caixa d'água aberta...\n");
}
}
else{
gpio_set_level(Abertura_da_caixa_dagua,0);
printf("caixa d'água fechada...\n");
}
vTaskDelay(pdMS_TO_TICKS(1000));
}
vTaskDelete( NULL );
}
void app_main() {
Nivel_da_agua_ok_semaphore = xSemaphoreCreateBinary();
xTaskCreate(
&Ligando_a_Bomba, // task function
"Ligando a bomba", // task name
2048, // stack size in words
NULL,
//&Linha1, // pointer to parameters
5, // priority
NULL); // out pointer to task handle
xTaskCreate(
&Nivel_reservatorio, // task function
"nivel", // task name
2048, // stack size in words
NULL,
//&Linha1, // pointer to parameters
5, // priority
NULL); // out pointer to task handle
xTaskCreate(
&Abertura_da_caixa_Dagua_Task, // task function
"abertura", // task name
2048, // stack size in words
NULL,
//&Linha1, // pointer to parameters
5, // priority
NULL); // out pointer to task handle
}