O display 16×2 LCD é barato e relativamente fácil de usar. Entretanto, em alguns casos, os caracteres desenhados podem parecer pequenos, ainda mais se vistos de longe. Sendo assim, neste post, mostrarei um código que desenha os caracteres maiores.

Se você quiser aprender a utilizar o display 16×2, veja este post.

Informações básicas

O que é o projeto

Normalmente, cada caractere no display 16×2 ocupa 1 linha e 1 coluna. E a ideia deste projeto é desenhá-los ocupando 2 linhas e 3 colunas igual mostra a imagem abaixo:

Display 16x2 com fonte grande

No tópico adiante, explicarei como isso será feito. Mas preciso deixar claro que a concepção original não é minha. Na realidade, o que fiz foi estruturar o código de uma forma mais otimizada (na minha visão) e criar funções para facilitar o seu uso. O projeto que utilizei como referência pode ser visto neste link.

Criação dos caracteres grandes

Dentro de cada quadrado do display 16×2, existem outros quadradinhos (pixels) formando 5 colunas e 8 linhas. E é possível criar nossos próprios símbolos personalizados desenhando nestes 5×8 pixels. Neste post, ensino a criar estes símbolos customizados.

A criação dos símbolos consiste em escrever na memória do display qual é o desenho do símbolo que queremos. E o display consegue armazenar no máximo 8 símbolos. Ou seja, fica bem complicado criar uma fonte grande para as 26 letras do alfabeto e os 10 digitos (0 a 9). Portanto, teremos que reaproveitar muitos símbolos.

Por sorte, o autor (mpilchfamily) do post de onde tirei a referência, encontrou um conjunto de 8 símbolos que permitem escrever todo o alfabeto e todos os digitos. Veja estes símbolos abaixo:

Fonte: mpilchfamily

Com isto em mente, desenvolvi um código com três funções facilitadoras que veremos adiante.

Obs: Como no post de referência só havia o desenho de algumas letras, acabei improvisando as demais e acho que o resultado ficou satisfatório. Além das letras e dígitos, implementei alguns caracteres especiais, como a exclamação e o ponto.

Como usar a fonte grande no display 16x2

Circuito

Vou utilizar um shield de display 16×2, mas, se você for usar o display diretamente, abaixo está um exemplo de como ligá-lo ao Arduino.

circuito display lcd

Alteração no código

Dependendo de como você ligou o display, você precisa alterar as linhas 8 a 13 do código:

#define DISPLAY_RS 8
#define DISPLAY_EN 9
#define DISPLAY_D4 4
#define DISPLAY_D5 5
#define DISPLAY_D6 6
#define DISPLAY_D7 7

Basta alterar o número no final do “#define” para corresponder ao número do pino que você ligou cada entrada do display. A correspondência acima se refere ao shield. No caso da ligação que mostrei anteriormente, o certo seria:

#define DISPLAY_RS 12
#define DISPLAY_EN 11
#define DISPLAY_D4 5
#define DISPLAY_D5 4
#define DISPLAY_D6 3
#define DISPLAY_D7 2

Comandos disponíveis

Adiante estão listados os comandos que criei para facilitar o uso da fonte grande.

  • display_init();
    • Deve ser chamado no “void setup” para iniciar o display e criar os símbolos.
  • display_special_print(texto, cursor);
    • Imprime no display um texto utilizando a fonte grande.
    • O primeiro parâmetro é o texto desejado e o segundo indica a coluna que você quer escrever o texto (0 a 15).
    • Exemplo: display_special_print(“teste”, 2);
  • display_special_scroll(texto, delay);
    • Imprime um texto grande no display que “anda” da direta para a esquerda.
    • O primeiro parâmetro é o texto desejado e o segundo é o tempo (em milissegundos) entre cada movimento do texto.
    • Exemplo: display_special_scroll(“Texto deslocando”, 400);

Caracteres disponíveis

As 26 letras do alfabeto e os 10 dígitos (0 a 9) podem ser usados sem problemas. Além deles, alguns símbolos também estão disponíveis, são eles:

! ” # $ % & ‘ ( )  * + ,  – . /

No caso, estes símbolos ocupam 2 linhas e 1 coluna ao contrário das letras e números.

As letras com acento não estão disponíveis e nem o ç.

Código completo

Abaixo está o código completo com as funções desenvolvidas. E já coloquei no “void setup” a função de inicialização, além da função de “andar” com o texto no “void loop” para exemplificar.

O ideal seria cria uma biblioteca com estas funções, mas pra facilitar o uso, resolvi colocar tudo em um código só.

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
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
// ----- Bibliotecas -----
#include <LiquidCrystal.h>
#include <avr/pgmspace.h>


// ----- Definições -----
// Pinos do display
#define DISPLAY_RS  8
#define DISPLAY_EN  9
#define DISPLAY_D4  4
#define DISPLAY_D5  5
#define DISPLAY_D6  6
#define DISPLAY_D7  7


// ----- Variáveis globais -----
LiquidCrystal lcd(DISPLAY_RS, DISPLAY_EN, DISPLAY_D4, DISPLAY_D5, DISPLAY_D6, DISPLAY_D7);


// Símbolos
const uint8_t display_fonte_desenhos[][8] PROGMEM  = {
// Formato 0
  {0b00111,
   0b01111,
   0b11111,
   0b11111,
   0b11111,
   0b11111,
   0b11111,
   0b11111},
// Formato 1
  {0b11111,
   0b11111,
   0b11111,
   0b00000,
   0b00000,
   0b00000,
   0b11111,
   0b11111},
// Formato 2
  {0b11100,
   0b11110,
   0b11111,
   0b11111,
   0b11111,
   0b11111,
   0b11111,
   0b11111},
// Formato 3
  {0b11111,
   0b11111,
   0b11111,
   0b00000,
   0b00000,
   0b00000,
   0b00000,
   0b00000},
// Formato 4
  {0b11111,
   0b11111,
   0b11111,
   0b11111,
   0b11111,
   0b11111,
   0b01111,
   0b00111},
// Formato 5
  {0b11111,
   0b00000,
   0b00000,
   0b00000,
   0b00000,
   0b11111,
   0b11111,
   0b11111},
// Formato 6
  {0b11111,
   0b11111,
   0b11111,
   0b11111,
   0b11111,
   0b11111,
   0b11110,
   0b11100},
// Formato 7
  {0b00000,
   0b00000,
   0b00000,
   0b00000,
   0b00000,
   0b11111,
   0b11111,
   0b11111},
};


// Valores iguais a 8 serão espaços nulos e 255 serão caracteres totalmente preenchidos
// Índice dos desenhos de cada letra organizadas alfabeticamente
const uint8_t display_fonte_letras[26][6] = {{0,1,2,4,3,6},     // A
                                             {255,1,2,255,1,6}, // B
                                             {0,3,3,4,7,7},     // C
                                             {255,3,2,255,7,6}, // D
                                             {0,1,1,4,1,1},     // E
                                             {0,1,1,4,8,8},     // F
                                             {0,3,3,4,7,2},     // G
                                             {0,8,2,4,3,6},     // H
                                             {3,255,3,7,255,7}, // I
                                             {3,3,255,4,7,255}, // J
                                             {0,7,6,4,3,2},     // K
                                             {255,8,8,4,7,7},   // L
                                             {2,7,0,255,8,255}, // M
                                             {2,7,7,255,8,255}, // N
                                             {255,3,255,255,7,255}, // O
                                             {0,1,2,255,8,8},   // P
                                             {0,3,2,4,7,1},     // Q
                                             {0,1,2,4,8,2},     // R
                                             {0,1,1,7,5,6},     // S
                                             {3,255,3,8,255,8}, // T
                                             {255,8,255,4,7,6}, // U
                                             {2,8,0,4,7,6},     // V
                                             {2,7,0,255,255,255},  // W
                                             {2,7,0,6,3,4},     // X
                                             {2,7,0,8,255,8},   // Y
                                             {3,1,2,4,5,7},     // Z
                                            };
                                           
// Índice dos desenhos de cada número organizados em ordem crescente                                      
const uint8_t display_fonte_numeros[10][6] = {{0,3,2,4,7,6},  // 0
                                              {8,3,2,8,8,255},// 1
                                              {1,1,2,4,5,5},  // 2
                                              {1,1,2,1,1,6},  // 3
                                              {0,7,2,8,8,6},  // 4
                                              {255,1,1,5,5,6},// 5
                                              {0,1,1,4,5,6},  // 6
                                              {3,3,2,8,8,6},  // 7
                                              {0,1,2,4,5,6},  // 8
                                              {0,1,2,7,7,6}   // 9
                                             };

// Índice dos desenhos dos símbolos especiais organizados segundo a tabela ASCII                              
const uint8_t display_fonte_especiais[16][6] = {{8,8},    // ESPAÇO
                                                {255,5},  // !
                                                {2,8},    // "
                                                {35,8},   // #
                                                {36,36},  // $
                                                {37,8},   // %
                                                {38,8},   // &
                                                {2,8},    // '
                                                {0,4},    // (
                                                {2,6},    // )
                                                {42,8},   // *
                                                {43,8},   // +
                                                {8,6},    // ,
                                                {7,3},    // -
                                                {8,7},    // .
                                                {47,8},   // /
                                               };


// ----- Protótipo das funções -----
void display_init();
void display_special_print(char * text, uint8_t cursor);
void display_special_scroll(char * text, uint16_t delay_ms);


void setup()
{
  display_init();
}

void loop()
{
  display_special_scroll("Mundo Projetado", 400);
}


/*
 * Inicializa o display e cria os símbolos
 */

void display_init()
{
  uint8_t i, j;
  uint8_t simb[8];
 
  lcd.begin(16, 2);

  // Cria os símbolos
  for(i = 0; i < 8; i++)
  {
 
    for(j = 0; j < 8; j++)
    {
      simb[j] = pgm_read_byte_near(display_fonte_desenhos[i] + j);
    }
 
    lcd.createChar(i, simb);
  }
}


/*
 * Imprime um conjunto de caracteres utilizando uma fonte 2x3
 * Parâmetros:
 *  text - Conjunto de caracteres
 *  cursor - Coluna onde o texto deve ser impresso (0 a 15)
 */

void display_special_print(char * text, uint8_t cursor)
{
  uint8_t i, j, carac, idx;

  // Percorre por todos os pontos
  for(i = 0; *(text+i) != 0; i++)
  {
    // Lê o caractere
    carac = *(text+i);

    // Se o cursor chegou ao fim, sai do for
    if(cursor > 15)
    {
      break;
    }

    // ----- Identifica o tipo do caractere -----

    // Número
    if(carac >= 48 && carac < 58)
    {
      carac -= 48;

      // Aqui 'carac' vale de 0 a 9 (indice em ordem crescente)
      for(j = 0; j < 6; j++)
      {
        idx = display_fonte_numeros[carac][j];
 
        if(j < 3)
        {
          lcd.setCursor(cursor + j, 0);
        }
        else
        {
          lcd.setCursor(cursor + j%3, 1);
        }
       
        // Índice 8 é um espaço vazio
        if(idx == 8)
        {
          lcd.print(" ");
        }
        else
        {
          lcd.write(idx);
        }
      }

      cursor += 3;
    }

    // Caracteres especiais
    else if(carac >= 32 && carac < 48)
    {
      carac -= 32;

      // Aqui 'carac' vale de 0 a 15
      for(j = 0; j < 2; j++)
      {
        idx = display_fonte_especiais[carac][j];
 
        lcd.setCursor(cursor, j);
       
        // Índice 8 é um espaço vazio
        if(idx == 8)
        {
          lcd.print(" ");
        }
        else
        {
          lcd.write(idx);
        }
      }

      cursor += 1;
    }

    // Letra:
    else
    {
      // Letras minúsculas
      if(carac >= 97 && carac < 123)
      {
        carac -= 97;
      }
      // Letras maiusculas
      else if(carac >= 65 && carac < 91)
      {
        carac -= 65;
      }
 
      // Aqui 'carac' vale de 0 a 25 (indice em ordem alfabetica)
      for(j = 0; j < 6; j++)
      {
        idx = display_fonte_letras[carac][j];
 
        if(j < 3)
        {
          lcd.setCursor(cursor + j, 0);
        }
        else
        {
          lcd.setCursor(cursor + j%3, 1);
        }

        // Índice 8 é um espaço vazio
        if(idx == 8)
        {
          lcd.print(" ");
        }
        else
        {
          lcd.write(idx);
        }
      }
     
      cursor += 3;
    }
  }
}


/*
 * Cria um texto que se desloca da direta pra esquerda
 * Parâmetros:
 *  text - Conjunto de caracteres
 *  delay_ms - Delay do deslocamento
 */

void display_special_scroll(char * text, uint16_t delay_ms)
{
  uint8_t len, i;
  uint8_t cursor = 12;

  // Calcula o tamanho completo do texto (tamanho max de 254)
  for(len = 0; len < 254; len++)
  {
    if(*(text+len) == 0)
    {
      break;
    }
  }
  // Aqui len = tamanho do texto

  for(i = 0; i < len + 4; i++)
  {
    lcd.clear();

    if(cursor > 0)
    {
      display_special_print(text, cursor);
      cursor -= 3;
    }
    else
    {
      display_special_print(text+i-4, 0);
    }

    delay(delay_ms);
  }
  lcd.clear();
}

Resultado

Veja o código anterior em funcionamento: