Control de un módulo LCD con PIC y CCS C

Partiendo de saber la Conexión y funciones de un módulo LCD ahora veremos como se utiliza en la práctica. Para empezar aquí les dejo el diagrama de la conexión mas básica para poder comenzar a utilizar el display.

Conexión LCD a PIC16F84A

En el diagrama utilizamos el Pin 0 del puerto A para la señal Enable del display y el Pin 1 del mismo puerto para la señal RS.

R/W lo conectamos directamente a GND ya que en este proyecto no leeremos el estado del display en ningún momento.
El puerto B lo dedicaremos enteramente al bus de datos del LCD.

Todos los puertos que no utilizaremos, asi como el RESET del PIC, los conectamos a 5V por medio de un resistor.

Alimentamos todo a 5V por medio de una fuente que puede llegar a ser la Fuente de alimentación y cargador de baterías explicada en este blog y listo.

Pero falta algo, el programa o firmware que hace que el display haga algo... Para eso debemos crear el código, compilarlo y grabarlo en el PIC para que este lo ejecute, nosotros usaremos CCS C .

La rutina que hace esto sería esta:

#include <16f84a.h>
#use delay (clock=4000000)

#define E Pin_A0
#define RS Pin_A1

/*  Declaro las funciones antes de utilizarlas en main()
    para que sean reconocidas  */

void print(int c);
void Enviar(int8 Dato, int1 Comando);
void Iniciar_LCD(void);

//Comienzo del programa

void main(void){
   Iniciar_LCD();                // Inicio el Modulo
   print ("PICROBOT");           // Escribo PICROBOT en la pantalla
}
                                       
//Funciones

void print(int8 c){
   enviar (c,1);                 // Envio caracter c con RS a 1 (dato)
                                 // CCS C se encarga de enviar uno a uno
}                                // los caracteres contenidos en c
                                     
void Enviar(int8 Dato, int1 Comando){
   output_low(E);                // E en bajo
   output_b(Dato);               // Cargo el puerto B con Dato
   output_bit(RS,comando);       // Pongo RS en 0 o 1 dependiendo si es
                                 // un comando o dato lo que estoy
                                 // enviando
   output_high(E);               // E en alto
   delay_us(1);                  // Espero a estabilizar tensión
   output_low(E);                // E en bajo
   delay_us(40);                 // Espero 40 uS a que el LCD trabaje
                                 //
   if (Dato < 4) delay_us(1600); // Si envio un Home o un Clear display
                                 // espero otros 1600 uSegundos que
                                 // sumado a los 40 uS anteriores hacen
}                                // 1.64 mS que es lo que tardan estas
                                 // operaciones

void Iniciar_LCD(void){          //
   delay_ms(15);                 // Espero a que se estabilice
                                 // la tensión.
   
   enviar(0b00000001,0);         // Envio un CLEAR DISPLAY
                                 // (Borra la pantalla)
   
   delay_ms(5);                  // Espero 5 mS
   
   enviar(0b00111000,0);         // Envio un FUNCTION SET para bus de 8
                                 // bits, 2 lineas y caracteres de 5x7
                                 // pixeles.
   
   enviar(0b00001100,0);         // Envio un DISPLAY ON/OFF CONTROL
                                 // con pantalla encendida, Cursor
                                 //  apagado y si parpadear.
   
   enviar(0b00000110,0);         // Envio un ENTRY MODE SET con 
                                 // Incrementa cursor y desplaza cursor
}

Este programa introducido en el PIC conectado al circuito anterior hace que nuestro módulo muestre en pantalla la frase:

PICROBOT

En realidad lo único que hace es inicializar el LCD y mostrar el mensaje, se puede adaptar y hacer que muestre cualquier frase cambiando simplemente la palabra PICROBOT por lo que deseen en la línea:

print ("PICROBOT");

Hay que aclarar que para que funcione hay que respetar las comillas.

Pero si arman el circuito y graban el PIC con la rutina, verán que pueden modificar la frase, pero siempre aparecerá en la primer línea. Si volvemos a Conexión y funciones de un módulo LCD y consultamos dichas funciones, veremos que hay una que se llama SET DD RAM ADDRESS; La memoria DD RAM es la que contiene los caracteres que están en pantalla. De modo que esa función se llama Establecer la dirección de la DD RAM, o sea, que lo que hace es cambiar la posición donde se almacenará el próximo caracter, por lo tanto, lugar donde aparecerá en pantalla.

Para hacer que escriba donde queramos, antes de escribir, deberemos ejecutar un SET DD RAM ADDRESS. Continuando con nuestra rutina lo podemos hacer del siguiente modo:

void locate(x,y){
   int d=128;                // Cargo d con 128 (10000000) b7 a 1
   d+=y*64;                  // si y (linea) es 1 sumo 64 a d (11000000) b6 a 1
   d+=x;                     // a todo esto le sumo la posicion de x
   enviar (d,0);             // envio todo al display con RS a 0 (comando)
}

Entonces si, por ejemplo, queremos escribir Hola en la primer línea y Mundo en la segunda, el main() de nuestra rutina se vería así:

void main(void){
   Iniciar_LCD();             // Inicio el Módulo
   locate(6,0);               // Ubico el cursor en la columna 6
                              // de la primer línea
   print ("HOLA");            // Escribo HOLA
   locate(5,1);               // Ubico el cursor en la columna 5
                              // de la segunda línea
   print ("MUNDO");           // y escribo MUNDO
}

En un display de 16 caracteres x 2 líneas se verá centrada la frase HOLA MUNDO. Cabe destacar que antes de poder utilizar la función locate() se debe declarar mediante la sentencia:

void locate(x,y);

Luego podemos simplificar el borrado de la pantalla (CLEAR DISPLAY) con la función:

void cls(void){
   enviar (1,0);              // envio 00000001 (Clear display) 
}                             // con RS a 0 (comando)

Recuerden que CLEAR DISPLAY era 00000001 que es igual a 1 en decimal. De esta forma y previamente declarado cada vez que querramos borrar la pantalla introduciremos en el código la línea cls(); Por último en la entrada Librería para el manejo de un módulo LCD en CCS C encontrarás todas las funciones y la opción para descargarla.

26 comentarios:

  1. Anónimo25/10/10

    MUY BUENO TODO, EL TEMA ES QUE EN MI CASO LO SIMULO EN PROTEUS Y NO ME MUESTRA NADA, POR QUE PUEDE SER?? ES PARA CUALQUIER LCD??

    ResponderEliminar
  2. Lo acabo de comprobar y el ejemplo funciona, lo único que encontré es que el diagrama está explicado con un PIC16F84A y el ejemplo en CCS C está escrito para un PIC16F876A.
    Debes cambiar la primera línea donde dice:

    #include <16f876a.h>

    por:

    #include <16f84a.h>

    o reemplazarla por el PIC que utilices.

    Saludos.

    ResponderEliminar
  3. Anónimo17/12/10

    simon lo programe en assambly para un pic16f877 y funciona al 100, valiosa informacion, primera ves que trabajo con lcd, saludos!!!!!

    ResponderEliminar
  4. Anónimo9/3/11

    HOLA AMIGO, LE COMENTO QUE CUANDO LE VOY CAMBIAR DONDE DICE #include <16f876a.h> por:

    #include <16f84a.h> ME DA ERROR A LA COMPILACION,
    O SINO ME PODRIAS REGALAR EL ESQUEMATICO PARA PODERLO GRABAR CON EL PIC 16F876A.

    GRACIAS JOSE LUIS
    DESDE BOGOTA COLOMBIA

    ResponderEliminar
  5. Hola, aparte de esa línea, prueba cambiando las líneas:

    #define E Pin_C0
    #define RS Pin_C1

    por

    #define E Pin_A0
    #define RS Pin_A1

    El problema se debe a que el ejempo está escrito para el PIC16F876A y el esquema está hecho para el PIC16F84A y este último no tiene implementado el Puerto C.

    De todos modos también corrijo lo errores del ejemplo. Gracias por colaborar.

    Saludos.

    ResponderEliminar
  6. Anónimo14/3/11

    HOLA TE COMENTO, YA EL PROGRAMA NO GENERA ERROR, PERO AL SIMULARLO, NO ME APARACE NADA EN EL LCD.

    JOSE LUIS

    ResponderEliminar
  7. Anónimo14/3/11

    HOLA AMIGO, COMO SE PUEDE HACER QUE EL MENSAJE SE DESPLACE DE DERECHA A IZQUIERDA, IZQUIERDA A DERECHA.

    JOSE LUIS

    ResponderEliminar
  8. En la entrada http://picrobot.blogspot.com/2008/11/display-lcd-cmo-se-controlan.html está explicado el comando CURSOR OR DIPLAY SHIFT.

    Debes implementarlo con el bit D3 en 1 (Mover display) y el bit D2 a 0 para mover el display a la derecha o en 1 para moverlo a la izquierda.

    Supongo que has solucionado el problema por el cual no aparecía nada en pantalla...

    Saludos.

    ResponderEliminar
  9. Anónimo14/3/11

    hola amigo, le entendi su mensaje, pero en que parte del programa va esa funcion de mover el mesnaje, de izquierda a derecha viceversa, y lo del mensaje ya lo solucione, era que no habia colocado la resistencia de 1k a positivo, por eso no me aparecia.

    y como se hace para colocar mas caracteres, por que tu en tu programa solo admite 8 caracteres.

    jose luis

    ResponderEliminar
  10. Envíame un mail a picblog@hotmail.com y te aclararé las dudas por ese medio. Para no cargar de mensajes el post.

    Saludos.

    ResponderEliminar
  11. Anónimo11/4/11

    hola por favor me interesa saber si si "print" y "enviar" son funciones predefinidas porque normalmente solemos utilizar el "printf" y de "enviar" no se ni de donde sale.

    UN SALUDO

    ResponderEliminar
  12. No, ENVIAR se encarga de gestionar los comandos o datos a "enviar" al display. PRINT "envía" una serie de ENVIAR al display, son funciones creadas.

    ENVIAR "envia" un caracter; PRINT("HOLA");, es como hacer:

    Enviar("H", 1);
    Enviar("O", 1);
    Enviar("L", 1);
    Enviar("A", 1);

    printf envía datos preformateados a una salida que en este caso podría ser print, es una "función" del lenguaje.

    Para usar printf aquí deberías usar:

    printf(print,"texto formateado",...);

    con la sintaxis de printf, en la ayuda de CCS C encontrarás todo lo necesario para continuar.

    saludos.

    ResponderEliminar
  13. Anónimo1/7/11

    Una pregunta, que software utilizas para programar ya que programe en MICKROC pero hay algunas instrucciones que no encuentro como int8, una pregunta más que modelo de LCD utiliza ya que yo probe con un LCD SC162A3 y pues no puedo hacer ke despliege caracteres

    ResponderEliminar
  14. Te contesté en la otra entrada, donde haz hecho la misma pregunta.

    Saludos.

    ResponderEliminar
  15. Anónimo11/10/12

    hola!alguien me ayude! quiero controlar una lcd lm016l con un pic16f84a necesito el codigo he probado algunos pero no me ha funcionado
    alguien puede ayudarme!!!!

    ResponderEliminar
  16. http://picrobot.blogspot.com.es/2010/03/lcdgar.html
    En esta entrada de este mismo blog tienes mi librería para controlar ese tipo de displays con casi cualquier microcontrolador.
    Échale un vistazo, la puedes modificar a tu gusto aunque no haría falta.
    Solo tienes que configurarla para que funcione co ese microcontrolador.

    Saludos.

    ResponderEliminar
  17. HOLA UNA GRANDIZIMA DUDA COMO PODRIA ROTAR EL TEXTO YA SEA A LA DERECHA O A LA IZQUIERDA?

    ResponderEliminar
  18. http://picrobot.blogspot.com.es/2008/11/display-lcd-cmo-se-controlan.html

    En esa entrada tienes todos los comandos que soporta el display.

    Con la librería podrías usar el comando enviar(), con 5 o 7 como parámetro:

    enviar(5,0);
    y
    enviar(7,0);

    Para hacer que el display se mueva a la derecha o a la izquierda.

    Examina bien la entrada para aprender mas comandos, de todos modos el comando enviar(); comunica directamente al display.

    Saludos.

    ResponderEliminar
  19. hola me podrias sacar una duda, que diferencia hay entre init_LCD(); y iniciar_lcd()

    ResponderEliminar
  20. Ninguna, simplemente que en este ejemplo llamé a la función que inicia el display de ese modo, podría haberla llamado init_LCD(); o de cualquier otra forma.

    Saludos.

    ResponderEliminar
  21. hice el esquema en proteus pero solo enciende la pantalla y no aparece nada si me podrías ayudar el porque
    la causa del error

    ResponderEliminar
  22. Hola que tal, he simulado el circuito y todo sale muy bien pero al armar el circuito no logro que se muestre el mensaje en el display, he compilado sin problemas y he grabado el firmware en el pic sin ningun error. ¿Podrías ayudarme? Gracias!

    ResponderEliminar
  23. Anónimo24/12/13

    Hola podrias decirme como mandar mas de 8 letras grax

    ResponderEliminar
  24. Anónimo14/2/14

    Hola, a mí me pasa lo mismo que EZTLICOATL lo he compilado con CCS, sin error, he grabado el archivo .hex al pic y he montado el esquema del pic + lcd pero no me aparece ningún mensaje en el lcd.

    Un saludo.

    ResponderEliminar
  25. hola podrias decir como es el codigo para un bus de 4 bits gracias!

    ResponderEliminar
  26. Anónimo2/9/14

    hola me podrías ayudar con este programa
    #include <16F877A.h>
    #device adc=8
    #FUSES NOWDT
    #FUSES HS
    #FUSES PUT
    #FUSES NOPROTECT
    #FUSES NODEBUG
    #FUSES NOBROWNOUT
    #FUSES NOLVP
    #FUSES NOCPD
    #FUSES NOWRT
    #use delay(clock=20000000)
    #use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
    #define LCD_TYPE 1
    #include
    #include
    char k;
    void main()
    {
    setup_adc_ports(NO_ANALOGS);
    setup_adc(ADC_OFF);
    setup_psp(PSP_DISABLED);
    setup_spi(FALSE);
    setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
    setup_timer_1(T1_DISABLED);
    setup_timer_2(T2_DISABLED,0,1);
    setup_comparator(NC_NC_NC_NC);
    setup_vref(FALSE);
    lcd_init();
    lcd_putc("\fReady...\n"); while (TRUE)
    {
    k=kbd_getc();
    if(k!=0)
    if(k=='*')
    lcd_putc('\f');
    else
    lcd_putc(k);
    }

    }
    setup_adc_ports(NO_ANALOGS);
    setup_adc(ADC_OFF);
    setup_psp(PSP_DISABLED);
    setup_spi(FALSE);
    setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
    setup_timer_1(T1_DISABLED);
    setup_timer_2(T2_DISABLED,0,1);
    setup_comparator(NC_NC_NC_NC);
    setup_vref(FALSE);
    lcd_init();
    lcd_putc("\fReady...\n"); while (TRUE)
    {
    k=kbd_getc();
    if(k!=0)
    if(k=='*')
    lcd_putc('\f');
    else
    lcd_putc(k);
    }

    }

    me falta completarlo y no se que es lo que le pueda faltar, en si es para enviar caracteres a un LCD

    ResponderEliminar

Tal vez le interese: