Está en la página 1de 27

UNIVERSIDAD NACIONAL DEL CALLAO

FACULTAD DE INGENIERIA ELECTRICA Y ELECTRÓNICA

CURSO: MICROCONTROLADORES

PROGRAMACION DE MODULO LCD CON


ATMEGA8 - LENGUAJE C

PROFESOR: MSc ING. ASTOCONDOR VILLAR JACOB

CALLAO, ........... DEL ..............


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

CONTROL DEL LCD CON MICRO CONTROLADOR ATMEGA8


LCD
Introducción
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.

UN DISPLAY LCD DE 2 LÍNEAS, DE 16 CARACTERES CADA UNA.

PINES DEL LCD

Pines del display LCD.


Tabla Número de Pin
Número de Pin Símbolo
1 Vss
2 Vcc o Vdd
3 Vee o Vo
4 RS
5 R/W
6 E
7...14 DB0...DB7
15 y 16 AyK

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 1


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

pines del lcd.

Los pines 15 y 16 corresponden a la iluminación de fondo del LCD, pero aquí el orden
varía mucho. Sea como fuere, los 14 primeros pines siempre deberían coincidir

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.
o DB7 también se puede usar como bit busy flag. En operación de 4 bits solo se usa el nibble
D0-D7 alto.
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.

LCDS CON ILUMINACIÓN DE FONDO

Algunos LCDs tienen iluminación de fondo. Esta característica se basa en diferentes


tecnologías, siendo la más habitual el empleo de una matriz de diodos LED colocados detrás de
la pantalla.

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.

Si los pines de iluminación en tu LCD no están marcados como A y K puedes consultar su


datasheet para ver cuáles son o averiguarlo manualmente del mismo modo que compruebas la

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 2


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

polaridad de un LED: aplica 5 V entre los pines 15 y 16 y si prende, ya lo tienes. Como en todo
LED, no debes olvidar ponerle una resistencia en serie, como se ve arriba. ¿Resistencia de
cuánto?

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.

MEMORIAS DEL LCD

CGROM - CHARACTER GENERATOR ROM

Es la zona de memoria donde se encuentran grabados los patrones de todos los caracteres que
puede visualizar el LCD de fábrica. Tiene grabados cerca de 200 (varía mucho) tipos de
caracteres de 5×7 puntos (lo más común) o 32 caracteres de 5×10 puntos. Este último modo es
raramente usado porque no todos los modelos lo soportan.

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 3


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

Tabla estándar de caracteres de la CGROM.

DDRAM - DISPLAY DATA RAM

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 ejemplo, si quisiéramos mostrar el mensaje HELLO en la pantalla, deberíamos enviar a la


DDRAM los códigos ascii de cada letra de esa palabra. El controlador interno del LCD tomará
esos códigos para buscar en la CGROM sus correspondientes patrones de visualización y luego
los mostrará en la pantalla.

La siguiente figura muestra la correspondencia entre las locaciones de la DDRAM y las


posiciones de las letras que vemos en la pantalla de un LCD de 2 líneas, particularmente de uno
de 2×16. Fíjate en que los 80 bytes de la DDRAM se dividen en dos sectores de 40 bytes, un
sector por línea, así:

 Línea 1, con sector de DDRAM desde 0x00 hasta 0x27.


 Línea 2, con sector de DDRAM desde 0x40 hasta 0x67.

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.

CGRAM - CHARACTER GENERATOR RAM

La CGRAM es una RAM de 64 bytes donde el usuario puede programar los patrones de nuevos
caracteres gráficos, ya sean de 5×7 puntos (hasta 8 caracteres) o de 5×10 puntos (hasta 4
caracteres). Este tema lo detallaré en la práctica final.

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.

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 4


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

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.

Afortunadamente, en la gran mayoría de los casos, el Puntero de RAM estará apuntando a la


DDRAM. Además, en este caso viene a representar la posición del cursor (visible o no) del
LCD en la pantalla.

SET DE INSTRUCCIONES DEL DISPLAY LCD

Es el controlador interno HD44780 (u otro) del LCD quien ejecutará las operaciones de mostrar
las letras en la pantalla, mover el cursor, desplazar el contenido de la pantalla, etc. Lo que nos
toca a nosotros es enviarle los códigos de esas operaciones. A continuación, un resumen.

CÓDIGO
INSTRUCCIONES
RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
Clear Display 0 0 0 0 0 0 0 0 0 1
Return Home 0 0 0 0 0 0 0 0 1 ×
Entry Mode Set 0 0 0 0 0 0 0 1 I/D S
Display ON/OFF
0 0 0 0 0 0 1 D C B
Control
Instrucciones de
Cursor or Display Shift 0 0 0 0 0 1 S/C R/L × ×
comando
Function Set 0 0 0 0 1 DL N F × ×
Set CGRAM Address 0 0 0 1 Puntero de RAM (CGRAM)
Set DDRAM Address 0 0 1 Puntero de RAM (DDRAM)
Read Busy Flag Puntero de RAM (DDRAM o
0 1 BF
& RAM Pointer CGRAM)
Write to CGRAM
1 0 Escribir dato
or DDRAM
Instrucciones de datos
Read from CGRAM
1 1 Leer dato
or DDRAM

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.

Poniendo el pin RS = 1 accedemos al registro de datos y mediante él a cualquier locación de la


DDRAM o CGRAM, para operaciones de lectura y escritura de datos.

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.

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 5


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

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.

ENTRY MODE SET: 0 0 0 0 0 1 I/D S

Establece el modo de incremento o decremento y modo de desplazamiento del LCD.

 I/D = 1: El puntero de RAM se incrementa en 1 después de leer o escribir un dato. Así


accedemos automáticamente a la siguiente locación de DDRAM o CGRAM. Si es
DDRAM, este puntero representa la posición del cursor en la pantalla y el incremento
significa su avance a la derecha.
 I/D = 0: El puntero de RAM se decrementa en 1 después de leer o escribir un dato.
 S = 1: Si se escribe un nuevo dato de carácter en el LCD, entonces el display entero se
desplaza a la derecha cuando I/D = 0 o a la izquierda cuando I/D = 1.
 S = 0: El display no se desplaza luego de escribir en la DDRAM. Esto es lo usual.

DISPLAY ON/OFF CONTROL: 0 0 0 0 1 D C B

Prende o apaga el Display, el Cursor y la función Blink del cursor.

 D = 1: El display se prende.
 D = 0: Apaga el display. (No significa que los datos de las RAMs se vayan a borrar.)
 C = 1: Despliega el cursor.
 C = 0: No despliega el cursor
 B = 1: La letra indicada por el cursor parpadea.
 B = 0: La letra no parpadea.

CURSOR OR DISPLAY SHIFT: 0 0 0 1 S/C R/L X X

Desplaza el cursor o el display a la derecha o la izquierda sin escribir o leer datos.

S/C R/L Operación


0 0 Mueve el cursor a la izquierda (puntero de RAM se decrementa en 1)
0 1 Mueve el cursor a la derecha (puntero de RAM se incrementa en 1)
1 0 El Cursor y el display entero se desplazan a la izquierda
1 1 El Cursor y el display entero se desplazan a la derecha

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.
 N = 1: Configura un display de 2 líneas.
 N = 0: Configura un display de 1 línea.
 F = 0: Fuente de carácter de 5×7 puntos.
 F = 1: Fuente de carácter de 5×10 puntos.

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 6


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

SET DDRAM ADDRESS: 1AAAAAAA

Designa el puntero de RAM a la nueva dirección AAAAAAA de la DDRAM. Digamos que


sirve para controlar la posición del cursor del LCD.

Ejemplo, para escribir un texto en la segunda línea del display (que tiene dirección inicial 0x40),
primero habría que enviar el comando Set DDRAM Address con el número 0x40 en el
parámetro AAAAAAA.

SET CGRAM ADDRESS: 01AAAAAA

Designa el puntero de RAM a la nueva dirección AAAAAAA de la CGRAM.

READ BUSY FLAG & RAM POINTER: BF AAAAAAA

Leer bit Busy Flag (BF) y el valor del puntero de RAM. BF = 1 indica que una operación
interna está en progreso. El LCD no aceptará una nueva instrucción hasta que BF sea 0.

El valor de AAAAAAA leído representa el valor del puntero de RAM.

Es posible prescindir del bit BF. Para ello debemos esperar el tiempo adecuado antes de enviar
la siguiente instrucción.

WRITE DATA TO CGRAM / DDRAM: DDDDDDDD

Escribe el dato de 8 bits DDDDDDDD en la DDRAM o CGRAM, dependiendo de cuál de las


dos esté siendo direccionada actualmente. Después de la escritura el puntero de RAM se
incrementa o decrementa, según se haya configurado el display. Ver instrucción Entry Mode
Set.

READ DATA FROM CGRAM / DDRAM: DDDDDDDD

Lee un dato de 8 bits de la DDRAM o CGRAM, dependiendo de cuál de ellas esté siendo
direccionada actualmente. Después de la lectura el puntero de RAM se incrementa o decrementa
en uno, según la configuración del display. Ver instrucción Entry Mode Set.

INICIALIZACIÓN DEL LCD

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

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 7


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

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.

INICIALIZACIÓN DEL LCD CON BUS DE DATOS DE 4 BITS.

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 8


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

INICIALIZACIÓN DEL LCD CON BUS DE DATOS DE 8 BITS.

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 9


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

INTERFACE ENTRE UN MICROCONTROLADOR Y UN DISPLAY LCD

Esta presentación es poco usual. Los libros o los manuales de los compiladores suelen resaltar solo la
interface de la librería que proveen. Esta exposición va pensando en los noveles usuarios del Arduino, que
encuentran algo confusa la inicialización de su librería de LCD por contemplar tofdos los modos de
operación viables.

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)

Interface de display LCD


8 líneas de Datos 4 líneas de Datos
3 líneas de Control (con RW) Interface de 11 líneas Interface de 7 líneas
2 líneas de Control (sin RW) Interface de 10 líneas Interface de 6 líneas

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).

Interface de 11 líneas entre un microcontrolador y un LCD

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

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 10


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

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.

interface de 10 líneas entre un microcontrolador y un lcd

En la interface de 7 líneas el bus de datos del LCD se conecta con el microcontrolador por sus 4 pines
más altos: D4, D5, D6 y D7. Como todas las instrucciones (de datos y de comando) son de un byte, los
bytes deben ser transferidos en dos mitades. Primero se envía o recibe el nibble alto y luego el nibble
bajo, siendo cada nibble validado por un pulso del pin Enable. Esas rutinas extras harán crecer un poco el
firmware (programa del microcontrolador).

En la contraparte, con el microcontrolador aún disponiendo de las tres líneas de control, podemos realizar
cualquier operación de lectura y escritura, lo mismo que en la interface completa de 11 líneas pero
ahorrándonos 4 pines. Este beneficio suele prevalecer sobre el handicap derivado del firmware.

Los LCDs están fabricados con tecnología CMOS, por lo que algunos modelos sugieren conectar los
pines de entrada no usados a alguna señal estable para evitar que por ellos se filtre algún ruido que pueda
perturbar la operación del LCD.

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 11


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

interface de 7 líneas entre un microcontrolador y un lcd

Por último tenemos la interface de 6 líneas. 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.

Interface de 6 líneas entre un microcontrolador y un LCD

LIBRERÍA PARA DISPLAY LCD

Tenemos a continuación una librería para controlar un LCD con una interface de 4 bits y usando el bit BF
(Busy Flag). Si tuviste la paciencia de leer las páginas anteriores, verás que es un claro reflejo de todo lo
expuesto. Y si no, de todos modos en seguida citaré ligeramente cómo utilizarla.

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 12


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

La librería trabaja para los compiladores IAR C y AVR GCC y consta de dos archivos lcd.h y lcd.c.
Ambos deberán ser indexados al proyecto en el entorno de AVR IAR C o Atmel Studio 6 para WinAVR
(ante alguna duda puedes ir a la sección Adición de Archivos o Librerías al Proyecto). En el código
fuente, sin embargo, solo se debe indicar el archivo de cabecera i2c.h mediante la directiva #include.

#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.

Funciones Básicas Disponibles

 lcd_init(). Obviamente es la primera función a llamar. Tras ejecutarse el LCD debe quedar
inicializado, con la pantalla limpia y con el cursor en el primer casillero.
 lcd_gotorc(r,c). El LCD tiene un cursor que, si bien puede mostrarse en pantalla, suele
configurarse para que permanezca oculto. Bien, visible o no, el cursor avanza automáticamente
tras cada letra que se escribe. Con lcd_gotorc(r,c) podemos mover el cursor manualmente a la
fila r y columna c. El parámetro r puede valer entre 1 y 2, y el valor de c va de 1 en adelante.
 lcd_puts(s). Visualiza la cadena s en el LCD empezando en la posición actual del cursor. La
cadena s es almacenada en RAM. No se suelen mostrar grandes datos en un LCD, así que no
implemente una función análoga que opere sobre la memoria FLASH.
 lcd_clear(). Limpia la pantalla del LCD y coloca el cursor al inicio, en la fila 1, columna 1.
 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:

lcd_cmd(LCD_LINE2); // Mover cursor al inicio de línea 2


lcd_cmd(LCD_CLEAR); // Limpiar pantalla
lcd_cmd(LCD_CURBLK); // Mostrar Cursor + Blink
lcd_cmd(LCD_CURSOR); // Mostrar solo Cursor
lcd_cmd(LCD_CGRAM+7);//Mover Puntero de RAM a dirección 7 de la
CGRAM

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 el puerto a donde se conectará el bus de datos del LCD


* Se utilizará el nible alto del puerto escogido (ejem. PB4-
DB4,...,PB7-DB7)*/

#define lcd_DATAout PORTB // Registro PORT del puerto

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 13


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

#define lcd_DATAin PINB // Registro PIN del puerto


#define lcd_DATAddr DDRB // Registro DDR del puerto

/* Define el puerto a donde se conectarán las líneas de control del LCD


* E, RW y RS. Puede ser el mismo puerto del bus de datos.*/
#define lcd_CTRLout PORTB // Registro PORT del puerto
#define lcd_CTRLin PINB // Registro PIN del puerto
#define lcd_CTRLddr DDRB // Registro DDR del puerto

/* 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
void lcd_puts(char * s); // Envía una cadena ram al LCD
void lcd_gotorc(char r, char c); // Cursor a fila r, columna c
void lcd_clear(void); // Limpia el LCD y regresa el cursor al inicio
void lcd_data(char dat); // Envía una instrucción de dato al LCD
void lcd_cmd(char com); // Envía una instrucción de comando al LCD
char lcd_read(char RS); // Lee un dato del LCD
void lcd_write(char inst, char RS); // Escribe una instrucción en el LCD
void lcd_nibble(char nibble);
void ldelay_ms(unsigned char );
/*********************************************************************
* 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);

/* Secuencia de inicialización del LCD en modo de 4 bits*/

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 14


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

lcd_CTRLout &= ~((1<<lcd_E)|(1<<lcd_RW)|(1<<lcd_RS));


ldelay_ms(45); // > 40 ms
lcd_nibble(0x30); // Function Set: 8-bit
ldelay_ms(5); // > 4.1 ms
lcd_nibble(0x30); // Function Set: 8-bit
ldelay_ms(1); // > 100 µs
lcd_nibble(0x30); // Function Set: 8-bit
ldelay_ms(1); // > 40 µs
lcd_nibble(0x20); // Function Set: 4-bit
ldelay_ms(1); // > 40 µs
lcd_nibble(0x20); // Function Set: 4-bit, 2lines, 4×7font
lcd_nibble(0x80); //
lcd_write(0x0C,0);//isplay ON/OFF Control:Displayon,Cursor off,Blink off
lcd_write(0x01, 0); // Clear Display
lcd_write(0x06, 0); // Entry Mode Set
}
//***********************************************************
// Escribe una instrucción en el LCD:
// Si RS = 0 la instrucción es de comando (Function Set, Entry Mode set, etc).
// Si RS = 1 la instrucción es de dato y va a la DDRAM o CGRAM.
//*********************************************************
void lcd_write(char inst, char RS)
{
while(lcd_read(0)&0x80); // Esperar mientras LCD esté ocupado
if(RS)
lcd_CTRLout |= (1<<lcd_RS); //Para escribir en DDRAM o CGRAM
else
lcd_CTRLout &= ~(1<<lcd_RS);//Para escribir en Registro de Comandos
delay_us(5); // Permite actualizar el Puntero de RAM
lcd_nibble(inst); // Enviar nibble alto
lcd_nibble(inst<<4); // Enviar nibble bajo
}
//********************************************************
// Envía el nibble alto de 'nibble' al LCD.
//******************************************************
void lcd_nibble(char nibble)
{
lcd_CTRLout &= ~(1<<lcd_RW); // Establecer Modo de escritura
lcd_DATAddr |= 0xF0; // Hacer nibble alto de bus de datos salida
lcd_DATAout = (nibble&0xF0)|(lcd_DATAout&0x0F); // Colocar dato
delay_us(2); // tAS, set-up time > 140 ns
lcd_CTRLout |= (1<<lcd_E); // Pulso de Enable
delay_us(2); // Enable pulse width > 450 ns
lcd_CTRLout &= ~(1<<lcd_E); //
lcd_DATAddr &= 0x0F; // Hacer nibble alto entrada
}
//********************************************************
// Lee un byte de dato del LCD.
// Si RS = 1 se lee la locación de DDRAM o CGRAM direccionada actualmente.
// Si RS = 0 se lee el 'bit de Busy Flag' + el 'Puntero de RAM'.
//*******************************************************
char lcd_read(char RS)
{
char high, low;
if(RS)
lcd_CTRLout |= (1<<lcd_RS); // Para leer de DDRAM o CGRAM
else
lcd_CTRLout &= ~(1<<lcd_RS); // Para leer Busy Flag + Puntero de RAM
lcd_CTRLout |= (1<<lcd_RW); // Establecer Modo Lectura
lcd_DATAddr &= 0x0F; // Hacer nibble alto entrada
delay_us(2); // tAS, set-up time > 140 ns

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 15


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

lcd_CTRLout |= (1<<lcd_E); // Habilitar LCD


delay_us(2); // Data Delay Time > 1320 ns
high = lcd_DATAin; // Leer nibble alto
lcd_CTRLout &= ~(1<<lcd_E); // Para que el LCD prepare el nibble bajo
delay_us(2); // Enable cycle time > 1200 ns
lcd_CTRLout |= (1<<lcd_E); // Habilitar LCD
delay_us(2); // Data Delay Time > 1320 ns
low = lcd_DATAin; // Leer nibble bajo
lcd_CTRLout &= ~(1<<lcd_E); //
return (high&0xF0)|(low>>4); //
Juntar nibbles leídos
}
//****************************************************
// Envían cadenas RAM terminadas en nulo al LCD.
//**************************************************
void lcd_puts(char * s)
{
unsigned char c, i=0;
while(c = s[i++])
lcd_write(c, 1); // Instrucción 'Write Data to
DDRAM/CGRAM'
}
//*********************************************************
// Ubica el cursor del LCD en la columna c de la línea r.
//********************************************************
void lcd_gotorc(char r, char c)
{
if(r==1) r = LCD_LINE1;
else r = LCD_LINE2;
lcd_write(r+c-1, 0); // Instrucción 'Set DDRAM Address'
}
//*************************************************************
// Limpia la pantalla del LCD y regresa el cursor a la primera posición
// de la línea 1.
//*************************************************************
void lcd_clear(void)
{
lcd_write(LCD_CLEAR, 0); // Instrucción 'Clear Display'
}

//*********************************************************
// 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);
}

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 16


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

PRÁCTICAS CON LCD-PARTE I

TITULO: MOSTRAR MENSAJES EN EL LCD CON EL ATMEGA8

OBJETIVO Mostrar un mensaje de “Hello World” en el LCD es un programa casi tan trillado
como hacer parpadear un LED.

FUNDAMENTO TEORICO

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.

PROCEDIMIENTO

1.- Implemente el Circuito para el LCD y el microcontrolador AVR.

2.- Realizar el programa considerando las instrucciones comentadas

/*********************************************************
* FileName: main.c
* Purpose: LCD - Visualización de texto
* Processor: ATmega164P
* Compiler: AVR IAR C y AVR GCC (WinAVR)
*******************************************************/

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 17


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

#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("Hello"); // Escribir Hello
lcd_gotorc(2,7); // Cursor a fila 2 posición 7
lcd_puts("World"); // ...
delay_ms(600); // Pausa de 600 ms
lcd_clear(); // Limpiar pantalla
delay_ms(400); // ...
}
}

Laboratorio –PARTE II
VISUALIZACIÓN DE NÚMEROS

Los LCDs solo entienden de caracteres alfanuméricos y algunos otros, pero no saben reconocer números.
En esta práctica veremos cómo hacerlo implementando un sencillo reloj. No será el más preciso, pero
servirá de buen ejemplo parar formatear números.

FUNDAMENTO
Para el circuito, de ahora en adelante, en vez del potenciómetro, colocaremos un diodo 1N4148 en el pin
VEE para fijar la tensión (VDD-VEE) a cerca de 4.3 V. En la mayoría de los LCDs este valor brinda un
muy aceptable nivel de contraste de la pantalla.

Circuito para el LCD y el microcontrolador AVR.

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 18


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

La función lcd_puts recibe como parámetro un array de tipo char, que en su forma más usada sería una
cadena texto.

Para visualizar números en el LCD primero debemos convertirlos en cadenas de texto. La conocida
función sprintf (acrónimo de string print formatted) puede formatear cadenas y números en diferentes
bases y colocarlas en el array que recibe como primer parámetro. Sprintf está basada en printf, así que
tiene las mismas características y limitaciones. En este programa solo se convierten números enteros.
Pero si deseas utilizar números de punto flotante tendrás que habilitar el uso de la librería que contiene
printf en versión completa. Para más información puedes revisar la sección Configuración de printf del
capítulo Atmel Studio 6 y WinAVR.

Sprintf soporta varios formatos de números e incluso en su modo básico requiere de cierta memoria que a
veces podría ser de consideración. Para ese caso también se pueden usar otras funciones de la librería C
estándar stdlib.h, como itoa, por ejemplo. Normalmente no las uso porque tienen variaciones entre los
compiladores y al menos para las prácticas como ésta prefiero no tocar esas divergencias.

PROCEDIMIENTO
2.1 Implemente el circuito de la figura 2
2,2 Realizar el programa

/*******************************************************************
* FileName: main.c
* Purpose: LCD - Visualización de números
* Processor: ATmega164P
* Compiler: AVR IAR C y AVR GCC (WinAVR)

*******************************************************************/
#include "avr_compiler.h"
#include "lcd.h"
void delay_ms(unsigned int t)
{
while(t--)
delay_us(1000);
}

int main(void)
{
char buff[17]; // Array de 17 elementos tipo char
unsigned seg, min, hor;
seg = min = 0;
hor = 12;
lcd_init(); // Inicializar LCD
lcd_gotorc(1,4); // Cursor a fila 1 posición 4
lcd_puts("easy clock");
for(;;)
{
sprintf(buff, "%2d:%02d:%02d ", hor, min, seg); // Formatear
lcd_gotorc(2,5); // Cursor a fila 2 posición 5
lcd_puts(buff); // Enviar buffer a LCD
if(++seg > 59)
{
seg = 0;
if(++min > 59)
{
min = 0;
if(++hor > 12)
hor = 1;
}
}
delay_ms(998);
}

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 19


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

PARTE III
MOSTRAR TEXTO EN DESPLAZAMIENTO EN LCD
FUNDAMENTO
Como parte de su funcionalidad, el controlador interno del LCD puede ejecutar instrucciones para
desplazar lo mostrado en la pantalla una posición hacia la izquierda o la derecha. Los códigos para
desplazar la pantalla (ver la sección referida) son 0x1C y 0x18. Con eso en el código solo tendríamos que
escribir
lcd_cmd(0x1C);
Para mover todo el display incluyendo el cursor a la derecha, y
lcd_cmd(0x18);
Para mover el display a la izquierda.

Puede parecer interesante, pero como lo comprobarás en la práctica Comunicación PC-AVR-LCD,


funciona en un rango restringido y no es útil cuando solo queremos desplazar el texto de una sola línea.
Estas limitaciones llevan a muchos a realizar esos efectos mediante rutinas software, como lo que
haremos en esta práctica: Mostrar por el LCD un mensaje que pasa como una marquesina.

Circuito para el LCD y el microcontrolador AVR.

PROCEDIMIENTO

1.- Implemente el circuito de la figura


2.- Realizar el programa

El Código fuente

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 20


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

/***************************************************************
* FileName: main.c
* Purpose: LCD - Textos en desplazamiento
* Processor: AVR ATmegaXX4
* Compiler: AVR IAR C & AVR GCC (WinAVR)
*******************************************************************/
#include "avr_compiler.h"
#include "lcd.h"
#define LCD_LEN 16 // Para LCD de 2×16
PROGMEM const char Taine[] = "\"EL HAMBRE PRODUCE POEMAS INMORTALES. \
LA ABUNDANCIA, SOLAMENTE INDIGESTIONES Y TORPEZAS\" ";
void delay_ms(unsigned int t)
{
while(t--)
delay_us(1000);
}
int main(void)
{
unsigned char j; // Índice relativo
unsigned char i; // Índice base
char c;
lcd_init();
lcd_puts(" Scrolling text "); //Escribir "Scrolling text" en LCD
while(1)
{
start:
i = 0;
for(;;)
{
lcd_cmd(LCD_LINE2); // Cursor a inicio de línea 2
for(j=0; j<LCD_LEN-1; j++)
{
c = pgm_read_byte(&Taine[i+j]); // Obtener dato de matriz
if(c) // Si es dato válido,
lcd_data(c); // enviarlo a LCD
else // Si no (c = 0x00 = fin),
goto start; // salir de los dos bucles for
}
delay_ms(400);
i++;
}
}
}

3.- Descripción del programa

El texto de la pantalla se desplaza una posición cada 400 ms. Si te parece que avanza muy lento,
puedes disminuir esta pausa. No obstante, podrías empezar a ver como si hubiera dos letras por
casillero de la pantalla. Ello se debe a que el carácter enviado al LCD no se muestra ni se borra
de inmediato. Es lo que sus datasheets indican como tiempo de respuesta de visualización.

En general, a diferencia del Basic, en C es muy mal visto el uso de un goto, salvo un caso extremo. goto
funciona como en el ensamblador: salta a otro punto del programa, identificado con una etiqueta. Mi goto
salta a la etiqueta start para salir de dos bucles al mismo tiempo. Dicen que ése es uno de los pocos casos
considerados extremos: salir intempestivamente de varios bucles anidados. A decir verdad,
siempre hay algoritmos alternativos para evitar el goto.

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 21


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

PARTE IV

MOSTRAR CARACTERES GRÁFICOS EN LCD CON EL ATMEGA8

FUNDAMENTO

La creación de caracteres gráficos puede ser un tema superfluo. he preparado esta práctica para ir
cerrando el capítulo.

Hagamos un poco de memoria. Cuando enviamos el código de un carácter alfanumérico a la DDRAM del
LCD, su chip interno buscará en la CGROM el patrón correspondiente y luego lo visualizará en la
pantalla. Así se escriben todos textos (y así hemos trabajado hasta ahora).

Ahora bien, si el código enviado vale entre 0x00 y 0x07 (o 0x08 y 0x0F), el chip interno buscará su
patrón de visualización en la CGRAM. Siendo ésta una RAM de lectura/escritura, podemos programar en
ella los diseños que se nos ocurran.

Mapa de memoria para la creación de nuevos caracteres.

La CGRAM (Character Generator RAM) consta de 64 bytes en los que se pueden escribir los patrones de
8 nuevos caracteres de 5×7 puntos ó 4 caracteres de 5×10 puntos. Aquí veremos el primer caso.

Cuando los caracteres son de 5×7 puntos los 64 bytes se dividen en 8 bloques de 8 bytes cada uno, y cada
bloque almacena el patrón de un nuevo carácter. El esquema mostrado arriba indica que:

 El primer bloque de CGRAM, con direcciones desde 0b00000000 hasta 0b00000111,


corresponde al código 0x00 (ó 0x80) de la DDRAM.

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 22


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

 El segundo bloque CGRAM, con direcciones desde 0b00001000 hasta 0b00001111,


corresponde al código 0x01 (ó 0x88) de la DDRAM; y así sucesivamente.

Por ejemplo, la figura de arriba indica que se han rellenado los dos primeros bloques con los patrones de
dos pacman. Hasta ahí solo se han creado dos nuevos caracteres. Para mostrarlos en el LCD habría que
escribir un código así:

lcd_data(0x00); // Visualizar primer pacman


lcd_data(0x01); // Visualizar segundo pacman

PROCEDIMIENTO
1.- IMPLEMENTE EL CIRCUITO DE LA FIGURA
Se muestra en el LCD un pacman que se desplaza de uno a otro lado.

Circuito para el LCD y el microcontrolador AVR.

2.- Realizar el programa comentando cada instrucción

El código fuente
/******************************************************************
* FileName: main.c
* Purpose: LCD - Creación de caracteres gráficos personalizados
* Processor: AVR ATmegaXX4
* Compiler: AVR IAR C & AVR GCC (WinAVR)

*******************************************************************/
#include "avr_compiler.h"
#include "lcd.h"
#define LCD_LEN 16 // Para LCD de 2×16

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 23


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

/* Identificadores de los nuevos caracteres */


#define PacR1 0x00
#define PacR2 0x01
#define PacL1 0x02
#define PacL2 0x03
/* Patrones de los nuevos caracteres a crearse */
PROGMEM const char Pattern1[] = {0x0F,0x1C,0x18,0x10,0x18,0x1C,0x0F,0x00};
PROGMEM const char Pattern2[] = {0x00,0x0E,0x1F,0x10,0x1F,0x0E,0x00,0x00};
PROGMEM const char Pattern3[] = {0x1E,0x07,0x03,0x01,0x03,0x07,0x1E,0x00};
PROGMEM const char Pattern4[] = {0x00,0x0E,0x1F,0x01,0x1F,0x0E,0x00,0x00};
void delay_ms(unsigned int t)
{
while(t--)
delay_us(1000);
}
void create_char(unsigned char a, PGM_P p)
{
unsigned char i;
lcd_cmd(LCD_CGRAM + a); // Instrucción Set CGRAM Address
for (i=0; i<8; i++)
lcd_data(pgm_read_byte(p+i));
}
int main(void)
{
signed char i; // Debe ser variable con signo
lcd_init(); // Inicializar LCD
/* Crear los nuevos caracteres (los pacman's)
* Esto es volcar los patrones de los pacman en la CGRAM */
create_char(PacR1*8, Pattern1);
create_char(PacR2*8, Pattern2);
create_char(PacL1*8, Pattern3);
create_char(PacL2*8, Pattern4);
lcd_clear(); // Limpiar pantalla y regresar a DDRAM
lcd_puts(" Hungry Pacman "); // Escribir "Hungry Pacman" en LCD
while(1)
{
/* Pacman desplazándose a la derecha */
for(i=0; i<LCD_LEN; i++)
{
lcd_cmd(LCD_LINE2+i); // Cursor a posición i de línea 2
if(i & 0x01) // Si bit 0 de i es 1,
lcd_data(PacR1); // enviar pacman abierto
else // Si no,
lcd_data(PacR2); // enviar pacman cerrado
lcd_cmd(LCD_LINE2+i-1); // Cursor a posición anterior de línea 2
lcd_data(' '); // para borrar pacman previo
delay_ms(200);
}
/* Pacman desplazándose a la izquierda */
for(i=LCD_LEN; i>=0; i--)
{
lcd_cmd(LCD_LINE2+i); // Cursor a posición i de línea 2
if(i & 0x01) // Si bit 0 de i es 1,
lcd_data(PacL1); // enviar pacman abierto
else // Si no,
lcd_data(PacL2); // enviar pacman cerrado
//lcd_cmd(LCD_LINE2+i+1); // Cursor a posición anterior de línea 2
lcd_data(' '); // para borrar pacman previo
delay_ms(200);
}
}
}

3.- Descripción del programa


Después de iniciado el LCD, los datos que se le envíen irán a la DDRAM (para mostrar caracteres en la
pantalla). Como los patrones de los pacman deben ir en la CGRAM necesitamos establecerla como
destino. Para eso enviamos el comando Set CGRAM Address con la dirección de CGRAM que queremos

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 24


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

acceder. La función create_char rellena con 8 bytes del array p que se le pasa como parámetro el
segmento de CGRAM que empieza en la dirección a.
void create_char(unsigned char a, PGM_P p)
{
unsigned char i;
lcd_cmd(LCD_CGRAM + a); // Instrucción Set CGRAM Address
for (i=0; i<8; i++)
lcd_data(pgm_read_byte(p+i));
}

Notemos que al término de la función create_char el puntero de RAM sigue dirigido a la CGRAM. Por
tanto para visualizar los caracteres en la pantalla, incluyendo los nuevos caracteres creados, tenemos que
volver a seleccionar la DDRAM. Para esto tenemos la instrucción Set DDRAM Address, Return Home y
Clear Display. Todas estas instrucciones están relacionadas con el cursor, el cual a su vez no es otra cosa
que el puntero RAM trabajando sobre la DDRAM. Yo usé la tercera opción con sentencia lcd_clear() que
aparemtenente no tenía sentido porque la pantalla ya está limpia tras la inicialización.

Como hemos creado los 4 pacman en los 4 primeros bloques (de 8 bytes) de la CGRAM, los códigos para
accederlos serán 0 (PacR1), 1 (PacR2), 2 (PacL1) y 3 (PacL2), respectivamente.

Por si no quedó claro cómo se forman los patrones de los pacman, aquí tenemos los dos primeros. (Los
bits × no importan, pueden ser 1s o 0s.)

PROGMEM const char Pattern1 [] =


{0x0F,0x1C,0x18,0x10,0x18,0x1C,0x0F,0x00};
PROGMEM const char Pattern2 [] =
{0x00,0x0E,0x1F,0x10,0x1F,0x0E,0x00,0x00};

Solo debemos tener un poco de paciencia para elaborar los arrays de los patrones. Ahora que si no la
tienes o prefieres un atajo, puedes utilizar una de las tantas herramientas que abundan (me gusta la
flexibilidad de LCD Font Creator). Inclusive los mismos compiladores como CodeVisionAVR o MikroC
proveen los suyos. Abajo se ve cómo el generador de caracteres de MikroC nos cambia el descifrado de
código binario por simples clics. El código generado incluye una función que crea y visualiza el nuevo
carácter, pero a mí solo me interesa el array.

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 25


UNIVERSIDAD NACIONAL DEL CALLAO--------FIEE

Prof. MSc. Ing. JACOB ASTOCONDOR VILLAR 26

También podría gustarte