13 março 2014

Arduino - Como realizar um scroll no LCD 16x2, deixando uma linha fixa

Um leitor do site enviou uma pergunta hoje, sobre como realizar um scroll no LCD 16x2 ligado ao Arduino, mas apenas em uma linha. A outra ficaria estática.

A pergunta é aparentemente simples mas, ao pesquisar o assunto, vi que realizar o scroll em apenas uma linha envolve questões como mexer diretamente na memória do LCD e alterar (ou criar) bibliotecas.

Ao invés de usar uma biblioteca nova, por que não fazer isso utilizando a LiquidCrystal, amplamente utilizada por todos e provavelmente já instalada na sua IDE ?

Encontrei um colega lá da India (http://nishantarora.in/), que criou um programinha exatamente para isso, mas que infelizmente resolvia apenas parte do problema : a linha inferior permanecia estática, mas a linha superior realizava o scroll uma única vez.

O que eu fiz foi alterar o código para que o scroll não só fosse realizado de forma ininterrupta, como também aceitasse qualquer tamanho de string que fosse colocada no programa. O resultado você pode ver no vídeo abaixo :



O circuito utilizado é o mesmo mostrado no post Display LCD Winstar WH1602A. O modelo do LCD é o WH1602A mas o programa pode ser utilizado sem problemas em outros modelos de display 16x2, como o HD44780, que eu abordei neste artigo.

Além do LCD, usei como componente adicional um resistor de 10 K para ajuste do contraste :


Circuito Scroll LCD 16x2 Arduino






Abaixo, o programa utilizado para testes e mostrado no vídeo acima :

 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
// Programa : Scroll LCD 16x2 apenas em uma linha  
// Alteracoes e adaptacoes : Arduino e Cia  
//  
// Baseado no programa original de Nishant Arora  
   
#include <LiquidCrystal.h>  
   
//Inicializacao do display  
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);  
   
//Configuracoes LCD 16x2  
int screenWidth = 16;  
int screenHeight = 2;  
   
//String para as 2 linhas 
 
//line1 = Scroll linha superior
String line1 = "Arduino e Cia, dicas, projetos e tutoriais: www.arduinoecia.com.br"; 
 
//line2 = Linha inferior - estatica  
String line2 = " Arduino e Cia";  
   
// just some reference flags  
int stringStart, stringStop = 0;  
int scrollCursor = screenWidth;  
int tamanho =0;  
   
void setup() 
{  
  //Inicializacao do display  
  lcd.begin(screenWidth,screenHeight);  
}  
   
void loop() 
{  
  lcd.setCursor(scrollCursor, 0);  
  lcd.print(line1.substring(stringStart,stringStop));  
  lcd.setCursor(0, 1);  
  lcd.print(line2);  

  //Quanto menor o valor do delay, mais rapido o scroll  
  delay(250);  
  scroll_sup(); //Chama a rotina que executa o scroll  

  //Verifica o tamanho da string  
  tamanho = line1.length();  
  if (stringStart == tamanho)  
  {  
    stringStart = 0;  
    stringStop = 0;  
  }  
}  
   
void scroll_sup()  
{  
  lcd.clear();  
  if(stringStart == 0 && scrollCursor > 0)
  {  
    scrollCursor--;  
    stringStop++;  
  } else if (stringStart == stringStop){  
    stringStart = stringStop = 0;  
    scrollCursor = screenWidth;  
  } else if (stringStop == line1.length() && scrollCursor == 0) {  
    stringStart++;  
  } else {  
    stringStart++;  
    stringStop++;  
  }  
}  

Basicamente o que o programa faz é calcular a posição do cursor, imprimir a string line1 na linha superior e a string line2 na linha inferior. Depois ele apaga a tela, calcula a nova posição do cursor e imprime novamente as duas strings.

E o procedimento vai se repetindo até que toda a string line1 seja mostrada na linha superior. Quando isso acontece, todo o processo é reiniciado.

Este é um código que pode ser melhorado, especialmente para retirar o efeito "piscar" da tela, causado pelo uso do comando lcd.clear(), mas que serve de base para o seu projeto. :-)

15 comentários:

  1. Muito obrigado! Ajudou bastante!
    E parabéns pelo blog...

    ResponderExcluir
  2. Arduino e Cia, pela sua experiência, q venho acompanho de seus tutoriais pelo teu blog, lhe peço encarecidamente q vc de atenção neste problema q eu estou tendo a pelo menos 2Mêses e meio, e já procurei recursos na net p/ resolver, como: função Millis, Timer, etc, mais sem sucesso, com as fontes q consegui não deu para entender, então resolvi recorrer a vc. É o seguinte:
    Programei alguns comandos, para acionar alguns led´s pela Serial, Juntamente com um Display lcd 1602 para mostrar informações:
    Temperatura, Acionamentos de leds ex: "led1 esta ligado", "led2 esta desligado", etc...

    O problema é q, a soma dos delay´s q declarei p/ fixar cada informação no LCD por 2segundos, esta gerando uma resposta muito demorada dos comandos, por exemplo: quando jogo o comando '1' na Serial p/ acionar um led, o mesmo led esta sendo acionado após uns 16segundos, eu ter dado o comando. Gostaria muito mais muito mesmo, que vc me ajudasse, me passe o teu e-mail, para eu te passar o código, desde já lhe agradeço..

    ResponderExcluir
    Respostas
    1. Boa noite Marcos,

      Sem problemas, não posso prometer nada, mas vamos ver no que posso te ajudar. rs

      Por favor utilize o formulário de contato no lado direito da página do site, ok ?

      Aguardo sua mensagem. Abraço !

      Excluir
  3. Procurei por isso a muito tempo!!! Muito obrigado e parabéns!!!

    ResponderExcluir
    Respostas
    1. Bom dia Willian,

      Bom poder ajudar. Abraço e obrigado !

      Excluir
  4. muito bom o site!
    Mas como eu faço para inserir outros códigos de leitura? Por exemplo, quero que passe meu nome na linha de cima e na linha de baixo quero ler uma distância por um sensor ultra som em tempo real.
    Estou tentando aqui e até consegui, mas as mensagens passam piscando.

    ResponderExcluir
    Respostas
    1. Oi Wendel,

      Esse efeito de piscar acontece por causa do comando lcd.clear que eu usei no programa... uma alternativa é você retirar esse comando e usar o lcd.print pra imprimir caracteres em branco em cima da segunda linha.

      Abraço !

      Excluir
  5. desenvolvi um projeto aqui mas está dando erro;

    #include
    #define echoPin 13 //Pino 13 recebe o pulso do echo
    #define trigPin 12 //Pino 12 envia o pulso para gerar o echo
    #include
    #include
    LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
    int distancia =0;

    //Configuracoes LCD 16x2
    int screenWidth = 16;
    int screenHeight = 2;

    //String para as 2 linhas

    //line1 = Scroll linha superior
    String line1 = "Wendel Areas Pelicioni";

    //line2 = Linha inferior - estatica
    String line2 = distancia;

    // just some reference flags
    int stringStart, stringStop = 0;
    int scrollCursor = screenWidth;
    int tamanho =0;

    void setup()
    {
    //Inicializacao do display
    lcd.begin(screenWidth,screenHeight);
    pinMode(echoPin, INPUT); // define o pino 13 como entrada (recebe)
    pinMode(trigPin, OUTPUT); // define o pino 12 como saida (envia)

    }

    void loop()
    {
    lcd.setCursor(scrollCursor, 0);
    lcd.print(line1.substring(stringStart,stringStop));
    lcd.setCursor(0, 1);
    lcd.print(line2);

    //Quanto menor o valor do delay, mais rapido o scroll
    delay(500);
    scroll_sup(); //Chama a rotina que executa o scroll

    //Verifica o tamanho da string
    tamanho = line1.length();
    if (stringStart == tamanho)
    {
    stringStart = 0;
    stringStop = 0;
    }
    //seta o pino 12 com um pulso baixo "LOW" ou desligado ou ainda 0
    digitalWrite(trigPin, LOW);
    // delay de 2 microssegundos
    delayMicroseconds(2);
    //seta o pino 12 com pulso alto "HIGH" ou ligado ou ainda 1
    digitalWrite(trigPin, HIGH);
    //delay de 10 microssegundos
    delayMicroseconds(10);
    //seta o pino 12 com pulso baixo novamente
    digitalWrite(trigPin, LOW);
    //pulseInt lê o tempo entre a chamada e o pino entrar em high
    float duration = pulseIn(echoPin,HIGH);
    //Esse calculo é baseado em s = v . t, lembrando que o tempo vem dobrado
    //porque é o tempo de ida e volta do ultrassom
    float distancia = duration /29 / 2 ;

    }

    void scroll_sup()
    {
    lcd.clear();
    if(stringStart == 0 && scrollCursor > 0)
    {
    scrollCursor--;
    stringStop++;
    } else if (stringStart == stringStop){
    stringStart = stringStop = 0;
    scrollCursor = screenWidth;
    } else if (stringStop == line1.length() && scrollCursor == 0) {
    stringStart++;
    } else {
    stringStart++;
    stringStop++;
    }

    }

    ResponderExcluir
    Respostas
    1. Faltou incluir a biblioteca do ultrassônico?

      Excluir
  6. Perfeito para uma aplicação que estou desenvolvendo. Obrigada!

    ResponderExcluir
  7. Poderia explicar como funciona esse scroll_sup()?
    ooo dúvida cruel...

    ResponderExcluir
  8. boa tarde: poderia me ajudar?
    os caracteres não aparecem.
    modelo do lcd é qc1602A v.2
    obriado.

    Seus tutoriais são otimos muito bem detalhados e de fácil compreensão e de todos, é o primeiro que eu não consegui êxito vlw

    ResponderExcluir
    Respostas
    1. Oi Marcos,

      Obrigado! Bom, olhei a pinagem do seu display, e aparentemente é "padrão"... vc tentou fazer um teste simples, de escrever algo na tela ?

      Abraço!

      Excluir