#include <Wire.h>
#include <RTClib.h>
#include <SD.h>
#include <SPI.h>
#include <SSD1306Ascii.h>
#include <SSD1306AsciiAvrI2c.h>
#include <avr/wdt.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Adafruit_GFX.h>
// Número de sensores de temperatura
#define NUM_SENSORES 8
#define PINO_SENSORES 34
#define NUM_MOSTRAR 10 // Número de valores para média móvel
// Definições para os sensores de temperatura
OneWire oneWire(PINO_SENSORES);
DallasTemperature sensores(&oneWire);
DeviceAddress sensoresTemperatura[NUM_SENSORES];
// Definições para o display OLED
#define I2C_ADDRESS 0x3C
SSD1306AsciiAvrI2c oled;
// Definições para o RTC DS3231
RTC_DS3231 rtc;
// Definições para o SD Card
const int chipSelect = 53;
File arquivoCSV;
unsigned long tamanhoArquivoCSV = 0;
bool cartaoSDPresente = false;
// Base64 encoding table
const char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
String base64_encode(byte* input, int length) {
String encoded = "";
int i = 0;
while (i < length) {
byte a = i < length ? input[i++] : 0;
byte b = i < length ? input[i++] : 0;
byte c = i < length ? input[i++] : 0;
byte b1 = (a >> 2) & 0x3F;
byte b2 = ((a << 4) | (b >> 4)) & 0x3F;
byte b3 = ((b << 2) | (c >> 6)) & 0x3F;
byte b4 = c & 0x3F;
if (i - 1 >= length) b3 = 64;
if (i - 2 >= length) b4 = 64;
encoded += base64_table[b1];
encoded += base64_table[b2];
encoded += base64_table[b3];
encoded += base64_table[b4];
}
return encoded;
}
// Definições para os sensores de umidade
const int numSensores = 8;
const int pinosSensores[numSensores] = {A0, A1, A2, A3, A4, A5, A6, A7};
const char* nomesSensores[numSensores] = {
"U1", "U2", "U3", "U4",
"U5", "U6", "U7", "U8"
};
bool sensoresConectados[numSensores] = {false};
// Arrays para armazenar os últimos 10 valores
float ultimosTemperaturas[NUM_SENSORES][NUM_MOSTRAR] = {0};
float ultimosUmidades[numSensores][NUM_MOSTRAR] = {0};
int indiceTemperatura[NUM_SENSORES] = {0};
int indiceUmidade[numSensores] = {0};
// Pinos e variáveis para o botão de delete e reset
const int pinoBotaoReset = 6;
const int pinoBotaoSwitch = 8;
const int pinoBotaoDelete = 10;
unsigned long tempoPressionadoDelete = 0;
bool buttonPressedDelete = false;
const unsigned long tempoBarraProgresso = 4000;
// Variáveis para rastrear o tempo
unsigned long ultimoVerificaConexao = 0;
const unsigned long intervaloVerificaConexao = 1000;
const unsigned long intervaloAtualizacaoUmidade = 10000;
unsigned long ultimoAtualizacaoUmidade = 0;
unsigned long ultimoMonitoramentoArquivo = 0;
const unsigned long intervaloMonitoramentoArquivo = 20000;
// Intervalo de tempo para leitura da temperatura
const unsigned long INTERVALO = 1000;
unsigned long tempoAnterior = 0;
// Variáveis para os sensores de temperatura
DeviceAddress ds18;
byte c;
int i;
float tempC;
// Fatores de calibração específicos para cada sensor DS18B20
float CALIBRACAO_TEMP[] = {
2., 0.5, -0.3, 0.2, 0.5, 0.2, 0.2, 0.2
};
// Funções
void exibirErro(const char* mensagem);
void abrirOuCriarArquivoCSV();
void verificarConexaoSensores();
void atualizarUmidadeSensores();
void verificarEstadoSD();
void monitorarTamanhoArquivoCSV();
void deletarArquivo();
void mostrarBarraProgresso(unsigned long tempoPressionado, unsigned long tempoBarraProgresso);
void verificarEstadoSwitch();
void atualizarDisplaySensores();
void imprimirDadosMonitorSerial();
void resetarArduino();
float calcularMedia(float* valores, int tamanho);
String base64_encode(byte* input, int length);
void listFiles();
void downloadFile(String filename);
void sendFileSize(String filename);
void setup() {
Serial.begin(115200);
Wire.begin();
oled.begin(&Adafruit128x64, I2C_ADDRESS);
oled.setFont(System5x7);
Serial.print("Initializing SD card...");
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
return;
}
Serial.println("Card initialized.");
if (!rtc.begin()) {
exibirErro("Erro: RTC nao encontrado!");
while (true);
}
abrirOuCriarArquivoCSV();
pinMode(pinoBotaoReset, INPUT_PULLUP);
pinMode(pinoBotaoDelete, INPUT_PULLUP);
pinMode(pinoBotaoSwitch, INPUT_PULLUP);
oled.clear();
oled.println("Iniciando Sensor...");
oled.displayRows();
delay(2000);
oled.clear();
oled.println("Modulos OK");
oled.displayRows();
delay(2000);
sensores.begin();
for (int i = 0; i < NUM_SENSORES; i++) {
if (sensores.getAddress(sensoresTemperatura[i], i)) {
Serial.print("Sensor ");
Serial.print(i);
Serial.print(": ");
for (int j = 0; j < 8; j++) {
Serial.print(sensoresTemperatura[i][j], HEX);
Serial.print(" ");
}
Serial.println();
} else {
Serial.print("Falha ao obter o endereço do sensor ");
Serial.println(i);
}
}
}
void loop() {
// Verifica se há comandos disponíveis na porta serial
if (Serial.available()) {
String command = Serial.readStringUntil('\n');
if (command == "LIST") {
listFiles();
} else if (command.startsWith("DOWNLOAD ")) {
String filename = command.substring(9);
downloadFile(filename);
} else if (command.startsWith("FILESIZE ")) {
String filename = command.substring(9);
sendFileSize(filename);
}
}
unsigned long tempoAtual = millis();
sensores.requestTemperatures();
for (int i = 0; i < NUM_SENSORES; i++) {
float tempC = sensores.getTempCByIndex(i);
// Aplicar calibração
tempC += CALIBRACAO_TEMP[i];
Serial.print("Sensor ");
Serial.print(i + 1);
Serial.print(": ");
Serial.print(tempC, 1);
Serial.println(" °C");
// Atualiza os valores de temperatura
ultimosTemperaturas[i][indiceTemperatura[i]] = tempC;
indiceTemperatura[i] = (indiceTemperatura[i] + 1) % NUM_MOSTRAR; // Circular
}
if (tempoAtual - ultimoVerificaConexao >= intervaloVerificaConexao) {
ultimoVerificaConexao = tempoAtual;
verificarConexaoSensores();
}
if (tempoAtual - ultimoAtualizacaoUmidade >= intervaloAtualizacaoUmidade) {
ultimoAtualizacaoUmidade = tempoAtual;
atualizarUmidadeSensores();
}
verificarEstadoSD();
if (tempoAtual - ultimoMonitoramentoArquivo >= intervaloMonitoramentoArquivo) {
ultimoMonitoramentoArquivo = tempoAtual;
monitorarTamanhoArquivoCSV();
}
if (digitalRead(pinoBotaoDelete) == HIGH) {
if (!buttonPressedDelete) {
tempoPressionadoDelete = millis();
buttonPressedDelete = false;
} else {
unsigned long tempoPressionado = millis() - tempoPressionadoDelete;
if (tempoPressionado >= tempoBarraProgresso) {
deletarArquivo();
while (digitalRead(pinoBotaoDelete) == HIGH) {
delay(100);
}
buttonPressedDelete = true;
} else {
mostrarBarraProgresso(tempoPressionado, tempoBarraProgresso);
}
}
} else {
buttonPressedDelete = true;
}
if (digitalRead(pinoBotaoReset) == LOW) {
resetarArduino();
while (digitalRead(pinoBotaoReset) == LOW) {
delay(100);
}
}
verificarEstadoSwitch();
atualizarDisplaySensores();
imprimirDadosMonitorSerial();
}
void mostrarBarraProgresso(unsigned long tempoInicial, unsigned long duracao) {
unsigned long tempoAtual = millis();
float progresso = float(tempoAtual - tempoInicial) / duracao;
oled.clear();
oled.setCursor(0, 0);
oled.println("Deletando arquivo...");
int barraComprimento = 16;
int barraPreenchida = int(barraComprimento * progresso);
oled.print("[");
for (int i = 0; i < barraComprimento; i++) {
if (i < barraPreenchida) {
oled.print("#");
} else {
oled.print("-");
}
}
oled.print("]");
oled.displayRows();
delay(100);
}
void verificarEstadoSwitch() {
if (digitalRead(pinoBotaoSwitch) == LOW) {
oled.ssd1306WriteCmd(SSD1306_DISPLAYOFF);
} else {
oled.ssd1306WriteCmd(SSD1306_DISPLAYON);
}
}
void deletarArquivo() {
unsigned long tempoInicio = millis();
unsigned long duracao = tempoBarraProgresso;
oled.clear();
oled.println("Aguarde...");
oled.displayRows();
while (millis() - tempoInicio < duracao) {
mostrarBarraProgresso(tempoInicio, duracao);
}
if (SD.exists("dados.csv")) {
if (SD.remove("dados.csv")) {
oled.clear();
oled.println("Arquivo deletado com sucesso");
} else {
oled.clear();
oled.println("Erro ao deletar arquivo");
}
} else {
oled.clear();
oled.println("Arquivo nao encontrado");
}
oled.displayRows();
}
void resetarArduino() {
oled.clear(); // Limpa o display OLED
oled.println("Reiniciando..."); // Exibe mensagem de reinício
oled.displayRows(); // Atualiza o display
delay(1000); // Aguarda 1 segundo antes de reiniciar
wdt_enable(WDTO_15MS); // Habilita o watchdog timer para reiniciar o Arduino
while (true) {
// Espera o watchdog timer reiniciar o Arduino
}
}
void verificarConexaoSensores() {
for (int i = 0; i < numSensores; i++) {
int leituraSensor = analogRead(pinosSensores[i]);
if (leituraSensor <= 376) { //
sensoresConectados[i] = false;
} else {
sensoresConectados[i] = true;
}
}
}
void atualizarUmidadeSensores() {
if (!arquivoCSV) {
return;
}
DateTime agora = rtc.now();
String data = String(agora.day()) + "/" + String(agora.month()) + "/" + String(agora.year());
String hora = String(agora.hour()) + ":" + String(agora.minute()) + ":" + String(agora.second());
arquivoCSV.print(data);
arquivoCSV.print(", ");
arquivoCSV.print(hora);
arquivoCSV.print(", ");
for (int i = 0; i < NUM_SENSORES; i++) {
float tempC = sensores.getTempCByIndex(i);
if (tempC == DEVICE_DISCONNECTED_C) {
arquivoCSV.print("--");
} else {
arquivoCSV.print(tempC);
}
if (i < NUM_SENSORES - 1) {
arquivoCSV.print(", ");
}
}
for (int i = 0; i < numSensores; i++) {
if (sensoresConectados[i]) {
int umidade = analogRead(pinosSensores[i]);
umidade = constrain(map(umidade, 600, 1023, 0, 100), 0, 100);
arquivoCSV.print(umidade,1);
} else {
arquivoCSV.print("--");
}
if (i < numSensores - 1) {
arquivoCSV.print(", ");
}
}
arquivoCSV.println();
arquivoCSV.flush();
tamanhoArquivoCSV = arquivoCSV.size();
}
void verificarEstadoSD() {
if (!SD.begin(chipSelect)) {
if (cartaoSDPresente) {
cartaoSDPresente = false;
oled.clear();
oled.println("Erro: Cartao SD removido!");
oled.displayRows();
}
} else {
if (!cartaoSDPresente) {
cartaoSDPresente = true;
abrirOuCriarArquivoCSV();
}
}
}
void monitorarTamanhoArquivoCSV() {
oled.clear();
oled.println("CSV:");
float tamanhoKB = tamanhoArquivoCSV / 1024.0;
oled.print(tamanhoKB, 1);
oled.println(" KB");
oled.displayRows();
delay(2000);
}
void atualizarDisplaySensores() {
oled.clear(); // Limpa o display antes de atualizar
if (digitalRead(pinoBotaoSwitch) == HIGH) {
oled.setCursor(0, 0); // Posiciona o cursor no início da primeira linha
for (int i = 0; i < NUM_SENSORES; i++) {
oled.setCursor(0, (i + 1) * 8); // Ajusta a posição para cada linha, começando na segunda linha
// Identificador dos sensores
String idUmidade = String("U") + String(i + 1);
String idTemperatura = String("T") + String(i + 1);
// Leitura de umidade
String umidadeTexto = "--";
if (sensoresConectados[i]) {
int leituraSensor = analogRead(pinosSensores[i]);
int umidade = constrain(map(leituraSensor, 600, 373, 0, 100), 0, 100);
umidadeTexto = String(umidade) + "%";
}
// Leitura de temperatura
float tempC = sensores.getTempCByIndex(i);
String temperaturaTexto = (tempC == DEVICE_DISCONNECTED_C) ? "--" : String(tempC + CALIBRACAO_TEMP[i], 1) + " C";
// Exibe as informações formatadas
oled.print(idUmidade + ":" + umidadeTexto + " / ");
oled.println(idTemperatura + ":" + temperaturaTexto);
}
oled.displayRows(); // Atualiza o display com as informações
delay(3000);
}
}
float calcularMedia(float* valores, int tamanho) {
float soma = 0;
for (int i = 0; i < tamanho; i++) {
soma += valores[i];
}
return soma / tamanho;
}
void listFiles() {
File root = SD.open("/");
if (!root) {
Serial.println("Error opening root directory");
return;
}
root.rewindDirectory();
File file = root.openNextFile();
while (file) {
Serial.println(file.name());
file = root.openNextFile();
}
file.close();
Serial.println("END");
}
void downloadFile(String filename) {
File file = SD.open(filename);
if (!file) {
Serial.println("Error opening file");
return;
}
Serial.println("START");
while (file.available()) {
byte buffer[32];
int bytesRead = file.read(buffer, sizeof(buffer));
Serial.print(base64_encode(buffer, bytesRead));
Serial.println();
}
Serial.println("END");
file.close();
}
void sendFileSize(String filename) {
File file = SD.open(filename);
if (!file) {
Serial.println("Error opening file");
return;
}
Serial.println(file.size());
file.close();
}
void exibirErro(const char* mensagem) {
oled.clear();
oled.println(mensagem);
oled.displayRows(); // Atualiza o display
while (true) {
delay(1000); // Aguarda indefinidamente
}
}
void abrirOuCriarArquivoCSV() {
arquivoCSV = SD.open("dados.csv", FILE_WRITE);
if (!arquivoCSV) {
exibirErro("Erro: Falha ao abrir ou criar arquivo CSV!");
return;
}
// Mover o cursor para o início do arquivo para leitura
File fileForCheck = SD.open("dados.csv", FILE_READ);
bool hasHeader = false;
if (fileForCheck) {
if (fileForCheck.available()) {
String firstLine = fileForCheck.readStringUntil('\n');
// Verifica se a primeira linha é o cabeçalho esperado
if (firstLine.startsWith("Data, Hora, T1, T2, T3, T4, T5, T6, T7, T8, U1, U2, U3, U4, U5, U6, U7, U8")) {
hasHeader = true;
}
}
fileForCheck.close();
}
// Se não encontrou o cabeçalho, insere-o no arquivo
if (!hasHeader) {
arquivoCSV.println("Data, Hora, T1, T2, T3, T4, T5, T6, T7, T8, U1, U2, U3, U4, U5, U6, U7, U8");
arquivoCSV.flush();
}
}
void imprimirDadosMonitorSerial() {
Serial.println("Dados dos Sensores:");
for (int i = 0; i < NUM_SENSORES; i++) {
float tempC = sensores.getTempCByIndex(i);
if (tempC == DEVICE_DISCONNECTED_C) {
Serial.print("T");
Serial.print(i + 1);
Serial.print(": --");
} else {
// Aplicar calibração
tempC += CALIBRACAO_TEMP[i];
Serial.print("T");
Serial.print(i + 1);
Serial.print(": ");
Serial.print(tempC, 1);
Serial.print(" °C");
}
Serial.println();
}
Serial.print("Tamanho do arquivo CSV: ");
float tamanhoKB = tamanhoArquivoCSV / 1024.0;
Serial.print(tamanhoKB, 1);
Serial.println(" KB");
Serial.println();
}
Loading
ds18b20
ds18b20