⬤ Intermédio

🖥️ Display LCD 1602

⏱️ 35 min 🧩 LCD I2C — A4 (SDA) · A5 (SCL)

Exercícios

📌 Pinagem e Biblioteca

MóduloConector InterfacePino ArduinoNotas
SDA — Dados I2CLCD_SDAA4Barramento de dados I2C
SCL — Relógio I2CLCD_SCLA5Relógio I2C — 100 kHz
VCC5V5VConsumo ~30 mA com retroiluminação
GNDGNDGND—
📦
Biblioteca necessária: LiquidCrystal_I2C
No Arduino IDE: Sketch → Incluir Biblioteca → Gerir Bibliotecas
Pesquisa "LiquidCrystal I2C" e instala a de Frank de Brabander ou johnrickman.
⚠️
Endereço I2C: O endereço padrão é 0x27. Se o LCD não aparecer, testa 0x3F. Para descobrir o endereço certo corre o sketch I2C Scanner disponível nos exemplos do IDE.
LCD 1602 — 16 colunas × 2 linhas
Kit C Casa LED
Pronto!

📋 Métodos Essenciais

MétodoDescriçãoExemplo
lcd.init()Inicializa o LCDNo setup()
lcd.backlight()Liga retroiluminaçãolcd.backlight()
lcd.noBacklight()Desliga retroiluminaçãolcd.noBacklight()
lcd.clear()Limpa todo o ecrãlcd.clear()
lcd.setCursor(col, lin)Posiciona cursor (col 0–15, lin 0–1)lcd.setCursor(0, 1)
lcd.print(valor)Escreve texto, int, float ou charlcd.print("Temp: ")
lcd.createChar(id, bitmap)Cria carácter 5×8 personalizado (0–7)lcd.createChar(0, grau)
lcd.write(id)Escreve carácter personalizadolcd.write(0)
lcd.scrollDisplayLeft()Faz scroll do ecrã para a esquerdaNo loop()
lcd.home()Move cursor para (0,0)lcd.home()

Exercício 1 — Olá, mundo!

Primeiro contacto com o LCD. Mostra uma mensagem fixa nas duas linhas e pisca a retroiluminação.

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

// addr 0x27, 16 colunas, 2 linhas
LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup() {
  lcd.init();
  lcd.backlight();

  lcd.setCursor(0, 0);   // Coluna 0, Linha 0 (1.ª linha)
  lcd.print("Kit C Domotica");

  lcd.setCursor(0, 1);   // Coluna 0, Linha 1 (2.ª linha)
  lcd.print("LED Portugal!");
}

void loop() {
  // Pisca retroiluminação 3×
  for (int i = 0; i < 3; i++) {
    lcd.noBacklight();
    delay(400);
    lcd.backlight();
    delay(400);
  }
  delay(3000);
}

Exercício 2 — Mostrar dados de sensores

Mostra em tempo real a luminosidade (LDR) na primeira linha e o estado do PIR na segunda. Actualiza sem usar clear() para evitar flickering — sobrescreve os caracteres directamente.

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

#define LDR A0
#define PIR  2

LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup() {
  pinMode(PIR, INPUT);
  lcd.init();
  lcd.backlight();

  // Cabeçalhos fixos — escrevemos só uma vez
  lcd.setCursor(0, 0); lcd.print("Luz:");
  lcd.setCursor(0, 1); lcd.print("PIR:");
}

void loop() {
  int luz = analogRead(LDR);
  int mov = digitalRead(PIR);

  // Actualiza valor da luz (col 5 para não apagar "Luz:")
  lcd.setCursor(5, 0);
  lcd.print(luz);
  lcd.print("     ");   // Limpa dígitos antigos

  // Actualiza estado do PIR
  lcd.setCursor(5, 1);
  lcd.print(mov == HIGH ? "Movimento!" : "Sem mov.  ");

  delay(400);
}
💡
Sem flickering: Em vez de lcd.clear() a cada ciclo (que pisca o ecrã), reposiciona o cursor com setCursor() e sobrescreve só os valores que mudam. Os espaços extras a seguir (" ") limpam os dígitos que possam ter ficado do valor anterior.

Exercício 3 — Scroll e mensagens longas

Fazer scroll de uma mensagem maior que 16 caracteres e criar um efeito de ticker de notícias.

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

LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup() {
  lcd.init();
  lcd.backlight();
}

void loop() {
  // Método 1: Scroll automático integrado
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Casa Inteligente");
  lcd.setCursor(0, 1);
  lcd.print("LED Portugal PRR");
  delay(2000);

  // Faz scroll para a esquerda 16× (sai do ecrã)
  for (int i = 0; i < 16; i++) {
    lcd.scrollDisplayLeft();
    delay(200);
  }
  delay(1000);

  // Método 2: Ticker — mensagem longa com scroll manual
  String msg = "  ** Sistema OK: Luz, Gas, PIR, Janela, Porta  **  ";
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Ticker:");

  for (int pos = 0; pos < msg.length() - 16; pos++) {
    lcd.setCursor(0, 1);
    lcd.print(msg.substring(pos, pos + 16));
    delay(250);
  }
}

Exercício 4 — Caracteres personalizados

O LCD suporta 8 caracteres personalizados (índices 0–7) definidos numa grelha 5×8 píxeis. Útil para criar ícones de temperatura °, setas ↑↓, coração ♥ ou símbolos da casa.

Grau °
Seta ↑
Casa 🏠
ex4_lcd_chars_custom.ino
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

// Símbolo de grau ° — grelha 5×8 em binário (cada byte = linha)
byte grau[8] = {
  0b01100,   // ░▓▓░░
  0b10010,   // ▓░░▓░
  0b10010,   // ▓░░▓░
  0b01100,   // ░▓▓░░
  0b00000,
  0b00000,
  0b00000,
  0b00000
};

// Ícone de casa
byte casa[8] = {
  0b00100,
  0b01110,
  0b11111,
  0b10001,
  0b10101,
  0b10001,
  0b11111,
  0b00000
};

// Seta para cima
byte setaCima[8] = {
  0b00100,
  0b01110,
  0b11111,
  0b00100,
  0b00100,
  0b00100,
  0b00000,
  0b00000
};

void setup() {
  lcd.init();
  lcd.backlight();

  // Regista chars personalizados (índices 0–7)
  lcd.createChar(0, grau);
  lcd.createChar(1, casa);
  lcd.createChar(2, setaCima);

  lcd.setCursor(0, 0);
  lcd.write(1);                // ícone casa
  lcd.print(" Temp: 24");
  lcd.write(0);                // símbolo grau
  lcd.print("C");

  lcd.setCursor(0, 1);
  lcd.write(2);                // seta cima
  lcd.print(" Tendencia: sobe");
}

void loop() { }

Exercício 5 — Painel de estado da casa

O LCD funciona como painel de monitorização — alterna entre dois ecrãs a cada 3 segundos: o ecrã A mostra luz e movimento, o ecrã B mostra gás e estado geral.

Ecrã A
Luz:342 PIR:OFF
Estado: NORMAL
Ecrã B
Gas:120 OK
Casa Segura
ex5_lcd_painel_estado.ino
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

#define LDR     A0
#define MQ2_ANA A1
#define PIR      2

LiquidCrystal_I2C lcd(0x27, 16, 2);

int ecra = 0;                      // 0 = ecrã A, 1 = ecrã B
unsigned long ultimaTroca = 0;
const unsigned long INTERVALO = 3000;  // Troca a cada 3s

void setup() {
  pinMode(PIR, INPUT);
  lcd.init();
  lcd.backlight();
  lcd.print("Casa Domotica");
  lcd.setCursor(0, 1);
  lcd.print("LED Portugal");
  delay(2000);
  lcd.clear();
}

void loop() {
  int luz = analogRead(LDR);
  int gas = analogRead(MQ2_ANA);
  bool mov = digitalRead(PIR) == HIGH;
  bool gasAlerta = gas > 600;

  // Troca de ecrã com millis (não bloqueia o loop)
  if (millis() - ultimaTroca > INTERVALO) {
    ecra = 1 - ecra;   // Alterna 0↔1
    ultimaTroca = millis();
    lcd.clear();
  }

  if (ecra == 0) {
    // Ecrã A: Luz + PIR
    lcd.setCursor(0, 0);
    lcd.print("Luz:"); lcd.print(luz); lcd.print("  PIR:");
    lcd.print(mov ? "ON " : "OFF");
    lcd.setCursor(0, 1);
    lcd.print(gasAlerta ? "!! GAS ALERTA !!" : "Estado: NORMAL  ");
  } else {
    // Ecrã B: Gás + estado geral
    lcd.setCursor(0, 0);
    lcd.print("Gas:"); lcd.print(gas); lcd.print("       ");
    lcd.setCursor(0, 1);
    lcd.print(gasAlerta ? "ALARME DE GAS!  " : "Casa Segura     ");
  }
}

🏆 Desafios