Os LCDs (Liquid-Crystal Display) são módulos simples de serem conectados aos microcontroladores, sendo assim muito úteis em projetos que necessitam de uma comunicação com o usuário. Os LCDs mais comuns possuem 16 colunas por 2 linhas, normalmente indicados por 16×2 ou 1602 e podem possuir 14 ou 16 pinos, sem e com backlight (luz de fundo) respectivamente e são equipados com um controlador compatível com o chip HD44780 da Hitachi. E é exatamente este modelo que vamos ver a seguir.

Disposição das Linhas e Colunas
Tomando como exemplo um display de 16×2, a disposição dos caracteres estão numa matriz com as colunas numeradas de 0 a 15 e linhas numeradas 0 e 1.

Pinos
A numeração e descrição dos pinos:
| Pino | Descrição | |
| 1 | VSS | GND (terra) |
| 2 | VDD | +5V |
| 3 | VO | Ajuste do contraste – utilizar com um resistor fixo ou variável (potenciômetro ou trimpot) |
| 4 | RS | Register Select – sinaliza a instrução ou caractere que está sendo escrito (linha de controle) |
| 5 | R/W | Read/Write – sinaliza ao microcontrolador do LCD se a operação é de escrita ou gravação (linha de controle) |
| 6 | Enable | Ativação do LCD – se nível baixo, ignora RS e R/W (linha de controle) |
| 7 | D0 | Linha de dado |
| 8 | D1 | Linha de dado |
| 9 | D2 | Linha de dado |
| 10 | D3 | Linha de dado |
| 11 | D4 | Linha de dado |
| 12 | D5 | Linha de dado |
| 13 | D6 | Linha de dado |
| 14 | D7 | Linha de dado |
| 15 | LED + | backlight (anodo) +5V |
| 16 | LED – | backlight (catodo) GND |
Nos LCDs sem backlight não temos os pinos 15 e 16.
Módulo I2C para LCD
Uma outra opção, bem mais interessante, é a utilizar um módulo I2C acoplado ao display LCD, como o da figura a seguir.

Este módulo conta com um trimpot para ajuste do contraste e um jumper para ligar/desligar o LED de luz de fundo (backlight). Porém, podemos ligar e desligar este LED por software.

I2C
I2C (IIC – Inter Integrated Circuit) é um barramento de comunicação desenvolvido pela Philips, hoje NXP Semiconductors, para permitir troca de dados entre os componentes que residem na mesma placa de circuito impresso. A vantagem de usar este tipo de barramento é que precisamos de apenas dois pinos para comunicação, além do pino de alimentação (5V) e o pino terra (GND).
Este módulo em específico possui o chip PCF8574.
Vamos usar a biblioteca Wire (nativa no software Arduino) para facilitar o desenvolvimento com o protocolo I2C. Os dois fios de comunicação são conhecidos por SDA (Serial Data Line) e SCL (Serial Clock Line).
Nas placas Arduino Uno e compatíveis, o
SDA é o pino analógico 4 (A4) e o
SCL é o pino analógico 5 (A5).
No Arduino Mega o SDA é o pino digital 20 e o SCL é o pino digital 21.
Os módulos I2C possuem um endereço único para cada módulo. A seleção do endereço é feita pela combinação dos pads A0, A1 e A2. No caso deste módulo, o endereço padrão é 0x27 (os três pads isolados). Para configurar outro endereço, conforme a tabela abaixo, solde (coloque em curto) os pads desejados. Por exemplo: pad sem solda é igual a 0 (zero), pad em curto é igual a 1.
| A0 | A1 | A2 | endereço |
| 0 | 0 | 0 | 0x27 |
| 1 | 0 | 0 | 0x26 |
| 0 | 1 | 0 | 0x25 |
| 1 | 1 | 0 | 0x24 |
| 0 | 0 | 1 | 0x23 |
| 1 | 0 | 1 | 0x22 |
| 0 | 1 | 1 | 0x21 |
| 1 | 1 | 1 | 0x20 |
Quer dizer que poderíamos ligar até oito módulos LCD no mesmo Arduino, combinando os pads? Sim, mas lembre-se que existem outros módulos I2C no mercado, como módulos de relógio (RTC) e cada um deverá ter o seu próprio endereço.
Exemplo prático – monitor de temperatura com o LM35.
Vamos mostrar dois exemplos: sem e com o módulo I2C.
Providencie:
- 1 sensor de temperatura LM35
- 1 potenciômetro ou trimpot de 1KΩ (caso monte com a opção sem módulo I2C)
- 1 módulo LCD 16 x 2 *
- 1 protoboard
- e muitos (muitos) fios jumpers.
* é muito mais econômico, caso você não possua um módulo LCD, comprá-lo com o módulo I2C já acoplado (soldado). Se você já possui um ou mais LCDs sem este módulo talvez seja vantajoso comprar o módulo I2C separado, mas terá que soldá-lo ao módulo LCD caso queira uma conexão definitiva entre os módulos.
Conectando o LCD no Arduino – sem módulo I2C
A biblioteca LiquidCrystal (nativa no software Arduino) utiliza apenas as linhas de dados D4 a D7, ou seja, apenas 4 bits. Para controle/ajuste do contraste utilizamos um trimpot ou um potenciômetro de 1KΩ.
O sketch deverá incluir a biblioteca LiquiCrystal através da diretiva #include e para facilitar a manutenção, os pinos associados ao LCD estarão definidos pela diretiva #define.
| Obs.: toda diretiva de pré-processamento começa com o símbolo #. As diretivas não são comandos da linguagem C ou Arduino. São instruções que antes da compilação efetiva, são tratadas (processadas) no código fonte (sketch) e posteriormente entregues ao compilador. Ah, a sintaxe também difere dos comandos/declarações C/Arduino. Não temos o ponto e virgula (;) ao termino de uma diretiva. Por convenção, o nome das constantes da diretiva #define são escritas em maiúsculas. |
A principal linha do sketch (mais adiante) é
LiquidCrystal lcd( RS, RW, EN, D4, D5, D6, D7 );
onde lcd é a representação da classe LiquidCrystal (pode ser qualquer nome, mas lcd nos parece mais apropriado 😉 ). Também indicamos os pinos de controle e os pinos de dados.
Outro destaque é a função sprintf() da linguagem C (consulte a apostila do mini curso Linguagem C), que formata dados e copia-os para um array de caracteres. Isto facilita muito o trabalho, porém da forma como esta função está implementada no Arduino, não conseguimos manipular dados do tipo float, por isso temperatura foi definido como int.
Métodos usados no exemplo:
begin( num_colunas, num_ linhas )
Inicializa o LCD e especifica o seu tamanho (linhas e colunas). Note que a ordem dos parâmetros são número de colunas por número de linhas.
clear()
“Limpa” o LCD e posiciona o cursor nas coordenadas 0,0.
setCursor( coluna, linha )
Posiciona o cursor nas coordenadas coluna e linha.
print( dados, [base] )
Imprime dados no LCD a partir do posicionamento do cursor. O parâmetro base é opcional e só se aplica quando dados for numérico (consulte a apostila do curso Linguagem Arduino), tópico Serial.print).
print() também retorna o número de bytes impressos no LCD.
Acompanhe o diagrama abaixo para montagem. São muitos fios jumpers e nossa sugestão é começar pelo módulo LCD.

Olhando o LCD de frente, da esquerda para direita, temos:
| pino LCD | pino Arduino |
| VSS | GND |
| VDD | 5V |
| VO | pino central do potenciômetro |
| RS | 6 |
| RW | 7 |
| E | 8 |
| D0 | GND |
| D1 | GND |
| D2 | GND |
| D3 | GND |
| D4 | 2 |
| D5 | 3 |
| D6 | 4 |
| D7 | 5 |
| A (LED backlight anodo) | 5V |
| K (LED backlight catodo) | GND |
LM35 – oriente-se pela figura a seguir.
| pino LM35 | pino Arduino |
| VS | 5V |
| Vout | A0 (pino analógico zero) |
| GND | GND |
Exemplo
#include <LiquidCrystal.h>
#define RS 6
#define RW 7
#define EN 8
#define D4 2
#define D5 3
#define D6 4
#define D7 5
#define TEMP A0
float leitura;
int temperatura;
char msg[255];
LiquidCrystal lcd(RS, RW, EN, D4, D5, D6, D7);
void setup() {
lcd.begin(2, 16);
lcd.setCursor(2, 0);
lcd.print("* EADuino *");
delay(3000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Temperatura");
}
void loop() {
leitura = analogRead( TEMP );
temperatura = (5 * leitura * 100) / 1024;
sprintf( msg, "%2d C", temperatura );
lcd.setCursor(0, 1);
lcd.print(msg);
delay(5000);
}
Conectando o LCD no Arduino – com módulo I2C
Primeiro, verifique se você tem instalado a biblioteca LiquidCrystal_I2C. Vá até o gerenciador de bibliotecas (atalho CTRL-SHIFT-i), digite liquidcrystal. Optamos por instalar esta mostrada na figura. Caso não encontre, uma boa fonte é o site Arduino Library List (link no final deste artigo), porém para este módulo faça o download aqui https://www.arduinolibraries.info/libraries/liquid-crystal-i2-c

Oriente-se pela imagem abaixo.

| pino I2C | pino Arduino |
| GND | GND |
| VCC | 5V |
| SDA | A4 |
| SCL | A5 |
Note como o circuito fica muito (mas muito) mais simples. Além da economia de pinos Arduino.

No sketch a seguir instanciamos a classe
LiquidCrystal_I2C lcd( 0x27, 16, 2 );
e informamos o endereço do módulo, quantidade de colunas e linhas. Na função setup() iniciamos o módulo e na função loop() mantemos o backlight aceso por 10 segundos e em seguida desligamos o backlight por 20 segundos.
Métodos usados no exemplo:
init( )
Inicializa o LCD.
clear( ) – idêntico ao exemplo anterior
setCursor( ) – idêntico ao exemplo anterior
print( ) – idêntico ao exemplo anterior
noBacklight( )
desliga luz de fundo
backlight( )
liga luz de fundo
setBacklight( HIGH | LOW )
liga/desliga luz de fundo
Exemplo
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define TEMP A0
float leitura;
int temperatura;
LiquidCrystal_I2C lcd(0x27, 16, 2);
void setup() {
lcd.init();
}
void loop() {
leitura = analogRead( TEMP );
temperatura = (5 * leitura * 100) / 1024;
lcd.clear();
lcd.backlight(); // ou setBacklight( HIGH );
lcd.setCursor(0, 0);
lcd.print("Temperatura");
lcd.setCursor(10, 1);
lcd.print(temperatura);
lcd.print("C");
delay(10000);
lcd.noBacklight(); // ou setBacklight( LOW );
delay(20000);
}
Criando novos caracteres (custom chars)
Com o método createChar( ) é possível criar e exibir caracteres personalizados no LCD. Isso é especialmente útil se você deseja exibir um caractere que não faz parte do conjunto de caracteres ASCII padrão.
Em módulos LCDs baseados no controlador HD44780 temos dois tipos de memórias: CGROM e CGRAM (memórias do gerador de caracteres).
- O CGROM gera todos os padrões de caracteres de 5 x 8 pontos.
- O CGRAM pode gerar até 8 padrões de caracteres definidos pelo usuário (personalizados).
Como sugestão utilize uma folha de papel quadriculado, separe os quadrados em grupos de 8 por 5 e preencha os quadrados que deseja mostrar ou, melhor ainda, acesse este site https://maxpromer.github.io/LCD-Character-Creator/. Você pode escolher se é um LCD com ou sem I2C e ainda gerar os valores em binário ou hexadecimal. Depois é só colar o código 😎 .
Métodos usados no exemplo:
createChar( posiçao, mapa de bits )
armazena na memória CGRAM, na posição de 0 a 7, o mapa de bits do caractere customizado.
write( posição )
exibe no display o caractere customizado na posição de memória de 0 a 7.
Carregue e execute o sketch a seguir.
Exemplo
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
// caracteres personalizados - os vetores abaixo foram populados com numeros binarios
byte Heart[] = {
B00000,
B01010,
B11111,
B11111,
B01110,
B00100,
B00000,
B00000
};
byte Bell[] = {
B00100,
B01110,
B01110,
B01110,
B11111,
B00000,
B00100,
B00000
};
byte Alien[] = {
B11111,
B10101,
B11111,
B11111,
B01110,
B01010,
B11011,
B00000
};
byte Check[] = {
B00000,
B00001,
B00011,
B10110,
B11100,
B01000,
B00000,
B00000
};
byte Speaker[] = {
B00001,
B00011,
B01111,
B01111,
B01111,
B00011,
B00001,
B00000
};
byte Sound[] = {
B00001,
B00011,
B00101,
B01001,
B01001,
B01011,
B11011,
B11000
};
byte Skull[] = {
B00000,
B01110,
B10101,
B11011,
B01110,
B01110,
B00000,
B00000
};
byte Lock[] = {
B01110,
B10001,
B10001,
B11111,
B11011,
B11011,
B11111,
B00000
};
void setup() {
lcd.init();
lcd.backlight();
// cria os novos caracteres
lcd.createChar(0, Heart);
lcd.createChar(1, Bell);
lcd.createChar(2, Alien);
lcd.createChar(3, Check);
lcd.createChar(4, Speaker);
lcd.createChar(5, Sound);
lcd.createChar(6, Skull);
lcd.createChar(7, Lock);
lcd.clear();
}
void loop() {
byte coluna = 0;
for ( byte indice = 0; indice <= 7; indice++ ) {
lcd.setCursor(coluna, 1);
lcd.write( indice );
coluna += 2; //incrementa a variavel de dois em dois
}
}
Um outro exemplo com os vetores populados com números hexadecimais. Preferimos com números binários, pois praticamente você transcreve o que desenhou para o valor binário.
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
// caracteres personalizados - os vetores abaixo foram populados com numeros hexadecimais
byte sino[] = {0x4, 0xe, 0xe, 0xe, 0x1f, 0x0, 0x4};
byte nota[] = {0x2, 0x3, 0x2, 0xe, 0x1e, 0xc, 0x0};
byte relogio[] = {0x0, 0xe, 0x15, 0x17, 0x11, 0xe, 0x0};
byte coracao[] = {0x0, 0xa, 0x1f, 0x1f, 0xe, 0x4, 0x0};
byte pato[] = {0x0, 0xc, 0x1d, 0xf, 0xf, 0x6, 0x0};
byte checklist[]= {0x0, 0x1, 0x3, 0x16, 0x1c, 0x8, 0x0};
byte cruz[] = {0x0, 0x1b, 0xe, 0x4, 0xe, 0x1b, 0x0};
byte enter[] = {0x1, 0x1, 0x5, 0x9, 0x1f, 0x8, 0x4};
void setup() {
lcd.init();
lcd.backlight();
// cria os novos caracteres
lcd.createChar(0, sino);
lcd.createChar(1, nota);
lcd.createChar(2, relogio);
lcd.createChar(3, coracao);
lcd.createChar(4, pato);
lcd.createChar(5, checklist);
lcd.createChar(6, cruz);
lcd.createChar(7, enter);
lcd.clear();
}
void loop() {
byte coluna = 0;
for ( byte indice = 0; indice <= 7; indice++ ) {
lcd.setCursor(coluna, 1);
lcd.write( indice );
coluna += 2; //incrementa a variavel de dois em dois
}
}
Outros Métodos
home()
posiciona o cursor no topo/esquerda do display – não limpa a tela.
blink()
noBlink()
exibe/esconde cursor em formato de bloco na próxima coluna disponível.
cursor()
noCursor()
exibe/esconde cursor em formato sublinhado (underscore) na próxima coluna disponível.
display()
noDisplay()
liga/desliga o display, mas não apaga o conteúdo em memória.
scrollDisplayLeft()
scrollDisplayRight()
desloca toda a tela do display uma posição a esquerda/direta.
Exemplo
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
void setup() {
lcd.init();
lcd.backlight();
}
void loop() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("EADuino");
lcd.setCursor(0, 1);
lcd.print("Bem-vindo(a)!");
delay(5000);
lcd.clear();
lcd.print("cursor ");
lcd.cursor();
delay(5000);
lcd.home();
lcd.print("sem cursor ");
lcd.noCursor();
delay(5000);
lcd.clear();
lcd.print("cursor - bloco");
lcd.blink();
delay(5000);
lcd.print("sem cursor ");
lcd.noBlink();
delay(5000);
lcd.clear();
lcd.print("EADuino!");
delay(2000);
lcd.noDisplay();
delay(2000);
lcd.display();
delay(5000);
lcd.clear();
int bloco, tamanho, quantidade_blocos, caracteres_restantes;
tamanho = lcd.print("EADuino - Cursos de Arduino Online!");
delay(3000);
quantidade_blocos = tamanho / 16;
caracteres_restantes = tamanho % 16;
for (bloco = 1; bloco <= quantidade_blocos - 1; bloco++) {
for (byte scroll = 0; scroll < 16; scroll++) {
lcd.scrollDisplayLeft();
delay(200);
}
delay(3000);
}
if ( caracteres_restantes > 0 ) {
for (byte scroll = 0; scroll <= caracteres_restantes; scroll++) {
lcd.scrollDisplayLeft();
delay(200);
}
delay(3000);
}
}
Links úteis
- http://en.wikipedia.org/wiki/Liquid-crystal_display
- https://en.wikipedia.org/wiki/Hitachi_HD44780_LCD_controller
- https://www.nxp.com/docs/en/data-sheet/PCF8574_PCF8574A.pdf
- https://en.wikipedia.org/wiki/I%C2%B2C
- https://www.arduinolibraries.info/
- https://www.arduino.cc/en/Reference/LiquidCrystal




