/*
* TCC - Sistema Automatizado de Controle e Monitoramento de Nível de Água
* Curso: Técnico em Eletromecânica
* Controlador: ESP32
*
* Funcionalidades:
* - Monitoramento por 2 Sensores Ultrassônicos (HC-SR04)
* - Validação por 3 Boias Elétricas (Redundância e Cavitação)
* - Acionamento de Bomba 1/2 CV via Relé Auxiliar e Contator
* - Display LCD 16x2 I2C
* - Proteção de Timeout (Enchimento máximo)
* - Alarmes e indicação via Monitor Serial e LCD
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_timer.h"
#include "esp_rom_sys.h"
#include "driver/i2c.h"
#include "esp_log.h"
// ================= I2C =================
#define I2C_MASTER_SCL_IO 22
#define I2C_MASTER_SDA_IO 21
#define I2C_MASTER_NUM I2C_NUM_0
#define I2C_MASTER_FREQ_HZ 100000
// ================= LCD =================
#define LCD_ADDR 0x27
// ================= ULTRASSÔNICOS =================
#define TRIG_CAIXA 5
#define ECHO_CAIXA 18
#define TRIG_CISTERNA 19
#define ECHO_CISTERNA 21
// ================= BOIAS =================
#define BOIA_CAIXA_ALTA 25
#define BOIA_CISTERNA_BAIXA 26
// ================= SAÍDAS =================
#define RELE_BOMBA 33
#define LED_ALARME 32
#define BUZZER 14
// ================= LEDs NÍVEL =================
// Caixa
#define LED_CX_BAIXO 18
#define LED_CX_MEDIO 19
#define LED_CX_ALTO 23
// Cisterna
#define LED_CI_BAIXO 22
#define LED_CI_ALTO 4
// ================= PARÂMETROS =================
#define DIST_VAZIO 38.0
#define DIST_CHEIO 5.0
#define NIVEL_LIGA 40
#define NIVEL_DESLIGA 95
#define NIVEL_MIN_CISTERNA 20
// ================= VARIÁVEIS =================
int nivelCaixa = 0;
int nivelCisterna = 0;
bool bombaLigada = false;
// ================= I2C =================
void i2c_master_init() {
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = I2C_MASTER_SDA_IO,
.scl_io_num = I2C_MASTER_SCL_IO,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = I2C_MASTER_FREQ_HZ
};
i2c_param_config(I2C_MASTER_NUM, &conf);
i2c_driver_install(I2C_MASTER_NUM, conf.mode, 0, 0, 0);
}
// ================= DISTÂNCIA =================
float medirDistancia(int trig, int echo) {
gpio_set_level(trig, 0);
esp_rom_delay_us(2);
gpio_set_level(trig, 1);
esp_rom_delay_us(10);
gpio_set_level(trig, 0);
int64_t start = esp_timer_get_time();
while (!gpio_get_level(echo)) {
if (esp_timer_get_time() - start > 30000) return DIST_VAZIO;
}
int64_t echo_start = esp_timer_get_time();
while (gpio_get_level(echo)) {
if (esp_timer_get_time() - echo_start > 30000) return DIST_VAZIO;
}
int64_t duration = esp_timer_get_time() - echo_start;
float dist = (duration * 0.0343) / 2.0;
if (dist > DIST_VAZIO) dist = DIST_VAZIO;
if (dist < DIST_CHEIO) dist = DIST_CHEIO;
return dist;
}
// ================= % =================
int calcularNivel(float dist) {
int pct = (int)((DIST_VAZIO - dist) * 100 / (DIST_VAZIO - DIST_CHEIO));
if (pct < 0) pct = 0;
if (pct > 100) pct = 100;
return pct;
}
// ================= LEDs =================
void atualizarLEDs() {
// Caixa
gpio_set_level(LED_CX_BAIXO, nivelCaixa <= 30);
gpio_set_level(LED_CX_MEDIO, (nivelCaixa > 30 && nivelCaixa <= 70));
gpio_set_level(LED_CX_ALTO, nivelCaixa > 70);
// Cisterna
gpio_set_level(LED_CI_BAIXO, nivelCisterna < 30);
gpio_set_level(LED_CI_ALTO, nivelCisterna >= 30);
}
// ================= CONTROLE =================
void controleBomba() {
bool caixaCheia = (gpio_get_level(BOIA_CAIXA_ALTA) == 0);
bool cisternaVazia = (gpio_get_level(BOIA_CISTERNA_BAIXA) == 1);
if (bombaLigada) {
if (nivelCaixa >= NIVEL_DESLIGA || caixaCheia) {
gpio_set_level(RELE_BOMBA, 0);
bombaLigada = false;
}
else if (nivelCisterna < NIVEL_MIN_CISTERNA || cisternaVazia) {
gpio_set_level(RELE_BOMBA, 0);
bombaLigada = false;
}
} else {
if (nivelCaixa <= NIVEL_LIGA &&
nivelCisterna >= NIVEL_MIN_CISTERNA &&
!cisternaVazia) {
gpio_set_level(RELE_BOMBA, 1);
bombaLigada = true;
}
}
}
// ================= APP =================
void app_main(void) {
// I2C
i2c_master_init();
// GPIOs
gpio_set_direction(TRIG_CAIXA, GPIO_MODE_OUTPUT);
gpio_set_direction(ECHO_CAIXA, GPIO_MODE_INPUT);
gpio_set_direction(TRIG_CISTERNA, GPIO_MODE_OUTPUT);
gpio_set_direction(ECHO_CISTERNA, GPIO_MODE_INPUT);
gpio_set_direction(RELE_BOMBA, GPIO_MODE_OUTPUT);
gpio_set_direction(LED_ALARME, GPIO_MODE_OUTPUT);
gpio_set_direction(BOIA_CAIXA_ALTA, GPIO_MODE_INPUT);
gpio_set_direction(BOIA_CISTERNA_BAIXA, GPIO_MODE_INPUT);
// LEDs
gpio_set_direction(LED_CX_BAIXO, GPIO_MODE_OUTPUT);
gpio_set_direction(LED_CX_MEDIO, GPIO_MODE_OUTPUT);
gpio_set_direction(LED_CX_ALTO, GPIO_MODE_OUTPUT);
gpio_set_direction(LED_CI_BAIXO, GPIO_MODE_OUTPUT);
gpio_set_direction(LED_CI_ALTO, GPIO_MODE_OUTPUT);
while (1) {
float d1 = medirDistancia(TRIG_CAIXA, ECHO_CAIXA);
float d2 = medirDistancia(TRIG_CISTERNA, ECHO_CISTERNA);
nivelCaixa = calcularNivel(d1);
nivelCisterna = calcularNivel(d2);
controleBomba();
atualizarLEDs();
printf("Cx:%d%% Ci:%d%% | Bomba:%s\n",
nivelCaixa,
nivelCisterna,
bombaLigada ? "ON" : "OFF");
vTaskDelay(pdMS_TO_TICKS(1000));
}
}