13 junho 2019

Como mostrar números grandes no display LCD I2C

Hoje eu mostro uma nova versão de um post que eu publiquei à algum tempo onde eu usei um display LCD 16x2 para mostrar números grandes que ocupavam as duas linhas do display. Aqui, vou usar o mesmo princípio para mostrar como fazer isso em um display LCD 16x2 I2C.

Como mostrar numeros grandes no display LCD 16x2

Neste post, uso então o display mencionado juntamente com uma placa Arduino Uno e um sensor DHT11 para mostrar as informações de temperatura e umidade em intervalos regulares.


Material usado


Nesse projeto vamos usar o seguinte material:


Coloquei na lista o LCD 16x2 I2C mas você também pode montar o projeto com display LCD 20x4 I2C realizando pequenas modificações no programa como veremos mais adiante.

Circuito LCD 16x2 I2C com Arduino Uno e DHT11


A conexão do display e dos sensores será feita conforme a imagem abaixo. O sensor de temperatura DHT11 está conectado na porta digital 7 do Arduino e o display I2C nos pinos analógicos A4 (SDA) e A5 (SCL)

Circuito Arduino Uno DHT11 e LCD 16x2 I2C


A alimentação tanto do display como do sensor de temperatura DHT11 é feita por meio do pino 5V do Arduino.

Verificando o endereço I2C do display


Antes de partir para o programa, vamos descobrir o endereço I2C do display que estamos usando para evitar erros no funcionamento do projeto, sendo o mais comum deles justamente a configuração incorreta do endereço I2C.

Carregue o programa abaixo (I2C_Scanner) no Arduino. Ele faz uma varredura no barramento I2C e lista os dispositivos que foram detectados.

 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
//Programa: I2CScanner - Escaneamento de barramento I2C

#include <Wire.h>

void setup()
{
  Wire.begin();
  Serial.begin(9600);
  Serial.println("\nI2C Scanner");
}

void loop()
{
  byte error, address;
  int nDevices;

  Serial.println("Scanning...");
  nDevices = 0;
  for(address = 1; address < 127; address++ ) 
  {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
    if (error == 0)
    {
      Serial.print("Dispositivo I2C encontrado no endereco 0x");
      if (address<16) 
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");

      nDevices++;
    }
    else if (error==4) 
    {
      Serial.print("Erro desconhecido no endereco 0x");
      if (address<16) 
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("Nenhum dispositivo I2C encontrado\n");
  else
    Serial.println("Concluido. Novo escaneamento em 5 segundos...\n");

  delay(5000);           // wait 5 seconds for next scan
}

Confira o endereço I2C do dispositivo no Serial Monitor:

Serial Monitor Endereço I2C Display LCD



Guarde o endereço que foi mostrado no Serial Monitor pois vamos utilizá-lo no nosso programa. No caso, o endereço detectado foi o 0x3B.

Bibliotecas e programa LCD I2C com números grandes


No programa vamos usar as bibliotecas DHT11 e LiquidCrystal_I2C, e ambas podem ser instaladas a partir da própria IDE do Arduino no menu Sketch -> Incluir Biblioteca -> Gerenciar Bibliotecas.

Na janela do gerenciador de bibliotecas, procure por DHT11 e selecione a biblioteca DHT Sensor Library by Adafruit e clique em Instalar, conforme a imagem abaixo:

Instalacao biblioteca DHT IDE Arduino


Faça o mesmo para a biblioteca LiquidCrystalI2C:

Instalacao biblioteca LiquidCrystalI2C IDE Arduino



Todo mundo que já usou um display LCD 16x2 sabe que podemos mostrar na tela letras, números e caracteres especiais nas suas duas linhas, e esse é o uso mais comum desse tipo de componente.

O que o programa faz é criar blocos customizáveis que vão formar os números, onde cada número vai ocupar uma parte da linha superior e uma parte da linha inferior do display. Assim o número 1 por exemplo, será formado pelos blocos 1 (UB), 2 (RT), e 5 (LR). Você pode alterar esses blocos para criar sua própria "fonte" e usar números com cantos mais retos ou mais arredondados ou até letras, dependendo da necessidade.

Carregue o programa abaixo no Arduino, tomando o cuidado de configurar na linha 07 o endereço I2C que vimos lá no Serial Monitor, lembra? :)

Na linha 07 você também define o tipo de display LCD que você está usando. No nosso caso, estamos usando um LCD 16x2 (16 linhas e 2 colunas). Se você optar por um display LCD 20x4 por exemplo, a linha ficaria:

LiquidCrystal_I2C lcd(0x3B, 20, 4);

Depois de tudo isso, o programa ficou assim:

  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
//Programa: LCD 16x2 I2C Numeros Grandes com DHT11
//Autor: Arduino e Cia

#include <DHT.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3B, 16, 2);

//Pino digital ligado ao pino DATA do DHT11
#define DHTPIN 7
#define DHTTYPE DHT11

DHT dht(DHTPIN, DHTTYPE);

int x, numero;
int intervalo = 3000;

//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()
{
  Serial.begin(9600);
  lcd.init();
  lcd.backlight();
  //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);

  //Inicializa o Sensor de Temperatura DHT11
  dht.begin();
}

void loop()
{
  //Leitura da temperatura e umidade
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  //Mostra as informacoes no Serial Monitor
  Serial.print(F("Temperatura: "));
  Serial.print(t, 0);
  Serial.print(F("°C - Umidade: "));
  Serial.print(h, 0);
  Serial.println(F(" %"));

  //Mostra temperatura no display
  MostraTemperatura(t);
  //Aguarda o intervalo
  delay(intervalo);
  //Mostra a umidade no display
  MostraUmidade(h);
  delay(intervalo);
}

void MostraTemperatura(int temperatura)
{
  lcd.clear();
  lcd.setCursor(12, 0);
  lcd.print("o");

  //Primeiro digito da temperatura
  x = 4;
  numero = temperatura / 10;
  mostranumero();

  //Primeiro digito da temperatura
  x = 8;
  numero = temperatura % 10;
  mostranumero();
}

void MostraUmidade(int umidade)
{
  lcd.clear();
  lcd.setCursor(12, 0);
  lcd.print("%");

  //Primeiro digito da umidade
  x = 4;
  numero = umidade / 10;
  mostranumero();

  //Segundo digito da umidade
  x = 8;
  numero = umidade % 10;
  mostranumero();
}

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 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;
  }
}

Pronto. Assim que for carregado, o programa vai mostrar os valores de temperatura e umidade lidos pelo sensor DHT11, alternando esses valores no display a cada 3 segundos. Na linha 16 a variável intervalo (configurada em milisegundos) armazena justamente esse tempo entre as trocas do display.

Um comentário: