#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// ===CONFIGURAÇÕES GERAIS===
// - Conexões dos pinos
// Tela OLED
#define SDA_PIN 21
#define SCL_PIN 22
// Sensor Ultrassonico
#define TRIGGER 26
#define ECHO 25
// Bomba de água
#define RELE_BOMBA 0
// Leds indicadores
#define LED_VERMELHO 33
#define LED_LARANJA 32
#define LED_AMARELO 12
#define LED_VERDE 14
// Potenciometro
#define POT_UMIDADE 2
// === Prototipos Leds ===
// Protótipo da função para configurar os pinos dos LEDs indicadores
void ativarLedsIndicadores();
/*
Protótipos das funções para controlar os LEDs indicadores de acordo com o CM
do sensor ultrassônico:
*/
void atualizarLedVerde();
void atualizarLedAmarelo();
void atualizarLedVermelho();
void atualizarLedLaranja();
// === Prototipos Rele ===
// Protótipo da função iniciar o relé da bomba
void iniciarReleBomba();
// Protótipo da função para ligar a bomba de água
void ligarBomba(bool estado);
// === Prototipo Sensor ===
// Prototipo Função para ativar o sensor ultrassônico
void ativarSensorUltrassonico();
// Protótipo Função para medir a distância usando o sensor ultrassônico
long medirDistancia();
// === Prototipo Potenciometro (simulando sensor de Umidade) ===
// Medir a umidade pelo potenciômetro
float medirUmidade();
// === Prototipo Tela LCD ===
// Classe para gerenciar o display OLED
class TelaOLED {
public:
TelaOLED();
void inicializar();
void exibirMensagem(const char* mensagem);
void exibirValor(const char* label, long valor);
void limparTela();
private:
Adafruit_SSD1306 display;
};
TelaOLED tela;
bool statusRele = 0;
void setup() {
Serial.begin(115200);
// Funcoes para ativar o sensor ultrassônico, os LEDs indicadores,
// o relé da bomba e a tela OLED
ativarSensorUltrassonico();
ativarLedsIndicadores();
iniciarReleBomba();
// Inicialização da tela OLED
tela.inicializar();
}
void loop() {
// Leitura da umidade do potenciômetro
float umidade = medirUmidade();
// Leitura da distância do sensor ultrassônico
long distancia = medirDistancia();
if (distancia >= 200){
atualizarLedVermelho(); // Acende o LED vermelho
while (distancia >= 30) {
distancia = medirDistancia(); // Atualiza a leitura da distância
tela.exibirValor("Distancia", distancia); // Exibe a distância atualizada na tela OLED
delay(1000); // Pequena pausa para evitar leituras muito rápidas
}
} else if (distancia < 200 && distancia > 100){
atualizarLedLaranja(); // Acende o LED laranja
// Exibe mensagem de alerta na tela OLED
tela.exibirMensagem("Recipiente com pouca agua!");
delay(1000); // Pequena pausa para evitar leituras muito rápidas
} else if (distancia <= 100 && distancia > 30){
atualizarLedAmarelo(); // Acende o LED amarelo
// Exibe mensagem de alerta na tela OLED
tela.exibirMensagem("Recipiente com agua suficiente!");
delay(1000); // Pequena pausa para evitar leituras muito rápidas
}else if (distancia <= 30){
atualizarLedVerde(); // Acende o LED verde
// Exibe mensagem de alerta na tela OLED
tela.exibirMensagem("Recipiente cheio!");
delay(1000); // Pequena pausa para evitar leituras muito rápidas
}
// Exibe umidade e distância na tela OLED
tela.exibirDoisValores("Umidade", umidade, "Distancia", distancia);
delay(1500); // Pequena pausa para evitar leituras muito rápidas
if (umidade <= 20.0 && distancia < 170) {
// Se a umidade estiver abaixo do limite e o recipiente tiver água suficiente, liga a bomba
statusRele = 1; // Liga a bomba
} else {
if (umidade > 20.0) {
// Se a umidade estiver acima do limite, nao liga a bomba
tela.exibirMensagem("Umidade alta, bomba nao liga!");
} else if (distancia >= 170) {
// se o recipiente estiver quase vazio, nao liga a bomba
tela.exibirMensagem("Recipiente abaixo do nivel minimo, bomba nao liga!");
}
statusRele = 0; // Desliga a bomba
delay(1500); // Pequena pausa para evitar leituras muito rápidas
}
// Saida Centralizada para controle da bomba de água
ligarBomba(statusRele); // Liga ou desliga a bomba com base no status do relé
if (statusRele) {
while (umidade < 85.0) {
umidade = medirUmidade(); // Atualiza a leitura da umidade
distancia = medirDistancia(); // Atualiza a leitura da distância
tela.exibirValor("Umidade", umidade); // Exibe a umidade atualizada na tela OLED
delay(1000); // Pequena pausa para evitar leituras muito rápidas
if (distancia >= 200) {
// se o recipiente estiver quase vazio, desliga a bomba
tela.exibirMensagem("Recipiente abaixo do nivel minimo, adicione agua!");
ligarBomba(0); // Desliga a bomba
break; // Sai do loop para evitar que a bomba continue ligada
}
}
}
// Impressão da distância medida no monitor serial para depuração
Serial.print("Distancia: ");
Serial.print(distancia);
Serial.println(" cm");
// Impressão do status da bomba no monitor serial para depuração
Serial.print("Status da Bomba: ");
Serial.println(statusRele ? "Ligada" : "Desligada");
// Pequena pausa para evitar leituras muito rápidas
delay(1000);
}
// === Funções LEDs ===
// Função para configurar os pinos dos LEDs como saída
void ativarLedsIndicadores() {
pinMode(LED_VERMELHO, OUTPUT);
pinMode(LED_LARANJA, OUTPUT);
pinMode(LED_AMARELO, OUTPUT);
pinMode(LED_VERDE, OUTPUT);
}
/*
Função para atualizar os LEDs indicadores com base na distância medida
- LED_VERMELHO: Indica que o nível de água está crítico (distância muito alta).
- LED_LARANJA: Indica que o nível de água está baixo (distância alta).
- LED_AMARELO: Indica que o nível de água está moderado (distância média).
- LED_VERDE: Indica que o nível de água está adequado (distância baixa).
*/
void atualizarLedVermelho(){
digitalWrite(LED_VERDE, LOW);
digitalWrite(LED_AMARELO, LOW);
digitalWrite(LED_LARANJA, LOW);
digitalWrite(LED_VERMELHO, HIGH);
}
void atualizarLedLaranja(){
digitalWrite(LED_VERDE, LOW);
digitalWrite(LED_AMARELO, LOW);
digitalWrite(LED_LARANJA, HIGH);
digitalWrite(LED_VERMELHO, LOW);
}
void atualizarLedAmarelo(){
digitalWrite(LED_VERDE, LOW);
digitalWrite(LED_AMARELO, HIGH);
digitalWrite(LED_LARANJA, LOW);
digitalWrite(LED_VERMELHO, LOW);
}
void atualizarLedVerde(){
digitalWrite(LED_VERDE, HIGH);
digitalWrite(LED_AMARELO, LOW);
digitalWrite(LED_LARANJA, LOW);
digitalWrite(LED_VERMELHO, LOW);
}
// === Funções Rele ===
// Função para ativar o relé da bomba
void iniciarReleBomba(){
pinMode(RELE_BOMBA, OUTPUT); // Configura o pino do relé como saída
}
// Função para ligar a bomba
void ligarBomba(bool estado){
digitalWrite(RELE_BOMBA, estado); // Ativa o relé (liga ou desliga a bomba)
}
// === Funções Sensor Ultrassônico ===
// Função para ativar o sensor ultrassônico
void ativarSensorUltrassonico(){
// Configura os pinos do sensor ultrassônico
pinMode(TRIGGER, OUTPUT);
pinMode(ECHO, INPUT);
}
// === Potencieometro (simulando sensor de umidade) ===
// Função para medir a umidade usando o potenciômetro
float medirUmidade() {
// Lê o valor analógico do potenciômetro
int valorAnalogico = analogRead(POT_UMIDADE);
// Converte o valor analógico para um valor de umidade (0 a 100%)
float umidade = (valorAnalogico / 4095.0) * 100.0;
return umidade;
}
// Função para medir a distância usando o sensor ultrassônico
long medirDistancia(){
// Envia um pulso de 10 microsegundos para o pino de trigger
digitalWrite(TRIGGER, LOW);
delayMicroseconds(2);
digitalWrite(TRIGGER, HIGH);
delayMicroseconds(10);
digitalWrite(TRIGGER, LOW);
// Lê o tempo do pulso de retorno no pino de echo
long duration = pulseIn(ECHO, HIGH);
// Calcula a distância em centímetros (velocidade do som é aproximadamente 343 m/s)
long distance = duration * 0.034 / 2;
return distance;
}
// === Definições Da Classe da Tela Oled ===
// Definições para o display OLED
#define SCREEN_WIDTH 128 // Largura do display OLED em pixels
#define SCREEN_HEIGHT 64 // Altura do display OLED em pixels
#define OLED_RESET -1 // Reset pin # (ou -1 se compartilhado com o microcontrolador)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Implementação da classe TelaOLED
// Construtor que inicializa o display OLED com as dimensões e pino de reset definidos
TelaOLED::TelaOLED() : display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET) {
}
// Método para inicializar o display OLED
void TelaOLED::inicializar() {
Wire.begin(SDA_PIN, SCL_PIN);// Inicializa a comunicação I2C com os pinos definidos
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Endereço I2C do display
Serial.println(F("Falha na alocação do SSD1306"));
for (;;); // Loop infinito se a alocação falhar
}
display.clearDisplay(); // Limpa o buffer do display
display.setTextSize(1); // Define o tamanho do texto
display.setTextColor(SSD1306_WHITE); // Define a cor do texto
display.setCursor(0, 0); // Define a posição do cursor
display.println(F("Sistema de monitoramento")); // Exibe mensagem de inicialização
display.display(); // Atualiza o display para mostrar a mensagem
}
// Método para exibir uma mensagem no display OLED
void TelaOLED::exibirMensagem(const char* mensagem) {
display.clearDisplay(); // Limpa o buffer do display
display.setCursor(0, 0); // Define a posição do cursor
display.println(mensagem); // Exibe a mensagem fornecida
display.display(); // Atualiza o display para mostrar a mensagem
}
// Método para exibir um valor numérico com um rótulo no display OLED
void TelaOLED::exibirValor(const char* label, long valor) {
display.clearDisplay(); // Limpa o buffer do display
display.setCursor(0, 0); // Define a posição do cursor
display.print(label); // Exibe o rótulo fornecido
display.print(": "); // Adiciona um separador entre o rótulo e o valor
display.println(valor); // Exibe o valor numérico fornecido
display.display(); // Atualiza o display para mostrar o rótulo e o valor
}
void TelaOLED::limparTela() {
display.clearDisplay(); // Limpa o buffer do display
display.display(); // Atualiza o display para mostrar a tela limpa
}