Documentos de Académico
Documentos de Profesional
Documentos de Cultura
3 Puertos de Inp - Out V3 PDF
3 Puertos de Inp - Out V3 PDF
Entrada/Salida
1
3. Los Puertos Paralelos de Entrada/Salida
Los integrados PIC16F874 y PIC16F877 poseen 5 puertos de entrada/salida denominados
PORTA, PORTB, PORTC, PORTD y PORTE, mientras que el PIC16F873 y PIC16F876 poseen 3.
Estos puertos son totalmente programables, es decir, sus pines pueden ser configurados
para trabajar como entradas o como salidas a selección del programador.
3.1. El Puerto A (PORTA)
El puerto A posee 6 pines bidireccionales. Los 3 registros asociados a este puerto son:
1. Registro PORTA (05H), que es el registro de estado del Puerto A. Cada uno de los 6 bits
menos significativos (RA5,...,RA0) de este registro están asociados al p i n físico
correspondiente del puerto. Al hacer una lectura este registro se lee el estado de todas los pines
del puerto. Todas las escrituras al registro son operaciones del tipo “lee- modifica-escribe”, es
decir, toda escritura al puerto implica que el estado de los pines es leído, luego es modificado y
posteriormente se escribe al latch de datos del puerto.
2. Registro TRISA (85H). Cada bit de este registro configura la dirección en que fluye la
información del pin correspondiente del puerto A, así, para k=0,1,...,5:
Todos los pines del puerto A poseen diodos de protección conectados a Vdd (contra altos
voltajes de entrada) y a Vss (contra voltajes negativos) además, manejan niveles de entrada tipo
TTL y como salidas se comportan como drivers tipo CMOS. Excepto el pin RA4, e l cual
como entrada posee un Disparador Schmitt trigger y como salida es de Drenaje abierto, además
RA4 sólo posee un diodo de protección conectado a Vss.
3. El Registro ADCON1 (9FH). Los pines RA0, RA1, RA2, RA3 y RA5 están
multiplexados con las entradas analógicas AN0,...,AN4, respectivamente; de manera que
antes de utilizarlos se debe configurar si serán usadas como entradas analógicas o como
entradas/salidas digitales. Para seleccionar la segunda opción (entradas/salidas digitales) se
debe colocar en el nible menos significativa de este registro un 01102 (es decir, un 06h).
2
Registro ADCON1 (dirección 9Fh)
bit 3-0: PCFG3:PCFG0: bits de configuración de los canales de entrada del convertidor A/D.
Se utilizan para configurar las patillas como E/S digital o como entrada analógica.
En las siguientes dos figuras se muestra el detalle de implementación interna de los pines del
puerto A, mostrando la diferencia entre los pines RA4 y los demás pines del puerto A:
El PIC puede ser implementado en diversas topologías de estado de escritura para el pin de I/O,
teniendo en cuenta que los pines de los puertos E/S tienen igual comportamiento o ligeramente difiere
uno del otro. Conociendo el funcionamiento de diversos estados de escritura del puerto, se puede
aprovechar de mejor manera las características y optimizar el proyecto.
1. Estado de lectura y escritura de los pines RA0, RA1, RA2, RA3 y RA5
El esquema para estos pines muestra el estado de escritura extraído del “data sheet del Microchip”.
Por ejemplo, se toma el pin RA0 para analizar el funcionamiento del estado de salida cuando el
mismo funciona como entrada o como salida:
3
a. Funcionamiento como Entrada
Para configurar el pin RA0 como entrada, se debe poner a 1 el bit 0 del registro TRISA:
bsf TRISA, 0
Esta instrucción determina una conmutación a 1 del estado lógico del Flip Flop del latch D
indicado en el circuito con el nombre TRIS latch. Para otro pin de I/O existe uno de estos Flip
Flop y el estado lógico en que se mantiene depende estrictamente del estado lógico del bit
relativo al registro TRIS (en otras palabras, el mejor diseño de todos los bits del registro TRIS
es físicamente realizable con un latch TRIS).
La salida Q del latch TRIS es conectada a la entrada de una compuerta lógica de tipo OR, esto
significa que independientemente del valor presente en la otra entrada, la salida de la compuerta
OR siempre estará en uno si una de sus entradas están en uno. En esta condición, el transistor P
no conduce manteniendo el pin RA0 desconectado del positivo de la alimentación.
Del mismo modo la salida negativa Q del latch TRIS es conectada a la entrada de una
compuerta AND, en donde, la salida de ésta estará siempre en 0 mientras una de sus entradas
valga 0. En esta condición el transistor N no conduce manteniendo el pin RA0 desconectado de
la tierra. El estado lógico del pin RA0 dependerá exclusivamente del circuito externo al cual
estará conectado. Aplicando 0 o 5 volts al pin RA0, será posible leer el estado presente del
circuito externo en la entrada del bloque representado por “TTL input buffer” y el latch de
entrada.
Para configurar el pin RA0 como salida, se debe colocar 0 en el bit 0 del registro TRISA con la
instrucción:
bcf TRISA, 0
Esta instrucción determina la conmutación a cero de la salida Q del latch TRIS (a 1 si la salida
Q es negativa). En este estado el valor de la salida de las compuertas OR y AND dependen
exclusivamente del estado de salida del Q negado del latch de datos. Como para el latch TRIS,
el latch de datos depende del estado de un bit de un registro, particularmente del registro
PORTA. Su salida negativa será enviada a la entrada de las dos compuertas lógicas OR y AND
que está directamente sobre la base del transistor P y N. Si ponemos en 0 el bit 0 del registro
PORTA con la instrucción:
bcf PORTA, 0
Se obtendrá la conducción del transistor N y por tanto irá a 0 el pin RA0. Si se coloca en 1 el bit
0 con la instrucción:
bsf PORTA, 0
Se obtendrá la conducción del transistor P y por tanto irá a +5 V el pin RA0. Con esta condición
será siempre posible revisar el valor enviado sobre el pin a través del circuito de entrada.
4
2. Estado de Salida del pin RA4
Se analiza el funcionamiento del estado de salida del pin RA4 que es diferente de las otros pines de
I/O, en cuanto a la distribución del pin en el PIC16C84 con el TOCKI, lo cual se analizará luego.
Se describe el esquema de bloques del estado de salida extraído del data sheet. La lógica de
conmutación es substancialmente idéntica al grupo de pines RA0 a RA3 con ausencia de la
compuerta OR y del transistor P, o de todos los circuitos que permiten una conexión a positivo del
pin RA4. Esto significa en términos prácticos que cuando un pin RA4 está programado para salida,
podrá asumir un nivel que dependerá del circuito externo, pues en realidad no está conectada al
positivo y sí desconectada. Este tipo de circuito de salida se llama de “colector abierto” y es útil
para aplicaciones en que es necesario compartir una misma ligación con más pines de salida,
porque se tiene la necesidad de colocar en alta impedancia un pin de salida y pudiendo así
reprogramarla como pin de entrada.
Si se quiere asegurar que el pin RA4 sea 1 se debe conectar externamente un resistor de PULL-UP,
ya sea un resistor conectado al positivo de alimentación.
El puerto B es un puerto digital de 8 bits, todas sus pines son bidireccionales y trabaja en forma
similar al puerto A. Tiene tres registros asociados: el registro de datos PORTB, el registro de
dirección de los datos TRISB y el registro OPTION_REG.
1. Registro PORTB (06H, 106H). Los ocho bits que contiene reflejan directamente el estado de
los ocho pines del puerto B: RB0,...,RB7.
2. Registro TRISB (86H, 186H).- En forma similar a TRISA, al poner un 0 en un bit de TRISB
se configura el pin RB correspondiente como salida y al poner un 1 en un bit de TRISB se
configura el pin RB correspondiente como entrada.
3. Registro OPTION_REG (81H, 181H). El bit 7 de este registro, denominado RBPU es usado
para conectar/desconectar una resistencia “pull-up” conectada a cada pin RB. Poniendo un 0 en
este bit todas las resistencias se conectan. Para desconectar las resistencias “pull-up” se
debe poner este bit en 1, también se desconectan automáticamente cuando e l pin
correspondiente es configurado como salida. Un Reset desconecta todas las resistencias.
A continuación se indica el registro OPTION_REG, que puede ser leído o escrito y que contiene
varios bits de control para configurar la asignación del preescaler al TMR0 o al WDT, la
interrupción externa, el TMR0 y las resistencias de pull-up del PORTB.
5
Bit 7: #RBPU: Resistencia de Pull-up en el PORTB
1=Resistencia de Pull-up desactivada
0= Resistencia de Pull-up activada
Pines RB4, ... ,RB7. Estos cuatro pines del puerto B tienen la capacidad de generar una solicitud de
interrupción a la CPU cuando están configuradas como entradas. El estado de estos pines es
comparado con el último estado que tenían durante la última lectura a PORTB, guardado en un
latch. Los bits que indican que hay una diferencia entre estos valores por cada pin están
conectados a una puerta OR cuya salida activa el bit RBIF del registro INTCON solicitando
con esto una interrupción. Esta interrupción es especialmente útil para despertar al dispositivo de
su estado de SLEEP cuando alguno de los cuatro pines es activado, por ejemplo, en respuesta a la
presión de una tecla.
Esta característica de solicitud de interrupción cuando se detecta un cambio junto con las
resistencias “pull-up” configurables para estos cuatro pines, los hacen ideales para el manejo de
teclados en dispositivos portátiles que requieren “dormirse” durante largos ratos para economizar
baterías y “despertarse” cuando una tecla es presionada.
En las siguientes figuras se muestra el alambrado interno de los pines del puerto B:
Para este grupo de pines permanece sustancialmente invariante la lógica de conmutación, estas
disponen de un circuito WEAK PULL-UP que se activa cuando el pin es programado como
entrada.
6
La entrada del evento, como se explicó anteriormente, el pin viene completamente desligado del
PIC. Un estado del pin depende entonces exclusivamente del circuito externo. Sí un circuito es del
tipo colector abierto o simplemente está constituido de un simple switche que cuando es
presionado, conecta a tierra la línea de I/O, es necesario poner una resistencia del PULL-UP desde
el positivo para tomar cuando el switche se suelte y volver al nivel a una condición lógica activa
sobre un pin de entrada. El circuito de WEAK PULL-UP evita el uso del resistor PULL-UP e
inhabilita que sea activado sobre el bit RBPU (0 habilita, 1 deshabilita) del registro OPTION.
La figura anterior representa un esquema de salida extraído del data sheet del Microchip. El pin
RB0 solo presenta una característica especial, cuando está configurado como pin de entrada, puede
generar, en correspondencia un cambio de estado lógico, una interrupción ya sea una interrupción
inmediata del programa en ejecución o una llamada a una subrutina especial denominada interrupt
handler, lo que se indicará más adelante.
Un circuito de conmutación de este grupo es muy similar al grupo de RB0 a RB3. Este pin dispone
también de un circuito de “weak pull-up”. También tienen con respecto a los pines anteriores la
ventaja de poder revelar variaciones de estado sobre cualquier pin y generar una interrupción, la
misma que se hablará más adelante.
La figura representa un esquema de salida extraído del data sheet del Microchip. Donde, el bit
RBIF corresponde al registro INTCON.
El puerto C consta de 8 pines bidireccionales. Trabaja en forma similar a los dos puertos
anteriores y tiene asociados los registros:
2. Registro TRISC (87H).- Registro de control de dirección de los pines del puerto C.
Poniendo un 1 en un bit del registro TRISC se configura los pines correspondiente como entrada
y poniendo un 0 se configura la línea correspondiente como salida.
Los pines del puerto C se encuentran multiplexados con varios pines controlados por otros
periféricos, cuando se habilita el pin del periférico respectivo puede ser ignorada la configuración
de TRISC, de hecho, algunos periféricos configuran e l p i n como salida mientras que otros la
configuran como entrada.
Cada entrada del puerto C posee un buffer con disparador trigger. Además, cuando se selecciona la
función I2C, los pines PORTC<4,3> pueden ser configurados con niveles I2C o con niveles SMBus
mediante el bit CKE del registro SSPSTAT<6>, como se muestra en las figuras siguientes.
En las siguientes figuras se muestra el alambrado interno de los pines del puerto B.
7
Pines 7, 6, 5, 2, 1 y 0 del puerto C Pines 4 y 3 del puerto C
3.3.2. Periféricos que están multiplexados con los p i n e s del puerto C
En la siguiente tabla se resumen los p i n e s del puerto C y los de los periféricos que están
multiplexados con ellos.
3.5. Ejemplo 31
Entradas digitales. En este ejemplo se configura el pin RA5 del puerto A como salida conectado a
un LED, el cual se controla de acuerdo al estado de los pines RA0 y RA1 configurados como
entradas.
Hardware necesario. Como prácticamente en todos los programas para PIC, si no se conecta el
hardware adecuado no se puede ver ningún efecto al ejecutar el programa. En la siguiente
figura se muestra la conexión de los dos botones y el LED necesarios para probar el programa,
además claro está de la circuitería de reloj necesaria.
En este programa el rebote generado por los switches no es problema, porque funciona correctamente
haya o no haya rebote.
9
1. Diagrama de Flujo:
INICIO
NO
RA0=1
SI
RA5←0
NO
RA1=1
SI
RA5←1
2. Código en Assembler:
;*****************************************************************************
;* Ejemplo31.asm
;* Este programa Enciende un LED conectado a RA5 cuando se presiona un botón
;* conectado a RA1 y lo apaga cuando se presiona un botón conectado a RA0
;*****************************************************************************
PROCESSOR 16F877
RADIX DEC
INCLUDE "P16F877A.INC"
;Reset Vector
org 0x00 ;Inicia en el vector de reset
;Una vez inicializado el puerto, se procede leer los pines RA0 y RA1
BCF STATUS,RP0 ;regresa al banco 0
chRA0 BTFSS PORTA,0 ;checa si RA0=1
10
GOTO chRA1 ;si RA=0 salta a checar RA1
BCF PORTA,5 ;si RA0=1 apaga el LED
chRA1 BTFSS PORTA,1 ;checa si RA1=1
GOTO chRA0 ;si RA1=0 salta a checar RA0
BSF PORTA,5 ;si RA1=1 enciende el LED
GOTO chRA0
END
La experiencia empírica indica que el periodo transitorio de un rebote depende entre otros factores,
de la calidad de los switches y de la rapidez de su accionamiento, pero a lo más puede durar unos
20 milisegundos, En la siguiente figura se muestra un rebote real en los contactos de un
relevador capturado en la pantalla de un osciloscopio digital Fluke 123. (Obsérvese que el rebote
mostrado duró solamente 3 milisegundos).
11
3.6.2. Limpiado del rebote (debouncing)
El rebote de un switch puede durar a lo más unos 20 milisegundos, por lo que para el limpiado del
rebote se debe realizar una subrutina con una pausa de 20 mseg, la cual se desarrolla a continuación.
La subrutina pau20ms simplemente realiza una pausa de 20 milisegundos. Se tiene dos formas de
implementación de esta subrutina (suponiendo un reloj de 100 Khz):
12
pau20ms
W←N
cont←W
cont←cont-1
NO
Z=1
SI
FIN
2. Código en Assembler:
;* Subrutina de pausa que dura 20 milisegundos (usando memoria de datos)
;* (Supone un reloj de 100 Khz)
;**************************************************************************
;Define constantes
N EQU 0xA5
cont EQU 0x20
; inicia subrutina
pau20ms MOVLW N ;Carga dato que controla la duración, W=N
MOVWF cont ;inicializa contador con el dato, cont=N
rep DECFSZ cont,1 ;Decrementa contador y escapa si cero, cont=cont-1
GOTO rep ;si no es cero, repite
RETURN ;regresa de esta subrutina
N = (Tsub/Tcy – 5)/3
Por ejemplo, suponiendo Tsub = 20 mseg y que se está usando un reloj de 100 Khz y (fcy =
fosc/4 = (100x103 Hz)/4 =25x103 Hz entonces Tcy = 1/(25x103) = 40x10-6 seg = 40 µseg):
N = (20 mseg /40µseg – 5)/3
N = 165 = A5H
Observación. La máxima duración que se puede lograr con esta subrutina y con la frecuencia del
reloj de 100 Khz supuesta (Tcy = 40 µseg), es cuando el ciclo se ejecute 256 veces, es decir con
un valor N=256, lo cual en el programa se logra con el valor inicial N=0:
Así, si la frecuencia del reloj es mayor, por ejemplo, en el modo de oscilador interno se
tienen 4 Mhz, que da un Tcy=1µseg, esta subrutina no podrá proporcionar nunca los 20 mseg,
por lo que habrá que realizar una pausa más larga anidando dos ciclos.
La pausa pau20ms es demasiado corta, de manera que para frecuencias altas de reloj no puede
alcanzar ni siquiera los 20 mseg. A continuación se muestra una pausa que puede dar tiempos
mucho más largos usando ciclos anidados. A continuación se va realizar una subrutina d20ms de
20 mseg con un reloj de 4 Mhz:
1. Diagrama de Flujo:
14
d20ms
W←N
cont1←W
W←M
cont2←W
cont2←cont2-1
NO
Z=1
SI
cont1←cont1-1
NO
Z=1
SI
FIN
2. Código en Assembler:
;* Subrutina de pausa para frecuencias medias
;* (Adecuada para un reloj de 4 Mhz)
;**************************************************************************
;Define constantes para 20 milisegundos
N EQU 0x1A
M EQU 0x00
cont1 EQU 0x20
cont2 EQU 0x21
;inicia subrutina
d20ms MOVLW N ;(1) Carga dato N
MOVWF cont1 ;(1) inicializa contador1 ciclo externo
rep1 MOVLW M ;(1) Carga dato M
MOVWF cont2 ;(1) inicializa contador2 ciclo interno
rep2 DECFSZ cont2,1 ;(1,2)Decrementa contador2 y escapa si cero
GOTO rep2 ;(2) si no es cero, repite ciclo interno
DECFSZ cont1,1 ;(1,2)Decrementa contador1 y escapa si cero
GOTO rep1 ;(2) si no es cero repite ciclo externo
RETURN ;(2) regresa de esta subrutina
15
La duración de esta subrutina en ciclos de reloj será
N = (Tsub/Tcy –
7)/(3M+4)
Observación. Hasta aquí se están realizando pausas de duración controlada por software, sin
embargo, lo más adecuado para controlar tiempo de manera más exacta es usar los timers
que se verán más adelante.
Para realizar la pausa de un segundo, d1seg, se puede hacer uso de la subrutina d20ms con su
máxima duración Tsub = 0,197639 seg, teniendo los valores N=M=256 (con los valores
iniciales de N=M=0 en el programa). Para ello se implementa un tercer ciclo externo que repita
esta pausa p veces.
1. Diagrama de Flujo:
16
d1seg
W←p
cont3←W
d20ms
cont3←cont3-1
NO
Z=1
SI
FIN
2. Código en Assembler:
La máxima duración de esta subrutina (para p =256), suponiendo un reloj de 4 Mhz (Tcy = 1
µseg), se tiene un Tsubmáximo=50,596357 seg. Sin embargo, si se desea un Tsub=1seg. Se
obtiene:
p = (Tsub/Tcy – 5)/197642 = 5,059628 ~ 5
17
3.7. Ejemplo 2
En este ejemplo se usa sólo el botón conectado al pin RA0 para controlar el encendido y
apagado del LED en el pin RA5, cuando se presiona el botón conectado a RA0 se enciende el LED
conectado en el pin RA5 y lo apaga cuando se presiona nuevamente el mismo botón y así
sucesivamente. Se incluye el limpiado del rebote con un reloj de 4Mhz.
Hardware necesario. En la siguiente figura se muestra la conexión del botón y el LED necesarios
para probar el programa.
1. Diagrama de Flujo:
INICIO
N←0x1A
M←0x00
NO
RA0=1
SI
d20ms
NO
RA0=1
SI
W←0x20
RA5←W XOR RA5
18
El diagrama de flujo de la Subrutina d20ms se realiza en el subtema “Limpiado del rebote”.
2. Código en Assembler:
;**************************************************************************
;* Ejemplo32.asm
;* Este programa Enciende un LED conectado a RA5 cuando se presiona un botón
;* conectado a RA0 y lo apaga cuando se presiona nuevamente el mismo botón y
;* así sucesivamente.
;**************************************************************************
PROCESSOR 16F877
RADIX DEC
INCLUDE "P16F877A.INC"
;Define constantes
N EQU 0x1A
M EQU 0x0
;Define variables
CBLOCK 0x20
cont1
cont2
ENDC
;Reset Vector
org 0x00 ;Inicia en el vector de reset
END
3.8. Ejemplo 3
Hardware necesario. Sólo se requieren los ocho LEDs conectados a los pines RBP0,...,RBP7,
como se muestra en la siguiente figura.
1. Diagrama de Flujo:
20
INICIO
N←0x00
M←0x00
p←0x05
C←0
PORTB←0
RB0←1
d1seg
SI
C=0
NO
RB0←1
C←0
Los diagramas de flujo de la Subrutinas d1seg y d20ms se realiza en el subtema “Limpiado del
rebote”.
2. Código en Assembler:
;**********************************************************************
;* Ejemplo33.asm
;* Este programa Enciende en secuencia (uno a la vez) 8 LEDs conectados
;* a los pines del puerto B
;**********************************************************************
PROCESSOR 16F877
RADIX DEC
INCLUDE "P16F877A.INC"
21
p EQU 0x05
;Define variables
CBLOCK 0x20
;Define variables para pausa de 200 mseg
cont1
cont2
;Define variable para pausa de 1 segundo
cont3
ENDC
;Reset Vector
org 0x00 ;Inicia en el vector de reset
END
22
3.9. Ejemplo 4
El presente ejemplo realiza el ingreso de datos numéricos hexadecimales mediante un teclado de tipo
telefónico, controlando las 3 columnas con las salidas RB1, RB2 y RB3 y las 4 filas con las entradas
RB4, RB5, RB6 y RB7 con resistencias pull-up internas para evitar resistencias externas. Luego
mostrar el dato ingresado en el puerto C.
La mayoría de los teclados están organizados en forma matricial como un conjunto de switches en
las intersecciones de varios renglones y columnas conductoras como se muestra en la siguiente
figura que ejemplifica un teclado de tipo telefónico.
En la figura también se ilustra una conexión típica con tres pines de entrada del puerto B que
controlan las columnas y cuatro pines de salida del mismo puerto que recogen la información de los
renglones.
1. Detección. Se ponen en bajo todos las filas (cuidando que haya diodos de protección) y se
leen las columnas.
2. Si hay alguna columna activa se limpia el rebote, si es tecla válida se pasa al paso 3, si
no es tecla válida se asigna un código de “ninguna tecla presionada”.
3. Codificación. El puerto activa una fila a la vez colocando un cero lógico en el pin
correspondiente a la fila a activar.
23
4. Por cada fila activa se lee la información de columnas y dependiendo de la fila y la
columna activada (en bajo) se asigna el código a la tecla de la intersección.
1. Diagrama de Flujo:
INICIO
N←0x1A
M←0x00
initB
W←0xFF
masq←W
detect
masq←W-masq
NO
Z=1
SI
codif
PORTC←W
24
initB
STATUS←0
PORTB←0
TRISB←0xF0
RBPU←0
FIN
INICIO
PORTB←0 A
NO NO
RB7=1 RB7=1
SI SI
NO NO
RB6=1 RB6=1
SI SI
NO NO
RB5=1 RB5=1
SI SI
NO NO
RB4=1 RB4=1
SI SI
NO NO NO
RB7=1 RB7=1 RB7=1
NO NO NO
RB6=1 RB6=1 RB6=1
SI SI SI
W←’4’ W←’5’ W←’6’
NO NO NO
RB5=1 RB5=1 RB5=1
NO NO NO
RB4=1 RB4=1 RB4=1
A B W←0x00
2. Código en Assembler:
;*********************************************************************
;* Ejemplo34.asm
;* Ingreso de datos numéricos hexadecimales mediante un teclado de
;* tipo telefónico, controlando las 3 columnas con las salidas RB1,RB2 y RB3
;* y las 4 filas con las entradas RB4,RB5,RB6 y RB7 con resistencias pull-up
;* internas para evitar resistencias externas.
;* Luego mostrar el dato ingresado en el puerto C.
;*********************************************************************
PROCESSOR 16F877
RADIX DEC
INCLUDE "P16F877A.INC"
26
;Define variables
CBLOCK 0x20
;Define variables para pausa de 20 mseg
cont1
cont2
;Define variable para mascara 0xFF (tecla pulsada)
masq
ENDC
;Reset Vector
org 0x00 ;Inicia en el vector de reset
;Programa principal
CALL initB ;Llama a la subtutina initB
repite MOVLW 0xFF ;Almacena en W la mascara 0xFF
MOVWF masq ;Almacena en masq la mascara 0xFF
CALL detec ;Llama a la subtutina detect
SUBWF masq,1 ;
BTFSS STATUS,Z ;Resultado en W=0
GOTO repite ;Repite el proceso
CALL codif ;Llama a la subtutina codif
MOVWF PORTC ;Mueve la tecla presionada al puerto C
GOTO repite ;Repite el proceso
27
BTFSS PORTB,7 ;lee renglón 1,2,3
RETLW 0xFF ;tecla presionada, retorna con w=0xFF
BTFSS PORTB,6 ;lee renglón 4,5,6
RETLW 0xFF ;tecla presionada, retorna con w=0xFF
BTFSS PORTB,5 ;lee renglón 7,8,9
RETLW 0xFF ;tecla presionada, retorna con w=0xFF
BTFSS PORTB,4 ;lee renglón *,0,#
RETLW 0xFF ;tecla presionada, retorna con w=0xFF
RETLW 0x0 ;falsa alarma retorna con w=0
; Segunda columna
MOVLW 0xFB ;Activa la segunda columna
MOVWF PORTB ;y activa la columna 2,5,8,0
BTFSS PORTB,7 ;Es la tecla 2?
RETLW '2' ;retorna código del ?2?
BTFSS PORTB,6 ;Es la tecla 5?
RETLW '5' ;retorna código del ?5?
BTFSS PORTB,5 ;Es la tecla 8?
RETLW '8' ;retorna código del ?8?
BTFSS PORTB,4 ;Es la tecla 0?
RETLW '0' ;Retorna código del ?0?
; Tercera columna
MOVLW 0xFD ;Activa la tercera columna
MOVWF PORTB ;y activa la columna 3,6,9,#
BTFSS PORTB,7 ;Es la tecla 3?
RETLW '3' ;retorna código del ?3?
BTFSS PORTB,6 ;Es la tecla 6?
RETLW '6' ;retorna código del ?6?
BTFSS PORTB,5 ;Es la tecla 9?
RETLW '9' ;retorna código del ?9?
BTFSS PORTB,4 ;Es la tecla #?
RETLW '#' ;Retorna código del ?#?
RETLW 0x00 ;falsa alarma, no hay tecla presionada
28
MOVWF cont2 ;(1) inicializa contador2 ciclo interno
rep2 DECFSZ cont2,1 ;(1,2)Decrementa contador2 y escapa si cero
GOTO rep2 ;(2) si no es cero, repite ciclo interno
DECFSZ cont1,1 ;(1,2)Decrementa contador1 y escapa si cero
GOTO rep1 ;(2) si no es cero repite ciclo externo
RETURN ;(2) regresa de esta subrutina
END
3.10. Ejemplo 5
Para este ejemplo se supone un display de ánodo común conectado al puerto C como se muestra a
continuación:
Dato a b c d e f g Código
29
0 0 0 0 0 0 0 1 01
1 1 0 0 1 1 1 1 4F
2 0 0 1 0 0 1 0 12
3 0 0 0 0 1 1 0 06
4 1 0 0 1 1 0 0 4C
5 0 1 0 0 1 0 0 24
6 0 1 0 0 0 0 0 20
7 0 0 0 1 1 1 1 0F
8 0 0 0 0 0 0 0 00
9 0 0 0 0 1 0 0 04
A 0 0 0 1 0 0 0 08
b 1 1 0 0 0 0 0 60
C 0 1 1 0 0 0 1 31
d 1 0 0 0 0 1 0 42
E 0 1 1 0 0 0 0 30
F 0 1 1 1 0 0 0 38
1. Diagrama de Flujo:
30
INICIO
N←0x1A
M←0x00
PORTB←0x01
cont←0
NO
RC7=1
SI
d20ms
NO
RC7=1
SI
cont←cont+1
codigo
POTC←W
NO
RC7=0
SI
31
codigo
W←0x0F
W←W AND cont
PCL←W + PCL
Selecciona un
valor de acuerdo
a cont:
0: W←0x01
1: W←0x4F
2: W←0x12
3: W←0x06
4: W←0x4C
5: W←0x24
6: W←0x20
7: W←0x0F
8: W←0x00
9: W←0x04
10: W←0x08
11: W←0x60
12: W←0x31
13: W←0x42
14: W←0x30
15: W←0x38
FIN
2. Código en Assembler:
;************************************************************************
;* Ejemplo35.asm
;* Este programa despliega un dígito hexadecimal en un display de ánodo
;* común conectado al puerto C. El dígito se incrementa en 1 cada vez que
;* se presiona un botón conectado al MSB del mismo puerto C
;************************************************************************
PROCESSOR 16F877
RADIX DEC
INCLUDE "P16F877A.INC"
;Define variables
CBLOCK 0x20
;Define variables contador
cont
32
;Define variables para pausa de 20 mseg
cont1
cont2
;Define variable para pausa de 1 segundo
cont3
ENDC
;Reset Vector
org 0x00 ;Inicia en el vector de reset
MOVLW 0x01 ;
MOVWF PORTC ;Despliega un cero. Codificado
CLRF cont ;Inicializa contador en cero
tecla BTFSS PORTC,7 ;checa botón si se ha presionado
GOTO tecla ;Si no se ha presionado espera
CALL d20ms ;pausa de 20 milisegundos
BTFSS PORTC,7 ;checa nuevamente el botón si esta presionado
GOTO tecla ;tecla falsa, espera de nuevo
INCF cont,1 ;tecla válida, incrementa contador
CALL codigo ;obtiene código para desplegar el contador
MOVWF PORTC ;despliega contador
suelta BTFSC PORTC,7 ;checa de nuevo el botón si se ha soltado
GOTO suelta ;si sigue presionado espera
GOTO tecla ;si ya se soltó espera nueva presión.
codigo
MOVLW 0x0F ;carga máscara
ANDWF cont,0 ;enmascara el contador y lo deja en W
ADDWF PCL,1 ;Salta W instrucciones adelante
RETLW 0x01 ;código del 0
RETLW 0x4F ;código del 1
RETLW 0x12 ;código del 2
RETLW 0x06 ;código del 3
RETLW 0x4C ;código del 4
RETLW 0x24 ;código del 5
RETLW 0x20 ;código del 6
RETLW 0x0F ;código del 7
RETLW 0x00 ;código del 8
RETLW 0x04 ;código del 9
33
RETLW 0x08 ;código de la A
RETLW 0x60 ;código de la b
RETLW 0x31 ;código de la C
RETLW 0x42 ;código de la d
RETLW 0x30 ;código de la E
RETLW 0x38 ;código de la F
;inicia subrutina
d20ms MOVLW N ;(1) Carga dato N
MOVWF cont1 ;(1) inicializa contador1 ciclo externo
rep1 MOVLW M ;(1) Carga dato M
MOVWF cont2 ;(1) inicializa contador2 ciclo interno
rep2 DECFSZ cont2,1 ;(1,2)Decrementa contador2 y escapa si cero
GOTO rep2 ;(2) si no es cero, repite ciclo interno
DECFSZ cont1,1 ;(1,2)Decrementa contador1 y escapa si cero
GOTO rep1 ;(2) si no es cero repite ciclo externo
RETURN ;(2) regresa de esta subrutina
END
Observación: Una manera más cómoda de escribir la lista de instrucciones RETLW al final del
programa anterior puede lograrse usando la directiva DT (Define Table) del ensamblador, la cual
nos permite definir una tabla de datos que será sustituida por una lista de instrucciones RETLW; así,
la lista anterior puede quedar como sigue:
DT 0x01,0x4F,0x12,0x06,0x4C,0x24,0x3F,0x0F
DT 0x00,0x04,0x08,0x60,0x31,0x42,0x30,0x38
http://www.geekfactory.mx/tutoriales/tutoriales-pic/pantalla-lcd-16x2-con-pic-libreria/
por Jesus Ruben Santa Anna Zamudio | Ago 2, 2014 | Tutoriales PIC | 3 Comments
11.1. Descripción:
Cuando los simples indicadores luminosos con led ya no son suficientes, habitualmente el siguiente
paso para todo programador es ir por una pantalla lcd 16×2. Se encuentra que existen módulos LCD
que facilitan la interfaz con este periférico. El estándar en la industria para estos módulos con
“controlador a bordo” es el chipset HD44780 (y otros más compatibles desarrollados a partir de este),
para los cuales se encuentra soporte en prácticamente cualquier plataforma: Arduino, PIC, AVR,
MSP430, etc.
En la Figura 1 se muestra un LCD 2x16 que está compuesto por 2 líneas de 16 caracteres, con
iluminación azul y letras color blanco.
Se realizará la interface del PIC16F877 con un LCD (Liquid Crystal Display) compuesto por dos líneas
de 16 caracteres cada una. Los LCD más comunes, disponen de una interface ideada por Hitachi y
adoptada como estándar por otros fabricantes. Esta interface hace que el LCD pueda ser conectado al
micro a través de un bus de 4 u 8 líneas más tres líneas de control y las de alimentación.
En la Tabla 1 están descriptas las funciones de cada línea disponible del LCD. Las descripciones en
negrita, indican las líneas efectivamente utilizadas en la aplicación de 4 bits de datos.
Para reducir al máximo las conexiones entre el micro y el LCD, se usará la modalidad de interconexión
de datos a 4 bit, usando sólo las líneas DB4, DB5, DB6, DB7. Las líneas DB0, DB1, DB2 y DB3 no
serán usadas y serán conectadas a tierra.
Tampoco la línea R/W# será utilizada por lo que será puesta a tierra. De este modo, quedará
seleccionado el modo escritura. En la práctica, sólo se podrá enviar datos al LCD pero no recibirlos.
Para poder visualizar una frase en el LCD, el PIC debe enviar una serie de comandos a través del
bus de datos (líneas DB4 a DB7). Para hacer esto, son utilizadas dos líneas de control con las que
se comunica al LCD la operación de transferencia que realizará el bus.
Las dos líneas de control son Register Select (pin 4) y Enable (pin 6) del LCD, las cuales se
describen a continuación:
Con la línea Register Select, el PIC indica al display que el dato presente en el bus es un
comando ( RS=0 ) o un dato a ser visualizado ( RS=1 ). A través de los comandos, el PIC puede
indicar al LCD el tipo de operación a realizar, como por ejemplo "limpiar pantalla". Con los
datos, el PIC puede enviar directamente los caracteres ASCII a ser visualizados.
La línea Enable habilita al LCD para leer el comando o el dato enviado en el bus por el PIC. El
PIC debe ocuparse de haber enviado en el bus de datos el comando o el dato correcto antes de
poner a 1 la señal Enable.
Puesto que los comandos son datos de 8 bits ¿Cómo es posible enviarlos al LCD si el bus de datos
dispone sólo de 4 líneas?
Los módulos LCD responden a un conjunto especial de instrucciones, estas deben ser enviadas por el
microcontrolador o sistema de control al display, según la operación que se requiera. Se muestran en la
Tabla 2 el conjunto de instrucciones del módulo LCD.
36
Tabla 2. Conjunto de instrucciones del módulo LCD
Código de Operación Tiempo de
Instrucción Descripción
RS R/W B7 B6 B5 B4 B3 B2 B1 B0 Ejecución
Borra el contenido de la pantalla y
Clear display 0 0 0 0 0 0 0 0 0 1 retorna el cursor a la posición “home” 1.52 ms
(dirección 0).
Retorna el cursor a la posición
“Home”. Retorna también el área de
Cursor home 0 0 0 0 0 0 0 0 1 * visión a la posición inicial. El 1.52 ms
contenido de la DDRAM permanece
intacto.
Incrementar/Decrementar dirección
(I/D); Habilitar corrimiento de
Entry mode set 0 0 0 0 0 0 0 1 I/D S 37 μs
pantalla (S). Estas operaciones se
realizan al leer o escribir datos
Enciende o apaga el display (D),
Display on/off
0 0 0 0 0 0 1 D C B Cursor encendido / apagado (C), 37 μs
control
destello del cursor (blink) (B).
Selecciona entre desplazamiento de
pantalla o de cursor (S/C), selecciona
Cursor/display
0 0 0 0 0 1 S/C R/L * * la dirección de desplazamiento (R/L). 37 μs
shift
El contenido de la DDRAM
permanece intacto.
Configurar en ancho de bus (4 u 8
Function set 0 0 0 0 1 DL N F * * bits) (DL), Número de líneas de 37 μs
display (N), y tipo de fuente (F).
Escribe la dirección de CGRAM. Los
Set CGRAM Dirección generador de datos a almacenar en CGRAM pueden
0 0 0 1 37 μs
address RAM ser enviados después de esta
instrucción
Escribe la dirección de DDRAM. Los
Set DDRAM datos a almacenar en DDRAM pueden
0 0 1 Dirección de datos RAM 37 μs
address ser enviados después de esta
instrucción
Leer bandera “Ocupado” (Bussy Flag)
indicando si el controlador está
Read busy flag realizando alguna operación interna o
&address 0 1 BF CGRAM/DDRAM address está listo para aceptar datos/comandos. 0 μs
counter Lee la dirección CGRAM o DDRAM
(dependiendo de la instrucción
previa).
Write CGRAM Escribe datos a las memorias CGRAM
1 0 Escritura de Dato 37 μs
orDDRAM o DDRAM.
Read from Lee datos desde las memorias
1 1 Lectura de Dato 37 μs
CG/DDRAM CGRAM o DDRAM.
NOTA: nótese que el pin RS# debe tomar el valor 0 (cero) cuando lo que se va a enviar es una
instrucción de control y debe tomar el valor 1 (uno) cuando lo que se va a enviar es un dato.
37
Tabla 3. Significado de las abreviaturas
SIGNIFICADO DE LAS ABREVIATURAS
(Nombres y significado de bits en instrucciones)
I/D – 0 = disminuir el contador de dirección, 1 = incrementar el contador de dirección;
N – 0 = 1 línea, 1 = 2 líneas;
La interface entre el microcontrolador y el LCD se puede hacer con el bus de datos del PIC trabajando
a 4 u 8 bits. Las señales de control trabajan de la misma forma en cualquiera de los dos casos, la
diferencia se establece en el momento de iniciar el display, ya que existe una instrucción que permite
establecer dicha configuración. O sea se tiene que avisarle al LCD que se va a operar en 8 o a 4 bits.
Los caracteres que se envían al display se almacenan en la memoria RAM del módulo. Existen
posiciones de memoria RAM, cuyos datos son visibles en la pantalla y otras que no son visibles, estas
últimas se pueden utilizar para guardar caracteres que luego se desplazan a la zona visible.
Es importante anotar que solo se pueden mostrar caracteres ASCII de 7bits, por lo tanto algunos
caracteres especiales no se pueden ver (es aconsejable tener a mano una tabla de caracteres ASCII para
conocer los datos que son prohibidos). También se tiene la opción de mostrar caracteres especiales
creados por el programador y almacenarlos en la memoria RAM que posee el módulo.
http://www.bolanosdj.com.ar/SOBRELCD/TEORIALCDV1.pdf
El HD44780 permite conectarse a través de un bus de 4 u 8 bits. El modo de 4 bits permite usar solo 4
pines para el bus de datos, dándonos un total de 6 o 7 pines requeridos para la interfaz con el LCD,
38
mientras que el modo de 8 bits requiere 10 u 11 pines. El pin RW es el único que puede omitirse si se
usa la pantalla en modo de solo escritura y deberá conectarse a tierra si no se usa. En este caso el
microcontrolador no puede leer desde el chip controlador de pantalla, pero en la mayoría de las
situaciones esto no es necesario.
11.3.1. Conexión básica de una pantalla lcd 16×2 con una interface de 8 bits
Las conexiones para el modo de 8 bits son algo más complicadas, ya que se requiere las 8 líneas de
datos activas. En este caso se utiliza los 8 bits del puerto B, aunque se puede usar cualquier
combinación de pines. RA0 ahora funciona como señal de selección de registro (RS) y RA1 como
señal de habilitación (E). En la Figura 2 se muestra las conexiones para el modo de 8 bits en un
PIC16F877.
Esta forma de manejo es la más sencilla de programar, pero tiene la desventaja de utilizar 8 pines del
microcontrolador solo para el envío de datos y otros 2 pines para las señales de control.
En principio en la mayor parte de las aplicaciones se va requerir escribir en el LCD y rara vez leer en el
mismo, por lo tanto en este curso se dedicará exclusivamente a escribir en el LCD. Esto implica que el
pin de selección de lectura/escritura (R/W) se conectará siempre a tierra GND.
Si se utiliza el puerto B como bus de datos (manejará los pines D0 a D7 del LCD) y el puerto A se
encarga de manejar las señales de control (manejará los pines E y RS del LCD).
39
Se debe programar 2 subrutinas, una que se llama INSTRUC que será invocada cuando se quiera enviar
una instrucción al módulo LCD, por ejemplo limpiar pantalla, indicar una posición de memoria, indicar
si se utiliza interfaz de 8 o 4 bits etc. Y otra subrutina que se llama ESCRIB que será invocada cuando
se quiera escribir un dato para ser visualizado en el módulo LCD.
Se configurará entonces todo el puerto B como salida al igual que los pines RA0 y RA1 del puerto A,
estando asignado cada pin del puerto como se indica a continuación:
Pin PORTB RB7 RB6 RB5 RB4 RB3 RB2 RB1 RB0
Pin LCD D7 D6 D5 D4 D3 D2 D1 D0
RECORDAR: Como solo se va a escribir en pantalla, el pin R/W vale siempre 0 (cero), así que se lo
conecta directamente a tierra.
Evidentemente se debe configurar el PORTB del PIC como salida, y en el PORTA los pines RA0 y
RA1 deben ser configurados como salidas. El resto de los pines del PORTA se puede configurar como
se desee. Recuerde que se está basando esta explicación para interface de 8 bits.
Lo primero que hay que hacer es mandar una serie de instrucciones al módulo LCD que constituyen la
configuración del mismo. Luego recién se podrá escribir el mensaje a presentar en pantalla.
11.3.3. Instrucciones muy importantes (son independientes a que se use interface de 4 u 8 bits)
Se informa el tipo de interfaz que se va a usar, 4 o 8 bits. La cantidad de líneas (1 o 2). La fuente de
caracter (5x8 dots o 5x10 dots).
RS R/W# D7 D6 D5 D4 D3 D2 D1 D0
0 0 0 0 0 DL N F - -
DL = 0 interfaz de 4 bits.
DL = 1 interfaz de 8 bits.
40
D7 D6 D5 D4 D3 D2 D1 D0
0 0 1 1 0 0 0 1
DL = 1 interfaz de 8 bits.
N=0 se va a usar 1 sola línea del display.
F=0 fuente de caracter 5x8 dots.
Ahora se debe llamar a la subrutina INSTRU (esta subrutina debe ser creada por el programador, se le
puede dar el nombre que se quiera), la cual va a enviar 30h al PORTB, hacer RS=0 o sea le dice al
LCD que lo que va a recibir es una instrucción (RA0= 0 del PORTA) y E=1 o sea habilita al LCD
(RB1= 0 del PORTA), luego vuelve a hacer E=0 deshabilita.
Configura el estado ON/OFF de todo el display, el estado del cursor y el parpadeo del caracter en la
posición del cursor.
RS R/W# D7 D6 D5 D4 D3 D2 D1 D0
0 0 0 0 0 0 1 D C B
Donde:
D7 D6 D5 D4 D3 D2 D1 D0
0 0 0 0 1 1 0 0
Se está diciendo:
Ahora se debe llamar nuevamente a la subrutina INSTRU (esta subrutina debe ser creada por el
programador, se le puede dar el nombre que se quiera), la cual va a enviar 0Ch al PORTB, hacer RS=0
41
o sea le dice al LCD que lo que va a recibir es una instrucción (RA0=0 del PORTA) y E=1 o sea
habilita al LCD (RB1= 0 del PORTA), luego vuelve a hacer E=0 deshabilita.
RS R/W# D7 D6 D5 D4 D3 D2 D1 D0
0 0 0 0 0 0 0 0 0 1
RS R/W# D7 D6 D5 D4 D3 D2 D1 D0
0 0 0 0 0 0 0 1 ID S
ID = 1 incremento.
ID = 0 decremento.
D7 D6 D5 D4 D3 D2 D1 D0
0 0 0 0 0 1 1 0
NOTAR que los unos enviados a D2 y D1 carecen de sentido porque no hay desplazamiento.
Hasta aquí se han enviado las instrucciones previas para inicializar el módulo LCD y dejarlo listo para
la escritura de datos en pantalla.
El envió de los datos se realiza por medio de los pines D0 a D7 del LCD, que se encuentran conectados
a los pines RB0 a RB7 del PORTB B del PIC. Por lo tanto los datos a escribir deben ser enviados a
través del PORTB B.
Un dato se envía por medio de su código ASCII, pero previamente se debe indicar al módulo la
posición de memoria en que deseo escribir el dato que se enviará a continuación. Esto se hace por
medio de la instrucción DDRAM.
42
DDRAM (Instrucción)
Le informa al módulo LCD la dirección de memoria en la cual se va almacenar el código del dato que
se le enviará a continuación.
RS R/W# D7 D6 D5 D4 D3 D2 D1 D0
0 0 1 Posición de memoria a escribir dato
Se aclara algo para no confundirse. Supóngase que se desea escribir 'A' en la posición de memoria 00h
del LCD.
Como se tiene que asegurar el 1 en el D7 se debe enviar al PORTB (recordar que D0 ... D7 del LCD
está conectado a RB0 ... RB7 del PORTB) en lugar de 00h el 80h, esto es para asegurar el 1 en el D7
(el 1 en D7 hace 00000000 se convierta en 10000000 o sea 80h).
D7 D6 D5 D4 D3 D2 D1 D0
1 0 0 0 0 0 0 0
Ahora que se le informa donde se va a escribir el dato, se debe enviarlo y aclararle que se está enviando
un dato, para lo cual se necesita una subrutina que justamente hará esto y que se la llamará ESCRIB.
43
Tabla 4. Mapa de la Memoria del Módulo LCD (2 líneas x 16 caracteres)
00h 01h 02h 03h 04h 05h 06h 07h 08h 09h 0Ah 0Bh 0Ch 0Dh 0Eh 0Fh 10h --- 1Fh
40h 41h 42h 43h 44h 45h 46h 47h 48h 49h 4Ah 4B 4C 4D 4Eh 4Fh 50h --- 5Fh
Área no
Área visible visible - 16
posiciones
Como se había mencionado anteriormente, al enviar una dirección hay que asegurar el 1 en D7
Por ejemplo:
D7 D6 D5 D4 D3 D2 D1 D0
1 0 0 0 0 0 0 0
De este modo se podría pensar en un mapa de memoria equivalente del módulo LCD como muestra en
la Tabla 5, en el caso de solo utilizar la zona visible.
80h 81h 82h 83h 84h 85h 86h 87h 88h 89h 8Ah 8Bh 8Ch 8Dh 8Eh 8Fh
C0h C1h C2h C3h C4h C5h C6h C7h C8h C9h CAh CB CC CD CEh CFh
Ejemplo 6
44
LCD1
LCD16x2
VDD
VSS
VEE
RW
RS
D0
D1
D2
D3
D4
D5
D6
D7
E
1
2
3
4
5
6
7
8
9
10
11
12
13
14
BOXER
13 33
OSC1/CLKIN RB0/INT
14 34
OSC2/CLKOUT RB1
X1 1 35
MCLR/Vpp/THV RB2
36
RB3/PGM
2 37
RA0/AN0 RB4
3 38
RA1/AN1 RB5
20Mhz R1 4
RA2/AN2/VREF- RB6/PGC
39
10k 5 40
RA3/AN3/VREF+ RB7/PGD
C2 C1 6
RA4/T0CKI
22p 22p 7 15
RA5/AN4/SS RC0/T1OSO/T1CKI
16
RC1/T1OSI/CCP2
8 17
RE0/AN5/RD RC2/CCP1 VDD
9 18
RE1/AN6/WR RC3/SCK/SCL
10 23
VDD RE2/AN7/CS RC4/SDI/SDA
24
RC5/SDO
25
RC6/TX/CK
26
RC7/RX/DT
19
RD0/PSP0
20
RD1/PSP1
21
RD2/PSP2
22
RD3/PSP3
27
RD4/PSP4
28
RD5/PSP5
29
RD6/PSP6
30
RD7/PSP7
PIC16F877
processor 16f877
include <p16f877.inc>
;Define variables
cblock 0x20
temp5
endc
org 00
inicio
bsf STATUS,5 ;se posiciona en banco1
clrf TRISB ;define el PORTB como salida
clrf TRISA ;define el PORTA como salida
movlw 06h ; carga w con literal 06h
movwf ADCON1; carga ADCON1 con w = 06h para entradas digitales
bcf STATUS,5
;------------Una instruccion-----------
movlw 30h; carga w con literal 30h
;la intrucc asociada dice: interface de datos de 8 bits y se va a usar
;1 linea - corresponde a la intruccion ACTIVAR FUNCION
call instruc; enviaremos este valor al PORTB y por lo tanto al LCD
45
;------------otra instruccion-----------
movlw 06h; carga w con literal 06h
;la intrucc asociada dice: dato fijo en pantalla- corresponde a la intruccion
;SELECCIONAR MODO
call instruc; enviaremos este valor al PORTB y por lo tanto al LCD
;------------otra instruccion-----------
movlw 0Ch; carga w con literal 0Ch
;la intrucc asociada dice: encienda la pantalla y desactive el cursor-
;corresponde a la intruccion ENCENDER O APAGAR PANTALLA
call instruc; enviaremos este valor al PORTB y por lo tanto al LCD
;------------otra instruccion-----------
movlw 01h; carga w con literal 01h
;la intrucc asociada dice: BORRAR PANTALLA
call instruc; enviaremos este valor al portb y por lo tanto al LCD
;---escritura de datos---------------
movlw 80h; se indica posicion de memoria del LCD en que quiere
; escibir el dato
call instruc
movlw " "; este es dato - al estar entre comillas se le indica al
; compilador que el dato requerido es el valor ASCII del
; caracter
call escrib
movlw 81h;
call instruc
movlw "H";
call escrib
movlw 82h;
call instruc
movlw "O";
call escrib
movlw 83h;
call instruc
movlw "L";
call escrib
movlw 84h;
call instruc
movlw "A";
call escrib
movlw 85h;
call instruc
movlw " ";
call escrib
movlw 86h;
call instruc
movlw "M";
call escrib
46
movlw 87h;
call instruc
movlw "U";
call escrib
movlw 88h;
call instruc
movlw "N";
call escrib
movlw 89h;
call instruc
movlw "D";
call escrib
movlw 8Ah;
call instruc
movlw "O";
call escrib
movlw 8Bh;
call instruc
movlw ".";
call escrib
movlw 8Ch;
call instruc
movlw ".";
call escrib
;---fin escritura de datos-----------
;--------SUBRUTINAS-------------
;----------------------------------------
;Subrutina que manda una instruccion al LCD
instruc
bcf PORTA,0 ; hace 0 el bit 0 del PORTA o sea hace RS=0 - Le dice
; al LCD que es una intruccion lo que va a recibir
bsf PORTA,1 ; hace 1 el bit 1 del PORTA - O sea E=1 habilita LCD
movwf PORTB; carga contenido de w en PORTB
call retardo
bcf PORTA,1; hace 0 el bit 1 del PORTA - O sea E=0 habilita LCD
call retardo
return
;----------------------------------------
;Subrutina que manda un dato al LCD
escrib
bsf PORTA,0 ; hace 1 el bit 0 del PORTA o sea hace RS=1 - Le dice
; al LCD que es es un dato lo que va a recibir
bsf PORTA,1 ; hace 1 el bit 1 del PORTA - O sea E=1 habilita LCD
movwf PORTB; carga contenido de w en PORTB
call retardo
bcf PORTA,1; hace 0 el bit 1 del PORTA - O sea E=0 habilita LCD
call retardo
return
;----------------------------------------
;Subrutina retardo
retardo
47
movlw 0ffh; carga literal 0ffh en w
movwf temp5; mueve contenido de w a temp5
decr
decfsz temp5,1 ; decrementa temp5 y guarda resultado en temp5- salta
; la intruccion siguiente si temp es igual a cero
goto decr
return
;--------FIN SUBRUTINAS--------
end
Realizar una aplicación que muestre el siguiente mensaje en el lcd 2x16, en forma repetida, con un
tiempo de muestreo de 1 seg:
1. Diagrama de Conexiones
2. El código es el siguiente:
48
processor 16F877
include <P16F877.INC>
;Configuración de puertos
clrf PORTB ;Limpia PORTB
clrf PORTD ;Limpia PORTD
bsf STATUS, RP0
bcf STATUS, RP1 ;Selecciona el banco 1
clrf TRISB ;Configura PORTB como salida
clrf TRISD ;Configura PORTD como salida
bcf STATUS,RP0 ;Regresa al banco 0
START_LCD:
call INICIA_LCD ;Configura el LCD
call M1 ;Muestra Mensaje
call LINEA2 ;Configura línea 2
call M2 ;Muestra Mensaje
goto START_LCD
;Mensaje a enviar
M1:
movlw 'H' ;Mueve 'H' a W
movwf PORTB ;Mueve lo que hay en W a PORTB
call ENVIA ;Imprime en LCD
movlw 'e'
movwf PORTB
call ENVIA
movlw 'l'
movwf PORTB
call ENVIA
movlw 'l'
movwf PORTB
call ENVIA
movlw 'o'
movwf PORTB
call ENVIA
movlw ' '
movwf PORTB
call ENVIA
movlw 'W'
movwf PORTB
call ENVIA
movlw 'o'
movwf PORTB
call ENVIA
movlw 'r'
movwf PORTB
call ENVIA
movlw 'l'
movwf PORTB
call ENVIA
movlw 'd'
49
movwf PORTB
call ENVIA
movlw '!'
movwf PORTB
call ENVIA
return
M2:
movlw 'I' ;Mueve 'I' a W
movwf PORTB ;Mueve lo que hay en W a PORTB
call ENVIA ;Imprime en LCD
movlw 'm'
movwf PORTB
call ENVIA
movlw ' '
movwf PORTB
call ENVIA
movlw 'O'
movwf PORTB
call ENVIA
movlw 'p'
movwf PORTB
call ENVIA
movlw 'e'
movwf PORTB
call ENVIA
movlw 'n'
movwf PORTB
call ENVIA
movlw 'B'
movwf PORTB
call ENVIA
movlw 'o'
movwf PORTB
call ENVIA
movlw 'x'
movwf PORTB
call ENVIA
movlw 'e'
movwf PORTB
call ENVIA
movlw 'r'
movwf PORTB
call ENVIA
return
50
;Subrutina para enviar comandos
COMANDO:
bsf PORTD,1 ; Pone ENABLE en 1
call DELAY ; Tiempo de espera
call DELAY
bcf PORTD, 1 ; ENABLE=0
call DELAY
return
; Subrutina de retardo
DELAY:
movlw 0xFF
movwf val2
ciclo:
movlw 0xFF
movwf val1
ciclo2:
decfsz val1,1
goto ciclo2
decfsz val2,1
goto ciclo
return
END
11.4.1. Conexión básica de una pantalla lcd 16×2 con una interface de 4 bits
Las conexiones para el modo de 4 bits en un PIC16F877 se muestran en la Figura 5. Se utilizan los
primeros 4 bits del puerto A (RA0-RA3) como bus de datos. RB0 como señal de habilitación (E) y
RB1 como señal de selección de registro (RS).
51
Figura 5. Las conexiones para el modo de 4 bits en un PIC16F877
Es el caso más utilizado para aprovechar los puertos del PIC. Dejando disponibles pines de los mismos
para otras funciones.
RW va a tierra
Las subrutinas INSTRUC y ESCRIB serán diferentes que para el caso de interfaz de 8 bits. Estas
enviaran primero los 4bit MSB y luego los 4 bits LSB.
Ejemplo 8
Limpia la pantalla
52
(C) DJB_2009 Primera fila
Limpia la pantalla
RECREO…… Primera fila
Limpia la pantalla
ALARMA…… Primera fila
LCD1
LCD16x2
VDD
VSS
VEE
RW
RS
D0
D1
D2
D3
D4
D5
D6
D7
E
1
2
3
4
5
6
7
8
9
10
11
12
13
14
BOXER
13 33
OSC1/CLKIN RB0/INT
14 34
OSC2/CLKOUT RB1
X1 1 35
MCLR/Vpp/THV RB2
36
RB3/PGM
R1 2
RA0/AN0 RB4
37
10k 3 38
RA1/AN1 RB5
4 39
20Mhz RA2/AN2/VREF- RB6/PGC
5 40
RA3/AN3/VREF+ RB7/PGD
C2 C1 6
RA4/T0CKI
22p 22p 7 15
RA5/AN4/SS RC0/T1OSO/T1CKI
16
RC1/T1OSI/CCP2
8 17
VDD RE0/AN5/RD RC2/CCP1 VDD
9 18
RE1/AN6/WR RC3/SCK/SCL
10 23
RE2/AN7/CS RC4/SDI/SDA
24
RC5/SDO
25
RC6/TX/CK
26
RC7/RX/DT
19
RD0/PSP0
20
RD1/PSP1
21
RD2/PSP2
22
RD3/PSP3
27
RD4/PSP4
28
RD5/PSP5
29
RD6/PSP6
30
RD7/PSP7
PIC16F877
processor 16f877
include <p16f877.inc>
org 00
inicio
bsf STATUS,5 ;se posiciona en banco1
clrf TRISB ;define el PORTB como salida
movlw b'00001100'
movwf TRISA
movlw 06h ; carga w con literal 06h
movwf ADCON1; carga ADCON1 con w = 06h para entradas digitales
mostrar
btfsc PORTA,2 ; si en el pin 2 del PORTA hay un 0 entonces muestra
; mensaje1-alternado con mensaje3
goto frase2
call mensaje1
call espera
frase2
btfsc PORTA,3 ; si en el pin 3 del PORTA hay un 0 entonces muestra
; mensaje2-alternado con mensaje3
goto frase3
call mensaje2
call espera
frase3
call copyright ; si recibe un 0 en pines 2 y 3 de PORTA muestra
; mensaje3
call espera
goto mostrar
;--------SUBRUTINAS-------------
;------------otra instruccion-----------
movlw 28h; carga w con literal 28h
;la intrucc asociada dice: interfase de datos de 4 bits y se va a usar 2
;lineas - corresponde a la intruccion ACTIVAR FUNCION
call instruc; enviaremos este valor al PORTB y por lo tanto al LCD
;------------otra instruccion-----------
movlw 06h; carga w con literal 06h
54
;la intrucc asociada dice: dato fijo en pantalla- corresponde a la intruccion
;SELECCIONAR MODO
call instruc; enviaremos este valor al PORTB y por lo tanto al LCD
;------------otra instruccion-----------
movlw 0Ch; carga w con literal 0Ch
;la intrucc asociada dice: encienda la pantalla y desactive el
;cursor- corresponde a la intruccion ENCENDER O APAGAR PANTALLA
call instruc; enviaremos este valor al PORTB y por lo tanto al LCD
;------------otra instruccion-----------
movlw 01h; carga w con literal 01h
;la intrucc asociada dice: BORRAR PANTALLA
call instruc; enviaremos este valor al PORTB y por lo tanto al LCD
return
;-------Fin Subrutina LCD --------
;--------------------Subrutina INSTRC/ESCRIB-------------------------
;Subrutina que manda una instruccion o dato al LCD
;Esta subrutina utiliza el registro de proposito general aux
instruc
bcf PORTB,0; RB0=0 o sea RS=0 es una instruccion para LCD
goto dato2
escrib
bsf PORTB,0; RB0=1 o sea RS=1 es una dato para LCD
dato2
;lo que se va hacer es para no alterar el contenido de los 4 bit menos
;significativos del PORTB
movwf aux; guarda contenido de w en aux
movlw 0fh; carga 00001111 en w
andwf PORTB,1 ; AND entre w=00001111 y PORTB y guarda resultado en
; PORTB
;lo que se termino de hacer es para no alterar el contenido de los 4 bit
;menos significativos dell PORTB
return
;---------Fin subrutina que manda instruccion o dato al LCD------
retardo4
incf tempo1,1
retardo5
incf tempo2,1
retardo6
incf tempo3,1
btfss tempo3,7
goto retardo6
clrf tempo3
btfss tempo2,7
goto retardo5
clrf tempo2
btfss tempo1,7
goto retardo4
clrf tempo1
56
;Limpia la E en display que escribio al principio
movlw 0CFh;
call instruc
movlw " ";
call escrib
;Termino de limpiar la E
return
;-----Fin subrutina largaespera-----------------------
;---Subrutina copyright-----------
copyright
movlw 01h
; call instruc; borrar pantalla
movlw 82h;
call instruc
movlw ")";
call escrib
movlw 83h;
call instruc
movlw " ";
call escrib
57
movlw 84h;
call instruc
movlw "D";
call escrib
movlw 85h;
call instruc
movlw "J";
call escrib
movlw 86h;
call instruc
movlw "B";
call escrib
movlw 87h;
call instruc
movlw "-";
call escrib
movlw 88h;
call instruc
movlw "2";
call escrib
movlw 89h;
call instruc
movlw "0";
call escrib
movlw 8Ah;
call instruc
movlw "0";
call escrib
movlw 8Bh;
call instruc
movlw "9";
call escrib
call espera
call espera
call espera
call espera
return
;---Fin subrutina copyright-----------------------------------------------
;---Subrutina mensaje1-----------
mensaje1
movlw 01h
; call instruc; borrar pantalla
movlw 82h;
call instruc
movlw "C";
call escrib
movlw 83h;
call instruc
movlw "R";
call escrib
movlw 84h;
call instruc
movlw "E";
call escrib
movlw 85h;
call instruc
movlw "O";
call escrib
movlw 86h;
call instruc
movlw ".";
call escrib
movlw 87h;
call instruc
movlw ".";
call escrib
movlw 88h;
call instruc
movlw ".";
call escrib
movlw 89h;
call instruc
movlw ".";
call escrib
movlw 8Ah;
call instruc
movlw ".";
call escrib
movlw 8Bh;
call instruc
movlw ".";
call escrib
59
call espera
call espera
call espera
call espera
return
;---Fin subrutina mensaje1-----------------------------------------------
;---Subrutina mensaje2-----------
mensaje2
movlw 01h
; call instruc; borrar pantalla
movlw 82h;
call instruc
movlw "A";
call escrib
movlw 83h;
call instruc
movlw "R";
call escrib
movlw 84h;
call instruc
movlw "M";
call escrib
movlw 85h;
call instruc
movlw "A";
call escrib
movlw 86h;
call instruc
movlw ".";
call escrib
movlw 87h;
call instruc
movlw ".";
call escrib
movlw 88h;
call instruc
movlw ".";
60
call escrib
movlw 89h;
call instruc
movlw ".";
call escrib
movlw 8Ah;
call instruc
movlw ".";
call escrib
movlw 8Bh;
call instruc
movlw ".";
call escrib
call espera
call espera
call espera
call espera
return
;---Fin subrutina mensaje2-----------------------------------------------
;--------FIN SUBRUTINAS-------------
end
HELLO WORD!_
NOTA: Si no se logra ver nada en el LCD, tal vez, sea necesario regular el contraste del LCD a
través de R2 conectado al pin 3 del LCD.
El circuito a ser utilizado para comprender mejor las explicaciones de la Gestión de un LCD, se
presenta en la Figura 7:
61
Figura 7. Circuito de la Gestión de un LCD
1. Diagrama de Flujo:
Diagrama de flujo del Programa Principal:
62
INICIO
RS←2
E←3
DB4←4
DB5←5
DB6←6
DB7←7
LcdInit
W←10H
LcdLocate
W←’H’
LcdSendData
.
.
W←’!’
LcdSendData
Los diagramas de flujo de las subrutinas de este programa no se presentan, pero en la Tabla 5 se
describen brevemente las Subrutinas de gestión del LCD.
63
LcdLocate Posiciona arbitrariamente el cursor dentro del área visible del display.
Necesita el valor de fila y columna para posicionar el cursor en el registro W. Los bits desde D0 a D3 contienen
el valor de columna (eje Y) y los bits desde D4 a D7 los valores de filas (eje X). La numeración de las filas parte
de cero hacia arriba, la de columna parte de cero hacia la derecha.
LcdSendData Envía el carácter ASCII al LCD a ser visualizado en la posición donde se encuentra el cursor.
2. Código en Assembler:
;**************************************************
;
; LCD.ASM
;
;**************************************************
PROCESSOR 16F877
RADIX DEC
INCLUDE "P16F877.INC"
ORG 20H
tmpLcdRegister res 2
msDelayCounter res 2
Start
bsf STATUS,RP0 ;Swap to register bank 1
;LCD inizialization
call LcdInit
foreverLoop
goto foreverLoop
;**********************************************************************
; Delay subroutine
; W = Requested delay time in ms (clock = 4MHz)
;**********************************************************************
msDelay
movwf msDelayCounter+1
clrf msDelayCounter+0
decfsz msDelayCounter+1,F
goto msDelayLoop
return
;**********************************************************************
; Init LCD
; This subroutine must be called before each other lcd subroutine
;**********************************************************************
65
LcdInit
movlw 30 ;Wait 30 ms
call msDelay
;****************
; Reset sequence
;****************
bcf PORTB,LCD_DB4
bsf PORTB,LCD_DB5
bcf PORTB,LCD_DB6
bcf PORTB,LCD_DB7
66
call LcdSendCommand
;Clear display
call LcdClear
return
;**********************************************************************
; Clear LCD
;**********************************************************************
LcdClear
;Clear display
movlw 01H
call LcdSendCommand
movlw 2 ;Wait 2 ms
call msDelay
return
;**********************************************************************
; Locate cursor on LCD
; W = D7-D4 row, D3-D0 col
;**********************************************************************
LcdLocate
movwf tmpLcdRegister+0
movlw 80H
movwf tmpLcdRegister+1
movf tmpLcdRegister+0,W
andlw 0FH
iorwf tmpLcdRegister+1,F
btfsc tmpLcdRegister+0,4
bsf tmpLcdRegister+1,6
movf tmpLcdRegister+1,W
call LcdSendCommand
return
;**********************************************************************
; Send a data to LCD
;**********************************************************************
LcdSendData
bsf PORTB,LCD_RS
call LcdSendByte
return
;**********************************************************************
; Send a command to LCD
67
;**********************************************************************
LcdSendCommand
bcf PORTB,LCD_RS
call LcdSendByte
return
;**********************************************************************
; Send a byte to LCD by 4 bit data bus
;**********************************************************************
LcdSendByte
;Save value to send
movwf tmpLcdRegister
btfsc tmpLcdRegister,4
bsf PORTB,LCD_DB4
btfsc tmpLcdRegister,5
bsf PORTB,LCD_DB5
btfsc tmpLcdRegister,6
bsf PORTB,LCD_DB6
btfsc tmpLcdRegister,7
bsf PORTB,LCD_DB7
btfsc tmpLcdRegister,0
bsf PORTB,LCD_DB4
btfsc tmpLcdRegister,1
bsf PORTB,LCD_DB5
btfsc tmpLcdRegister,2
bsf PORTB,LCD_DB6
btfsc tmpLcdRegister,3
bsf PORTB,LCD_DB7
68
return
END
Estas constantes definen la asociación entre las líneas del PIC (todas conectadas al PortB) y las líneas
del LCD. Cada definición en particular, será usada en las subrutinas de gestión del LCD en lugar de
cada número de identificación de las líneas de I/O.
tmpLcdRegister res 2
msDelayCounter res 2
Seguidamente, se reserva el espacio para dos registros: tmpLcdRegister, usado por la subrutina de
gestión del LCD y msDelayCounter usada por la subrutina msDelay que generan los retardos por
sofware de 1 ms para el contenido del registro W. Estas subrutinas son usadas siempre por las
subrutinas de gestión para generar las temporizaciones requeridas durante la transmisión de datos y
comandos.
Sigue la definición de las líneas de conexión entre el PIC y el LCD y luego se arriba a la primera
subrutina que interesa:
call LcdInit
LcdInit es una subrutina que debe ser llamada solamente una vez en el inicio del programa y antes de
cualquier otra subrutina de gestión. Ella se ocupa de efectuar todas las operaciones necesarias para
inicializar correctamente el LCD y permite que las funciones sucesivas operen correctamente.
movlw 00H
call LcdLocate
se posiciona el cursor del display en la primera fila y en la primera columna de la pantalla. Los
caracteres enviados sucesivamente, serán visualizados a partir de esta posición. Los cuatro bits más
significativos del valor cargado en el registro W con la instrucción:
movlw 00H
69
Contienen el número de fila donde se quiere posicionar el cursor, los cuatro bits menos significativos,
contienen el número de columna.
Cambiando el valor en el registro W, se obtiene posicionamientos diferentes. Con el valor 10H, por
ejemplo, se obtiene:
HELLO WORD!_
A esta altura, para visualizar cada carácter de la frase, se usan las siguientes instrucciones:
movlw 'H'
call LcdSendData
Y así sucesivamente para cada letra a ser visualizada. El incremento de la posición del cursor, se hace
automáticamente.
Mayor información sobre el uso de los LCD’s, puede obtenerse de la hoja de datos que el fabricante
debe proveer.
70