Módulo 1 - Manejo de Puertos Digitales
Módulo 1 - Manejo de Puertos Digitales
Módulo 1 - Manejo de Puertos Digitales
El PIC16F877A contiene 5 puertos que pueden ser configurados como entrada o salida digitales (A, B, C,
D, E). El puerto A contiene 6 bits (RA0-5). El puerto B (RB0-7), el puerto C (RC0-7) y el puerto D (RD0-7)
tienen cada uno 8 líneas. El puerto E solo cuenta con 3 líneas (RE0-2)
- Ingresar al banco 1
- Configurar los puertos (registros TRISA, TRISB, TRISC, TRISD y TRISE)
- Regresar al banco 0
- Escribir o leer datos desde los puertos. (registros PORTA, PORTB, PORTC, PORTD y PORTE )
Hemos indicado que la memoria de datos del PIC16F877A se divide en cuatro bancos: 0, 1, 2 y 3. En las
posiciones inferiores de ambos bancos se encuentran los registros especiales de función (SFR). En la
posición 0x05, 0x06, 0x07, 0x08 y 0x09 respectivamente se encuentran los registros PORTA, PORTB,
PORTC, PORTD y PORTE que se usan para leer o escribir datos en tanto que en las posiciones 0x85, 0x86,
087, 0x88 y 0x89 se encuentran los registros TRISA, TRISB, TRISC, TRISD y TRISE respectivamente, es allí
donde se configuran los puertos como entradas o salidas. Cabe señalar que el PORTB también aparece
en el banco 2 en la posición de memoria 0x106 y el TRISB en la posición de memoria 0x186.
Cada una de las líneas de los puertos puede ser configurada como entrada o como salida. En los registros
TRIS determinamos la configuración de los puertos. Los registros son una especie de mascara. Por
ejemplo si escribimos un 0 en el bit 0 del TRISA la línea RA0 se comportará como una línea de salida. Si
colocamos a 1 el bit 0 del TRISA a la línea RA0 se comportará como entrada.
A través de los valores que escribamos en los registros TRIS determinamos el comportamiento de los
puertos.
La escritura y lectura de valores desde los puertos se hace a través de los registros PORT que se
encuentran en el Banco 0 (y banco 2 para el puerto B). Desde luego si configuramos un puerto como
entrada (lectura) los valores que escribamos en el no tendrán efecto porque fue configurado como
entrada y no como salida. A través de las instrucciones MOV podemos leer o escribir valores.
NOTA.- El puerto A es un puerto multifunción que se puede configurar como digital o como analógico
este modo de funcionamiento dependerá del registro ADCON1 (banco 1 posición 0x1F). Por el momento
no profundizaremos en el tema sino cuando lleguemos al módulo ADC. Solo nos bastará saber que el
debemos configurar los bits de la siguiente manera:
Los programas están compuestos por instrucciones. El PIC16F877A cuenta con 35 instrucciones que
iremos desarrollando conforme avancemos en el curso. Cada instrucción está representada por 14 bits.
Los 14 bits a su vez se dividen en:
- Operadores, cada instrucción es aplicada sobre determinados operadores, parte de los 14 bits
están destinados a especificar quienes son los registros o valores que se verán afectados como
resultado de la aplicación de la instrucción.
Las instrucciones orientadas a byte reservan los 7 bits de menor peso para indicar la dirección del
registro que será operado. Una vez que se lleva a efecto la operación usamos el bit d para indicar donde
será almacenado el resultado. Si d es 0 el resultado se almacena en el registro de trabajo W, si d es 1 el
resultado será guardado en el mismo registro (o file) que se opero.
Las operaciones orientas a bit buscan escribir o leer una posición (bit) dentro de un file o registro. Una
vez más los 7 bits inferiores son destinados para indicar la dirección de registro o file que vamos a
trabajar y los siguientes tres bit especifican el bit dentro del registro.
Las instrucciones de control son las que ayudan a formar bucles dentro de los programas así como
sirven para llamar a rutinas o procedimientos (instrucciones CALL o GOTO). En este caso en particular se
emplea los 11 bits inferiores para enviar la dirección a la cual el contador de programa (PC) saltará. Los
bits superiores de la instrucción sirven para identificar a la instrucción.
En ocasiones es necesario cargar constantes a los registros del microcontrolador, las instrucciones
literales nos sirven para mover las constantes a un registro en particular, en este caso empleamos los 8
bits inferiores para definir la constante que deseamos almacenar, en tanto que los bits restantes sirven
para identificar la instrucción.
El siguiente es un cuadro resumen de las instrucciones clasificadas en función a las categorías que
hemos descrito:
a) Desarrollar un programa que configure las líneas del puerto A como entrada y las líneas del
puerto B como salida. Y que muestre en forma permanente la entrada del puerto A en el puerto
B.
DIRECTIVAS
Antes de codificar el diagrama anterior es conveniente revisar algunos conceptos breves de las partes
que componen un programa en ensamblador para el PIC16F877 usando el MPLAB.
Además de las instrucciones que necesitamos es necesario revisar las directivas de compilación que son
comandos que permiten mejorar la programación.
Directiva ORG
Sirve para indicar la direccion de memoria en la cual será colocada el código generado a continuación . Si
el ORG no es indicado se empieza en la dirección 0. Ejemplo:
ORG 0x04
nop
Directiva EQU
Directiva END
END
Es de uso obligatorio y siempre se coloca al final del programa sirve para marcar el final del programa. El
MPLAB solo reconoce las líneas que esten escritas previas a la aparición de la directiva END.
Directiva LIST
Sirve para indicarle al MPLAB cuál es el formato del archivo *.list dentro de los parámetros está el tipo
de procesador que se va a emplear. Ejemplo:
list p=16F877
Directiva INCLUDE
include<file>
Sirve para incluir en el ensamblado el archivo indicado por el parametro “file”. Es como si el “file” fuera
parte del archivo, como si se hubiera situado en la posición en la cual la directiva aparece. El parámetro
“file”puede incluir el path o camino en el cual se encuentra el fichero a incluir. En caso se omita asumirá
losdirectorios del MPLAB y del archivo fuente. Ejemplo
include<p16f877.inc>
Incluye el archivo “p16F877.inc” que contiene las etiquetas genéricas del PIC16F877
Primeras INSTRUCCIONES
CLRF Clear f
Sintaxis: [ label] CLRF f
Operandos: 0 ≤ f ≤ 127
Operación: 00h → (f)
1→Z
Afecta Status : Z
Descripción: El contenido del registro ’f’ es puesto a 0-lógicos y el bit Z del STATUS es puesto a 1-lógico.
Los once primeros bits son cargados en el registro PC bits <10:0>. Los bits superiores de PC son cargados de
PCLATH<4:3>. GOTO es una instrucción que demora dos ciclos de instrucción.
MOVWF Move W to f
Sintaxis: [ label] MOVWF f
Operandos: 0 ≤ f ≤ 127
Operación: (W) → (f)
Afecta Status: No
Descripción: Mueve el dato del registro W al registro 'f'.
Con las directivas y las instrucciones mostradas procedemos a elaborar el código del primer programa.
config _CP_OFF & _PWRTE_ON & _WDT_OFF & _LVP_OFF & _HS_OSC
list p=16F877a
include "p16f877a.inc"
Observaciones:
Las instrucciones de escritura en puertos siempre son precedidas de una operación de lectura. Es decir
ponemos el valor del registro PORTA o PORTB en el registro de trabajo W. Allí modificamos su valor
(podemos variar uno o más bits) y luego llevamos el valor de W al registro del puerto. Esto se hace por
ejemplo en la ejecución de las instrucciones BCF y BSF. Por tanto debemos tener cuidado con aquellos
puertos cuyas líneas son configuradas como entrada y salida a la vez. Por ejemplo: una instrucción bsf
PORTB,5 hace que W =PORTB luego en bit 5 de W se pone a 1 y finalmente W es llevado a PORTB. Si
otro bit del PORTB es definido al inicio del programa como entrada y en el desarrollo del programa es
reconfiguardo como salida, la línea no necesariamente coincidirá con el valor que habia antes, por tanto
se pierde.
La introducción de las instrucciones de “no operación” (nop) no hacen más que crear un espacio de
tiempo para leer el dato después que el transitorio ha finalizado. Si la frecuencia de funcionamiento del
clock es muy alta conviene ubicar más instrucciones nop a fin de evitar la pérdida de data.
Hemos indicado que la memoria de datos del microcontrolador se divide en bancos de memoria, las
posiciones inferiores están destinadas a los registros especiales de función (SPECIAL FUNCTION
REGISTER). En esta sección profundizaremos un poco más acerca de los principales registros y
observaremos el uso que se les puede dar en el desarrollo del programa.
Bit 7: IRP Register Bank Select Bit (es un bit que se usa para las operaciones de direccionamiento
indirecto)
0 = Si se trabaja sobre el banco 0 ó 1 ( posiciones de memoria que van desde 00h hasta FFh)
1 = Si trabajamos con el banco 2 ó 3 (posiciones de memoria que van desde 100h hasta 1FFh)
Bit 6-5: RP1, RP0 Register Bank Select (bits usando en el direccionamiento directo)
00 = Banco 0, (posiciones de memoria 00-7Fh)
01 = Banco 1, (posiciones de memoria 80-FFh)
10 = Banco 2, (posiciones de memoria 100-17Fh)
11 = Banco 3, (posiciones de memoria 180-1FFh)
Los bancos pueden contener hasta 128 posiciones.
Bit 4: -T0 Time out bit
1 = Asume el valor de 1 después de encenderse el PIC o por la aplicación de la instrucción
CLRWDT o por la aplicación de la instrucción SLEEP
0 = Cuando se ha vencido el periodo programado en el Watchdog
Bit 3 : -PD Power down bit
1 = Después de encender el microcontrolador o por la aplicación de una instrucción CLRWDT
0 = Cuando se ejecuta la instrucción SLEEP
Bit 2: Z Zero Bit
1 = Cuando el resultado de una instrucción aritmética lógica da por resultado 0.
0 = Si el resultado de la operación aritmética o lógica da por resultado un valor distinto de cero
Bit 1: DC Digit carry/borrow bit usado como acarreo en las instrucciones de suma ( ej: ADDWF y
ADDWL) en caso se lleve a cabo una operación de resta se procede a tomarlo como bit de préstamo).
Este bit trabaja con los 4 bits inferiores o nible bajo.
1 = Si se ha producido el acarreo en el nible bajo.
0 = No se ha producido acarreo en el nible bajo.
Bit 0: C: Carry/borrow bit Similar al anterior con la diferencia que toma el acarreo de todo el registro es
decir trabaja en 8 bits.
1 = Si se ha producido el acarreo en el nible bajo.
0 = No se ha producido acarreo en el nible bajo.
Los tres bits que se encuentran en la parte inferior son bits que reportan el estado de la ALU tras la
ejecución de una instrucción. Estos bits son de lectura. Los bits pueden ser de escritura si y solo si la
instrucción no afecta el estado de los bits Z, DC y C. Las instrucciones que no afectan al STATUS son BCF,
BSF, SWAP y MOVWF. Si quisiéramos colocar todos los bits del STATUS a 0 lógico la aplicación de la
instrucción CLRF STATUS fallaría por que la instrucción afecta a los bis Z, DC y C. De hecho los bits C y
DC conservarían el valor previo a la aplicación de la instrucción CRLF STATUS en tanto que el bit Z se
colocaría a 1 por que el resultado de la última operación fue un 0.
Los bits que se encuentran en medio (-T0 y -PD) son usados para registrar si el microcontrolador esta
trabajando y cuál es el modo de operación. El microcontrolador puede estar encendido y a su vez tiene
dos modos de operación: activo y reposo (o bajo consumo). Los bits también reportan el estado del
WATCHDOG, cuando el periodo de tiempo del WATCHDOG se ha vencido el bit -T0 se coloca a 1. Es
necesario indicar que ambos bits son solo de lectura y se modifican en función al modo de operación de
microcontrolador (visto desde el punto de vista de la alimentación o consumo de energía). En
consecuencia la aplicación de la instrucción CLRF STATUS fallaría también porque no es posible modificar
el estado de los bits.
Los bits localizados en la parte superior del registro STATUS son relacionados al uso de los bancos la
combinación de los mismo determina cual es el banco actual con el que estamos trabajando. Las
instrucciones recomendables para manipular los bits son BSF y BCF. Los bits superiores son de lectura y
escritura.
Observaciones
Cuando se aplican las instrucciones de rotación de bits a la izquierda o derecha (RLF ó RRF) el bit de C es
el valor que se emplea para llenar el agujero producido por la instrucción, motivo por el cual es
necesario colocar el bit C a cero o uno lógico dependiendo si deseamos que la posición libre sea cubierta
por uno de los dos valores.
La instrucción SWAPF no modifica el estado de los bits Z, DC y C pero eso no implica que la aplicación de
la instrucción sobre el STATUS vaya a lograr el intercambio de los nibles. Al aplicar las instrucciones
seguramente los bits IRP, RP1, RP0, Z, DC y C se intercambiarán uno a uno pero los bits -T0 y -PD no
seran intercambiados ya que son de lectura.
Cuando una instrucción es ejecutada puede afectar el estado del STATUS, este hecho resulta
aparentemente irrelevante mas la ayuda que presta es valiosa en la elaboración de soluciones por
ejemplo:
Considere la instrucción:
La instrucción lleva el contenido desde el file REGISTRO hacia el W (registro de trabajo) y nuevamente lo
deja donde lo encontró (REGISTRO). Esta operación parece intrascendente pero es una forma bastante
práctica y simplificada de preguntar si el valor contenido en el file REGISTRO es 0. Porque recordemos
que el bit Z se pone a 1 si la última instrucción aplicada en la ALU dio como resultado 0. En este caso en
particular solo se movió entonces si se movió un 0 y se devolvió a su posición seguramente el bit Z será
colocado 1.
Ejercicio 1: Suponga una lámpara que debe ser prendida o apagada desde tres puntos. Diseñe un
programa que la encienda si y solo si hay dos interruptores activados.
Supongamos que tenemos los tres interruptores dispuestos en el PORTB (RB0, RB1 y RB2) y definimos la
línea RB3 como salida tendríamos la siguiente tabla de verdad:
a) Definiciones previas.
Como se puede apreciar en el algoritmo anterior es necesario contar con instrucciones que nos
permitan realizar bifurcaciones en el programa. Para ello revisaremos las instrucciones de control de
salto y bifurcación.
SUBWF Substrae W de f
Sintaxis: [ etiqueta ] SUBWF f,d
Operandos: 0 <= f <= 127 d= [0,1]
Operación: (f) – (W)-> (destino)
Bits afectados en el STATUS: C, DC, Z
Descripción: Substrae (usa en método de complemento a 2) el registro W del registro 'f'. Si 'd' es 0 el
resultado es almacenado en W. Si 'd' es 1el resultado es almacenado devuelta en el registro 'f'.
Pese a que el manejo es correcto este no resulta el más apropiado sobre todo si el programa es extenso.
Para hacerlo simple nos apoyamos en la directiva de compilación EQU que permite definir equivalencias:
c) Trabajo en el MPLAB
1. Ingrese al MPLAB:
Cree un proyecto en la carpeta de trabajo en el escritorio.
Asigne como nombre puertos_digitales.pjt.
Abra un nuevo archivo e ingrese el siguiente código:
Dato B Dato A
RB7 RB6 RB5 RB4 RB3 RB2 RB1 RB0
B3 B2 B1 B0 A3 A2 A1 A0
a) Definiciones previas.
Para solucionar el problema nos apoyaremos en el uso de la instrucción SUBWF. La definición de la
instrucción es la siguiente:
SUBWF Substrae W de f
Sintaxis: [ etiqueta ] SUBWF f,d
Operandos: 0 <= f <= 127 d= [0,1]
Operación: (f) – (W)-> (destino)
Bits afectados en el STATUS: C, DC, Z
Descripción: Substrae (usa en método de complemento a 2) el registro W del registro 'f'. Si 'd' es 0 el
resultado es almacenado en W. Si 'd' es 1el resultado es almacenado devuelta en el registro 'f'.
Vista de la aplicación:
c) Trabajo en el MPLAB
Ingrese al MPLAB:
Abrimos el proyecto en la carpeta de trabajo del escritorio.
El nombre del proyecto es puertos_digitales.pjt.
Abra un nuevo archivo e ingrese el siguiente código:
Ejercicio3:
Se tiene tres válvulas (A,B y C) que alimentan un tanque, el tanque a su vez tiene una salida. Existen 3
sensores de nivel (X,Y y Z). Cuando el tanque está vacío los 3 sensores estan a 0-lógico y es necesario
activar el trabajo de las tres bombas. Cuando se llena 1/3 del tanque el sensor X pasa a 1-lógico y la
bomba C deja de funcionar. Cuando se llenan 2/3 del tanque el sensor Y esta activado y la bomba B
deja de funcionar. Cuando está lleno el tanque el sensor Z se activa y la bomba A deja de funcionar.
Una vez que el tanque está lleno este empieza a expulsar el líquido acumulado. Cuando los 3 sensores
pasan a 0-lógico la secuencia antes descrita se repite ANTES NO.
Algoritmo
1. Configurar PORTB como entrada y PORTC como salida
2. Si PORTB != 0 entonces Ir paso2
3. Abrir las 3 válvulas (PORTC=0x07)
4. Si PORTB != 0x01 entonces Ir paso4
5. Abrir 2 válvulas (PORTC= 0x06)
6. Si PORTB != 0x03 entonces Ir paso6
7. Abrir 1 válvulas (PORTC= 0x04)
8. Si PORTB != 0x07 entonces Ir paso8
9. Cerrar todas las válvulas (PORTC= 0x00)
10.Ir paso 2
Diagrama de Flujo:
Ejercicio4:
Diseñar un programa que lea los 4 bits inferiores del puerto A y muestre el dato en un display de 7
segmentos que se encuentra conectado en el puerto C.
PORTC PORTA
Car RC6 RC5 RC4 RC3 RC2 RC1 RC0 RA3 RA2 RA1 RA0
G F E D C B A I3 I2 I1 I0
0 0 1 1 1 1 1 1 0 0 0 0
1 0 0 0 0 1 1 0 0 0 0 1
2 1 0 1 1 0 1 1 0 0 1 0
3 1 0 0 1 1 1 1 0 0 1 1
4 1 1 0 0 1 1 0 0 1 0 0
5 1 1 0 1 1 0 1 0 1 0 1
6 1 1 1 1 1 0 1 0 1 1 0
7 0 0 0 0 1 1 1 0 1 1 1
8 1 1 1 1 1 1 1 1 0 0 0
9 1 1 0 1 1 1 1 1 0 0 1
A 1 1 1 0 1 1 1 1 0 1 0
B 1 1 1 1 1 0 0 1 0 1 1
C 0 1 1 1 0 0 1 1 1 0 0
D 1 0 1 1 1 1 0 1 1 0 1
E 1 1 1 1 0 0 1 1 1 1 0
F 1 1 1 0 0 0 1 1 1 1 1
Algoritmo
1. Ir banco 0
2. Configurar RA0-3 como entrada digital
3. Configurar RC0-7 como salida digital
4. Ir banco 1
5. W=0x0F
6. W=PORTA AND W
7. W=Tabla[W]
8. PORTC=W
9. Ir paso 5
Tabla
Definimos una tabla como un arreglo de valores que tiene características similares, por ejemplo sea el
arreglo de letras:
Observamos que el arreglo “Tabla” tiene 4 elementos 'A', 'L', 'O' y 'S'. Cada uno de ellos posee
una posición, por ejemplo la 'A' está en la posición 0. El indicador que señala la posición que
ocupa el elemento dentro del arreglo se llama índice. Si conocemos el nombre de la tabla y el
indice podemos conocer el valor del elemento.
Ej: Tabla[2]= 'O'
a) Definiciones previas.
c) Trabajo en el MPLAB