#include <Arduino.h>
#include "Button.h"
#include "ACI_10K_an.h"
#include <Wire.h>
#include "LiquidCrystal_I2C.h"
// --- ATRIBUIÇÃO DE PINOS COM NOMES CLAROS ---
const int PIN_BOMBA = 10;
const int PIN_OSCILADOR = 11;
const int PIN_IONIZADOR = 12;
const int PIN_NIVEL_LED = 13;
const int PIN_BUZZER = 3;
const int PIN_SENSOR_TEMP= A1;
const int PIN_SENSOR_NIVEL= 2;
// Instâncias dos Botões
Button button2(7); // AMARELO - altera velocidade
Button button5(8); // Botão extra (pino 8)
Button button1(A2); // AZUL - bombeamento
Button button3(A3); // VERMELHO - ionizador
Button button4(A4); // VERDE - oscilador
// Controle dos LEDs de Velocidade
const int leds[] = {9, 6, 5, 4};
// Variáveis de Controle de Estado
int alterVeloc = 1;
int nivelTanque = HIGH;
int value;
float temperaturaAtual = 25.0; // Armazena a última leitura válida
unsigned long tempoAnteriorTemp = 0;
const int intervaloLeitura = 100; // Leitura do sensor a cada 100ms
// Variáveis para o Fade sem delay (Modos 4, 5 e 6)
unsigned long tempoAnteriorFade = 0;
int brilhoAtual = 0;
int direcaoFade = 1; // 1 = Aumentando, -1 = Diminuindo, 0 = Pausado
int brilhoMaximoDinamico = 255;
int velocidadeFade = 5;
unsigned long tempoPausaFade = 0;
int estadoFade = 0; // 0=FadeIn, 1=PausaAlta, 2=FadeOut, 3=PausaBaixa
// Configuração do LCD I2C
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Instanciação única do sensor para evitar recriação na memória
Aci_10K an10k(3.3, 14);
// Protótipos das funções
void gerenciarLeituraSensor();
void velocidade();
void autatemperatura();
void bombeamento();
void oscilador();
void ionizador();
float lerTemperatura();
void atualizarDisplay();
void setup() {
Serial.begin(9600);
// Configuração manual e assertiva dos pinos necessários
pinMode(PIN_SENSOR_NIVEL, INPUT_PULLUP);
pinMode(PIN_BOMBA, OUTPUT);
pinMode(PIN_OSCILADOR, OUTPUT);
pinMode(PIN_IONIZADOR, OUTPUT);
pinMode(PIN_NIVEL_LED, OUTPUT);
pinMode(PIN_BUZZER, OUTPUT);
for (int i = 0; i < 4; i++) {
pinMode(leds[i], OUTPUT);
}
button1.begin();
button2.begin();
button3.begin();
button4.begin();
button5.begin();
randomSeed(analogRead(A0));
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Iniciando...");
lcd.setCursor(0, 1);
lcd.print("Aguarde...");
delay(2000);
lcd.clear();
}
void loop() {
gerenciarLeituraSensor(); // Atualiza a variável 'temperaturaAtual' sem travar
velocidade();
autatemperatura();
bombeamento();
oscilador();
ionizador();
atualizarDisplay();
}
// Centraliza a leitura do sensor por tempo
void gerenciarLeituraSensor() {
if (millis() - tempoAnteriorTemp >= intervaloLeitura) {
tempoAnteriorTemp = millis();
temperaturaAtual = lerTemperatura();
Serial.print("Temperatura: ");
Serial.print(temperaturaAtual);
Serial.println(" C");
}
}
float lerTemperatura() {
// Retorna a leitura baseada no pino analógico correto
return an10k.getTemp(analogRead(PIN_SENSOR_TEMP));
}
void autatemperatura() {
// Alarme visual e sonoro se a temperatura passar de 40°C
static unsigned long ultimoPiscaBuzzer = 0;
static bool estadoAlarme = false;
if (temperaturaAtual >= 40) {
alterVeloc = 3;
// Pisca o LED e o Buzzer a cada 100ms sem usar delay()
if (millis() - ultimoPiscaBuzzer >= 100) {
ultimoPiscaBuzzer = millis();
estadoAlarme = !estadoAlarme;
if (estadoAlarme) {
analogWrite(leds[3], 255);
tone(PIN_BUZZER, 262);
} else {
analogWrite(leds[3], 0);
noTone(PIN_BUZZER);
}
}
} else {
analogWrite(leds[3], 0);
noTone(PIN_BUZZER);
}
}
void velocidade() {
unsigned long currentTime = millis();
// Mapeamento do brilho conforme a temperatura
int brightnessBound = map(temperaturaAtual, 18, 30, 100, 256);
brightnessBound = constrain(brightnessBound, 100, 255); // Garante limites do PWM
// Verificação do Botão de Modos
if (button2.pressed()) {
tone(PIN_BUZZER, 262, 250);
alterVeloc++;
if (alterVeloc > 6) {
alterVeloc = 1;
}
// Reseta estados do Fade ao trocar de modo
estadoFade = 0;
brilhoAtual = 0;
tempoAnteriorFade = currentTime;
brilhoMaximoDinamico = random(100, brightnessBound);
velocidadeFade = random(2, 7);
// Apaga os leds de controle para a nova transição
analogWrite(leds[0], 0);
analogWrite(leds[1], 0);
analogWrite(leds[2], 0);
}
// Seleção dos Modos de Operação
switch (alterVeloc) {
case 1:
analogWrite(leds[0], 255);
analogWrite(leds[1], 0);
analogWrite(leds[2], 0);
break;
case 2:
analogWrite(leds[0], 0);
analogWrite(leds[1], 255);
analogWrite(leds[2], 0);
break;
case 3:
analogWrite(leds[0], 0);
analogWrite(leds[1], 0);
analogWrite(leds[2], 255);
break;
// Modos 4, 5 e 6 executam a mesma lógica de Brisa, mudando apenas o LED alvo
case 4:
case 5:
case 6:
int ledAlvo = leds[alterVeloc - 4]; // Associa Modo 4->leds[0], Modo 5->leds[1]...
// Apaga os outros dois LEDs que não estão em uso neste modo
for(int i=0; i<3; i++) {
if(leds[i] != ledAlvo) analogWrite(leds[i], 0);
}
// Máquina de estados para gerenciar o efeito fade sem travar o processador
if (estadoFade == 0) { // FADE IN
if (currentTime - tempoAnteriorFade >= (unsigned long)velocidadeFade) {
tempoAnteriorFade = currentTime;
brilhoAtual++;
analogWrite(ledAlvo, brilhoAtual);
if (brilhoAtual >= brilhoMaximoDinamico) {
estadoFade = 1; // Próximo passo: Pausa Alta
tempoPausaFade = currentTime;
}
}
}
else if (estadoFade == 1) { // PAUSA EM BRILHO MÁXIMO (1.5s)
if (currentTime - tempoPausaFade >= 1500) {
estadoFade = 2; // Próximo passo: Fade Out
}
}
else if (estadoFade == 2) { // FADE OUT
if (currentTime - tempoAnteriorFade >= (unsigned long)velocidadeFade) {
tempoAnteriorFade = currentTime;
brilhoAtual--;
analogWrite(ledAlvo, brilhoAtual);
if (brilhoAtual <= 0) {
estadoFade = 3; // Próximo passo: Pausa Baixa
tempoPausaFade = currentTime;
tempoAnteriorFade = random(500); // Guarda o tempo aleatório de descanso aqui
}
}
}
else if (estadoFade == 3) { // PAUSA EM BRILHO MÍNIMO (Aleatória)
if (currentTime - tempoPausaFade >= tempoAnteriorFade) {
// Reinicializa parâmetros para o próximo ciclo de brisa
estadoFade = 0;
brilhoAtual = 0;
brilhoMaximoDinamico = random(100, brightnessBound);
velocidadeFade = random(2, 7);
}
}
break;
}
}
void bombeamento() {
// Alarme visual e sonoro se a agua faltar
static unsigned long ultimoPiscaBuzzer2 = 0;
static bool estadoAlarme2 = false;
if (button1.toggled() && button1.read() == Button::PRESSED) {
// Aciona a bomba respeitando a lógica de segurança do nível do tanque
digitalWrite(PIN_BOMBA, !digitalRead(PIN_SENSOR_NIVEL) && !digitalRead(PIN_BOMBA));
}
value = digitalRead(PIN_SENSOR_NIVEL);
if (nivelTanque != value) {
nivelTanque = value;
if (value == HIGH) {
digitalWrite(PIN_BOMBA, LOW); // Segurança: desliga bomba se faltar água
// Pisca o LED e o Buzzer a cada 100ms sem usar delay()
if (millis() - ultimoPiscaBuzzer2 >= 100) {
ultimoPiscaBuzzer2 = millis();
estadoAlarme2 = !estadoAlarme2;
if (estadoAlarme2) {
analogWrite(PIN_NIVEL_LED, 255);
tone(PIN_BUZZER, 262);
} else {
analogWrite(PIN_NIVEL_LED, 0);
noTone(PIN_BUZZER);
}
}
Serial.println(" released");
} else {
digitalWrite(PIN_NIVEL_LED, LOW);
Serial.println(" pressed");
}
}
}
void oscilador() {
if (button4.toggled() && button4.read() == Button::PRESSED) {
digitalWrite(PIN_OSCILADOR, !digitalRead(PIN_OSCILADOR));
}
}
void ionizador() {
if (button3.toggled() && button3.read() == Button::PRESSED) {
digitalWrite(PIN_IONIZADOR, !digitalRead(PIN_IONIZADOR));
}
}
void atualizarDisplay() {
static unsigned long ultimoUpdate = 0;
if (millis() - ultimoUpdate >= 1000) {
ultimoUpdate = millis();
// Linha 0
lcd.setCursor(0, 0);
lcd.print("Temp:");
lcd.print(temperaturaAtual, 1); // Mostra com 1 casa decimal
lcd.print("C "); // Espaços limpam resíduos numéricos
lcd.setCursor(12, 0);
lcd.print("Ag:");
lcd.print(!value);
// Linha 1
lcd.setCursor(0, 1);
lcd.print("Modo:");
lcd.print(alterVeloc);
lcd.setCursor(8, 1);
if (alterVeloc >= 4) {
lcd.print("Brisa ");
} else {
lcd.print("Vento ");
}
}
}