#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Servo.h>
#include <Stepper.h>
// --- PINOS ---
#define PIN_TEMP_BUS 9
#define PIN_BUZZER 3
#define PIN_SERVO 10
// Joystick
#define PIN_JOY_X A1 // HORZ
#define PIN_JOY_Y A0 // VERT
// Botão amarelo
#define PIN_BUTTON 8 // IMPORTANTE: Ligar uma perna ao pino 8 e a outra ao GND
// --- OBJETOS ---
const int stepsPerRevolution = 2048;
Stepper fanMotor(stepsPerRevolution, 2, 5, 4, 6);
Servo windowServo;
OneWire oneWire(PIN_TEMP_BUS);
DallasTemperature sensors(&oneWire);
LiquidCrystal_I2C lcd(0x27, 16, 2);
// --- VARIÁVEIS DE TEMPO ---
unsigned long tempoAtual = 0;
unsigned long tempoAnteriorTemp = 0;
unsigned long tempoAnteriorBuzzer = 0;
unsigned long tempoAnteriorLCD = 0;
unsigned long tempoAnteriorJoy = 0; // Novo: para controlar a velocidade de mudança dos números
unsigned long ultimoDebounce = 0;
const long intervaloTemp = 500;
const long intervaloBuzzer = 300;
const long intervaloLCD = 200;
const long intervaloJoy = 150; // Novo: velocidade com que os números mudam
const long delayDebounce = 250;
// --- VARIÁVEIS DE SISTEMA ---
float temperaturaAtual = 0.0;
float limiteMaximo = 28.0;
float limiteMinimo = 5.0;
bool alarmeAtivo = false;
bool estadoBuzzer = false;
bool editandoMaximo = true; // true = editando Max, false = editando Min
void setup() {
Serial.begin(9600);
lcd.init();
lcd.backlight();
lcd.print("Sistema ON");
sensors.begin();
pinMode(PIN_BUZZER, OUTPUT);
// Joystick
pinMode(PIN_JOY_X, INPUT);
pinMode(PIN_JOY_Y, INPUT);
// Botão: INPUT_PULLUP significa que o estado normal é HIGH (1).
// Quando clica (liga ao GND), vai para LOW (0).
pinMode(PIN_BUTTON, INPUT_PULLUP);
windowServo.attach(PIN_SERVO);
windowServo.write(0);
fanMotor.setSpeed(15); // Velocidade do motor de passo
lcd.clear();
atualizarLCD(); // Primeira atualização
}
void loop() {
tempoAtual = millis();
// --- 1. LER ENTRADAS (Botão e Joystick) ---
lerBotaoAmarelo();
lerJoystick();
// --- 2. LER TEMPERATURA ---
if (tempoAtual - tempoAnteriorTemp >= intervaloTemp) {
tempoAnteriorTemp = tempoAtual;
sensors.requestTemperatures();
temperaturaAtual = sensors.getTempCByIndex(0);
verificarLimites();
}
// --- 3. ATUALIZAR LCD ---
// Atualiza periodicamente para mostrar a temperatura em tempo real
if (tempoAtual - tempoAnteriorLCD >= intervaloLCD) {
tempoAnteriorLCD = tempoAtual;
atualizarLCD();
}
// --- 4. CONTROLAR MOTORES ---
if (alarmeAtivo) {
gestaoAlarme();
if (temperaturaAtual >= limiteMaximo) {
// Motor de passo gira (aviso: step(1) pode ser lento na simulação)
fanMotor.step(1);
if (windowServo.read() != 0) windowServo.write(0);
}
else if (temperaturaAtual <= limiteMinimo) {
if (windowServo.read() != 90) windowServo.write(90);
}
} else {
noTone(PIN_BUZZER);
estadoBuzzer = false;
// Se estava aberta, fecha a janela (servo volta a 0)
if (windowServo.read() != 0) windowServo.write(0);
}
}
// --- FUNÇÕES AUXILIARES ---
void gestaoAlarme() {
if (tempoAtual - tempoAnteriorBuzzer >= intervaloBuzzer) {
tempoAnteriorBuzzer = tempoAtual;
estadoBuzzer = !estadoBuzzer;
if (estadoBuzzer) tone(PIN_BUZZER, 1000);
else noTone(PIN_BUZZER);
}
}
void verificarLimites() {
alarmeAtivo = (temperaturaAtual >= limiteMaximo) || (temperaturaAtual <= limiteMinimo);
}
void atualizarLCD() {
lcd.setCursor(0, 0);
lcd.print("T:");
lcd.print(temperaturaAtual, 1);
lcd.print("C ");
if (alarmeAtivo) {
if (temperaturaAtual >= limiteMaximo) lcd.print("! CALOR !");
else lcd.print("! FRIO ! ");
}
else lcd.print(" Seguro ");
lcd.setCursor(0, 1);
if (editandoMaximo) lcd.print(">Max: ");
else lcd.print(">Min: ");
if (editandoMaximo) lcd.print(limiteMaximo, 1);
else lcd.print(limiteMinimo, 1);
lcd.print("C ");
}
// --- BOTÃO (CORRIGIDO) ---
void lerBotaoAmarelo() {
// Como usamos INPUT_PULLUP, LOW significa pressionado
if (digitalRead(PIN_BUTTON) == LOW) {
if (tempoAtual - ultimoDebounce > delayDebounce) {
// Muda o modo de edição
editandoMaximo = !editandoMaximo;
// FIX CRÍTICO: Atualiza o LCD IMEDIATAMENTE para feedback visual
atualizarLCD();
ultimoDebounce = tempoAtual;
}
}
}
// --- JOYSTICK (MELHORADO) ---
void lerJoystick() {
// Só permite mudar os valores a cada X milissegundos para não ser demasiado rápido
if (tempoAtual - tempoAnteriorJoy >= intervaloJoy) {
int x = analogRead(PIN_JOY_X);
const int deadzone = 200; // Zona morta para o joystick não tremer
bool mudou = false;
if (editandoMaximo) {
if (x > 600 + deadzone) { limiteMaximo += 0.5; mudou = true; } // Aumenta
if (x < 400 - deadzone) { limiteMaximo -= 0.5; mudou = true; } // Diminui
}
else {
if (x > 600 + deadzone) { limiteMinimo += 0.5; mudou = true; }
if (x < 400 - deadzone) { limiteMinimo -= 0.5; mudou = true; }
}
if (mudou) {
tempoAnteriorJoy = tempoAtual;
atualizarLCD(); // Atualiza logo o número no ecrã
}
}
}