TUTORIAL
PROGRAMAÇÃO DE LCD (Liquid Crystal
Display) COM O 80C51
Freqüentemente, um programa em microprocessadores/
microcontroladores deve interagir com o meio externo usando dispositivos
de entrada e saída (I/O) para permitir a comunicação diretamente com o
ser humano. Um dos dispositivos mais comuns de acoplamento é o LCD.
Alguns dos LCDs mais utilizados são os displays de 16x2 e 20x2. Isto
significa 16 e 20 caracteres em cada uma das duas linhas do display
respectivamente. Felizmente, o HD44780U, que é o controlador padrão
mais popular utilizado pelos fabricantes, permite fazer uma comunicação
de forma simples com a maioria dos LCDs.
HD44780 - OPERAÇÃO E COMANDOS
O HD44780 requer 3 linhas de controle e também 4 ou 8 linhas
de I/O para o bus de dados. O usuário deve selecionar operação com 4 ou
8 bits no bus de dados. Se o usuário selecionar 4 bits, o LCD
necessitará de 7 linhas ( 3 para controle e 4 para dados ). Se
selecionar 8 bits, serão 11 linhas ( 3 para controle e 8 para dados ).
As três linhas de controle são denominadas EN, RS, RW, ou variações
próximas como E, R/S e R/W. A linha EN é chamada “Enable” . É
usada para mostrar ao LCD que dados estão sendo enviados. Para
enviá-los, seu programa deverá “setar” o EN e depois “setar” as duas
outras linhas de comando e/ou colocar os dados no bus de dados. Quando
as duas outras linhas estiverem definidas, leve o EN para nível baixo
novamente. A transição 1-0 diz ao HD44780 para capturar os dados nas
duas outras linhas de controle, no bus de dados e tratar isso como um
comando. A linha RS é chamada de “Register Select”. Quando
estiver em nível baixo, o dado é tratado como um comando ou uma
instrução especial ( como limpar tela, posicionar cursor, etc...).
Quando estiver em nível alto o dado que está sendo enviado é do tipo
texto. Por exemplo, para mostrar a letra “T” no LCD você deverá “setar”
a linha RS. A linha RW é o “Read/Write”. Quando RW estiver em
nível baixo, a informação que está no bus de dados é de escrita no LCD.
Quando estiver em nível alto, a informação é de leitura. Apenas uma
instrução ( “Get LCD status” ) é um comando de leitura. Todos os outros
comandos são de escrita, assim a linha RW deverá quase sempre estar em
nível baixo. Finalmente, o bus de dados consiste de 4 ou 8 linhas (
depende do modo de operação selecionado pelo usuário ). No caso de 8
bits, as linhas de referência são como DB0, DB1, DB2, DB3, DB4, DB5, DB6
e DB7.
EXEMPLO DE CONFIGURAÇÃO DE
HARDWARE
Como mencionado anteriormente, o LCD requer 8 ou 11 linhas
I/O para comunicação. Aqui usaremos 8 bits para o bus de dados,
assim estaremos usando 11 pinos I/O do 8051 para fazer a interface com o
LCD. Vamos desenhar um simples exemplo de como o LCD irá conectar-se
com o 8051:
No programa para acessar o LCD, serão usadas
constantes para as portas do 8051, para que possam ser referenciadas
pelos nomes das linhas do HD44780 ao invés de P0.1, P0.2,
etc.
DB0 EQU P1.0
DB1 EQU P1.1
DB2 EQU P1.2
DB3 EQU P1.3
DB4 EQU P1.4
DB5 EQU P1.5
DB6 EQU P1.6
DB7 EQU P1.7
EN EQU P3.7
RS EQU P3.6
RW EQU P3.5
DATA EQU P1
Tendo feito o relacionamento acima, as linhas I/O podem ser
referenciadas pelos nomes das portas do HD44780. Por exemplo, para
“setar” a linha RW, basta executar o seguinte comando:
SETB RW
MANIPULANDO A LINHA EN
Como mencionado acima, a EN é usada para dizer ao LCD para
capturar as informações colocadas no bus de dados e nas duas outras
linhas de controle. Note que a EN deve estar em nível alto/baixo
antes/depois de cada instrução enviada ao LCD, dessa forma o comando é
de leitura ou escrita, tipo texto ou comando. Em resumo, deve-se
manipular a EN a cada comando enviado ao LCD. Se não for realizada a
transição 1-0 (nível alto-baixo), o LCD não será capaz de realizar a
captura das informações nas duas outras linhas de controle.
Portanto, antes de interagir com o LCD, uma opção é levar a EN para
o nível alto com a seguinte instrução:
SETB EN
Depois de colocadas as informações nas duas outras linhas e
no bus de dados, deve-se “zerar” a EN novamente, assim:
CLR EN
Nota: O LCD interpreta e executa comandos no
instante em que a linha EN é colocada em nível baixo e isso requer uma
certa quantidade de tempo para a execução dos comandos. O tempo
solicitado depende da instrução e da velocidade que o cristal está
conectado ao HD44780.
VERIFICANDO TAREFAS NO LCD
Como mencionado acima, o tempo de execução de cada instrução
depende do tipo e da velocidade de comunicação do LCD com o HD44780.
Há um método quando colocamos um código de escrita que exige um
determinado tempo de espera para o LCD executar as instruções, esse
método não é flexível. Se a freqüência do cristal é modificada, o
software precisará mudá-lo. Adicionalmente, se trocarmos o LCD por
outro, embora com o HD44780 compatível, que necessite de mais tempo para
executar operações, o programa não funcionará até que o tempo não seja
ajustado de forma correta. O método mais utilizado para saber se o
LCD ainda está executando a ultima instrução recebida é usar o comando
“get LCD status”. O comando “get LCD status” retornará dois tipos de
informação, e a informação que é útil agora está no bit DB7. Em
resumo, quando usamos o comando “get LCD status” o LCD imediatamente
seta o bit DB7 se ele ainda está executando algum comando ou baixa o
mesmo para indicar que não está executando nada. Assim o programa pode
manter comunicação com o LCD sempre que o bit DB7 estija em nível baixo.
A partir desse ponto pode-se enviar o próximo comando. Pode-se usar
esse procedimento sempre que enviarmos alguma instrução ao LCD. A
subrotina abaixo executa a tarefa descrita anteriormente:
WAIT_LCD:
SETB
EN
; inicia os comandos no LCD CLR
RS
; SETB
RW
; comando de leitura MOV DATA,#0FFh ; seta todos
os pinos para
FF LENDO:
MOV A,DATA ; le
e retorna valor
JB ACC.7,LENDO ; se o
bit 7 estiver em alto,
;o LCD está ;executando a
;última tarefa CLR
EN
;finaliza os comandos CLR
RW
; coloca o RW para receber
;futuros comandos
RET
;
Assim, o procedimento padrão será enviar uma instrução ao
LCD e depois chamar a subrotina ( WAIT_LCD ) para aguardar até que a
última instrução seja executada. Garante-se assim que o programa dará ao
LCD o tempo necessário para executar instruções e também tornar o
programa compatível com qualquer cristal.
Nota: a rotina acima faz o trabalho de espera do LCD,
porém se o LCD não ficar “desocupado” o programa poderá travar esperando
o bit DB7 assumir nível baixo. Isto nunca deverá acontecer desde que o
hardware esteja trabalhando corretamente. Como uma solução, seria
interessante colocar algum tempo limite na espera - por exemplo, um
máximo de 256 tentativas para o que sinal de “ocupado” entre em nível
baixo. Isso garantiria até mesmo que o hardware falhe e o programa não
trave.
INICIALIZANDO O LCD
Antes de usar o LCD, deve-se inicializá-lo e configurá-lo.
Isso é feito com o envio de um número de instruções de inicialização.
A primeira instrução que deve ser enviada diz respeito ao modo de
operação do bus de dados: 4 ou 8 bits. Seleciona-se também a fonte de
caracteres de 5x8. Essas duas opções são selecionadas enviando o comando
38h ao LCD com o RS em baixo (tipo instrução). Deve-se chamar a
sub-rotina de espera WAIT_LCD. Assim, para enviar o comando 38h deve-se
executar as seguintes instruções:
SETB EN
CLR RS
MOV DATA,#38h
CLR EN
LCALL
WAIT_LCD
Nota: o comando do LCD 38h é na verdade
a soma de um número de opções. O código de instrução puro é 20h (
“Function set” ). Entretanto, agrega-se o valor 10h para indicar o valor
de 8 bits no bus de dados mais o 08h para indicar que o display é de
duas linhas.
O segundo byte a ser enviado é o 0Eh. Assim deve-se repetir o código
de inicialização acima:
SETB EN
CLR RS
MOV DATA,#0Eh
CLR EN
LCALL
WAIT_LCD
Nota: o comando 0Eh é na verdade um
código de instrução 08h mais 04h para ligar o LCD. Para isso um
02h adicional é agregado para ligar o cursor.
O último byte necessário é usado para parâmetros adicionais de
configuração. Deve-se enviar o código de instrução 06h.
SETB EN
CLR RS
MOV DATA,#06h
CLR EN
LCALL
WAIT_LCD
Nota: o comando 06h é a instrução 04h
mais 02h para dizer ao LCD que a todo tempo será enviado um caracter e o
cursor automaticamente se moverá para a direita.
Assim, a rotina de inicialização completa será a seguinte:
Init_LCD:
SETB EN CLR RS MOV DATA,#38h CLR EN
LCALL WAIT_LCD SETB EN CLR RS MOV DATA,#0Eh
CLR EN LCALL WAIT_LCD SETB EN CLR RS MOV
DATA,#06h CLR EN LCALL WAIT_LCD
RET Tendo
executado esse código o LCD estará completamente inicializado para
receber outros dados e os apresentar em sua tela.
LIMPANDO A TELA ( CLEAR SCREEN
)
Quando o LCD é inicializado pela primeira vez, a tela deverá
ser limpa automaticamente pelo HD44780. Entretanto, não é má a idéia de
limpar a tela em muitas das operações depois que o LCD foi inicializado.
O código de comando para executar essa função é o 01h. Limpar a
tela é uma função usada normalmente mais de uma vez, portanto uma boa
idéia é construir uma sub-rotina para isso:
CLEAR_LCD:
SETB EN
CLR RS
MOV DATA,#01h
CLR EN LCALL
WAIT_LCD
RET
Nota: executando a função “Clear Screen”
a posição do cursor irá automaticamente para a parte superior
esquerda.
ESCREVENDO TEXTO NO LCD
A rotina WRITE_LCD abaixo enviará o caracter do acumulador
para o LCD que o colocará no display:
WRITE_TEXT:
SETB EN
SETB RS
MOV DATA, A
CLR EN LCALL WAIT_LCD
RET
UM EXEMPLO DE PROGRAMA
Com todas as sub-rotinas necessárias escritas, o programa
abaixo escreverá o texto “HELLO WORLD” no LCD:
LCALL INIT_LCD LCALL CLEAR_LCD
MOV A,#’H’ LCALL WRITE_TEXT
MOV A,#’E’ LCALL WRITE_TEXT
MOV A,#’L’ LCALL WRITE_TEXT
MOV A,#’L’ LCALL WRITE_TEXT
MOV A,#’O’ LCALL WRITE_TEXT
MOV A,#’W’ LCALL WRITE_TEXT
MOV A,#’O’ LCALL WRITE_TEXT
MOV A,#’R’ LCALL WRITE_TEXT
MOV A,#’L’ LCALL WRITE_TEXT
MOV A,#’D’ LCALL
WRITE_TEXT O
programa acima deverá, quando executado, inicializar, limpar, e mostrar
“HELLO WORLD” no LCD começando do canto esquerdo superior do
cristal.
POSICIONANDO O CURSOR
O programa acima é simples, pois apenas imprime o texto na
primeira linha começando do lado esquerdo. Mas e se for necessário que a
palavra “HELLO” apareça na linha de cima, no canto esquerdo e a palavra
“WORLD” na linha de baixo e no caracter de número 10? Isto parece
simples, e na verdade é. Entretando, isso requer um maior entendimento
do design do LCD.
O HD44780 contém uma certa quantidade de memória que é dedicada ao
display. Todo o texto escrito é armazenado nessa memória, que é lida
pelo HD 44780 para a apresentação do texto no cristal. Essa memória pode
ser representada no seguinte mapa:
No mapa de memória acima, a área em verde é a parte visível
do display. Como pode-se observar, isso representa 16 caracteres em cada
uma das duas linhas. Os números em cada caixinha são os endereços de
memória que correspondem a uma determinada posição na tela.
Assim, o primeiro caracter na primeira linha, canto esquerdo, é o de
endereço 00h. A seguinte posição é a de endereço 01h, etc... E isso
continua até chegarmos ao caracter de número 16 na primeira linha que
corresponde ao endereço 0Fh.
Entretanto, o primeiro caracter da segunda linha, como é mostrado no
mapa, possui o endereço 40h. Isso significa que se escrevermos um
caracter na última posição da primeira linha e depois escrever o
próximo, o segundo caracter não aparecerá na segunda linha. Isso
acontece porque esse segundo caracter será escrito no endereço 10h, mas
a segunda linha começa pelo 40h.
Assim é necessário enviar um comando ao LCD que posiciona o cursor na
segunda linha. O código de instrução “Set Cursor Position” é 80h. Para
isso deve-se juntar a essa instrução o endereço de localização onde
deseja-se posicionar o cursor. No exemplo, a palavra “WORLD” será
apresentada na segunda linha e no décimo caracter.
Fazendo referência novamente ao mapa, pode-se ver que a posição do
décimo caracter da segunda linha corresponde ao endereço 4Ah. Antes de
escrever a palavra “WORLD”, deve-se enviar a instrução de posicionamento
do cursor; o valor desse comando será: 80h ( instrução de posicionamento
de cursor ) acompanhado do endereço 4Ah, ou seja, 80h + 4Ah = C4h.
Portanto, enviando o comando C4h, o LCD posicionará o cursor na segunda
linha e no décimo caracter:
SETB EN
CLR RS
MOV DATA,#0C4h
CLR EN
LCALL
WAIT_LCD
Para apresentar a palavra “HELLO” a partir do canto esquerdo
superior com a palavra “WORLD” na segunda linha e no décimo caracter
basta inserir os comandos escritos acima no programa anterior. Assim, o
programa ficaria:
LCALL INIT_LCD LCALL CLEAR_LCD
MOV A,#’H’ LCALL WRITE_TEXT
MOV A,#’E’ LCALL WRITE_TEXT
MOV A,#’L’ LCALL WRITE_TEXT
MOV A,#’L’ LCALL WRITE_TEXT
MOV A,#’O’ LCALL WRITE_TEXT
SETB EN CLR RS MOV DATA,#0C4h
CLR EN LCALL WAIT_LCD MOV
A,#’W’ LCALL WRITE_TEXT MOV A,#’O’
LCALL WRITE_TEXT MOV A,#’R’
LCALL WRITE_TEXT MOV A,#’L’
LCALL WRITE_TEXT MOV A,#’D’
LCALL
WRITE_TEXT
RESUMO
Esse tutorial apresentou conceitos básicos de programação no
LCD. Obviamente, não possui todas as funções do display. O controlador
HD44780 oferece muitas outras funções que são passadas usando
outros comandos, e alguns dos comandos já apresentados incluem outras
opções que não foram discutidas aqui. |