Display Gráfico, RTC DS3231

Olá, gostaria de alguma ajuda, tem um tempo que estou tentando sozinho descobrir o porque deste acontecimento, e de tantas tentativas falhas venho apelar por ajuda. Tenho um display gráfico I2C, modelo GM12864-59N ST7567, e estou usando também o RTC DS3231, e também um sensor de humidade HD-38. Todos elementos são vistos na tela do display, e funcionam, porém após um tempo, o display congela, e só volta quando faço a desenergização ou aperto o botão reset do arduino. Também notei que o millis para de ser contado também. Se alguém souber o que pode estar causando isto


```cpp
#include <Wire.h>
#include <RTClib.h>   // RTC
#include <U8g2lib.h>  // LCD
#include <stdlib.h>
RTC_DS3231 rtc;
U8G2_ST7567_ENH_DG128064I_F_HW_I2C u8g2(U8G2_R0, SCL, SDA, U8X8_PIN_NONE);  // DECLARAÇÃO DO OBJETO LCD

U8G2_WITH_HVLINE_SPEED_OPTIMIZATION;
U8G2_WITH_INTERSECTION;

char daysOfTheWeek[7][12] = { "Domingo", "Segunda", "Terca", "Quarta", "Quinta", "Sexta", "Sabado" };  // CHAR PARA OS DIAS DA SEMANA

float temperatura;        // VARIAVEL TIPO FLOAT PARA TEMPERATURA
char *temp_str = "00.0";  // VARIAVEL TIPO CHAR PARA TEMPERATURA
char minutoss[3];         // VARIAVEL TIPO CHAR PARA MINUTOS
uint8_t minutos = 0;      // VARIAVEL TIPO INT BYTE PARA MINUTOS
char horass[3];           // VARIAVEL TIPO CHAR PARA HORAS
uint8_t horas = 0;        // VARIAVEL TIPO INT BYTE PARA HORAS
//char segundoss[2];        // VARIAVEL TIPO CHAR PARA SEGUNDOS
//uint8_t segundos = 0;     // VARIAVEL TIPO INT BYTE PARA SEGUNDOS
char diass[3];     // VARIAVEL TIPO CHAR PARA DIAS
uint8_t dia = 0;   // VARIAVEL TIPO INT BYTE PARA DIAS
char mess[3];      // VARIAVEL TIPO CHAR PARA MES
uint8_t mes = 0;   // VARIAVEL TIPO INT BYTE PARA MES
char anos[5];      // VARIAVEL TIPO CHAR PARA ANO
uint16_t ano = 0;  // VARIAVEL TIPO INT BYTE PARA ANO
char diadasemana[12];

unsigned long tempo = 0;
unsigned long tempopassado = 0;

#define umidadeAnalogica A0   //Atribui o pino A0 a variável umidade - leitura analógica do sensor
#define umidadeDigital 7      //Atribui o pino 7 a variável umidadeDigital - leitura digital do sensor
char *umidade_str = "000.0";  //VARIAVEL TIPO CHAR PARA UMIDADE
int valorumidade;             //Declaração da variável que armazenará o valor da umidade lida - saída analogica
int valorumidadeDigital;      //Declaração da variável que armazenara a saída digital do sensor de umidade do solo
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void setup() {

  if (!rtc.begin()) {

    while (1) delay(10);
  }

  if (rtc.lostPower()) {
    // Serial.println("RTC lost power, let's set the time!");
    // When time needs to be set on a new device, or after a power loss, the
    // following line sets the RTC to the date & time this sketch was compiled
    //rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    //rtc.adjust(DateTime(2002, 12, 12, 12, 2, 0));
  }
  // rtc.adjust(DateTime(2024, 7, 12, 19, 29, 0));
  Serial.begin(9600);
  Wire.begin();
  u8g2.setI2CAddress(0x3F * 2);
  u8g2.begin();
  u8g2.setFont(u8g2_font_lucasfont_alternate_tf);

  u8g2.clearBuffer();
  pinMode(umidadeAnalogica, INPUT);  //Define umidadeAnalogica como entrada
  pinMode(umidadeDigital, INPUT);    //Define umidadeDigital como entrada
  tempo = millis();
}
//-------------------------------------------------------------
void loop() {  // INICIO DO LOOP
  tempopassado = millis();
  if (tempopassado - tempo >= 5000) {
    data();
    delay(500);
    umidade();
    delay(500);
    draw();
    tempo = millis();
  }
  Serial.println(tempo);
  Serial.println(tempopassado);
  u8g2.clearBuffer();
}  // FINAL DO LOOP

void draw() {  // INICIO DO DRAW
  u8g2.firstPage();
  do {
    u8g2.drawFrame(2, 2, 124, 60);       //Desenha um quadrado
    u8g2.drawRBox(7, 8, 59, 21, 0);      //Desenha um quadrado preenchido
    u8g2.setFont(u8g2_font_crox1hb_tf);  //Escolha da fonte

    u8g2.setFontMode(1);   //Tipo da fonte
    u8g2.setDrawColor(2);  //Cor da fonte

    u8g2.drawStr(39, 23, minutoss);  //Imprime minutos no LCD
    u8g2.drawStr(35, 22, ":");
    u8g2.drawStr(20, 23, horass);  //Imprime horas no LCD

    u8g2.setFont(u8g2_font_amstrad_cpc_extended_8f);
    u8g2.drawStr(14, 43, diadasemana);  // Imprime dias da semana no LCD

    u8g2.setFont(u8g2_font_lucasfont_alternate_tf);  //Escolha da fonte

    u8g2.drawStr(46, 58, anos);  //Imprime anos no LCD
    u8g2.drawStr(38, 58, "/");
    u8g2.drawStr(26, 58, mess);  //Imprime mes no LCD
    u8g2.drawStr(18, 58, "/");
    u8g2.drawStr(6, 58, diass);  //Imprime dias no LCD

    u8g2.setFont(u8g2_font_finderskeepers_tf);  // Escolha da fonte
    u8g2.drawFrame(71, 8, 50, 50);              // Desenha um quadrado

    u8g2.drawStr(75, 45, "Umidade:");   // Imprime umidade no LCD
    u8g2.drawStr(78, 55, umidade_str);  // Imprime umidade no LCD
    u8g2.drawStr(102, 55, "%");

    u8g2.drawStr(75, 18, "Temp:");         // Imprime "Temp" no LCD
    dtostrf(temperatura, 3, 1, temp_str);  // Transforma de temperatura para Char
    u8g2.drawStr(100, 30, "°C");
    u8g2.drawStr(78, 30, temp_str);  // Imprime temperatura no LCD

  } while (u8g2.nextPage());

}  // FINAL DO DRAW

void data() {
  //----------------------------------------//RTC-DS3231
  DateTime now = rtc.now();
  ano = now.year();                          //ARMAZENA O ANO NA VARIAVEL ANO
  mes = now.month();                         //ARMAZENA O MES NA VARIAVEL MES
  dia = now.day();                           //ARMAZENA O DIA NA VARIAVEL DIA
  (daysOfTheWeek[now.dayOfTheWeek()]);       //IMPRIME DIA DA SEMANA NO MONITOR SERIAL
  horas = now.hour();                        //ARMAZENA A HORA NA VARIAVEL HORA
  minutos = now.minute();                    //ARMAZENA MINUTOS NA VARIAVEL MINUTOS
  temperatura = (rtc.getTemperature() - 2);  //ARMAZENA TEMPERATURA NA VARIAVEL TEMPERATURA
  //----------------------------------------//Fim RTC-DS3231

  strcpy(minutoss, u8x8_u8toa(minutos, 2)); /* convert minutos to a string with two digits */
  strcpy(horass, u8x8_u8toa(horas, 2));     /* convert horas to a string with two digits */
  strcpy(diass, u8x8_u8toa(dia, 2));        /* convert dia to a string with two digits */
  strcpy(mess, u8x8_u8toa(mes, 2));         /* convert mes to a string with two digits */
  strcpy(anos, u8x8_u16toa(ano, 4));        /* convert ano to a string with two digits */
  strcpy(diadasemana, daysOfTheWeek[now.dayOfTheWeek()]);
}

void umidade() {
  valorumidade = analogRead(umidadeAnalogica);          //Realiza a leitura analógica do sensor e armazena em valorumidade
  valorumidade = map(valorumidade, 1023, 315, 0, 100);  //Transforma os valores analógicos em uma escala de 0 a 100
  dtostrf(valorumidade, 3, 0, umidade_str);             //Converte variavel int em um char
  valorumidadeDigital = digitalRead(umidadeDigital);    //Realiza a leitura digital do sensor e armazena em valorumidadeDigital
  if (valorumidadeDigital == 0) {                       //Se esse valor for igual a 0, será mostrado no monitor serial que o solo está úmido

  } else {  
  }
}

Olá! Bem vindo ao Forum.

Quanto tempo? Esse tempo se repete ou varia?

Em princípio eu não vi nada no seu código que possa estar causando isso.

Coloquei o millis no codigo, para atualizar o display, por ter visto em alguma pesquisa que fiz, que dizia que atualizar ele muito rápido poderia ser um motivo. Inicialmente também tinha interesse de ter os segundos, então abri mão dos segundos e coloquei o millis para atualizar o display em 1 minuto. Assim ele demorava dias para travar, porém reduzindo o tempo da atualização do display demoram algumas horas até que ele trave.

O que me veio à cabeça num primeiro momento é que talvez essa linha pudesse estar dando problema depois que o millis() girasse, porque a variável tempo estaria com valor muito alto. Só que para dar overflow no millis leva uns 50 dias e o tempo de atualização do display não faria diferença.

Então fiquei sem ideias do que pode ser. Se você souber escrever em inglês, vale a pena pedir ajuda no Forum internacional. Como muitas pessoas respondem lá, aumentam as chances de que alguém descubra o problema.

A propósito, muito legal seu projeto!

Muito obrigado, pela atenção e ajuda, seguirei em busca de respostas, tentarei em um fórum internacional então, obrigado!!

Assim de repente, estas duas variáveis são um problema... tu não estás a reservar espaço de memória para a string que queres, estás a declarar um ponteiro.

Deves trocar estas declarações para isto:

char temp_str[4]; 
char umidade_str[5]; 

Depois, quando escreves para elas, deves garantir que o que estás a escrever não vai saltar fora do espaço que reservaste.... sim, é difícil teres mais de 99 graus de temperatura ou 100 de humidade, mas se o sensor der um erro tu passas esse número para o LCD e podes escrever por cima de variáveis que bloqueiam tudo. Então aqui, faz assim:

u8g2.setCursor(78, 55);
u8g2.print(umidade, 2);
//u8g2.drawStr(78, 55, umidade_str);

Tens mais informação sobre como fazer isto aqui:

O problema do dtostrf é que não te garante o tamanho máximo da string e como tal pode dar erros como explicado em cima.

De resto, diria que removeres os delay(500) não fazia mal. :stuck_out_tongue:

Olá, muito obrigado pela atenção, vou fazer esses ajustes e assim que notar o resultado aviso aqui.

Olá fiz as alterações que você me aconselhou, porém seguiu travando, então estive lendo outros tópicos no fórum e notei que precisava resistores de pull-up para o barramento I2C. Fiz este ajuste e agora não está mais congelando, agradeço a ajuda e as dicas para o código, com certeza fizeram alguma diferença. Muito Obrigado!!

1 Like