Envio de datos de 8 bits a LCD con 4 pines del PIC

Hola a todos :D

La manera "común" de conectar un LCD (HD44780 o compatible) directamente al PIC, es poner el LCD en modo de 4 bits y sólo utilizar 6 pines del PIC (4 de datos, enable y RS).
Esta forma no me ayuda mucho en el proyecto que necesito, aunque ya logré obtener más pines libres utilizando el oscilador interno sin salidas, y desactivando el Reset del pic, me hacían falta 2 pines mas en algún puerto. Sin contar que la manera de enviar datos al LCD en modo de 4 bits es un poco tediosa y cansada para programar.

Así que opté por usar el LCD en modo de 8 bits, pero la pregunta es: Si mi circuito como estaba no era la solución, añadir 4 pines mas de datos sonaba de risa.

Buscando información en al red (de la cuál no existe mucha variedad), me topé con una variante del circuito que presento.

Se utiliza un TTL 74LS374, conectado como registro de corrimiento, para recibir de manera serial los datos del PIC y enviarlos al LCD de manera paralela, así sólo se utilizan 4 pines del PIC, 1 de datos, 1 de reloj para el TTL, enable y RS (estos dos últimos del LCD).

Ahora bien, si se quisiera utilizar el LCD en modo de 4 bits, se puede utilizar un TTL 74LS174 de sólo 6 registros. Así se usan 4 para datos, 1 para enable y 1 para RS, dejando el uso de pines del PIC reducido a dos solamente, 1 de datos y uno de reloj para el TTL.
Esta solución tiene un pequeño detalle, el último bit de salida del TTL debe ser casi por fuerza conetado al enable del LCD, ya que es el que activa la orden de leer e interpretar los demás datos en las entradas del LCD. si se conecta al otro bit, el LCD podría no responder al comando de enable, aunque esto depende mucho de los tiempos de propagación del TTL.

Una ventaja de este sistema es que ninguno de los dos TTL son caros, y son una manera sencilla de solucionar ese problema de los pines que nunca sobran en el PIC (Claro esto a menos que se cuente con bastante capital y se opte por un PIC de 40 o mas pines).

Pensando en el consumo de corriente, desafortunada mente los dos TTL tienen un consumo "elevado" del rango de los 30ma, y digo "elevado", ya que si el proyecto se va a utilizar con baterías, no esperen que duren demasiado. Pero claro, en su variante "CMOS", ya sea 74HC374 o 74HC174, las cosas cambian.

Ahora, esto es desde el punto de vista del hardware, pasando al tema del software, no es muy complicado realizar el envío serial al TTL.... mhhh bueno no es complicado una vez que se encuentra la manera correcta después de varias noches de desvelo ajjajajaj.

El código de pureba que utilicé es este:
(Solamente para enviar un comando, Encender o apagar el LCD, limpiar la pantalla, mover el cursos, hacer que parpadee, etc, para enviar las letras, se utiliza uno un poco diferente)

Código:
comando_LCD	
	movwf datos_seriales     ; Toma le valor de W, previamente cargado con los 8 bits del comando
	movlw 0x08
	movwf corrimiento           ; Se utiliza para recorrer 8 veces los datos
shift
	btfsc datos_seriales, 7    ; se checa el valor del bit 7 del registro datos_seriales
	bsf TTL_data                    ; si es 1
	goto setbit                       ; si es 0
setbit
	bsf TTL_clk			; cambia el nivel del pin de CLK del TTL o 1
	nop                                  ; espera
	bcf TTL_clk                       ; cambia el nivel del pin de CLK del TTL o 0
	bcf TTL_data                    ; Pone en 0 el pin de entrada de datos del TTL
	rlf datos_seriales, 1		; Rotar hacia la izquierda datos_seriales, poniendo el resultado en si mismo
	decfsz corrimiento, 1        ; resta uno al registro corrimiento, skip si es 0
	goto shift                          ; Si es 1 va al label "shift"
	bsf LCD_e                         ; Si es 0  Enciende el LCD Enable
	call delay01                       ; Retraso "X" de tiempo (Consultar la tabla de tiempos de espera para el LCD)
	clrf datos_seriales            ; Borra el registro datos_seriales
	bcf LCD_e				; Apaga LCD Enable
	bcf TTL_data                    ; Pone en 0 el pin de entrada de datos del TTL
	call delay01                     ; Retraso "Y" de tiempo (Consultar la tabla de tiempos de espera para el LCD)
        return                              ; Regresa a donde se hizo la llamada a esta sub-rutina

Antes de llamar a esta sub-rutina, se debe cargar el registro W con el valor del comando que se desea activar.
El registro "corrimiento" se carga a 8 ya que son 8 bits los que se van a rotar.

Claro que esta sólo es una de tantas maneras de hacerlo, pero es la primera a la que llegué y me funcionó, ya después lo aplique directamente a resto de mi programa haciendo los ajustes necesarios.


Espero y esta información dea de utilidad para todos :D
Saludos al foro :D
 

Adjuntos

  • lcd_a_8_bits_180.jpg
    lcd_a_8_bits_180.jpg
    66.4 KB · Visitas: 210
Muy interesante tu proyecto voy a ver si saco lo mismo en C de CCS. Lo que pasa es que no has tenido en cuenta las funciones para el control del LCD. Como ser desplzamiento de texto, escritura de texto , posicionamiento del cursor. Por lo demás un proyecto excelente ya que ahorra pines del PIC.
 
Moyano Jonathan dijo:
Muy interesante tu proyecto voy a ver si saco lo mismo en C de CCS. Lo que pasa es que no has tenido en cuenta las funciones para el control del LCD. Como ser desplzamiento de texto, escritura de texto , posicionamiento del cursor. Por lo demás un proyecto excelente ya que ahorra pines del PIC.
hola aca tenes algo en ccs tal vez te sirva para armar tu libreria http://www.e-radiocontrol.com.ar/?Cargadores_de_baterias:Cargador/Ciclador_NiCD/NiMH_con_PIC16F877
 
Moyano Jonathan dijo:
... Lo que pasa es que no has tenido en cuenta las funciones para el control del LCD. Como ser desplzamiento de texto, escritura de texto , posicionamiento del cursor...

Hola Jonathan :D

Precisamente es lo único que hace este código, enviar cualquier comando al LCD, sólo necesitas cargarlo en w y llamar a esta sub-rutina:

Código:
;==== (Set DDRAM Address) Mover el cursor a la 5ta posicion de la primera línea ====
      movlw 0x88                ; b'10001000' ( mi display comienza en 0x84)
      call comando_LCD

;==== (Cursor/Display shift) Desplazar el texto a la izquierda ====
     movlw 0x1C                ; b'00011100'
     call comando_LCD

;==== (Entry Mode set) Incrementar posición del cursor sin mover el display al llegar al final de la línea ====
     movlw 0x06                ; b'00000110'
     call comando_LCD

;==== (Display On/Off control) display encendido cursor apagado y parpadeo del cursor ====
     movlw 0x0D               ; b '00001101
     call comando_LCD

etc...

Al principio esta era mi única opción, enviar el código completo al lcd, ya después opté por una variable que se pudiera manejar bit por bit, la cuál agregue al inicio de la sub rutina comando_LCD, de modo que ya no tomaba el comando del registro W directamente ahora primero cambiabas la variable "comando" y luego se enviaba al LCD

Para el envío de caracteres, la sub-rutina es diferente, opté por enviar cada línea de texto como una cadena, tomando cada valor de una tabla de datos.
Para enviar la segunda linea de datos primero envias el comando de ir a la posición 0xC4 (Que en mi display corresponde al primer caracter de la segunda línea), y luego seleccionas de la tabla el texto:

Código:
...
...
      movlw 0xC4                
      call comando_LCD          ; Mover el cursor al primer caracter de la segunda línea
      movlw 0x10
      call seleccion_texto      ; llamar a la rutina de seleccion
      call envio_texto          ; ya con el valor de el caracter en W se envía y se repite con los 15
                                ; caracteres restantes
...
...

seleccion_texto
     addwf PCL, f
     dt " primera linea  "
     dt " segunda línea  "
...
...

Esta forma de enviar los caracteres es la que mejor me ha funcionado, ya que tienes control total sobre lo que envías y cómo lo envías., pero sobre todo, la facilidad de enviar toda una línea en un solo paso.

Saludos al foro :D
 
Atrás
Arriba