/*Código Arduino para Circulador de Ar (Atualizado)
16/07, 10:06
*/
// Inclusões de bibliotecas necessárias
#include <LiquidCrystal.h> // Para o display LCD
#include <Servo.h> // Para controlar o servo motor de oscilação
#include <Button.h> // Para botões físicos (melhor debounce)
// ============================================================================
// Definições de Pinos
// ============================================================================
// Pinos do LCD (RS, Enable, D4, D5, D6, D7)
const int LCD_RS = 12;
const int LCD_EN = 8;
const int LCD_D4 = 7;
const int LCD_D5 = 5;
const int LCD_D6 = 4;
const int LCD_D7 = 3;
LiquidCrystal lcd(LCD_RS, LCD_EN, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
//Pino para o controle do nível do tanque
const int TAQ_PWM_PIN = 2; // Pino 2 deve ser setado com um pino PULLUP
// Pino para o controle PWM do bombeamento (PWM pins: 3, 5, 6, 9, 10, 11 no Uno)
const int FAN_PWM_PIN = 6; // Pino 6 é um pino PWM
// Pino para o servo motor de oscilação
const int SERVO_PIN = 9; // Pino 9 é um pino PWM e bom para servos
Servo oscillationServo;
//Pino para o controle PWM do ventilador (PWM pins: 3, 5, 6, 9, 10, 11 no Uno)
const int PUP_PWM_PIN = 10; // Pino 10 é um pino PWM
// Pinos para os botões físicos
const int RANDOM_SEED_PIN = A0; // Pino analógico para semear o gerador de números aleatórios (deixar desconectado)
const int BUTTON_OSCILLATION_PIN = A1; // Botão para ligar/desligar a oscilação
const int POTENTIOMETER_PIN = A2; // Potenciômetro para ajuste fino da velocidade
const int BUTTON_FAN_MODE_PIN = A3; // Botão para mudar o modo do ventilador
const int BOMBEMAMENTO_PIN = A4;
// ============================================================================
// Instâncias de Botões Físicos
// ============================================================================
// Usamos INPUT_PULLUP para que os botões sejam conectados entre o pino e o GND
Button fanModeButton(BUTTON_FAN_MODE_PIN);
Button oscillationButton(BUTTON_OSCILLATION_PIN);
Button bombeamentoButton(BOMBEMAMENTO_PIN);
// ============================================================================
// Variáveis Globais de Estado
// ============================================================================
// Modos de velocidade do ventilador
enum FanMode {
FAN_OFF = 0,
FAN_LOW,
FAN_MEDIUM,
FAN_HIGH,
FAN_AUTO, // Controlado pelo potenciômetro
FAN_TEMP // Controle de vento aleatório ("Tempestade")
};
FanMode currentFanMode = FAN_OFF; // Estado inicial: ventilador desligado
int fanSpeedPWM = 0; // Valor PWM para o ventilador (0-255)
int nivelTanque = HIGH; // valor para o nivel inicial do tanque.
// Variáveis para o modo FAN_TEMP (Tempestade)
unsigned long lastRandomChangeTime = 0;
const unsigned long RANDOM_CHANGE_INTERVAL_MIN = 200; // Intervalo mínimo para mudança aleatória (ms)
const unsigned long RANDOM_CHANGE_INTERVAL_MAX = 1000; // Intervalo máximo para mudança aleatória (ms)
// Estado da oscilação
bool isOscillating = false;
// Variáveis para o controle do servo de oscilação
const int OSC_MIN_ANGLE = 30; // Ângulo mínimo de oscilação (ajuste conforme seu servo)
const int OSC_MAX_ANGLE = 150; // Ângulo máximo de oscilação (ajuste conforme seu servo)
int currentOscillationAngle = OSC_MIN_ANGLE; // Ângulo atual do servo
int oscillationDirection = 1; // 1 para aumentar ângulo, -1 para diminuir
unsigned long lastOscillationMoveTime = 0;
const unsigned long OSCILLATION_MOVE_INTERVAL = 50; // Intervalo para mover o servo (ms)
const int OSCILLATION_STEP = 1; // Quantos graus o servo se move por etapa
// ============================================================================
// Protótipos de Funções
// ============================================================================
void handleFanControl(); // Gerencia a velocidade do ventilador
void handleOscillationControl(); // Gerencia o movimento de oscilação
void handleButtonInputs(); // Lida com a leitura dos botões físicos
void updateLCD(); // Atualiza o display LCD
byte customChar[8] = // Matriz do caracter especial
{
0b00000,
0b11011,
0b11011,
0b00100,
0b00100,
0b10001,
0b01110,
0b00000
};
byte oscilaChar[7] = // Matriz do caracter especial
{
0b00100,
0b10001,
0b01010,
0b00100,
0b01010,
0b10001,
0b00100
};
// ============================================================================
// Função Setup
// Inicializa comunicação serial, LCD, pinos e periféricos.
// ============================================================================
void setup() {
Serial.begin(9600); // Inicia a comunicação serial para depuração
Serial.println("Circulador de Ar Arduino Iniciado!");
// Semeia o gerador de números aleatórios com ruído do pino analógico A3
// Isso deve ser feito apenas uma vez no setup para melhor aleatoriedade.
randomSeed(analogRead(RANDOM_SEED_PIN));
lcd.createChar(1, customChar); // criando o caracter especial 1
lcd.createChar(2, oscilaChar); // criando o caracter especial 2
lcd.begin(16, 2); // Inicializa o display LCD (16 colunas, 2 linhas)
lcd.print("Circulador ON!"); // Mensagem inicial no LCD
lcd.setCursor(15,0);
lcd.write((byte)1); // imprimindo o carcter especial 1
delay(2000);
lcd.clear();
// Configura os pinos como saída
pinMode(FAN_PWM_PIN, OUTPUT);
pinMode(PUP_PWM_PIN, OUTPUT);
pinMode(TAQ_PWM_PIN, INPUT_PULLUP);
// Anexa o servo ao pino
oscillationServo.attach(SERVO_PIN);
oscillationServo.write(currentOscillationAngle); // Posição inicial do servo
// Inicializa as instâncias dos botões
fanModeButton.begin();
oscillationButton.begin();
// Garante que o ventilador esteja desligado no início
analogWrite(FAN_PWM_PIN, 0);
}
// ============================================================================
// Função Loop Principal
// É executada continuamente, controlando o circulador de ar.
// ============================================================================
void loop() {
handleButtonInputs(); // Verifica e processa entradas dos botões
handleFanControl(); // Ajusta a velocidade do ventilador
handleOscillationControl(); // Controla o movimento de oscilação
updateLCD(); // Atualiza as informações no display LCD
bombeamento(); // Controla o bombeamento de climatização.
// Pequeno atraso para estabilizar leituras e evitar ciclos muito rápidos
delay(10); // Atraso não-bloqueante para este contexto
}
// ============================================================================
// Implementações das Funções
// ============================================================================
/**
* @brief Gerencia a velocidade do ventilador com base no modo atual.
* Utiliza analogWrite para controle PWM.
*/
void handleFanControl() {
unsigned long currentTime = millis(); // Obtém o tempo atual para o modo FAN_TEMP
switch (currentFanMode) {
case FAN_OFF:
fanSpeedPWM = 0; // Desliga o ventilador
break;
case FAN_LOW:
fanSpeedPWM = 80; // Velocidade baixa (ajuste este valor 0-255)
break;
case FAN_MEDIUM:
fanSpeedPWM = 150; // Velocidade média (ajuste este valor 0-255)
break;
case FAN_HIGH:
fanSpeedPWM = 255; // Velocidade alta (PWM máximo)
break;
case FAN_AUTO:
// Mapeia a leitura do potenciômetro (0-1023) para a faixa PWM (0-255)
fanSpeedPWM = map(analogRead(POTENTIOMETER_PIN), 0, 1023, 0, 255);
break;
case FAN_TEMP:
// Modo "Tempestade": Varia a velocidade do ventilador aleatoriamente
// de forma não-bloqueante.
if (currentTime - lastRandomChangeTime >= random(RANDOM_CHANGE_INTERVAL_MIN, RANDOM_CHANGE_INTERVAL_MAX)) {
lastRandomChangeTime = currentTime;
// Gera um valor PWM aleatório entre 50 (mínimo para sentir) e 255 (máximo)
fanSpeedPWM = random(50, 256); // random(min, max) exclui o max, então 256 para incluir 255
}
break;
}
analogWrite(FAN_PWM_PIN, fanSpeedPWM); // Aplica a velocidade PWM ao ventilador
}
/**
* @brief Gerencia o movimento de oscilação do circulador.
* Move o servo motor entre OSC_MIN_ANGLE e OSC_MAX_ANGLE.
*/
void handleOscillationControl() {
if (isOscillating) {
unsigned long currentTime = millis();
if (currentTime - lastOscillationMoveTime >= OSCILLATION_MOVE_INTERVAL) {
lastOscillationMoveTime = currentTime;
currentOscillationAngle += (oscillationDirection * OSCILLATION_STEP);
// Inverte a direção se o servo atingir os limites
if (currentOscillationAngle >= OSC_MAX_ANGLE) {
currentOscillationAngle = OSC_MAX_ANGLE; // Garante que não passe do limite
oscillationDirection = -1; // Muda para a direção de volta
} else if (currentOscillationAngle <= OSC_MIN_ANGLE) {
currentOscillationAngle = OSC_MIN_ANGLE; // Garante que não passe do limite
oscillationDirection = 1; // Muda para a direção de ida
}
oscillationServo.write(currentOscillationAngle); // Move o servo
}
} else {
// Se a oscilação estiver desligada, o servo pode ir para uma posição central ou parar
// Por exemplo, pode ir para o centro e parar:
// oscillationServo.write(90); // Posição central (ajuste se necessário)
// Ou simplesmente não fazer nada, mantendo a última posição
}
}
/**
* @brief Lida com a leitura dos botões físicos e atualiza os estados.
*/
void handleButtonInputs() {
// Botão de Modo do Ventilador
if (fanModeButton.toggled()) { // Verifica se o estado do botão mudou
if (fanModeButton.read() == Button::PRESSED) { // Se o botão foi pressionado
// Cicla entre os modos do ventilador
currentFanMode = (FanMode)((currentFanMode + 1) % (FAN_TEMP + 1));
Serial.print("Modo Ventilador: ");
switch (currentFanMode) {
case FAN_OFF: Serial.println("DESLIGADO"); break;
case FAN_LOW: Serial.println("BAIXA"); break;
case FAN_MEDIUM: Serial.println("MEDIA"); break;
case FAN_HIGH: Serial.println("ALTA"); break;
case FAN_AUTO: Serial.println("AUTOMATICO"); break;
case FAN_TEMP: Serial.println("TEMPESTADE"); break;
}
}
}
// Botão de Oscilação
if (oscillationButton.toggled()) { // Verifica se o estado do botão mudou
if (oscillationButton.read() == Button::PRESSED) { // Se o botão foi pressionado
isOscillating = !isOscillating; // Alterna o estado da oscilação
Serial.print("Oscilacao: ");
Serial.println(isOscillating ? "LIGADA" : "DESLIGADA");
// Se a oscilação for desligada, o servo pode voltar para uma posição padrão
if (!isOscillating) {
oscillationServo.write(90); // Exemplo: volta para o centro (ajuste)
}
}
}
}
//
void bombeamento() {
//float celsius = lerTemperatura();
if (bombeamentoButton.toggled() && bombeamentoButton.read() == Button::PRESSED) { // || celsius >= 40.00
digitalWrite(PUP_PWM_PIN, !digitalRead(TAQ_PWM_PIN) && !digitalRead(PUP_PWM_PIN));
}
int value = digitalRead(TAQ_PWM_PIN);
if (nivelTanque != value) {
nivelTanque = value;
if (value == HIGH) {
digitalWrite(13, HIGH);
digitalWrite(PUP_PWM_PIN, LOW);
Serial.println(" LIGADA");
}
if (value == LOW) {
digitalWrite(13, LOW);
Serial.println(" DESLIGADA");
}
}
int epup = digitalRead(PUP_PWM_PIN);
lcd.setCursor(13,1);
lcd.print(epup ? "Blg" : "Bds");
}
/**
* @brief Atualiza o display LCD com as informações do circulador.
*/
void updateLCD() {
lcd.setCursor(0, 0); // Define o cursor para a primeira coluna, primeira linha
lcd.print("Vent: ");
switch (currentFanMode) {
case FAN_OFF: lcd.print("DESL "); break;
case FAN_LOW: lcd.print("BAIXA "); break;
case FAN_MEDIUM: lcd.print("MEDIA "); break;
case FAN_HIGH: lcd.print("ALTA "); break;
case FAN_AUTO: lcd.print("AUTO ("); lcd.print(map(fanSpeedPWM, 0, 255, 0, 100)); lcd.print("%)"); break;
case FAN_TEMP: lcd.print("TEMP ("); lcd.print(map(fanSpeedPWM, 0, 255, 0, 100)); lcd.print("%)"); break;
}
if(isOscillating){
lcd.setCursor(15, 0); // Define o cursor para a primeira coluna, primeira linha
lcd.write((byte)2);
delay(10);
lcd.write((byte)3);
}
lcd.setCursor(0, 1); // Define o cursor para a primeira coluna, segunda linha
lcd.print("Agua:");
lcd.setCursor(5,1);
lcd.write((byte)1);
lcd.print(nivelTanque ? " Falta" : " Cheio");
lcd.print(" "); // Espaço para limpar qualquer caractere residual
}