MANEJO DE PANTALLAS GRAFICAS La presente nota trata sobre un POWERTIP PG12864 (128x64 pixeles) Este GLCD está basado en el controlador Hitachi HD6102 o el clon de este el Samsung KS0108. Tiene dos controladores, uno controla la parte izquierda y el otro la parte derecha, en general se parece mucho al ya conocido HD44780 controlador de pantalla alfanumérica, pero este agrega tres señales nuevas, las señales CS1 y CS2 para la activación de los chips de pantalla, una señal I/D que es el equivalente a RS en los alfanuméricos y una señal de RESET muy útil a la hora de inicializar el GLCD. Una diferencia importante en estas pantallas es la tensión de contraste que debe estar en el orden de los -8v, afortunadamente el PG12864 tiene su propio generador para el voltaje de contraste. Cada display tiene dos páginas de 64 columnas que van desde la dirección 0x40 a 0x7F esto conforma la dirección “Y”, que básicamente es como un contador que se auto incrementa de manera automática al escribir en la pantalla de tal forma que la coordenada “Y” se auto ajusta. En el caso de la coordenada “X” las cosas son un poco diferentes, no hay auto ajuste en esta coordenada y son 8 segmentos de 8 bits verticales. Para entender mejor, imaginemos que cada byte en cada segmento está colocada en una de las 64 columnas de la coordenada “Y”. Pagina 1 de 17 La página 0 de la coordenada “X” ocupa la dirección 0xB8 luego 0xB9......... hasta 0xBF. Veamos el siguiente esquema, aquí hay un byte con el binario 10101010 cada uno de estos bit´s del byte vertical tendrá incidencia en un pixel de la pantalla . Un uno lógico es un pixel activo un cero lógico es un pixel apagado. Es importante entender que el segmento o pagina “X 0” en la dirección 0xB8 tiene 64 bytes verticales correspondiendo cada uno de ellos a una columna de la coordenada “Y” por tanto cada segmento “X” puede controlar 512 pixeles los ocho segmentos controlan 4096 pixeles en cada mitad de la pantalla, cada controlador puede manejar 4096 pixeles y claro está la pantalla tiene un total 8192 pixeles que se manejan con los dos controladores de pantalla. En el ejemplo se puede ver como se encienden y apagan 8 pixeles en la pagina 0 del eje “X” y en la columna 35 de la coordenada “Y”. Para la correcta operación de estas pantallas es importante respetar el diagrama de tiempos que el fabricante recomienda. Pagina 2 de 17 Se puede ver aquí claramente que el ciclo de activación del pin E como mínimo dura 1uS (1000nS) toda operación sobre la pantalla está condicionada a esta ventana de tiempo total, mas allá claro de los tiempos individuales de cada una de las funciones que se deben respetar pero todo dentro de la ventana de tiempo de E. Las condiciones de RESET se pueden observar aquí, donde vemos que el pulso de reset debe finalizar luego de 1uS de puesta la alimentación en la pantalla. El reset ocurre por nivel bajo. Pagina 3 de 17 Como alimentar la pantalla y el voltaje de contraste: Como manejar la pantalla: El mayor problema que presenta el manejo de estas pantallas radica en que se debe disponer de mucha memoria en el dispositivo de control del GLCD, ya sea el microcontrolador o el procesador que se conecte a el debe ser capaz de manejar la información necesaria para “pintar” los pixeles. Cada grupo de 8 pixeles requiere de una posición de memoria para almacenarlo (cada uno de estos bytes verticales debe ser guardado para reproducir la imagen). Para pintar una pantalla completa, digamos un marco de fondo donde se pintaran los datos se necesitan de 1024 bytes. (1024 x 8 = 8192 pixeles disponibles en la pantalla). Un ejemplo de esto puede verlo aquí. En la imagen superior se observa la pantalla funcionando mostrando un fondo y el despliegue del dato capturado desde el conversor A/D. En la imagen blanco y negro se observa la pantalla de fondo tal cual como se la creo con el Paint de Windows. Esta imagen se dibuja con cualquier programa, lo importante es que la imagen debe ser Blanco y Negro y desde luego debe respetar el tamaño de pantalla, en este caso la pantalla es 128x64 pixeles. Pagina 4 de 17 Como termina la imagen en ByN dentro de la memoria del microcontrolador?. Aquí la respuesta: Se utiliza para esto un software decodificador GLC_EDITOR con el se toma la imagen en ByN y se la decodifica en una secuencia de números hexadecimales que conformaran los bytes cuyos bit´s activaran los pixeles. Cuando tenemos nuestra imagen decodificada solo tenemos que copiar la secuencia de números y pegarla de la siguiente forma para generar un string de 1024 números que formará la imagen de fondo en la pantalla gráfica. (Estamos suponiendo que nuestro lenguaje de programación en C). const char display[1024]={ 0xFF,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0xC1, 0xC1,0xE1,0xE1,0xE1,0xE1,0xA1,0x21,0x61, 0xC1,0xC1,0x81,0x01,0x01,0x01,0x01,0x01, 0xC1,0x61,0x31,0x11,0x91,0x91,0x91,0x91, 0xF1,0x01,0xF9,0x89,0x89,0xF9,0x01,0x01, 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00, Pagina 5 de 17 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xFE,0xFF,0xFF, 0xFF,0xFF,0xEF,0xC7,0xEF,0xFF,0xFF,0xFE, 0x00,0x01,0x01,0xFF,0x00,0x00,0x0E,0x0B, 0xF9,0x00,0x00,0xF9,0x09,0x0B,0x0E,0x00, 0x0F,0x09,0x09,0xF9,0x01,0xFE,0x00,0x00, 0x00,0x00,0xFF,0x01,0xCF,0x24,0x12,0x0B, 0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x07, . . . . . . . Para los caracteres el enfoque es similar, elegimos un carácter desde windows y luego creamos una plantilla y la decodificamos con el mismo programa. Supongamos que buscamos decodificar esta secuencia de números. Esto decodificará caracteres de 16x8 pixeles. Generando una secuencia de 30 bytes donde los 15 primero bytes son la mitad superior del carácter y los restantes 15 la parte inferior del carácter. Un carácter de este formato ocupa dos segmentos “X” (dos renglones) y tomaran 8 columnas en “Y”. El resultado final será este: const char dos [30]={ //Esto codifica el número 0 0x00,0x30,0x3C,0x3C,0x1E,0x0E,0x0E,0x8E,0x8E,0xCE,0xFC,0xFC,0x78,0x00,0x00, // Mitad superior 0x00,0x78,0x7C,0x7E,0x7E,0x77,0x77,0x73,0x73,0x71,0x71,0x70,0x70,0x00,0x00, // Mitad inferior }; const char tres [30]={ //Esto codifica el número 1 0x00,0x30,0x3C,0x3C,0x1E,0x0E,0xCE,0xCE,0xCE,0xCE,0xFE,0xFC,0x38,0x00,0x00, // Mitad superior 0x00,0x0C,0x3C,0x3C,0x78,0x70,0x71,0x71,0x71,0x79,0x3F,0x3F,0x1F,0x00,0x00, // Mitad inferior }; Para dibujar estos números solo basta colocar el cursor en la coordenada XY y recorrer el string, la coordenada Y se auto incrementa por tanto es simple, cuando llegamos al vector 15 del string debemos cambiar de coordenada X (otro renglón) y volver a definir Y dado que esta se fue modificando medida que se escribía en el primer renglón. Una forma sencilla de hacer esto es con un bucle for, veamos un ejemplo: /********************************************************************************************/ void Scan_Caracter(void){ bit_set(RS,PTD); // Se indica que se escribe un carácter. for(a=0;a<=30;a++) // El carácter tiene 30 bytes en total { if(a==15) { // Cuando termino de leer la primera linea debo pasar a la siguiente. // cada linea ocupa 15 bytes para este tipo de caracteres. bit_clr(RS,PTD); // Se indica que se escribe un byte de control (RS=0) EscribirDato(x+1); // Pagina X. (La línea o renglón donde se escribe) EscribirDato(y); // Se coloca el cursor nuevamente en la coordenada Y bit_set(RS,PTD); // Nuevamente se escriben caracteres. } EscribirDato(dato [a]) ; Pagina 6 de 17 } bit_clr(RS,PTD); } /*********************************************************************************/ void EscribirDato(char Dato) { PTB = Dato; // Se coloca el carácter en el puerto del micrcontrolador bit_set(E,PTD); // Se activa el GLCD mediante el pin E Retardo(); // Se espera al menor 1uS bit_clr(E,PTD); // El pin E pasa a 0 GLCD desactivado } Para entender esto un poco mejor, observemos la pagina siguiente. Aquí vemos el mapa completo de memoria de la pantalla para sus dos microcontroladores. Puede ver los 8 segmentos X que inician en 0xB8 terminando en 0xBF y como se ordenan las columnas Y desde 0x40 a 0x7F, D0, D1..... D7 son los bit´s de los bytes verticales de cada columna Y en los segmentos X. Pongamos un ejemplo: Supongamos que queremos encender el primer pixel del margen superior izquierdo, para eso la secuencia seria como sigue: ● ● ● ● ● ● ● ● ● Poner a cero el pin D/I para indicar que es una instrucción Enviar el comando 0x3F Esto activa la pantalla Activar el Chip 1 CS1 =1 y CS2=0 Definir y enviar la coordenada X = 0xB8 Definir y enviar la coordenada Y = 0x40 Linea dentro del segmento = C0 Poner a uno el pin D/I para indicar que es un dato Dato a enviar [00000001] Poner a uno el pin E Que es linea dentro del segmento? Observe el mapa de memoria, verá a la izquierda indicadores C0,C1.....FF, para explicar de manera simple lo que hace este parámetro imagine que si escribe C0 está indicando que el byte se ajustará al segmento, si escribe C1 el byte se desplaza 1 hacia arriba, es decir que si escribe el binario 10000001 en las coordenadas X=0xB8, Y = 0x40, todo el byte se desplazó un bit hacia arriba por tanto en el segmento 0xB8 el bit D6 estará encendido y en el segmento 0xBF el bit D7 estará encendido también. Pagina 7 de 17 Pagina 8 de 17 El seteo de la linea dentro del segmento solo es necesario hacerla una vez ya que esto se mantiene invariable una vez que ha sido definido, por ejemplo en una rutina de inicio para el diplay. Un pequeño truco: (array para limpiar la pantalla) Podemos imaginar los pixeles de la pantalla como bit´s de una memoria, cuando la pantalla se activa esta memoria está “borrada”, sin nada en estos pixeles (bit´s) y por tanto puestos a “1” es decir tendremos 8192 pixeles activos podemos activar la media pantalla de la izquierda y observaremos como la mitad de pantalla se oscurece con sus 4096 pixeles activados, interesante es “borrar” todos los pixeles, ponerlos a cero para eso una solución simple puede ser crear una matriz de 1024 bytes todos es cero y simplemente escribirlos, esto limpiará la pantalla. Claro que si escribo un fondo de presentación, un menú, etc, el efecto es el mismo los pixeles son inicializados. Puede verse un ejemplo de un array de este tipo aquí. Conexiones del GLCD: Pagina 9 de 17 Set de instrucciones del GLCD: En la siguiente pagina se puede ver un ejemplo completo, el mismo se implementó con un microcontrolador MC68HC908JK3 una pantalla PG12864 y como lenguaje de programación C CodeWarrior 5,7. El programa es meramente demostrativo de lo expuesto y solo despliega una imagen de fondo Pagina 10 de 17 Veamos un ejemplo completo de uso: #include <hidef.h> /* for EnableInterrupts macro */ #include "derivative.h" /* include peripheral declarations */ void Retardo(void); void EscribirDato(char Dato); #define bit_set(bit,ubicacion) (ubicacion |= 1<<bit) /* Pone un bit en 1 en la posicion indicada */ #define bit_clr(bit,ubicacion) (ubicacion &= ~(1<<bit)) /* Pone un bit en 0 en la posicion indicada */ unsigned char numero =0; /* Se declara e inicializa una variable tipo char */ #define #define #define #define RS E CS1 CS2 6 7 3 2 unsigned char banderas =0; unsigned char x,y,cs; int ptr = 0; char buffer = 0; Tabla que codifica la Imagen a mostrar const char display[1024]={ 0xFF,0x01,0x6D,0xB5,0xD9,0x6D,0xB5,0xD9, 0x6D,0xB5,0xD9,0x6D,0xB5,0xD9,0x6D,0xB5, 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 0x01,0xF9,0x49,0x49,0x49,0x09,0x09,0xF9, 0x09,0x09,0x01,0xF9,0x89,0x89,0x71,0x01, 0xFF,0x00,0x81,0x41,0x20,0x11,0x11,0x08, 0x09,0x09,0x08,0x09,0x09,0x08,0x09,0x09, 0x08,0x88,0x88,0x88,0x08,0x08,0x08,0x08, 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, 0x08,0x08,0x88,0x08,0x08,0x08,0x08,0x08, 0x08,0x0B,0x08,0x08,0x08,0x0A,0x0A,0x0B, 0x0A,0x0A,0x08,0x8B,0x08,0x09,0x0B,0x08, Pagina 11 de 17 0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C, 0x23,0x20,0x20,0x11,0x00,0x1C,0x26,0x22, 0x3E,0x00,0xFE,0x22,0x22,0x1C,0x00,0x1C, 0x26,0x22,0x3E,0x00,0x1C,0x26,0x22,0x22, 0x00,0x00,0x3E,0x00,0x02,0x3F,0x02,0x00, 0x1C,0x26,0x22,0x3E,0x00,0x1C,0x26,0x22, 0x22,0x00,0x00,0x3E,0x00,0x1C,0x22,0x23, 0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0xF0, 0x50,0x90,0x10,0x10,0x10,0x10,0x10,0x10, 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, 0x10,0x10,0x90,0x50,0xF0,0x00,0x00,0x00, 0x00,0x00,0x00,0xE0,0x20,0x20,0x20,0x00, 0xE0,0x00,0x00,0x80,0x80,0x80,0x00,0x00, 0x80,0x80,0x80,0x00,0x80,0xC0,0x80,0x00, 0x80,0x80,0x80,0x80,0x00,0x80,0xC0,0x20, 0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0xFF, 0x00,0x00,0x01,0x82,0xC4,0x68,0x30,0x20, 0x20,0x20,0x20,0x20,0x20,0x30,0x68,0xC4, 0x82,0x01,0x00,0x00,0xFF,0x00,0x00,0x00, 0x00,0x00,0x00,0x0F,0x09,0x09,0x09,0x00, 0x0F,0x00,0x07,0x0A,0x09,0x09,0x00,0x07, 0x09,0x08,0x08,0x00,0x00,0x0F,0x00,0x00, 0x0F,0x01,0x00,0x01,0x07,0x08,0x08,0x07, 0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x0F, 0x0C,0x0E,0x0B,0x09,0x08,0x08,0x08,0x08, 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, 0x09,0x0B,0x0E,0x0C,0x0F,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, Pagina 12 de 17 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xFF,0x00,0x7F,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xF4,0x00,0xF0, 0x30,0x10,0xF0,0x00,0x10,0xF8,0x14,0x14, 0x00,0xE0,0x10,0x10,0xE0,0x00,0xF0,0x30, 0x10,0x30,0x00,0xF0,0x10,0xF0,0x10,0xF0, 0x00,0xE0,0x50,0x30,0x30,0x00,0x30,0x50, 0xD0,0x00,0xF0,0x08,0xE4,0xB4,0xF4,0x84, 0x88,0x70,0x10,0xF8,0x14,0x14,0x00,0x00, 0xFF,0x80,0x83,0x80,0x88,0x90,0x90,0xA0, 0xA0,0xA0,0xA0,0xA0,0xA0,0xA1,0xA0,0xA1, 0xA0,0xA0,0xA1,0xA0,0xA0,0xA3,0xA0,0xA0, 0xA0,0xA0,0xA1,0xA1,0xA0,0xA0,0xA1,0xA0, 0xA0,0xA0,0xA0,0xA1,0xA0,0xA1,0xA0,0xA1, 0xA0,0xA0,0xA1,0xA1,0xA1,0xA0,0xA1,0xA1, 0xA1,0xA0,0xA0,0xA1,0xA2,0xA2,0xA2,0xA2, 0xA0,0xA0,0xA0,0xA3,0xA0,0xA0,0xA0,0xA0, 0x09,0x09,0xF9,0x09,0x09,0x09,0x01,0xF9, 0x49,0x49,0x49,0x01,0xC1,0x31,0x09,0x09, 0x19,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 0x6D,0xB5,0xD9,0x6D,0xB5,0xD9,0x6D,0xB5, 0xD9,0x6D,0xB5,0xD9,0x6D,0xB5,0x01,0xFF, 0x88,0x08,0x0B,0x08,0x08,0x08,0x08,0x0B, Pagina 13 de 17 0x0A,0x0A,0x0A,0x08,0x09,0x0A,0x0A,0x0A, 0x09,0x08,0x08,0x08,0x08,0x08,0x08,0x08, 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08, 0x09,0x09,0x08,0x09,0x09,0x08,0x09,0x09, 0x08,0x11,0x11,0x20,0x41,0x81,0x00,0xFF, 0x1C,0x00,0x3E,0x06,0x02,0x3E,0x00,0x00, 0x00,0x00,0x00,0x1C,0x2A,0x26,0x26,0x00, 0x3E,0x06,0x02,0x3E,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0xC0,0x70,0x18,0x0C, 0x86,0x67,0x17,0x8F,0xE7,0x33,0x3B,0x1B, 0x1B,0x3B,0x73,0xE6,0xCC,0x38,0xF0,0x80, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF, 0x00,0x80,0x80,0x80,0x80,0x00,0x00,0xA0, 0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x80, 0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFE,0xE1,0x00,0x00,0x00, 0xFF,0x00,0x00,0xFF,0x00,0x00,0x00,0x00, 0x01,0xFE,0x00,0xFF,0xFF,0xFE,0x01,0xFF, 0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF, 0x00,0x0F,0x01,0x00,0x0F,0x00,0x00,0x0F, 0x00,0x07,0x09,0x08,0x08,0x00,0x07,0x09, 0x08,0x0F,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x03,0x1F,0x7E,0xFE,0xFE, 0xFF,0xFC,0xE0,0x87,0x3C,0x60,0xC0,0xA0, 0xD8,0xF7,0x78,0xBF,0xDF,0xE7,0xF8,0xFF, Pagina 14 de 17 0x8F,0x08,0xF0,0xE0,0xC0,0x80,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, 0x03,0x07,0x07,0x07,0x07,0x06,0x06,0x06, 0x06,0x06,0x07,0x03,0x01,0x00,0x01,0x03, 0x07,0x0F,0x1F,0x3F,0x7F,0x7F,0xFF,0xFE, 0x04,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF, 0xF4,0x00,0xF0,0x30,0x10,0x30,0x10,0xF8, 0x10,0x00,0xE0,0x50,0x30,0x30,0x00,0xE0, 0x30,0x10,0x10,0x00,0x00,0x00,0x00,0x00, 0xE0,0x30,0x10,0x10,0x00,0xE0,0x10,0x10, 0xE0,0x00,0x00,0xF0,0x10,0xF0,0x10,0xF0, 0x00,0x00,0x00,0x00,0x00,0xE0,0x30,0x10, 0xF0,0x00,0xF0,0x30,0x10,0x30,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF, 0xA1,0xA0,0xA1,0xA0,0xA0,0xA0,0xA0,0xA1, 0xA0,0xA0,0xA0,0xA1,0xA1,0xA1,0xA0,0xA0, 0xA1,0xA1,0xA1,0xA0,0xA0,0xA1,0xA0,0xA0, 0xA0,0xA1,0xA1,0xA1,0xA0,0xA0,0xA1,0xA1, 0xA0,0xA0,0xA0,0xA1,0xA0,0xA1,0xA0,0xA1, 0xA0,0xA0,0xA1,0xA0,0xA0,0xA0,0xA1,0xA1, 0xA1,0xA0,0xA1,0xA0,0xA0,0xA0,0xA0,0xA0, 0xA0,0x90,0x90,0x88,0x84,0x83,0x80,0xFF, }; Pagina 15 de 17 void main(void) { CONFIG1 = 1; /* Desactiva el watch-dog */ DisableInterrupts; /* Desactiva las Interrupciones */ PTB = 0; /* Limpia puerto B por donde se comunicaran los datos al LCD*/ PTD = 0; /* Limpia puerto D por donde se controla la pantalla */ DDRD = 0xFF; /* Puerto D y B como salidas */ DDRB = 0XFF; for(cs=0;cs<=1;cs++) { bit_clr(RS,PTD); // Envía instrucción (RS=0) if(cs==1) { bit_clr(CS1,PTD); // Se seleccionan los chip's bit_set(CS2,PTD); // adecuados para el manejo } // de la pantalla visible. else { bit_set(CS1,PTD); bit_clr(CS2,PTD); } EscribirDato(0x3F); // Se activa el LCD EscribirDato(0xB8); // Coordena X (0xB8) EscribirDato(0xC0); // Primera linea dentro del segmento X for(x=0;x<=7;x++) { bit_clr(RS,PTD); // Envia instrucion (RS=0) EscribirDato(0x40); // Coordenada Y EscribirDato(0xB8 + x); // Incrementa X de 0 a 7 bit_set(RS,PTD); // Envía un caracter for(y=0;y<=63;y++) { EscribirDato(display[ptr]); ptr++; } } } bit_clr(CS1,PTD); bit_clr(CS2,PTD); while(1){ } void EscribirDato(char Dato) { PTB = Dato; bit_set(E,PTD); Retardo(); Retardo(); bit_clr(E,PTD); } void Retardo(void){ } Pagina 16 de 17 Circuito propuesto para el programa de ejemplo Pagina 17 de 17