Analicemos
ahora línea por línea el contenido de nuestro source LED.ASM. Para quien
dispone de una impresora es útil realizar una copia del source para seguir
mejor nuestra descripción. De lo contrario seria preferible visualizar el
source en una ventana separada de modo de poder seguir simultáneamente el
source y la relativa explicación.
Partimos
de la primera línea de código:
PROCESSOR 16F84
PROCESSOR es una directiva del compilador assembler que permite
definir para cual microprocesador se escribió nuestro source. Las directivas
no son instrucciones mnemónicas que el compilador traduce en el respectivo
pocode, pero si, simples indicaciones que se entrega al compilador para
determinar el funcionamiento durante la compilación. en este caso informamos
al compilador que las instrucciones entregadas a nuestro source son las
relativas a un PIC16F84.
RADIX DEC
La
directiva RADIX sirve para informar al compilador que los
números reportados sin notación, deben
entenderse como números decimales. Es decir, si queremos especificar, por
ejemplo el numero hexadecimal 10 (16 decimal) no podemos escribir solamente
10 porque seria interpretado como 10 decimal, pero sí 10h o también, 0x10
o también, H´10´.
INCLUDE "P16F84.INC"
Esta
es otra directiva. Esta vez indicamos al compilador nuestra intención de
incluir en el source un segundo archivo (file) denoninado P16F84.IN. El
compilador se limitara a sustituir la línea que contiene la directiva INCLUDE
con el contenido del archivo indicado y a efectuar por lo tanto la compilación
como si fuera también parte de nuestro source.
LED EQU 0
Todavía
directivas ! Pero cuando llegan las instrucciones ? Tengamos un poco de
paciencia.
La
directiva EQU es muy importante porque nos permite de definir
las constantes simbólicas al interno de nuestro source. En particular la
palabra LED de ahora en adelante en el source será equivalente
al valor 0. La finalidad principal de la existencia de la directiva EQU
es la poder hacer los source más legibles y de permitir cambiar los valores
constantes en un único punto del source.
Es
importante notar que la palabra LED no identifica una variable, es simplemente
un nombre simbólico valido durante la compilación. No será por lo tanto,
posible introducir instrucciones tipo LED = 3 al interno del source ya que
la asignación dinámica de un valor a una variable es una operación que requiere
la intervención de la CPU del PIC y por lo tanto debe ser expresada con
instrucciones y no con directivas.
Las
directivas tienen sentido solo durante la compilacion del source por lo
tanto, un PIC no podra nunca seguir una directiva.
Veamos
ahora la línea siguiente:
ORG 0CH
También
ORG es una directiva que nos permite definir la dirección
para la cual queremos que el compilador empiece a localizar los datos o
las instrucciones siguientes. En este caso, definiremos un arrea de datos
al interno del PIC es decir, un área en la cual memorizar variables y contadores
durante la ejecución de nuestro programa. Esta área coincide con el área
RAM del PIC definida por Microchip como
el área de los FILE REGISTER.
Los
file register son localizaciones RAM disponibles por el usuario a partir
de la dirección 0CH. Esta dirección de inicio es fija y no puede ser cambiada
respecto a las localizaciones precedentes que son ocupadas por otros registros
especializados para uso interno.
Count RES 2
En
esta línea encontramos una label (etiqueta): Count y una
directiva: RES.
La
directiva RES indica al compilador que queremos reservar un cierto numero
de byte o mejor de file register al interno del área de datos; in es caso
2 byte. La label Count, donde Count es un nombre escogido por nosotros,
es una marca que en el resto del source asumirá el valor de la dirección
en la cual fue colocado. Dado que en precedencia habíamos definido la dirección
de partida como 0CH con la directiva ORG, Count valdrá 0CH. Si por ejemplo
inserimos una label también en la línea sucesiva esta valdrá 0CH + 2 ( dos
son los byte que hemos reservado) es decir, 0EH. Los nombres de las label
(etiquetas) pueden ser cualquiera a excepción de las palabras reservadas
al compilador (tales como las instrucciones mnemónicas y las directivas).
Una
label se distingue de una constante simbólica porque su valor viene colocado
en fase de compilación y no asignado por nosotros estáticamente.
ORG 00H
Esta
segunda directiva ORG hace referencia a una dirección en el área de programa
(en la EEPROM) y no en el área de datos. A partir de este punto, empezaremos
a inserir las instrucciones mnemónicas que el compilador deberá convertir
en las oportunas opcode para el PIC.
El
primer opcode seguido por el PIC después del reset es el memorizado en la
localización 0, correspondiente al valor 00H inserido en la ORG.
bsf STATUS,RP0
Esta
es primera instrucción mnemónica completa con parámetros. Los PIC tienen
una CPU interna del tipo RISC para la cual cada instrucción
ocupa una sola localización de memoria, opcode y parámetros incluidos. En
este caso la instrucción mnemónica BSF significa BIT
SET FILE REGISTER es decir, pone un uno
(condición lógica alta) uno de los bit contenidos en la localización de
RAM especificada.
El
parámetro STATUS viene definido en el file P16F84.INC atraves de una directiva
EQU. El valor asignado a este file es 03H y corresponde a un file register
(es decir, una localización RAM en el área de datos) reservado.
También
el parámetro RPO viene definido en el file P17F84.INC con el valor 05H y
corresponde al numero del bit que se quiere poner en uno. Cada file register
tiene una longitud de 8 bit y la numeración de cada uno parte de 0 (bit
menos significativo) hasta llegar a 7 (bit más significativo).
Esta
instrucción en practica coloca un 1 en el quinto bit del file register STATUS.
Esta operación es necesaria, como veremos en las próximas lecciones, Para
acceder a los file register TRISA y TRISB como veremos ahora.
movlw 00011111B
Esta
instrucción significa: MOVE LITERAL TO
W REGISTER es decir, mueva un valor constante en el acumulador.
Como veremos mas adelante, el acumulador es un registro particular utilizado
por la CPU en todas estas situaciones en la cual se hacen operaciones entre
dos valores como operaciones de desplazamiento entre localizaciones de memoria.
En practica es un registro de apoyo utizado por la CPU para memorizar temporalmente
un byte cada vez que se presente la necesidad.
El valor constante de memorizar en el acumulador es 00011111B
es decir, un valor binario de 8
bit donde el bit mas a la derecha representa el bit 0 o el bit menos significativo.
En la instrucción siguiente:
movwf TRISA
el
valor 00011111 viene memorizado en el registro TRISA (como para el Registro
STATUS también TRISA es definido atraves una directiva EQU ) cuya función
es la de definir el funcionamiento de cada línea de I/O de la puerta A.
En particular cada bit con uno del registro TRISA determina un un ingreso
en la respectiva línea de la puerta A mientras cada 0 determina una salida.
En
la siguiente tabla viene reportada la configuración que asumirán los pines
del PIC después de la ejecución de esta instrucción:
|
N.bit registro TRISB |
Línea puerto A |
N.Pin |
Valor |
Estato |
|
0 |
RA0 |
17 |
1 |
Input |
|
1 |
RA1 |
18 |
1 |
Input |
|
2 |
RA2 |
1 |
1 |
Input |
|
3 |
RA3 |
2 |
1 |
Input |
|
4 |
RA4 |
3 |
1 |
Input |
|
5 |
- |
- |
0 |
- |
|
6 |
- |
- |
0 |
- |
|
7 |
- |
- |
0 |
- |
Como
es posible ver los bit 5,6 y 7 no corresponden a ninguna línea de i/o
por lo tanto su valor no tiene ninguna importancia.
Las
dos instrucciones siguientes realizan las mismas funciones para el puer
to B del PIC:
movlw B'11111110'
movwf TRISB
en
este caso la definición de las líneas será la siguiente:
|
N.bit registro TRISB |
Línea puerto B |
N.Pin |
Valor |
Estato |
|
0 |
RB0 |
6 |
0 |
Output |
|
1 |
RB1 |
7 |
1 |
Input |
|
2 |
RB2 |
8 |
1 |
Input |
|
3 |
RB3 |
9 |
1 |
Input |
|
4 |
RB4 |
10 |
1 |
Input |
|
5 |
RB5 |
11 |
1 |
Input |
|
6 |
RB6 |
12 |
1 |
Input |
|
7 |
RB7 |
13 |
1 |
Input |
Nótese
como el valor 0 en el bit 0 del registro TRISB determina la configuración
en la salida de la respectiva línea del PIC. En nuestra aplicación esta
línea viene utilizada para activar el LED que va prender y apagar.
Hemos
visto que la instrucción movwf TRISB transfiere el valor
contenido en el acumulador (inicializado oportunamente con la instrucción
movlw 11111110B) al registro TRISB. El significado de movwf
es por lo tanto MOVE W TO FILE
REGISTER.
bcf STATUS,RP0
Esta
instrucción es parecida a bsf vista anteriormente, con
la diferencia
que acera el bit en vez de hacerlo uno. La sigla en este caso es BIT
CLEAR
FILE REGISTER.
Del
punto de vista funcional instrucción se escogió para consentir el acceso
A los registros internos del banco 0 en vez de los registros internos del
banco 1 de los cuales hacen parte TRISA Y TRISB. Una descripción mas
detallada se dará mas adelante.
bsf PORTB,LED
Con
esta instrucción se efectúa la primera operación que tiene un reencuentro
con el externo del PIC. En particular viene acezado el LED conectado a la
línea RB0. PORTB es una constante definida en P16F84.INC
y permite de referenciar el file register correspondiente a las líneas I/O
del puerto B mientras LED es el numero de la línea que
debe poner en 1. Si recordamos bien, al inicio del sourse la constante LED
esta definida igual 0, por lo tanto, la línea interesada será RB0.
MainLoop
Esta
línea contiene una label o mejor una referencia simbólica
hacia una dirección de memoria. El valor de la label, como dicho anterior
mente, se calcula en fase de compilación en base al numero de instrucciones,
a las directivas ORG y a las otras instrucciones que de alguna manera ocupan
espacio en la memoria del PIC.En este caso, se cuentan las instrucciones
a partir de la ultima directiva ORG podemos calcular el valor que será asignado
MainLoop o sea, 07H.
En
realidad el valor que asumen las label no tienen mucha importancia puesto
que su finalidad es de evitar de conocer la posición precisa de los opcode
en la memoria del PIC permitiendo de todas maneras de diferenciar una determinada
posición de memoria.
En
este caso la label MainLoop viene utilizada como punto de inicio de un ciclo
(de ingles loop) de encendido y de apagado del LED, es decir, una parte
de código que vendrá repetida cíclicamente al infinito.Encontraremos mas
adelante una referencia a esta label.
call Delay
Esta
instrucción determina una llamada (del ingles call ) y una subrutina que
empieza en correspondencia con la label Delay.
Las
subrutinas son de las partes del programa especializadas para efectuar una
funcion especifica. Cada vez que sea necesaria esta función es suficiente
llamarla con una sola instrucción, en vez de repetir cada vez todas las
instrucciones necesarias para efectuarla.En este caso la subrutina introduce
un retardo igual al tiempo de encendido y apagado del LED.
Las
instrucciones que componen la subrutina Delay son introducidas
mas adelante en este curso.
btfsc PORTB,LED
El
significado de esta instrucción es BIT TEST
FLAG, SKIP IF CLEAR es
decir, controla el estado de un bit interno de un registro y salta a la
instrucción sucesiva si el valor de tal bit es cero. El bit a controlar
corresponde a la línea de output (salida) a que esta conectado el LED, por
medio de este test podremos determinar por lo tanto si el LED esta iluminado
o apagado e intervenir es decir, si el LED esta iluminado lo apagaremos,
si esta apagado lo prenderemos.
goto SetToZero
Esta
instrucción es un salto incondicional ( del ingles GO TO,
ir )a la etiqueta SetToZero donde encontraremos las instrucciones para apagar
el LED. Esta instrucción vendrá saltada de la instrucción sucesiva si el
LED esta ya apagado.
bsf PORTB,LED
goto MainLoop
Estas
dos instrucciones apagan el LED y reenvían el programa al inicio del ciclo
de prendido y apagado.
SetToZero
bcf PORTB,LED
goto MainLoop
Estas
dos instrucciones simplemente apagan el LED y reenvían
el progama al inicio del ciclo de prendido y apagado.
La
subrutina Delay
Como
descrito anteriormente esta subrutina introduce un retardo de alrede-
dor de un segundo y puede ser llamada tadas las veces en la sourse a tra-
ves de la instrucción call Delay.
Veamos
como funciona:
Delay
clrf Count
clrf Count+1
DelayLoop
decfsz Count,1
goto DelayLoop
decfsz Count+1,1
goto DelayLoop
retlw 0
END
Delay y DelayLoop son dos etiquetas. Delay
identifica la dirección de inicio de la subrutina y viene utilizado para
las llamadas del cuerpo principal del programa. DelayLoop
viene llamado internamente de la subrutina y sirve como punto de ingreso
para el ciclo ( del ingles loop ) de retardo.
¡En
practica el retardo viene obtenido siguiendo miles de instrucciones que
no hacen nada !
Este
tipo de retardo se llama retardo software o retardo a programa. Es el tipo
de retardo más simple de implementar y puede ser utilizado cuando no se
necesita que el PIC haga otras tareas mientras adelanta el retardo.
Las
instrucciones:
clrf Count
clrf Count+1
CLEAR FILE REGISTER aceran las dos sitios
de RAM reservados anteriormente con la instrucción :
Count RES 2
Estos
dos lugares son adyacentes a partir de la dirección referenciada por la
label Count.
decfsz Count,1
La
instrucción significa DECREMENT FILE REGISTER,
SKIP IF ZERO es decir, decrementar el
contenido de un registro ( en este caso Count y saltar a la instrucción
siguiente si el valor alcanzado es cero ). Si el valor alcanzado no es cero
viene ejecutada la instrucción siguiente:
goto DelayLoop
Que
ordena la ejecucion desde el principio del ciclo de retardo.Una vez alcanzado
el cero con el contador Count vienen ejecutadas las intrucciones:
decfsz Count+1,1
goto DelayLoop
Que
decrecen el registro siguiente hasta que este también alcance el cero. El
registro Count + 1 en particular sara decrementado de uno cada 256 decrementos
de Count.
Cuando
también Count + 1 alcance el cero la instrucción:
return
Cuyo
significado es RETURN FROM SUBROUTINE que determinara la
salida de la rutina de retardo y la continuación de la ejecución de la instruccion
sucesiva la call Delay.
Para terminar END es una directiva que indica al compilador
el final del source assembler.
En el paso siguiente compilaremos el source LED_1.ASM y programaremos el
PIC con el código generado en la salida del compilador assembler.