/*
Autores: Alba Sánchez Ibáñez, Lucas Colbert Eastgate
Refatorado e corrigido por Gemini
Este código foi refeito para usar a biblioteca PID_v1.h do Arduino.
A lógica de controle agora é delegada para a biblioteca, tornando o
código mais robusto e fácil de entender.
*/
#include <math.h>
#include <PID_v1.h>
#include "DHT.h"
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
// PINOS
const byte LEDROJO = 3;
const byte LEDVERDE = 5;
const byte THERMISTOR_PIN = 0;
const byte TRANSISTOR_PIN = 6; // PWM Pin para controle de potência
const byte DHT_PIN = 7;
const byte HUMIDITY_RELAY_PIN = 9;
const byte LCD_SDA_PIN = A4;
const byte LCD_SCL_PIN = A5;
// PERIODOS em milissegundos
const unsigned long PERIODO_TMP_MS = 1000;
const unsigned long PERIODO_MONITOR_MS = 1000;
const unsigned long PERIODO_DHT_MS = 2000; // DHT requires a 2-second delay between reads
const unsigned long PERIODO_DAY_MS = 8640; // 24 horas em milissegundos (24 * 60 * 60 * 1000)
// VALORES DO TERMISTOR (NTC 10kOhm)
const float THERMISTOR_T0 = 25.0; // Temperatura de referência
const float THERMISTOR_R0 = 10000.0; // Resistência na temperatura de referência
const float THERMISTOR_B = 3950.0; // Constante Beta
const int RESISTOR_DIVISOR = 10000; // Resistor em série com o termistor
// VALORES DE TEMPERATURA
double TMP_REF = 38.0; // Setpoint para a incubadora
const double TMP_MIN = 37.0;
const double TMP_MAX = 39.0;
// VALORES DE UMIDADE
double HUM_REF = 60.0; // Setpoint para a umidade
const double HUM_MIN = 58.0;
const double HUM_MAX = 62.0;
// VALORES DO CONTROLADOR PID
const float KP = 0.4044;
const float KI = 0.0100;
const float KD = 3.3718;
// VARIÁVEIS DE CONTROLE DO PID
double pid_input;
double pid_output;
// Cria a instância do objeto PID
PID myPID(&pid_input, &pid_output, &TMP_REF, KP, KI, KD, DIRECT);
// ESTRUTURAS DE ESTADO
struct Tmp {
unsigned long last_ms;
float val;
};
struct Monitor {
unsigned long last_ms;
};
struct Humidificador {
unsigned long last_ms;
float val;
};
struct Incubadora {
unsigned long last_ms;
byte dia=0;
};
// Instâncias
Tmp tmp;
Monitor mtr;
Humidificador hum;
Incubadora inc;
// Objetos para os componentes
DHT dht(DHT_PIN, DHT22);
LiquidCrystal_I2C lcd(0x27, 16, 2); // Ajuste o endereço se necessário (0x3F ou 0x27)
// --- FUNÇÕES DE CÁLCULO ---
float val2tmp(int analog_value) {
float resistance = RESISTOR_DIVISOR / ((1023.0 / analog_value) - 1.0);
float celsius = 1.0 / (log(resistance / THERMISTOR_R0) / THERMISTOR_B + 1.0 / (THERMISTOR_T0 + 273.15)) - 273.15;
return celsius;
}
float val2hum() {
float h = dht.readHumidity();
if (isnan(h)) {
return -1.0; // Retorna um valor inválido em caso de erro de leitura
}
return h;
}
// --- SETUP DAS TAREFAS ---
void setup_tmp(unsigned long curr_ms, struct Tmp& tmp) {
pinMode(LEDVERDE, OUTPUT);
tmp.last_ms = curr_ms - PERIODO_TMP_MS;
tmp.val = 0;
}
void setup_monitor(unsigned long curr_ms, struct Monitor& mtr) {
Serial.begin(9600);
while (!Serial);
Serial.println(" # > Arduino Control de Temperatura e Umidade PID");
Serial.println(" # $ - y20 :45 - w4 - l37.0 - l38.0 - l39.0 - tTemperatura - tCalefactor - tUmidade - tUmidificador");
mtr.last_ms = curr_ms - PERIODO_MONITOR_MS;
}
void setup_pid() {
myPID.SetMode(AUTOMATIC);
myPID.SetOutputLimits(0, 256);
myPID.SetSampleTime(1000);
}
void setup_dht(unsigned long curr_ms, struct Humidificador& hum) {
pinMode(HUMIDITY_RELAY_PIN, OUTPUT);
dht.begin();
hum.last_ms = curr_ms - PERIODO_DHT_MS;
hum.val = 0;
}
void setup_lcd(unsigned long curr_ms, struct Incubadora& inc) {
lcd.init();
lcd.backlight();
inc.last_ms = curr_ms - PERIODO_DAY_MS;
inc.dia;
}
// --- TAREFAS DE LOOP ---
void tarea_tmp(unsigned long curr_ms, struct Tmp& tmp) {
if (curr_ms - tmp.last_ms >= PERIODO_TMP_MS) {
tmp.last_ms += PERIODO_TMP_MS;
int val = analogRead(THERMISTOR_PIN);
tmp.val = val2tmp(val);
byte est_tmp = (TMP_MIN <= tmp.val && tmp.val <= TMP_MAX) ? HIGH : LOW;
digitalWrite(LEDVERDE, est_tmp);
}
}
void tarea_dht(unsigned long curr_ms, struct Humidificador& hum) {
if (curr_ms - hum.last_ms >= PERIODO_DHT_MS) {
hum.last_ms += PERIODO_DHT_MS;
hum.val = val2hum();
// Lógica simples de controle ON/OFF para umidade
if (hum.val != -1.0) { // Verifica se a leitura é válida
if (hum.val < HUM_REF) {
digitalWrite(HUMIDITY_RELAY_PIN, HIGH); // Ativa o umidificador
} else {
digitalWrite(HUMIDITY_RELAY_PIN, LOW); // Desativa o umidificador
}
}
}
}
void tarea_monitor(unsigned long curr_ms, struct Monitor& mtr, const struct Tmp& tmp, const double& rele_estado, const struct Humidificador& hum_data) {
if (curr_ms - mtr.last_ms >= PERIODO_MONITOR_MS) {
mtr.last_ms += PERIODO_MONITOR_MS;
if (Serial) {
Serial.print(tmp.val);
Serial.print(" ");
Serial.print(rele_estado);
Serial.print(" ");
Serial.print(hum_data.val);
Serial.print(" ");
Serial.print(digitalRead(HUMIDITY_RELAY_PIN));
Serial.print(" ");
Serial.println(analogRead(TRANSISTOR_PIN));
}
}
}
void tarea_lcd(unsigned long curr_ms, struct Tmp& tmp, struct Humidificador& hum, struct Incubadora& inc) {
if (curr_ms - inc.last_ms >= PERIODO_DAY_MS && inc.dia <= 21) {
inc.last_ms += PERIODO_DAY_MS;
inc.dia++;
}
lcd.setCursor(0, 0);
lcd.print("Dia: ");
if (inc.dia < 10) lcd.print("0");
lcd.print(inc.dia);
lcd.print(" de 21");
lcd.setCursor(0, 1);
lcd.print("T:");
lcd.print(tmp.val, 1);
lcd.print("C H:");
lcd.print(hum.val, 1);
lcd.print("%");
}
// --- MAIN ---
void setup() {
unsigned long curr_ms = millis();
pinMode(TRANSISTOR_PIN, OUTPUT);
pinMode(LEDROJO, OUTPUT);
setup_tmp(curr_ms, tmp);
setup_monitor(curr_ms, mtr);
setup_pid();
setup_dht(curr_ms, hum);
setup_lcd(curr_ms, inc);
}
void loop() {
unsigned long curr_ms = millis();
// Tarefas de leitura e controle
tarea_tmp(curr_ms, tmp);
tarea_dht(curr_ms, hum);
// Atualiza a entrada do PID e computa o novo valor de saída
pid_input = tmp.val;
myPID.Compute();
// Aplica a saída do PID para o aquecedor e o LED vermelho (PWM)
analogWrite(TRANSISTOR_PIN, pid_output);
analogWrite(LEDROJO, pid_output);
// Tarefa de monitoramento serial e LCD
tarea_monitor(curr_ms, mtr, tmp, pid_output, hum);
tarea_lcd(curr_ms, tmp, hum, inc);
}