O LCD tem 20 colunas mas pode conter mensagens maiores — o conteúdo extra fica oculto à direita. scrollDisplayLeft() desloca todo o conteúdo visível 1 posição à esquerda a cada chamada.
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
// Scroll de mensagem longa numa linha sem afectar as outras
void scrollLinha(int linha, const char* msg, int espera_ms) {
String s = String(" ") + msg + String(" ");
int total = s.length();
for (int i = 0; i <= total - 20; i++) {
lcd.setCursor(0, linha);
lcd.print(s.substring(i, i + 20));
delay(espera_ms);
}
}
void setup() {
lcd.init(); lcd.backlight();
// Linhas 0 e 2 ficam fixas enquanto 1 e 3 scrollam
lcd.setCursor(0, 0); lcd.print(" PR.FT9_5 LCD 20x4 ");
lcd.setCursor(0, 2); lcd.print("Temp: 23.5C Hum: 61%");
}
void loop() {
scrollLinha(1, "Interface LCD 20x4 com Motor Driver L293D para Arduino UNO Rev3", 220);
scrollLinha(3, "LED Portugal -- Laboratorios de Educacao Digital -- PR.FT9_5", 180);
}// Barra de carga em qualquer linha — não usa CGRAM
void barraCarregamento(int linha, int pct, const char* label) {
int blocos = pct * 18 / 100; // 18 blocos + '[' + ']'
lcd.setCursor(0, linha);
lcd.print("[");
for (int i = 0; i < 18; i++)
i < blocos ? lcd.write(0xFF) : lcd.write(' ');
lcd.print("]");
lcd.setCursor(0, linha + 1);
lcd.print(label);
lcd.print(" "); lcd.print(pct); lcd.print("% ");
}
void setup() {
lcd.init(); lcd.backlight();
lcd.setCursor(3, 0); lcd.print("A INICIALIZAR...");
}
void loop() {
for (int p = 0; p <= 100; p += 2) {
barraCarregamento(2, p, "Carreg.:");
delay(60);
}
lcd.setCursor(0, 2); lcd.print("[##################]");
lcd.setCursor(4, 3); lcd.print("SISTEMA PRONTO!");
delay(2000);
lcd.clear();
}millis().// Ticker na linha 3 — dados fixos nas linhas 0–2
const char* alertas[] = {
"Temp. acima do limite!",
"Motor em funcionamento",
"Humidade: 61% - OK",
"PR.FT9_5 LED Portugal"
};
#define N_ALERTAS 4
unsigned long tScroll = 0, tDados = 0;
int alertaAtual = 0, posScroll = 0;
String msgScroll;
void setup() {
lcd.init(); lcd.backlight();
msgScroll = String(" ") + alertas[0];
}
void atualizarDados() {
lcd.setCursor(0,0); lcd.print("Temp: ");
lcd.print(analogRead(A0) * 0.48828, 1); lcd.print("C ");
lcd.setCursor(0,1); lcd.print("Luz: ");
lcd.print(analogRead(A1)); lcd.print(" ");
}
void loop() {
unsigned long agora = millis();
if (agora - tDados > 500) { // Dados a cada 500ms
atualizarDados(); tDados = agora;
}
if (agora - tScroll > 250) { // Scroll a cada 250ms
lcd.setCursor(0, 3);
lcd.print(msgScroll.substring(posScroll, posScroll + 20));
posScroll++;
if (posScroll >= (int)msgScroll.length() - 19) {
posScroll = 0;
alertaAtual = (alertaAtual + 1) % N_ALERTAS;
msgScroll = String(" ") + alertas[alertaAtual];
}
tScroll = agora;
}
}// Slide-in da direita: novo ecrã entra col a col
void slideIn(const char* l0, const char* l1,
const char* l2, const char* l3) {
const char* linhas[4] = {l0, l1, l2, l3};
for (int col = 0; col < 20; col++) {
for (int row = 0; row < 4; row++) {
lcd.setCursor(19 - col, row);
int idx = (int)strlen(linhas[row]) - 1 - col;
if (idx >= 0) lcd.write(linhas[row][idx]);
else lcd.write(' ');
}
delay(25);
}
}
void loop() {
lcd.clear();
slideIn(" ECRA 1 — SENSOR ",
"Temp: 23.5C ",
"Luz: 412 ",
"Estado: OK ");
delay(3000);
lcd.clear();
slideIn(" ECRA 2 — MOTOR ",
"Dir: FORWARD ",
"Vel: 200/255 78% ",
"t: 00:02:15 ");
delay(3000);
}