CURSO: MICROCONTROLADORES
Este capítulo está dedicado a los LCDs alfanuméricos con controlador Hitachi HD44780 o
compatible, es decir, la mayoría. Hay diversas firmas, como Optrex, Sharp, Crystalfontz
America, Tianma, etc., que producen muchísimos LCDs de este tipo. Los hay desde 1 a 4 líneas,
desde 8 a 40 letras por línea, algunos con iluminación de fondo, con diferente tecnología de
fabricación, etc. Dada la compatibilidad en el control de todos ellos, la elección de un modelo
en particular queda a tu cargo. El LCD utilizado en este curso es de 2 líneas, de 16 letras cada
una.
Nombre de
Función
señal
DB0-DB7
8 líneas de bus de datos. Para transferencia bidireccional de datos entre el MCU y el LCD. DB7
o
también se puede usar como bit busy flag. En operación de 4 bits solo se usa el nibble alto.
D0-D7
E Enable – Señal de inicio de operación de lectura/escritura.
Señal para seleccionar operación de lectura o escritura.
R/W 0 : Escribir en LCD
1 : Leer de LCD
Register Select
0 : Registro de comandos (escritura).
RS
: Busy flag + puntero de RAM (lectura).
1 : Registro de datos (escritura, lectura). Acceso a DDRAM o CGRAM.
Vee o Vo Ajuste de contraste del LCD. Vee = GND es máximo contraste.
Vdd o Vcc Alimentación = +5 V típicamente.
Vss Alimentación = 0 V (GND).
AyK Son los pines de Anodo y Katodo de la iluminación de fondo que tienen algunos LCD.
Un modo de operación del LCD (con ventajas y desventajas) le permite trabajar sin conectar el
pin RW al microcontrolador. En ese modo pin RW siempre debe plantarse a GND.
La iluminación basada en LEDs suele activarse con los pines 15 y 16, identificados como A (de
ánodo) y K (de cátodo) pero no necesariamente en ese orden. Estos pines son independientes del
controlador interno del LCD así que de poco sirve que nuestro LCD diga ser compatible con
HD44780. La polaridad varía tanto que en los diagramas he puesto 15/16 para no especificar.
En todo caso, la independencia de los pines A y K permitirá que todas las prácticas de este curso
funcionen con iluminación o sin ella.
Tú sabes que hay todo tipo de diodos LED: algunos prenden a penas, mientras que otros, con la
misma energía, alumbran como una linterna (bueno, casi :). Creo que eso da cuenta de su
divergencia, pero en términos generales, los LEDs de la iluminación requieren cerca de 4.3V y
consumen algo de 300 mA. De aquí calculamos que el valor de la resistencia debe andar por los
5 a 20 ohms. Queda a tu criterio hacer los ajustes para que alumbren tanto como quieras.
La DDRAM almacena los códigos de las letras que se visualizan en la pantalla del LCD. Tiene
capacidad de 80 bytes, un byte por carácter si la fuente es de 5×7 puntos. Observa que no
siempre se podrán visualizar los 80 caracteres.
Por lo tanto, podemos entender que siempre tenemos un LCD virtual de 2×40; aunque solo
podamos ver 8, 16 ó 20 letras por cada línea. Los otros datos escritos en la DDRAM
permanecen allí aunque no se visualicen.
EL PUNTERO DE RAM
Llamado también Address Counter, es un registro que sirve para acceder a las memorias RAM
del LCD. Por ejemplo, si el Puntero de RAM vale 0x00, accedemos a la locación de DDRAM
(o CGRAM) de esa dirección.
Ahora bien, solo hay un puntero de RAM que trabaja con las dos RAMs del LCD, y para saber a
cuál de ellas accede actualmente debemos ver la instrucción enviada más recientemente.
Las instrucciones Clear Display, Return Home y Set DDRAM Address designan el Puntero de
RAM a la DDRAM, mientras que Set CGRAM Address lo designa a la CGRAM.
Conviene saber que las instrucciones Clear Display y Return Home tienen un tiempo de
ejecución de cerca de 1.52 ms. Las demás toman algo de 40 µs.
El LCD cuenta con dos registros internos principales, que dividen, grosso modo, las
instrucciones en de datos y de comando.
Con RS = 0 accedemos al registro de comandos para escribir instrucciones de control del LCD
(Clear Display, Function Set, etc.). En el caso de una lectura, obtenemos un dato particular que
contiene el valor del puntero de RAM junto con el bit Busy flag.
CLEAR DISPLAY: 0 0 0 0 0 0 0 1
Limpia toda la pantalla del LCD. También retorna el cursor a su posición inicial (cima
izquierda), esto es, designa el puntero de RAM a la dirección 0x00 de la DDRAM.
RETURN HOME: 0 0 0 0 0 0 1 X
Regresa el cursor a su posición inicial pero sin alterar el texto del display, es decir, solo designa
el puntero de RAM a la dirección 0x00 de la DDRAM.
FUNCTION SET: 0 0 1 DL N F X X
Configura la longitud del bus de datos, el número de líneas y el tipo de fuente.
DL = 1 : La interface con el LCD es mediante un bus de datos de 8 bits.
DL = 0 : La interface con el LCD es mediante un bus de datos de 4 bits.
Los LCDs tienen un circuito interno de reset que los inicializan automáticamente tras la
alimentación. Lo cierto es que la auto-inicialización no siempre es fiable. Por eso existe la
inicialización por software, que permite una completa configuración de los parámetros del LCD.
Se constituye de una serie de pasos aparentemente bastante exóticos, sobre todo los primeros,
pero que se justifican si tratamos de entender que este procedimiento debe ser capaz de
configurar el LCD para que funcione con bus de datos de 4 u 8 bits, sin importar cómo estuvo
operando antes, es decir, podemos cambiar "al vuelo" entre un modo y otro.
Además de ello cada nueva instrucción debe ser enviada al LCD asegurándonos de que
no se encuentre ocupado. El LCD indica su disponibilidad mediante el llamado bit BF
(Busy Flag). BF = 1 indica LCD ocupado y BF = 0 es LCD listo. BF es el MSbit del
byte que se lee del LCD cuando el pin RS = 0. Obviamente la lectura implica que
debemos poder controlar el pin RW. De no usar este pin en nuestra conexión, debemos
hacer pausas entre una instrucción y otra. Pero incluso si usamos el bit BF, al inicio
debemos poner pausas porque se supone que el LCD aún no sabe si va trabajar con bus
de datos de 4 u 8 bits y no sabe cómo responder a las instrucciones de lectura (no sabe si
entregar bytes enteros o en nibbles). Que enredo!, ¿verdad? Por eso los siguientes
flowcharts se ven tan complicados pese a tratarse de los LCD más simples del mundo.
La inicialización de los LCD gráficos por ejemplo es más pequeña.
Aunque los LCDs parezcan simples de usar, para bien o para mal sus características abren puertas a
diversos modos de interface. Considerando que el bus de datos puede ser de 8 o 4 bits y que se puede usar
o prescindir de la línea de control RW, podemos obtener los siguientes 4 tipos de conexión. (Nota, la
conexión de los pines de alimentación, de contraste y de la iluminación de fondo se estudia en la sección
pines del LCD)
LA INTERFACE DE 11 LÍNEAS
Se trabaja con los 8 bits del bus de datos y las 3 líneas de Control.
El uso del pin RW controla las operaciones de escritura (RW = 0) y lectura (RW = 1) del LCD. Las
lecturas nos permiten por un lado conocer si el LCD está ocupado o no para saber si podemos enviar la
siguiente instrucción de escritura, así como leer la posición actual del cursor.
La otra finalidad de las lecturas es obtener los datos de las memorias DDRAM y CGRAM del LCD. Los
datasheets dicen que el acceso bidireccional a las rams del LCD permiten utilizarlas como memoria
extendida del sistema. Ahora parece hasta ridículo pero tiene cierto sentido considerando que estos LCDs
nacieron en la prehistoria de los microcontroladores , donde los microcontroladores tenían muy poca
RAM o en su lugar se usaban microprocesadores (que simplemente no tienen RAM).
EN LA INTERFACE DE 10 LINEAS
El pin RW del LCD va siempre plantado a GND (RW = 0). Ello significa que el LCD solo aceptará
operaciones de escritura del microcontrolador. Renunciar a la lectura de las memorias RAM es un hecho
que pasa casi desapercibido. El punto clave de no controlar el pin RW es no enviar al LCD una nueva
instrucción sin que haya terminado de procesar la anterior. Ya que no podemos leer del LCD para saber
su estado, debemos calcular su disponibilidad a partir de los tiempos que demoran en ejecutarse las
instrucciones. Por ejemplo, una vez inviada la instrucción Clear Display debemos esperar al menos 1.6
ms (que es su tiempo de ejecución) antes de enviar la siguiente instrucción.
Aquí se nos juntan todas las desventajas software de tener que trabajar a base de nibbles y de renunciar a
las lecturas del LCD para obtener datos de sus memorias RAM o para saber si el LCD está ocupado o no
antes de poder enviarle una nueva instrucción. A pesar de todo eso, pueden darse ocasiones, como
disponer de un microcontrolador de muy pocos pines, donde tengamos que recurrir a esta conexión.
#include "lcd.h"
La librería utiliza por defecto el puerto B del AVR tanto para el bus de datos del LCD como para las
líneas de control E, RS y R/W. Esta interface se puede modificar en los #defines del archivo i2c.h. Nota
que por cada puerto se deben cambiar los tres registros, PORT, DDR y PIN. Esa podría ser una
configuración de cierta recurrencia, en cambio, no deberíamos tocar lcd.c, salvo que por alguna razón
deseemos editar su código.
lcd_data(c). Escribe una sola letra en el LCD, en la posición actual del cursor.
lcd_data() también permite crear caracteres gráficos, como se muestra en una práctica
más adelante.
lcd_cmd(com). Ocasionalmente también usaremos esta función para enviar comandos
al LCD, por ejemplo:
Las constantes LCD_CLEAR y algunas más se hallan definidas en el archivo lcd.h. Por supuesto que
también se pueden formar cualesquiera códigos de instrucciones de los estudiados antes.
/***************************************************************
* FileName: lcd.h
* Purpose: Librería de funciones para controlar un display LCD con chip
* Hitachi HD44780 o compatible. La interface es de 4 bits.
* Processor: ATmel AVR
* Compiler: AVR IAR C y AVR GCC (WinAVR)
*****************************************************************/
#include "avr_compiler.h"
//******************************************************************
// CONFIGURACIÓN DE LOS PINES DE INTERFACE
//********************************************************************
/* Define los números de los pines del puerto anterior que corresponderán a
* las líneas E, RW y RS del LCD. */
#define lcd_E 3 // Pin Enable
#define lcd_RW 2 // Pin Read/Write
#define lcd_RS 1 // Pin Register Select
//********************************************************************
// CÓDIGOS DE COMANDO USUALES
//*******************************************************************
#define LCD_CLEAR 0x01 // Limpiar Display
#define LCD_RETHOM 0x02 // Cursor a inicio de línea 1
#define LCD_LINE1 0x80 // Línea 1 posición 0
#define LCD_LINE2 0xC0 // Línea 2 posición 0
#define LCD_DDRAM 0x80 // Dirección 0x00 de DDRAM
#define LCD_CGRAM 0x40 // Dirección 0x00 de CGRAM
#define LCD_CURSOR 0x0E // Mostrar solo Cursor
#define LCD_BLINK 0x0D // Mostrar solo Blink
#define LCD_CURBLK 0x0F // Mostrar Cursor + Blink
#define LCD_NOCURBLK 0x0C // No mostrar ni Cursor ni Blink
//***************************************************************
// PROTOTIPOS DE FUNCIONES
//************************************************************
void lcd_init(void); // Inicializa el LCD
/*********************************************************************
* FileName: lcd.c
* Purpose: Librería de funciones para controlar un display LCD con chip
* Hitachi HD44780 o compatible. La interface es de 4 bits.
* Processor: ATmel AVR
* Compiler: AVR IAR C y AVR GCC (WinAVR)
******************************************************************/
#include "lcd.h"
//************************************************************
// Ejecuta la inicialización software completa del LCD. La configuración es
// de: interface de 4 bits, despliegue de 2 líneas y caracteres de 5x7 puntos.
//*******************************************************************
void lcd_init(void)
{
/* Configurar las direcciones de los pines de interface del LCD */
lcd_DATAddr |= 0xF0;
lcd_CTRLddr |= (1<<lcd_E)|(1<<lcd_RW)|(1<<lcd_RS);
//*********************************************************
// Envían instrucciones de comando y de datos al LCD.
//*************************************************
void lcd_cmd(char com)
{
lcd_write(com, 0); // Cualquier instrucción de comando
}
void lcd_data(char dat)
{
lcd_write(dat, 1); // Instrucción 'Write Data to DDRAM/CGRAM'
}
//***********************************************
// Genera un delay de n milisegundos
//*********************************************************
void ldelay_ms(unsigned char n)
{
while(n--)
delay_us(1000);
}
LABORATORIO
Visualizacion de mensajes con el modulo lcd
Mostrar EL mensaje :
“UNAC-FIEE 1ª FILA
MICRO –ATMEGA8 ” 2ª FILA
Según la configuración por defecto de la librería para el LCD, debemos usar la conexión
mostrada en el esquema de abajo. La configuración de puertos y de pines a usar se puede
cambiar en archivo lcd.h.
El pin VEE (o Vo) del LCD establece el contraste de la pantalla. Muchas veces se prefiere
quitar el potenciómetro y conectar VEE a tierra para fijar el máximo contraste. En los siguientes
circuitos haremos algo parecido
/******************************************************************
* FileName: main.c
******************************************************************/
#include "avr_compiler.h"
#include "lcd.h"
void delay_ms(unsigned int t)
{
while(t--)
delay_us(1000);
}
int main(void)
{
lcd_init(); // Inicializar LCD
while(1)
{
lcd_gotorc(1,7); // Cursor a fila 1 posición 7
lcd_puts(“UNAC-FIEE"); // Escribir Hello
lcd_gotorc(2,7); // Cursor a fila 2 posición 7
lcd_puts(“MICRO-ATMEGA8"); // ...
delay_ms(600); // Pausa de 600 ms
lcd_clear(); // Limpiar pantalla
delay_ms(400); // ...
}
}