quarta-feira, 21 de agosto de 2024

Projeto chocadeira inteligente, arduino e LCD 5110

 

O projeto consiste em montar um gerenciador inteligente para cuidar da chocadeira sozinha com viragem de ovo a cada 2 horas set de temperatura, contagem de dias. 

Lista de material e : 

LCD Nokia5110 o que estou utilizando e o modelo AZUL.

Arduino UNO ou similar

DHT22 

Rele simples para o vira ovo 

Rele solido para resistência

Resistencia para chocadeira 


O código para o Arduino 




#include <Adafruit_PCD8544.h>

#include <DHT.h>


#define DHTPIN 2

#define DHTTYPE DHT22

#define RELAY_PIN 3

#define BUTTON_UP 4

#define BUTTON_DOWN 5

#define BUTTON_SELECT 6

#define LDR_PIN A0 // Pino analógico para o LDR

#define BACKLIGHT_PIN 7 // Pino digital para controlar o transistor do backlight


// pin 8 - Serial clock out (SCLK)

// pin 9 - Serial data out (DIN)

// pin 10 - Data/Command select (D/C)

// pin 11 - LCD chip select (CS/CE)

// pin 12 - LCD reset (RST)


Adafruit_PCD8544 display = Adafruit_PCD8544(8, 9, 10, 11, 12);

DHT dht(DHTPIN, DHTTYPE);


// Variáveis para o menu

int menuOption = -1;  // -1 significa tela principal

int targetTemp = 377; // 37.7°C como padrão

unsigned long startTime;

bool heatingOn = false;

unsigned long lastToggle = 0;


// Variáveis para ajustar a data

int setDay = 1;

int setMonth = 1;

int setYear = 2024;


void setup() {

  pinMode(RELAY_PIN, OUTPUT);

  digitalWrite(RELAY_PIN, LOW);

  pinMode(BUTTON_UP, INPUT_PULLUP);

  pinMode(BUTTON_DOWN, INPUT_PULLUP);

  pinMode(BUTTON_SELECT, INPUT_PULLUP);

  pinMode(BACKLIGHT_PIN, OUTPUT);

  digitalWrite(BACKLIGHT_PIN, LOW); // Inicialmente desligado


  display.begin();

  display.setContrast(47);

  display.clearDisplay();

  display.display();

  

  dht.begin();

  

  startTime = millis();

}


void loop() {

  float temp = dht.readTemperature();

  float humidity = dht.readHumidity();

  int days = (millis() - startTime) / (1000 * 60 * 60 * 24);


  // Leitura do LDR e controle do backlight

  int ldrValue = analogRead(LDR_PIN);

  if (ldrValue < 500) { 

    digitalWrite(BACKLIGHT_PIN, HIGH);

  } else {

    digitalWrite(BACKLIGHT_PIN, LOW);

  }

  

  // Navegação no menu com o botão SELECT

  if (digitalRead(BUTTON_SELECT) == LOW) {

    menuOption++;

    if (menuOption > 3) {

      menuOption = -1;  // Volta para a tela principal

    }

    delay(200); // Atraso para evitar múltiplos incrementos acidentais

  }

  

  // Executa a ação de acordo com a opção do menu

  if (menuOption == 0) {  // Ajuste do dia

    adjustDay();

  } else if (menuOption == 1) {  // Ajuste do mês

    adjustMonth();

  } else if (menuOption == 2) {  // Ajuste do ano

    adjustYear();

  } else if (menuOption == 3) {  // Ajuste da temperatura

    adjustTemperature(temp, humidity, days);

  } else {  // Tela principal

    controlHeating(temp);

    displayMainScreen(temp, humidity, days);

  }

}


void adjustDay() {

  if (digitalRead(BUTTON_UP) == LOW) {

    setDay++;

    if (setDay > 31) setDay = 1;

    delay(100);

  }

  if (digitalRead(BUTTON_DOWN) == LOW) {

    setDay--;

    if (setDay < 1) setDay = 31;

    delay(100);

  }

  displayDate();

}


void adjustMonth() {

  if (digitalRead(BUTTON_UP) == LOW) {

    setMonth++;

    if (setMonth > 12) setMonth = 1;

    delay(100);

  }

  if (digitalRead(BUTTON_DOWN) == LOW) {

    setMonth--;

    if (setMonth < 1) setMonth = 12;

    delay(100);

  }

  displayDate();

}


void adjustYear() {

  if (digitalRead(BUTTON_UP) == LOW) {

    setYear++;

    delay(100);

  }

  if (digitalRead(BUTTON_DOWN) == LOW) {

    setYear--;

    delay(100);

  }

  displayDate();

}


void adjustTemperature(float temp, float humidity, int days) {

  if (digitalRead(BUTTON_UP) == LOW) {

    targetTemp++;

    delay(100);

  }

  if (digitalRead(BUTTON_DOWN) == LOW) {

    targetTemp--;

    delay(100);

  }

  displayMenu(temp, humidity, days);

}


void displayMainScreen(float temp, float humidity, int days) {

  display.clearDisplay();

  display.setCursor(0, 0);

  

  // Exibe a data configurada pelo usuário no formato DD/MM/AA

  display.print("Data: ");

  if (setDay < 10) display.print("0");

  display.print(setDay);

  display.print("/");

  if (setMonth < 10) display.print("0");

  display.print(setMonth);

  display.print("/");

  display.print(setYear % 100); // Exibe os dois últimos dígitos do ano


  display.setCursor(0, 10);

  display.print("Temp: ");

  display.print(temp);

  display.print(" C");

  

  display.setCursor(0, 20);

  display.print("Umid: ");

  display.print(humidity);

  display.print(" %");


  display.setCursor(0, 30);

  display.print("Dias: ");

  display.print(days);

  

  display.display();

}


void displayMenu(float temp, float humidity, int days) {

  display.clearDisplay();

  display.setCursor(0, 0);

  display.print("Set Temp:");

  display.setCursor(0, 10);

  display.print(targetTemp / 10.0);

  display.print(" C");


  display.setCursor(0, 20);

  display.print("Atual: ");

  display.print(temp);

  display.print(" C");


  display.setCursor(0, 30);

  display.print("Dias: ");

  display.print(days);


  display.display();

}


void displayDate() {

  display.clearDisplay();

  display.setCursor(0, 0);

  display.print("Set Date:");

  display.setCursor(0, 10);

  display.print("Day: ");

  display.print(setDay);


  display.setCursor(0, 20);

  display.print("Month: ");

  display.print(setMonth);


  display.setCursor(0, 30);

  display.print("Year: ");

  display.print(setYear % 100); // Exibe apenas os últimos 2 dígitos do ano


  display.display();

}


void controlHeating(float temp) {

  unsigned long currentTime = millis();

  

  // Lógica para alternar o estado do relé a cada 2 horas

  if (currentTime - lastToggle >= 2 * 60 * 60 * 1000) { // A cada 2 horas

    if (temp < (targetTemp / 10.0)) {

      digitalWrite(RELAY_PIN, HIGH);

      heatingOn = true;

    } else {

      digitalWrite(RELAY_PIN, LOW);

      heatingOn = false;

    }

    lastToggle = currentTime;

  }

  

  // Lógica para desativar o relé 3 dias antes do término

  unsigned long elapsedDays = (currentTime - startTime) / (1000 * 60 * 60 * 24);

  if (elapsedDays >= 18) { // Faltando 3 dias

    if (temp >= (targetTemp / 10.0) && heatingOn) {

      digitalWrite(RELAY_PIN, LOW);

      heatingOn = false;

    }

  }

}





Agora com um SD card para caso venha ocorrer desligamento ou falta de energia.


#include <Adafruit_PCD8544.h>
#include <DHT.h>
#include <SPI.h>
#include <SD.h>

#define DHTPIN 2
#define DHTTYPE DHT22
#define RELAY_PIN 3
#define BUTTON_UP 4
#define BUTTON_DOWN 5
#define BUTTON_SELECT 6
#define LDR_PIN A0 // Pino analógico para o LDR
#define BACKLIGHT_PIN 7 // Pino digital para controlar o transistor do backlight
#define SD_CS_PIN 10 // Pino de seleção do cartão SD

// pin 8 - Serial clock out (SCLK)
// pin 9 - Serial data out (DIN)
// pin 10 - Data/Command select (D/C)
// pin 11 - LCD chip select (CS/CE)
// pin 12 - LCD reset (RST)

Adafruit_PCD8544 display = Adafruit_PCD8544(8, 9, 10, 11, 12);
DHT dht(DHTPIN, DHTTYPE);

// Variáveis para o menu
int menuOption = -1;  // -1 significa tela principal
int targetTemp = 377; // 37.7°C como padrão
unsigned long startTime;
bool heatingOn = false;
unsigned long lastToggle = 0;

// Variáveis para ajustar a data
int setDay = 1;
int setMonth = 1;
int setYear = 2024;

// Variáveis para data log
unsigned long logInterval = 10000; // Intervalo de log em milissegundos
unsigned long lastLogTime = 0;
File logFile;

void setup() {
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, LOW);
  pinMode(BUTTON_UP, INPUT_PULLUP);
  pinMode(BUTTON_DOWN, INPUT_PULLUP);
  pinMode(BUTTON_SELECT, INPUT_PULLUP);
  pinMode(BACKLIGHT_PIN, OUTPUT);
  digitalWrite(BACKLIGHT_PIN, LOW); // Inicialmente desligado

  display.begin();
  display.setContrast(47);
  display.clearDisplay();
  display.display();
  
  dht.begin();
  
  // Inicializa o cartão SD
  if (!SD.begin(SD_CS_PIN)) {
    display.clearDisplay();
    display.setCursor(0, 0);
    display.print("SD Card failed");
    display.display();
    while (1); // Pare o programa se o SD falhar
  }

  // Abre o arquivo de log para leitura
  logFile = SD.open("datalog.txt", FILE_READ);
  if (logFile) {
    // Lê o último log para recuperar o estado
    String lastLine = "";
    while (logFile.available()) {
      lastLine = logFile.readStringUntil('\n');
    }
    logFile.close();
    
    // Parse the last line for state restoration
    int dayIndex = lastLine.indexOf("Day: ");
    int monthIndex = lastLine.indexOf("Month: ");
    int yearIndex = lastLine.indexOf("Year: ");
    int tempIndex = lastLine.indexOf("Temp: ");
    
    if (dayIndex > -1) setDay = lastLine.substring(dayIndex + 5, monthIndex - 1).toInt();
    if (monthIndex > -1) setMonth = lastLine.substring(monthIndex + 7, yearIndex - 1).toInt();
    if (yearIndex > -1) setYear = lastLine.substring(yearIndex + 5, tempIndex - 1).toInt();
  } else {
    // Cria o arquivo de log se não existir
    logFile = SD.open("datalog.txt", FILE_WRITE);
    if (!logFile) {
      display.clearDisplay();
      display.setCursor(0, 0);
      display.print("Failed to open log");
      display.display();
      while (1); // Pare o programa se falhar ao abrir o arquivo
    }
  }
  
  // Define startTime para o momento atual
  startTime = millis();
}

void loop() {
  float temp = dht.readTemperature();
  float humidity = dht.readHumidity();
  int days = (millis() - startTime) / (1000 * 60 * 60 * 24);

  // Leitura do LDR e controle do backlight
  int ldrValue = analogRead(LDR_PIN);
  if (ldrValue < 500) { 
    digitalWrite(BACKLIGHT_PIN, HIGH);
  } else {
    digitalWrite(BACKLIGHT_PIN, LOW);
  }
  
  // Navegação no menu com o botão SELECT
  if (digitalRead(BUTTON_SELECT) == LOW) {
    menuOption++;
    if (menuOption > 3) {
      menuOption = -1;  // Volta para a tela principal
    }
    delay(200); // Atraso para evitar múltiplos incrementos acidentais
  }
  
  // Executa a ação de acordo com a opção do menu
  if (menuOption == 0) {  // Ajuste do dia
    adjustDay();
  } else if (menuOption == 1) {  // Ajuste do mês
    adjustMonth();
  } else if (menuOption == 2) {  // Ajuste do ano
    adjustYear();
  } else if (menuOption == 3) {  // Ajuste da temperatura
    adjustTemperature(temp, humidity, days);
  } else {  // Tela principal
    controlHeating(temp);
    displayMainScreen(temp, humidity, days);
  }
  
  // Data log
  unsigned long currentTime = millis();
  if (currentTime - lastLogTime >= logInterval) {
    logData(temp, humidity, days);
    lastLogTime = currentTime;
  }
}

void adjustDay() {
  if (digitalRead(BUTTON_UP) == LOW) {
    setDay++;
    if (setDay > 31) setDay = 1;
    delay(100);
  }
  if (digitalRead(BUTTON_DOWN) == LOW) {
    setDay--;
    if (setDay < 1) setDay = 31;
    delay(100);
  }
  displayDate();
}

void adjustMonth() {
  if (digitalRead(BUTTON_UP) == LOW) {
    setMonth++;
    if (setMonth > 12) setMonth = 1;
    delay(100);
  }
  if (digitalRead(BUTTON_DOWN) == LOW) {
    setMonth--;
    if (setMonth < 1) setMonth = 12;
    delay(100);
  }
  displayDate();
}

void adjustYear() {
  if (digitalRead(BUTTON_UP) == LOW) {
    setYear++;
    delay(100);
  }
  if (digitalRead(BUTTON_DOWN) == LOW) {
    setYear--;
    delay(100);
  }
  displayDate();
}

void adjustTemperature(float temp, float humidity, int days) {
  if (digitalRead(BUTTON_UP) == LOW) {
    targetTemp++;
    delay(100);
  }
  if (digitalRead(BUTTON_DOWN) == LOW) {
    targetTemp--;
    delay(100);
  }
  displayMenu(temp, humidity, days);
}

void displayMainScreen(float temp, float humidity, int days) {
  display.clearDisplay();
  display.setCursor(0, 0);
  
  // Exibe a data configurada pelo usuário no formato DD/MM/AA
  display.print("Data: ");
  if (setDay < 10) display.print("0");
  display.print(setDay);
  display.print("/");
  if (setMonth < 10) display.print("0");
  display.print(setMonth);
  display.print("/");
  display.print(setYear % 100); // Exibe os dois últimos dígitos do ano

  display.setCursor(0, 10);
  display.print("Temp: ");
  display.print(temp);
  display.print(" C");
  
  display.setCursor(0, 20);
  display.print("Umid: ");
  display.print(humidity);
  display.print(" %");

  display.setCursor(0, 30);
  display.print("Dias: ");
  display.print(days);
  
  display.display();
}

void displayMenu(float temp, float humidity, int days) {
  display.clearDisplay();
  display.setCursor(0, 0);
  display.print("Set Temp:");
  display.setCursor(0, 10);
  display.print(targetTemp / 10.0);
  display.print(" C");

  display.setCursor(0, 20);
  display.print("Atual: ");
  display.print(temp);
  display.print(" C");

  display.setCursor(0, 30);
  display.print("Dias: ");
  display.print(days);

  display.display();
}

void displayDate() {
  display.clearDisplay();
  display.setCursor(0, 0);
  display.print("Set Date:");
  display.setCursor(0, 10);
  display.print("Day: ");
  display.print(setDay);

  display.setCursor(0, 20);
  display.print("Month: ");
  display.print(setMonth);

  display.setCursor(0, 30);
  display.print("Year: ");
  display.print(setYear % 100); // Exibe apenas os últimos 2 dígitos do ano

  display.display();
}

void controlHeating(float temp) {
  unsigned long currentTime = millis();
  
  // Lógica para alternar o estado do relé a cada 2 horas
  if (currentTime - lastToggle >= 2 * 60 * 60 * 1000) { // A cada 2 horas
    if (temp < (targetTemp / 10.0)) {
      digitalWrite(RELAY_PIN, HIGH);
      heatingOn = true;
    } else {
      digitalWrite(RELAY_PIN, LOW);
      heatingOn = false;
    }
    lastToggle = currentTime;
  }
  
  // Lógica para desativar o relé 3 dias antes do término
  unsigned long elapsedDays = (currentTime - startTime) / (1000 * 60 * 60 * 24);
  if (elapsedDays >= 18) { // Faltando 3 dias
    if (temp >= (targetTemp / 10.0) && heatingOn) {
      digitalWrite(RELAY_PIN, LOW);
      heatingOn = false;
    }
  }
}

void logData(float temp, float humidity, int days) {
  // Construa uma string com os dados
  String logEntry = String(setDay) + "/" + String(setMonth) + "/" + String(setYear % 100) + ", " +
                    String(temp) + " C, " + String(humidity) + " %, " + String(days) + " days\n";
  
  logFile = SD.open("datalog.txt", FILE_WRITE);
  if (logFile) {
    logFile.print(logEntry);
    logFile.flush(); // Garante que os dados sejam escritos no cartão SD
    logFile.close();
  }
}