27 abril 2013

LCD 16x2 + RTC + Numeros Grandes

Resolvi incrementar o post que eu fiz, sobre o LCD 16x2 (Display LCD Winstar WH1602A), e coloca-lo para funcionar com o DS1307 (RTC), do artigo anterior. A idéia foi juntar os 2 circuitos, e fazer um relógio mostrando os números, obviamente, no LCD.

Como eu não fiquei contente com o resultado, porque os números ficaram muito pequenos no LCD, comecei a caçar exemplos para aproveitar a tela inteira e mostrar os números em um formato maior, criando meu próprio programa. O resultado está aqui :

Relogio RTC DS1307 Arduino

RTC DS1307 - LCD 16x2


Se voce tiver dúvidas no circuito, recomendo a leitura dos posts mencionados, porque a ligação é exatamente a mesma. Vamos lá :
 
relogio Arduino DS1307
Carregue o seguinte programa no Arduino :

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
//Programa : Relogio com numeros customizados
//Autor : Arduino e Cia

#include <LiquidCrystal.h> //Biblioteca LCD

#include "Wire.h" //Biblioteca para uso do RTC DS1307

#define DS1307_ADDRESS 0x68

byte zero = 0x00; 

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

int numero, minutoanterior1,minutoanterior2,horaanterior1,horaanterior2;
int x = 0;

//Arrays para criação dos segmentos e customização dos números
byte LT[8] = 
{
  B01111,  B11111,  B11111,  B11111,  B11111,  B11111,  B11111,  B11111
};
byte UB[8] =
{
  B11111,  B11111,  B11111,  B00000,  B00000,  B00000,  B00000,  B00000
};
byte RT[8] =
{
  B11110,  B11111,  B11111,  B11111,  B11111,  B11111,  B11111,  B11111
};
byte LL[8] =
{
  B11111,  B11111,  B11111,  B11111,  B11111,  B11111,  B11111,  B01111
};
byte LB[8] =
{
  B00000,  B00000,  B00000,  B00000,  B00000,  B11111,  B11111,  B11111
};
byte LR[8] =
{
  B11111,  B11111,  B11111,  B11111,  B11111,  B11111,  B11111,  B11110
};
byte UMB[8] =
{
  B11111,  B11111,  B11111,  B00000,  B00000,  B00000,  B11111,  B11111
};
byte LMB[8] =
{
  B11111,  B00000,  B00000,  B00000,  B00000,  B11111,  B11111,  B11111
};

void setup()
{
  Wire.begin();
  //Associa cada segmento criado, a um número
  lcd.createChar(0,LT);
  lcd.createChar(1,UB);
  lcd.createChar(2,RT);
  lcd.createChar(3,LL);
  lcd.createChar(4,LB);
  lcd.createChar(5,LR);
  lcd.createChar(6,UMB);
  lcd.createChar(7,LMB);

  lcd.begin(16, 2); //Inicializa o LCD

  //A linha abaixo pode ser retirada apos setar a data e hora
  //SelecionaDataeHora(); 
}

void loop()
{
  lcd.setCursor(8,0);
  lcd.print(".");
  lcd.setCursor(8,1);
  lcd.print(".");
  //Chama rotina que extrai as informacoes do DS1307 e mostra no LCD
  Mostrarelogio(); 
  delay(1000);
}

void SelecionaDataeHora()   //Seta a data e a hora do DS1307
{
  byte segundos = 00; //Valores de 0 a 59
  byte minutos = 44; //Valores de 0 a 59
  byte horas = 22; //Valores de 0 a 23
  byte diadasemana = 1; //Valores de 0 a 6 - 0=Domgino, 1 = Segunda, etc.
  byte diadomes = 17; //Valores de 1 a 31
  byte mes = 4; //Valores de 1 a 12
  byte ano = 13; //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); //Start no CI
  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) );
}

void custom0()//Seleciona os segmentos para formar o numero 0
{ 
  lcd.setCursor(x, 0); //Seleciona a linha superior
  lcd.write((byte)0);  //Segmento 0 selecionado
  lcd.write(1);  //Segmento 1 selecionado
  lcd.write(2);
  lcd.setCursor(x, 1); //Seleciona a linha inferior
  lcd.write(3);  
  lcd.write(4);  
  lcd.write(5);
}

void custom1() //Seleciona os segmentos para formar o numero 1
{
  lcd.setCursor(x,0);
  lcd.write(1);
  lcd.write(2);
  lcd.setCursor(x+1,1);
  lcd.write(5);
}

void custom2() //Seleciona os segmentos para formar o numero 2
{
  lcd.setCursor(x,0);
  lcd.write(6);
  lcd.write(6);
  lcd.write(2);
  lcd.setCursor(x, 1);
  lcd.write(3);
  lcd.write(7);
  lcd.write(7);
}

void custom3()  //Seleciona os segmentos para formar o numero 3
{
  lcd.setCursor(x,0);
  lcd.write(6);
  lcd.write(6);
  lcd.write(2);
  lcd.setCursor(x, 1);
  lcd.write(7);
  lcd.write(7);
  lcd.write(5); 
}

void custom4()  //Seleciona os segmentos para formar o numero 4
{
  lcd.setCursor(x,0);
  lcd.write(3);
  lcd.write(4);
  lcd.write(2);
  lcd.setCursor(x+2, 1);
  lcd.write(5);
}

void custom5()  //Seleciona os segmentos para formar o numero 5
{
  lcd.setCursor(x,0);
  lcd.write((byte)0);
  lcd.write(6);
  lcd.write(6);
  lcd.setCursor(x, 1);
  lcd.write(7);
  lcd.write(7);
  lcd.write(5);
}

void custom6()  //Seleciona os segmentos para formar o numero 6
{
  lcd.setCursor(x,0);
  lcd.write((byte)0);
  lcd.write(6);
  lcd.write(6);
  lcd.setCursor(x, 1);
  lcd.write(3);
  lcd.write(7);
  lcd.write(5);
}

void custom7() //Seleciona os segmentos para formar o numero 7
{
  lcd.setCursor(x,0);
  lcd.write(1);
  lcd.write(1);
  lcd.write(2);
  lcd.setCursor(x+1, 1);
  lcd.write((byte)0);
}

void custom8()  //Seleciona os segmentos para formar o numero 8
{
  lcd.setCursor(x,0);
  lcd.write((byte)0);
  lcd.write((byte)6);
  lcd.write(2);
  lcd.setCursor(x, 1);
  lcd.write(3);
  lcd.write(7);
  lcd.write(5);
}

void custom9()  //Seleciona os segmentos para formar o numero 9
{
  lcd.setCursor(x,0);
  lcd.write((byte)0);
  lcd.write((byte)6);
  lcd.write((byte)2);
  lcd.setCursor(x+2, 1);
  lcd.write((byte)5);
}

void Mostrarelogio()
{
  byte minut[2];
  String minutostring;
  String digitosegundos;
  char buf;
  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());

  x = 0;
  numero = horas/10;
  
  //Condicional para evitar sobreposição de caracteres
  if (horaanterior1 != minutos %10) 
  {
    lcd.setCursor(0,0);
    lcd.print("   ");
    lcd.setCursor(0,1);
    lcd.print("   ");
    horaanterior1 = minutos %10;
  }

  //Chama rotina que mostra o numero customizado na tela
  mostranumero(); 

  x = 4;
  numero = horas % 10;
  if (horaanterior2 != minutos %10)
  {
    lcd.setCursor(4,0);
    lcd.print("   ");
    lcd.setCursor(4,1);
    lcd.print("   ");
    horaanterior2 = minutos %10;
  }
  mostranumero();
  
  x = 9;
  numero = minutos/10;

  if (minutoanterior1 != minutos %10)
  {
    lcd.setCursor(9,0);
    lcd.print("   ");
    lcd.setCursor(9,1);
    lcd.print("   ");
    minutoanterior1 = minutos %10;
  }
  mostranumero();

  x = 13;
  numero = minutos % 10;
  if (minutoanterior2 != minutos %10)
  {
    lcd.setCursor(13,0);
    lcd.print("   ");
    lcd.setCursor(13,1);
    lcd.print("   ");
    minutoanterior2 = minutos %10;
  }
  mostranumero();
}

void mostranumero() //Mostra o numero na posicao definida por "X"
{
  switch(numero)
    {
      case 0:custom0();
      break;
      case 1:custom1();
      break;
      case 2:custom2();
      break;
      case 3:custom3();
      break;
      case 4:custom4();
      break;
      case 5:custom5();
      break;
      case 6:custom6();
      break;
      case 7:custom7();
      break;
      case 8:custom8();
      break;
      case 9:custom9();
      break;
    }
}

O que o programa faz é criar blocos customizaveis, que vão formar os números grandes. Depois, associamos essas blocos conforme o caracter a ser gerado, assim, o número 1 será formado pelos blocos 1 (UB), 2 (RT), e 5 (LR), o número 2 será formado pelos blocos 6 (UMB), 6(UMB), 1(UB), 3(LL), 7(LMB) e 7(LMB) e assim por diante. É praticamente um quebra-cabeça, mas mais divertido. :-)

 Tente alterar essas linhas (byte UB[8], byte LT[8].....) para modificar o segmento e obter outros efeitos, como cantos retos, mais arredondados, etc.

Uma evolução do programa seria mostrar também a data, de tempos em tempos, ou ao toque de um botão, ou então usar esses blocos para montar as letras do alfabeto. Mas isso é assunto para outro post. Até lá !

16 comentários:

  1. tem como vc me explicar mais sobre a criação dos blocos customizáveis ? o que são esses blocos mostrando no lcd?

    ResponderExcluir
    Respostas
    1. Oi Lailla,

      Os displays LCD tem 8 posições de memória para que você crie blocos customizáveis, ou, se preferir, caracteres customizáveis. Eu já usei aqui no Arduino e Cia para desenhar, por exemplo, o simbolo de "grau" em sensores de temperatura. Mudando os 0s e 1s dos arrays, você pode criar os caracteres de sua preferencia (seta, sorriso, etc).

      Abraço !

      Excluir
  2. Olá, gostaria de saber como ficaria a programação sem o RTC. Utilizando somente os delays do micro do arduino.

    ResponderExcluir
    Respostas
    1. Boa tarde,

      Boa sugestão. Pode ser feito sim, vou estudar o assunto e tentar fazer um novo post sobre isso.

      Abraço !

      Excluir
  3. Respostas
    1. Boa noite Sidnei,

      O %10 é usado para calcular o "módulo" de uma divisão, ou seja, o resto de um número dividido pelo outro. No programa, eu uso o %10 para separar os números da hora, por exemplo. Vamos supor que eu tenha o valor 17, e quero separar o 1 e o 7. Para calcular isso, eu faço :

      primeiro_digito_hora = 17 / 10 = 1 (estou trabalhando apenas com números inteiros)
      segundo_digito_hora =17 % 10 = 7

      Você pode encontrar mais informações sobre como utilizar a função % (modulo) com Arduino nesse link : http://arduino.cc/en/Reference/Modulo

      Abraço !

      Excluir
  4. Amigo não entendi como vincular os blocos de caracteres aos algarismos..
    Exmplo. Estou fazendo um controlador de temperatura e usando um LCD para mostrar a temperatura gostaria de usar os números em blocos de caracteres como usados por vc no post.. Como fazer isso?

    ResponderExcluir
    Respostas
    1. Boa noite Ed,

      Defina o numero e chame a rotina mostranumero(). Fica mais ou menos assim:

      numero = temperatura_lida;
      mostranumero()

      Claro, vc vai precisar separar os digitos da temperatura lida, digamos que voce mediu a temperatura e ela é de 25 graus.

      //primeiro digito, defina como inteiro para ele pegar apenas o numero 2 na divisao
      numero = temperatura/10;
      mostranumero();
      //segundo digito, pega apenas o resto da divisao por 10, ou seja, 5
      numero = temperatura%10;
      mostranumero();

      Basicamente é isso.

      Abraço !

      Excluir
  5. Olá. não consigo acertar o relógio, mesmo alterando os valores nas linhas que é para setar o mesmo.

    ResponderExcluir
    Respostas
    1. Oi Odilon,

      Estranho. ele fica com qual horário ? 00:00 ?

      Abraço.

      Excluir
    2. Olá bom dia. desculpe a demora para o retorno.
      o relógio fica com a hora do módulo rtc. no caso ficou 04:02

      Excluir
  6. Usei este exemplo no Display LCD 20x4, mas não consigo fazer funcionar.
    usei as bibliotecas:
    #include Wire.h
    #include LCD.h
    #include LiquidCrystal_I2C.h

    Inicializacao do display
    LiquidCrystal_I2C lcd(0x3F,2,1,0,4,5,6,7,3, POSITIVE);

    Aqui funciona as informações na tela, mas para uso do código do
    "LCD 16x2 + RTC + Numeros Grandes " - não consigo fazer funcionar.

    ResponderExcluir
    Respostas
    1. Boa noite Nilton,

      Você chegou a testar com um LCD 16x2 ?

      Abraço!

      Excluir
  7. Não, porque tenho somente o LCD 20x4.
    Gostaria de concluir este projeto no 20x4

    ResponderExcluir
  8. O único problema que é que não achei como ver a data , s´mostra a Hora

    ResponderExcluir
    Respostas
    1. Oi Ecio,

      Realmente, eu coloquei essa opção no programa, mas não cheguei a mostrar na tela. Talvez um botão para alternar entre hora/data seja uma boa opção. :)

      Abraço!

      Excluir