Transição de telas no Display 16x2

Bom galera, o problema é o seguinte, eu quero fazer uma transição de telas sem usar o Delay, pq eu vou usar botões, aí pra ñ ter q usar Interrupts pra eles queria usar o metodo millis(), mas o display fica doidao e ñ da certo, alguém tem alguma sugestão, ou solução? :slight_smile:

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

#define I2C_ADDR    0x3F
#define DS1307_ADDRESS 0x68

byte zero = 0x00;
LiquidCrystal_I2C lcd(I2C_ADDR, 16, 2);  // set the LCD address to 0x27 for a 16 chars and 2 line display

unsigned long previousTime = 0;

void setup()
{
  lcd.init();
  lcd.backlight();
  Wire.begin();
  Serial.begin(9600);
  //SelecionaDataeHora(); //----- utilizar se for definir a data e a hora
}

void loop()
{
  screenManager();
}

//Aqui estou tentando fazer a transição das telas sem usar o delay, porque lá na frente vai atrapalhar
//ja que eu vou utilizar botões e nao quero usar Interrupt para eles.
//MAS é aqui que o display fica lokão... faço a minima idéia do que está errado.

void screenManager() 
{
    if ((millis() - previousTime) < 3000 )
    {     
      screenHome();
    }
    
    if ((millis() - previousTime) > 3000 && (millis() - previousTime) <= 6000)
    {
      screenHome2();
    }

    // aqui é onde atualiza o previousTime, após a transição das telas. Isso serve pra renovar as condicionais acima
    if ((millis() - previousTime) > 6000)
    {
      previousTime = millis();
    }
}

//!!!! DAQUI pra frente eu ja verifiquei individualmente o código e tá certo, aparece certinho
//no display, eu ñ usei o lcd.clear, pq como vai ficar rodando em loop ele fica piscando o display
//ai ao invés de piscar o display inteiro eu usei espaços em brancos onde fosse necessário. %Gambiarra%
void screenHome()
{
  // Le os valores (data e hora) do modulo DS1307
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(zero);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_ADDRESS, 7);
  int segundos = ConverteparaDecimal(Wire.read());
  int minutos = ConverteparaDecimal(Wire.read());
  int horas = ConverteparaDecimal(Wire.read() & 0b111111);

  // Mostra os dados no display
  lcd.setCursor(3, 0);
  lcd.print("EcoShower");
  lcd.setCursor(2, 1);
  lcd.print("   ");
  lcd.setCursor(5, 1);
  // Acrescenta o 0 (zero) se a hora for menor do que 10
  if (horas <10)
    lcd.print("0");
  lcd.print(horas);
  lcd.print(":");
  // Acrescenta o 0 (zero) se minutos for menor do que 10
  if (minutos < 10)
    lcd.print("0");
  lcd.print(minutos);
  lcd.print("     ");
  returningHome1 = HIGH;
}

void screenHome2() 
{
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(zero);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_ADDRESS, 7);
  int diadasemana = ConverteparaDecimal(Wire.read());
  int diadomes = ConverteparaDecimal(Wire.read());
  int mes = ConverteparaDecimal(Wire.read());
  int ano = ConverteparaDecimal(Wire.read());

  lcd.setCursor(5, 1);
  lcd.print("     ");
  lcd.setCursor(2, 1);
  // Mostra o dia da semana
  switch (diadasemana)
  {
  case 0:lcd.print("Dom");
    break;
  case 1:lcd.print("Seg");
    break;
  case 2:lcd.print("Ter");
    break;
  case 3:lcd.print("Quar");
    break;
  case 4:lcd.print("Qui");
    break;
  case 5:lcd.print("Sex");
    break;
  case 6:lcd.print("Sab");
  }
  lcd.setCursor(6, 1);
  // Acrescenta o 0 (zero) se dia do mes for menor do que 10
  if (diadomes < 10)
    lcd.print("0");
  lcd.print(diadomes);
  lcd.print("/");
  // Acrescenta o 0 (zero) se mes for menor do que 10
  if (mes < 10)
    lcd.print("0");
  lcd.print(mes);
  lcd.print("/");
  lcd.print(ano);
  returningHome2 = HIGH;
}

void SelecionaDataeHora()   //Seta a data e a hora do DS1307
{
  byte segundos = 00; //Valores de 0 a 59
  byte minutos = 20; //Valores de 0 a 59
  byte horas = 12; //Valores de 0 a 23
  byte diadasemana = 1; //Valores de 0 a 6 - 0=Domingo, 1 = Segunda, etc.
  byte diadomes = 1; //Valores de 1 a 31
  byte mes = 5; //Valores de 1 a 12
  byte ano = 17; //Valores de 0 a 99
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(zero); //Stop no CI para que o mesmo possa receber os dados

            //As linhas abaixo escrevem no CI os valores de 
            //data e hora que foram colocados nas variaveis acima
  Wire.write(ConverteParaBCD(segundos));
  Wire.write(ConverteParaBCD(minutos));
  Wire.write(ConverteParaBCD(horas));
  Wire.write(ConverteParaBCD(diadasemana));
  Wire.write(ConverteParaBCD(diadomes));
  Wire.write(ConverteParaBCD(mes));
  Wire.write(ConverteParaBCD(ano));
  Wire.write(zero);
  Wire.endTransmission();
}

byte ConverteParaBCD(byte val)
{
  //Converte o número de decimal para BCD
  return ((val / 10 * 16) + (val % 10));
}

byte ConverteparaDecimal(byte val)
{
  //Converte de BCD para decimal
  return ((val / 16 * 10) + (val % 16));
}

Saber qual a tua definição de doidão seria interessante para poder perceber o que é exactamente o problema.

Assim de repente, a única coisa que me salta à vista é que tu estás sempre a escrever para o lcd em vez de escreveres de 3 em 3 segundos.
Porque não algo deste género:

#define NUM_DISPLAYS   3
unsigned long displayTime = 0; 

void screenManager () {

static unsigned char curDisplay = 0; 

if ((millis() - displayTime) > 3000) {
switch (curDisplay)
case 0: 
          screenHome();
          break;
case 1: 
          screenHome2();
          break;
case 2: 
          screenHome3();
          break; 
}//end switch
displayTime = millis(); 
} //end if 

if (curDisplay++ == NUM_DISPLAYS) curDisplay = 0; 
}

Isto evita também que não possas usar o lcd.clear... o motivo pelo qual pisca não é estares a usar o lcd.clear é mesmo estares a escrever para o LCD repetidamente.

Explica exactamente qual é o problema que vês e talvez te possamos ajudar melhor.

Opa, obrigado pela resposta amigo, vou tentar sua lógica, e tbm vou anexar duas imagens do display, uma mostrando como deveria ficar, e a outra como acaba ficando. Contudo, mto obrigado por tentar me ajudar. :slight_smile:

Olhando um pouco mais, tens outras coisas desnecessárias no teu programa... por exemplo, tu estás continuamente a pedir a hora ao RTC... mas a mesma só muda de segundo a segundo. Aliás, tu nem sequer usas os segundos para mostrar no LCD. Então é também escusado estares sempre a perguntar a hora.

Outra coisa é que podes reduzir a comunicação com o RTC pedindo logo os dados todos duma vez em vez de o fazeres de x em x tempo.

Porque não fazer uma função UpdateTime que vai buscar a data e hora ao RTC para um conjunto de variáveis de segundo a segundo ou de 3 em 3 segundos?

Depois, como não usas o lcd.clear estás a escrever em cima dos dados que estavam já anteriormente no LCD... isso pode dar sarilho apesar de parecer que tu tomaste as precauções devidas.

Logo, o meu conselho é fazeres um update ao LCD apenas de segundo a segundo ou de 3 em 3 segundos (explicado em cima). Usares um lcd.clear quando mudas de tela. Fazeres update da data e hora com apenas uma comunicação com o RTC e fazeres isto de segundo a segundo ou até menos frequentemente já que não estás a mostrar os segundos.

Muito possivelmente o problema é mesmo estares sempre a escrever para o LCD... e tendo em conta que o LCD tem um microcontrolador a passar os dados I2C para o LCD, pode ser aí que dá problemas por teres uma frequência de update muito elevada.

Bom dia amigo. Então, eu consegui usar a sua lógica e deu certinho, ficou assim:

int currentScreen = 0;
static unsigned int numDisplay = 1;

if ((millis() - previousTime) > 3000 )
		{			
			switch (currentScreen)
			{
			case 0: 
				lcd.clear();
				screenHome();
				break;
				
			case 1: 
				lcd.clear();
				screenHome2();
				break;
			}

			if (currentScreen == numDisplay)
			{
				currentScreen = 0;
			}
			else {
				currentScreen++;
			}
			previousTime = millis();
		}

segue o link da imagem de como ficou:
http://ap.imagensbrasil.org/image/jIlJg8

Eu mudei o type da variável curDisplay, pois ñ tava dando certo…
Mas deixa eu te fazer uma pergunta, eu acabei descobrindo pq q o display ficava doidão, veja se eu colocasse esse código:

void screenHome2() 
{
	Wire.beginTransmission(DS1307_ADDRESS);
	Wire.write(zero);
	Wire.endTransmission();
	Wire.requestFrom(DS1307_ADDRESS, 7);
        int diadasemana = ConverteparaDecimal(Wire.read());
	int diadomes = ConverteparaDecimal(Wire.read());
	int mes = ConverteparaDecimal(Wire.read());
	int ano = ConverteparaDecimal(Wire.read());

	lcd.setCursor(3, 0);
	lcd.print("EcoShower");
	lcd.setCursor(2, 1);
	// Mostra o dia da semana
	switch (diadasemana)
	{
	case 0:lcd.print("Dom");
		break;
	case 1:lcd.print("Seg");
		break;
	case 2:lcd.print("Ter");
		break;
	case 3:lcd.print("Quar");
		break;
	case 4:lcd.print("Qui");
		break;
	case 5:lcd.print("Sex");
		break;
	case 6:lcd.print("Sab");
	}
	lcd.setCursor(7, 1);
	// Acrescenta o 0 (zero) se dia do mes for menor do que 10
	if (diadomes < 10)
		lcd.print("0");
	lcd.print(diadomes);
	lcd.print("/");
	// Acrescenta o 0 (zero) se mes for menor do que 10
	if (mes < 10)
		lcd.print("0");
	lcd.print(mes);
	lcd.print("/");
	lcd.print(ano);

AO INVÉS DESSE:

void screenHome2() 
{
	Wire.beginTransmission(DS1307_ADDRESS);
	Wire.write(zero);
	Wire.endTransmission();
	Wire.requestFrom(DS1307_ADDRESS, 7);
	int segundos = ConverteparaDecimal(Wire.read());
	int minutos = ConverteparaDecimal(Wire.read());
	int horas = ConverteparaDecimal(Wire.read() & 0b111111);
	int diadasemana = ConverteparaDecimal(Wire.read());
	int diadomes = ConverteparaDecimal(Wire.read());
	int mes = ConverteparaDecimal(Wire.read());
	int ano = ConverteparaDecimal(Wire.read());

	lcd.setCursor(3, 0);
	lcd.print("EcoShower");
	lcd.setCursor(2, 1);
	// Mostra o dia da semana
	switch (diadasemana)
	{
	case 0:lcd.print("Dom");
		break;
	case 1:lcd.print("Seg");
		break;
	case 2:lcd.print("Ter");
		break;
	case 3:lcd.print("Quar");
		break;
	case 4:lcd.print("Qui");
		break;
	case 5:lcd.print("Sex");
		break;
	case 6:lcd.print("Sab");
	}
	lcd.setCursor(7, 1);
	// Acrescenta o 0 (zero) se dia do mes for menor do que 10
	if (diadomes < 10)
		lcd.print("0");
	lcd.print(diadomes);
	lcd.print("/");
	// Acrescenta o 0 (zero) se mes for menor do que 10
	if (mes < 10)
		lcd.print("0");
	lcd.print(mes);
	lcd.print("/");
	lcd.print(ano);
	
}

O display ficava assim:
http://ap.imagensbrasil.org/image/jIlfuX

o que vc acha que pode ser?já que a única coisa que muda são as variáveis que foram declaradas; segue o bloco que configura a hora e a data:

void SelecionaDataeHora()   //Seta a data e a hora do DS1307
{
	byte segundos = 00; //Valores de 0 a 59
	byte minutos = 51; //Valores de 0 a 59
	byte horas = 7; //Valores de 0 a 23
	byte diadasemana = 3; //Valores de 0 a 6 - 0=Domingo, 1 = Segunda, etc.
	byte diadomes = 3; //Valores de 1 a 31
	byte mes = 5; //Valores de 1 a 12
	byte ano = 17; //Valores de 0 a 99
	Wire.beginTransmission(DS1307_ADDRESS);
	Wire.write(zero); //Stop no CI para que o mesmo possa receber os dados

					  //As linhas abaixo escrevem no CI os valores de 
					  //data e hora que foram colocados nas variaveis acima
	Wire.write(ConverteParaBCD(segundos));
	Wire.write(ConverteParaBCD(minutos));
	Wire.write(ConverteParaBCD(horas));
	Wire.write(ConverteParaBCD(diadasemana));
	Wire.write(ConverteParaBCD(diadomes));
	Wire.write(ConverteParaBCD(mes));
	Wire.write(ConverteParaBCD(ano));
	Wire.write(zero);
	Wire.endTransmission();
}

byte ConverteParaBCD(byte val)
{
	//Converte o número de decimal para BCD
	return ((val / 10 * 16) + (val % 10));
}

byte ConverteparaDecimal(byte val)
{
	//Converte de BCD para decimal
	return ((val / 16 * 10) + (val % 16));
}

ahh!! E eu ñ entendi oq vc falou a respeito de pedir os dados ao RTC de uma vez só, qual seria o ganho nisso? e tbm como faria isso, tipo como eu iria garantir de que as horas e os minutos fossem atualizados apenas UMA vez a cada 1s ou 3s? kkkkk
Aliás, eu já ñ to fazendo isso? Pois como as variáveis que pedem as hrs e os min são inicializadas juntos com as telas home1 e home2, e as telas são iniciadas a cada 3s, então eu já ñ estaria chamando o RTC a cada 3s?

O tipo static na variável curDisplay dá certo quando usado numa função que não a main... o facto de ser char ou int é apenas por uma questão de eficiência. O que é que não estava a dar bem?

Vê a tabela 2 na página 8 deste manual:

https://datasheets.maximintegrated.com/en/ds/DS1307.pdf

No pedaço de código errado estavas a ler os segundos como dia da semana, dia do mês como minutos, mês como horas e ano como o dia da semana. Se tivesses colocado a imagem no primeiro post, isso seria mais do que evidente. :wink:
O problema é que quando envias o valor zero para o RTC antes de leres as variáveis, estás a indicar o endereço da variável que queres começar a ler. Ou seja, segundos.
No teu exemplo que não funciona, se tivesses enviado 3 em vez de zero, os dados retornados estariam correctos.

Seja como for, o meu conselho de teres uma função para ir buscar os dados ao RTC duma só vez mantêm-se e é confirmada pelo que acabaste de ver também.

Ainda bem que o projecto está a funcionar então.

Então, na verdade o que estava dando erro era usar o define para Num_display, pois quando colocava dentro de uma condicional ñ compilava, sla pq....
E a sua idéia de criar uma função para chamar o RTC, seria assim?:

void callTimeAndDate()
{
	Wire.beginTransmission(DS1307_ADDRESS);
	Wire.write(zero);
	Wire.endTransmission();
	Wire.requestFrom(DS1307_ADDRESS, 7);
	int segundos = ConverteparaDecimal(Wire.read());
	int minutos = ConverteparaDecimal(Wire.read());
	int horas = ConverteparaDecimal(Wire.read() & 0b111111);
	int diadasemana = ConverteparaDecimal(Wire.read());
	int diadomes = ConverteparaDecimal(Wire.read());
	int mes = ConverteparaDecimal(Wire.read());
	int ano = ConverteparaDecimal(Wire.read());
}

Se for, como que eu iria usar as variáveis que estão dentro desta função?
tipo eu tentei fazer assim pra tentar pegar o valor de uma das variáveis após chamar essa função lá no screenManeger(), porém ñ deu certo:

callTimeAndDate().diadasemana

Não... isso não funciona porque as variáveis são locais à função callTimeAndDate().

O melhor é criar as variáveis de forma global

int segundos;
int minutos;
int horas;
int diadasemana;
int diadomes;
int mes;
int ano;

A função ficaria então assim.

void callTimeAndDate()
{
	Wire.beginTransmission(DS1307_ADDRESS);
	Wire.write(zero);
	Wire.endTransmission();
	Wire.requestFrom(DS1307_ADDRESS, 7);
	segundos = ConverteparaDecimal(Wire.read());
	minutos = ConverteparaDecimal(Wire.read());
	horas = ConverteparaDecimal(Wire.read() & 0b111111);
	diadasemana = ConverteparaDecimal(Wire.read());
	diadomes = ConverteparaDecimal(Wire.read());
	mes = ConverteparaDecimal(Wire.read());
	ano = ConverteparaDecimal(Wire.read());
}

O #define não é uma variável... logo não podes atribuir valor.

Se as variáveis forem globais como a variável "previousTime" ou a variável "zero", podes usá-las como meti na função acima.

Sim, sim eu viajei na minha duvida das variáveis...kkkkkk Obrigado amigo, vc me ajudou pra caramba, vlw pelo seu tempo

Na boa.

Para a próxima sê mais explicito no problema que estás a ter em vez de dizer que fica doidão e a ajuda poderá ser bastante mais rápida. :wink: