#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "DHT.h"
#define DHTPIN 2
#define DHTPIN2 7
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
DHT dht2(DHTPIN2, DHTTYPE);
// --- CONFIGURAÇÃO DO LCD I2C ---
LiquidCrystal_I2C lcd(0x27, 16, 2);
// --- PINOS ---
const int PINO_PWM_VENT = 3; // PWM do Ventilador (PID Temperatura)
const int PINO_PWM_RELE = 6; // PWM/Saída do Controle de Umidade (PID Umidade)
const int PINO_BOTATO_INC = 4; // Botão para aumentar Setpoint Temp
const int PINO_BOTATO_DEC = 5; // Botão para diminuir Setpoint Temp
// --- PARÂMETROS DO PID DE TEMPERATURA ---
float Kp_T = 25.0;
float Ki_T = 0.1;
float Kd_T = 1.0;
// --- PARÂMETROS DO PID DE UMIDADE ---
float Kp_H = 22.0;
float Ki_H = 0.05;
float Kd_H = 0.5;
// --- VARIÁVEIS DE CONTROLE ---
float tempDesejada = 35.0; // Setpoint Temperatura (°C)
float umiDesejada = 55.0; // Setpoint Umidade (%) - Alvo seguro p/ o Sumry Max
float erroAnterior_T = 0.0;
float integral_T = 0.0;
float erroAnterior_H = 0.0;
float integral_H = 0.0;
unsigned long tempoAnterior = 0;
// --- VARIÁVEIS DOS BOTÕES (DEBOUNCE) ---
unsigned long ultimoTempoBotao = 0;
const unsigned long delayDebounce = 200;
void setup() {
Serial.begin(9600);
pinMode(PINO_BOTATO_INC, INPUT_PULLUP);
pinMode(PINO_BOTATO_DEC, INPUT_PULLUP);
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Sumry 10.2kW PID");
lcd.setCursor(0, 1);
lcd.print("Iniciando...");
delay(2000);
lcd.clear();
pinMode(PINO_PWM_VENT, OUTPUT);
pinMode(PINO_PWM_RELE, OUTPUT);
tempoAnterior = millis();
dht.begin();
dht2.begin();
}
void loop() {
unsigned long tempoAtual = millis();
// --- LEITURA DOS BOTÕES DE AJUSTE DO SETPOINT ---
if (tempoAtual - ultimoTempoBotao > delayDebounce) {
if (digitalRead(PINO_BOTATO_INC) == LOW) {
tempDesejada += 0.5;
ultimoTempoBotao = tempoAtual;
atualizarDisplaySetpoint();
}
else if (digitalRead(PINO_BOTATO_DEC) == LOW) {
tempDesejada -= 0.5;
ultimoTempoBotao = tempoAtual;
atualizarDisplaySetpoint();
}
}
double dt = (double)(tempoAtual - tempoAnterior) / 1000.0;
// Executa o cálculo a cada 1 segundo (1000ms)
if (dt >= 1.0) {
float h1 = dht.readHumidity();
float t1 = dht.readTemperature();
float h2 = dht2.readHumidity();
float t2 = dht2.readTemperature();
// Validação da leitura do sensor 1
if (isnan(h1) || isnan(t1)) {
Serial.println(F("Falha no sensor DHT 1!"));
lcd.setCursor(0, 0); lcd.print("Erro Sensor 1 ");
return;
}
// Validação da leitura do sensor 2
if (isnan(h2) || isnan(t2)) {
Serial.println(F("Falha no sensor DHT 2!"));
lcd.setCursor(0, 1); lcd.print("Erro Sensor 2 ");
return;
}
// --- CÁLCULO DAS MÉDIAS ---
float tempMedia = (t1 + t2) / 2.0;
float umiMedia = (h1 + h2) / 2.0;
// ==========================================
// 1. PID DE TEMPERATURA (Controle Exaustor)
// ==========================================
float erro_T = tempMedia - tempDesejada;
float P_T = Kp_T * erro_T;
integral_T += erro_T * dt;
if (integral_T > 100.0) integral_T = 100.0;
if (integral_T < -100.0) integral_T = -100.0;
float I_T = Ki_T * integral_T;
float derivativa_T = (erro_T - erroAnterior_T) / dt;
float D_T = Kd_T * derivativa_T;
float saidaPID_T = P_T + I_T + D_T;
if (saidaPID_T > 255) saidaPID_T = 255;
if (saidaPID_T < 0) saidaPID_T = 0;
analogWrite(PINO_PWM_VENT, (int)saidaPID_T);
erroAnterior_T = erro_T;
// ==========================================
// 2. PID DE UMIDADE (Controle Desumidificador)
// ==========================================
// Erro positivo significa que a umidade real está ACIMA do desejado (precisa desumidificar)
float erro_H = umiMedia - umiDesejada;
float P_H = Kp_H * erro_H;
integral_H += erro_H * dt;
if (integral_H > 100.0) integral_H = 100.0;
if (integral_H < -100.0) integral_H = -100.0;
float I_H = Ki_H * integral_H;
float derivativa_H = (erro_H - erroAnterior_H) / dt;
float D_H = Kd_H * derivativa_H;
float saidaPID_H = P_H + I_H + D_H;
if (saidaPID_H > 255) saidaPID_H = 255;
if (saidaPID_H < 0) saidaPID_H = 0;
// Aplica o sinal calculado ao atuador de umidade
analogWrite(PINO_PWM_RELE, (int)saidaPID_H);
erroAnterior_H = erro_H;
// Finaliza o ciclo de tempo
tempoAnterior = tempoAtual;
// ==========================================
// 3. EXIBIÇÃO NO DISPLAY LCD I2C (Formatado para 16x2)
// ==========================================
// Linha 1: Temperatura Média Real e Setpoint desejado
lcd.setCursor(0, 0);
lcd.print("T:");
lcd.print(tempMedia, 1);
lcd.print("C SP:");
lcd.print(tempDesejada, 1);
lcd.print((char)223);
// Linha 2: Umidade Média Real e saída de controle em % (0-100%)
int pctPWM_H = map((int)saidaPID_H, 0, 255, 0, 100);
lcd.setCursor(0, 1);
lcd.print("U:");
lcd.print((int)umiMedia);
lcd.print("%D:");
lcd.print(pctPWM_H);
lcd.print("%C:");
lcd.print((int)saidaPID_T);
lcd.print(" "); // Espaços para limpar resíduos de dígitos anteriores
// ==========================================
// 4. MONITOR SERIAL (Diagnóstico Completo)
// ==========================================
Serial.print("T1: "); Serial.print(t1, 1);
Serial.print("°C | T2: "); Serial.print(t2, 1);
Serial.print("°C | T_Média: "); Serial.print(tempMedia, 1);
Serial.print("°C | PWM_Vent: "); Serial.print((int)saidaPID_T);
Serial.print(" || H1: "); Serial.print(h1, 0);
Serial.print("% | H2: "); Serial.print(h2, 0);
Serial.print("% | H_Média: "); Serial.print(umiMedia, 0);
Serial.print("% | PWM_Umi: "); Serial.println((int)saidaPID_H);
}
}
void atualizarDisplaySetpoint() {
lcd.setCursor(10, 0);
lcd.print("SP:");
lcd.print(tempDesejada, 1);
lcd.print((char)223);
}