MICROCONTROLADORES < VISUALIZAC VISUALIZACION ION DE DE DATOS DATOS – CARACTERE CARACTERES S -GRAFICOS -GRAFICOS CON LC>
PRÁCTICAS PRÁCTICAS CON CON LCD y ATMEGA8 ATMEGA8
PRACTICA1 VISUALIZACION DE CARACTERES 1.- Mostrar un mensaje mensaje de “Hello World” en el LCD LCD es un programa casi casi tan trillado como hacer parpadear un LED. Según la configuración por defecto de la librería para el LCD, 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 lcd.h.. El pin VEE (o Vo Vo)) del LCD establece el contraste de la pantalla. Muchas veces se prefiere quitar el potenciómetro y conectar VEE conectar VEE a tierra para fijar el máximo contraste. En los siguientes circuitos haremos algo parecido.
/****************************************************************** * FileName: main.c * Purpos Purpose: e: LCD - Visual Visualiza izació ción n de texto texto *******************************************************************/ #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 1
MICROCONTROLADORES < VISUALIZACION DE DATOS – CARACTERES -GRAFICOS CON LC>
while(1) { lcd_gotorc(1,7); lcd_puts("Hello"); lcd_gotorc(2,7); lcd_puts("World"); delay_ms(600); lcd_clear(); delay_ms(400);
// // // //
Cursor a fila 1 posición 7 Escribir Hello Cursor a fila 2 posición 7 ...
// Pausa de 600 ms // Limpiar pantalla // ...
} }
PRACTICA2 : VISUALIZACIÓN DE NÚMEROS 2.- 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. 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.
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.
2
MICROCONTROLADORES < VISUALIZACION DE DATOS – CARACTERES -GRAFICOS CON LC>
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.
/********************************************************** * FileName: main.c * Purpose: LCD - Visualización de números ********************************************************************/ #include "avr_compiler.h" #include "lcd.h" void delay_ms(unsigned int t) { while(t--) delay_us(1000); } int main(void) { char buff[17]; unsigned seg, min, hor; seg = min = 0; hor = 12; lcd_init(); lcd_gotorc(1,4); lcd_puts("easy clock");
// Array de 17 elementos tipo char
// Inicializar LCD // Cursor a fila 1 posición 4
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); } }
PRACTICA3 MOSTRAR TEXTO EN DESPLAZAMIENTO EN LCD 3.- 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 3
MICROCONTROLADORES < VISUALIZACION DE DATOS – CARACTERES -GRAFICOS CON LC>
mediante rutinas software, como lo que haremos en esta práctica: Mostrar por el LCD un mensaje que pasa como una marquesina.
El Código fuente /******************************************************************** * FileName: main.c * Purpose: LCD - Textos en desplazamiento *******************************************************************/ #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; unsigned char i; char c;
// Índice relativo // Índice base
lcd_init(); lcd_puts(" Scrolling text ");
// Escribir "Scrolling text" en LCD
while(1) { 4
MICROCONTROLADORES < VISUALIZACION DE DATOS – CARACTERES -GRAFICOS CON LC>
start: i = 0; for(;;) { lcd_cmd(LCD_LINE2);
// Cursor a inicio de línea 2
for(j=0; j
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.
5
MICROCONTROLADORES < VISUALIZACION DE DATOS – CARACTERES -GRAFICOS CON LC>
PRACTICA4
CARACTERES GRÁFICOS EN LCD
La creación de caracteres gráficos puede ser un tema superfluo. Aun así, suponiendo que no faltarán algunas personas obsesivas como yo, que siempre quieren probarlo todo, 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.
6
MICROCONTROLADORES < VISUALIZACION DE DATOS – CARACTERES -GRAFICOS CON LC>
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. 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 Esquema
Se muestra en el LCD un pacman que se desplaza de uno a otro lado.
El código fuente /******************************************************************* * FileName: main.c * Purpose: LCD - Creación de caracteres gráficos personalizados ********************************************************************/ #include "avr_compiler.h" #include "lcd.h" #define LCD_LEN 16 // Para LCD de 2×16 /* Identificadores de los nuevos caracteres */ #define PacR1 0x00 #define PacR2 0x01 #define PacL1 0x02 #define PacL2 0x03 7
MICROCONTROLADORES < VISUALIZACION DE DATOS – CARACTERES -GRAFICOS CON LC>
/* 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=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); } } } 8
MICROCONTROLADORES < VISUALIZACION DE DATOS – CARACTERES -GRAFICOS CON LC>
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 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_CGRAM + a); // Instrucción Set CGRAM Address lcd_cmd 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. 9
MICROCONTROLADORES < VISUALIZACION DE DATOS – CARACTERES -GRAFICOS CON LC>
10