Está en la página 1de 51

Programación PIC

en Asamblea
(http://www.mstracey.btinternet.co.uk/index.htm)

Tutorial 1
Buenas técnicas de programación.
Antes de llegar al meollo de la programación del PIC, creo que ahora es un
buen momento para explicar algunas buenas técnicas de programación.
Si escribe a; (punto y coma) en cualquier parte de su programa, el compilador
ignore cualquier cosa después de esto hasta que el carro regrese. Esto significa que podemos agregar
comentarios en nuestro programa para recordarnos qué demonios estábamos haciendo en
El primer lugar. Esta es una buena práctica, incluso para los programas más simples.
Es posible que comprenda completamente cómo funciona su programa ahora, pero en unos
meses, es posible que se esté rascando la cabeza. Entonces, usa comentarios
siempre que pueda, no hay límite.
En segundo lugar, puede asignar nombres a constantes a través de registros (más sobre
estos más tarde). Hace que sea mucho más fácil leer en inglés lo que estás escribiendo.
a, o cuál es el valor, en lugar de tratar de pensar en lo que todos estos
los números significan. Entonces, use nombres reales, como COUNT. Note que tengo
poner el nombre en mayúsculas. Esto lo hace destacar y también significa que
(por convención) es un valor constante.
En tercer lugar, coloque algún tipo de encabezado en sus programas utilizando el semi-
dos puntos. A continuación se muestra un ejemplo:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Autor:
;
; Fecha :
;
; Versión:
;
; Título:
;
;
;
; Descripción:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Observe que hice una especie de caja usando punto y coma. Esto solo
hace que se vea ordenado.

Por último, intente también documentar el programa en papel. Tu también puedes


utilice diagramas de flujo o algoritmos o cualquier otra cosa que desee. Esto ayudará
usted al escribir su programa, paso a paso.
Bien, esa es la conferencia, pasemos a lo real.

Tutorial 2
Los registros.
Un registro es un lugar dentro del PIC en el que se puede escribir, leer o
ambos. Piense en un registro como una hoja de papel donde puede mirar y
escribir información sobre.
La siguiente figura muestra el mapa del archivo de registro dentro del PIC16F84. No
preocuparse si no se ha encontrado con nada como esto antes, es sólo para
mostrar dónde están las diferentes partes y piezas dentro del PIC, y ayudará
explica algunos de los comandos.

Lo primero que notará es que está dividido en dos: Banco 0 y Banco 1.


El banco 1 se utiliza para controlar el funcionamiento real del PIC, por ejemplo para
decirle al PIC qué bits del puerto A son de entrada y cuáles de salida. El banco 0 es
utilizado para manipular los datos. Un ejemplo es el siguiente: digamos que
quiere hacer un bit en el puerto A alto. Primero tenemos que ir al Banco 1 para configurar
el bit o pin particular en el puerto A como salida. Luego volvemos a
Banco 0 y envíe un 1 lógico (bit 1) a ese pin.

Los registros más comunes en el Banco 1 que vamos a utilizar son STATUS,
TRISA y TRISB. La primera nos permite volver al Banco 0, TRISA
nos permite seleccionar qué pines en el puerto A salen y cuáles son de entrada,
TRISB nos permite seleccionar qué pines en el puerto B salen y cuáles son
entrada. El registro SELECT en el Banco 0 nos permite cambiar al Banco 1.
Echemos un vistazo más de cerca a estos tres registros.
ESTADO
Para cambiar del Banco 0 al Banco 1 le decimos al registro STAUS. Nosotros hacemos esto
estableciendo el bit 5 del registro STATUS en 1. Para volver al banco 0,
establecemos el bit 5 del registro STATUS en 0. El registro STATUS se encuentra
en la dirección 03h (la 'h' significa que el número está en hexadecimal).
TRISA y TRISB.
Estos se encuentran en las direcciones 85h y 86h respectivamente. Para programar un
pin para ser una salida o una entrada, simplemente enviamos un 0 o un 1 al
bit en el registro. Ahora, esto se puede hacer en binario o hexadecimal. yo
use personalmente ambos, ya que el binario ayuda a visualizar el puerto. Si usted es
no familiarizado con la conversión de binario a hexadecimal y viceversa, entonces
usa una calculadora científica.
Entonces, en el puerto A tenemos 5 pines y, por lo tanto, 5 bits. Si quisiera configurar uno de
los pines a la entrada, envío un '1' al bit correspondiente. Si quisiera configurar uno de
los pines a una salida, configuro el bit relevante en '0'. Los bits se arreglan en
exactamente de la misma manera que los pines, en otras palabras, el bit 0 es RA0, el bit 1 es
RA1, el bit 2 es RA2 y así sucesivamente. Pongamos un ejemplo. Si quisiera establecer
RA0, RA3 y RA4 como salidas, y RA1 y RA2 como entradas, envío esto:
00110 (06h). Tenga en cuenta que el bit cero está a la derecha, como se muestra:
Puerto A Pin RA4 RA3 RA2 RA1 RA0
Bit número 4
3
2
1
0
Binario
0
0
1
1
0
Lo mismo ocurre con TRISB.

PORTA y PORTB
Para enviar uno de nuestros pines de salida alto, simplemente enviamos un '1' al
bit correspondiente en nuestro registro PORTA o PORTB. El mismo formato
sigue lo mismo que para los registros TRISA y TRISB. Para leer si un pin es alto o
bajo en nuestros pines de puerto, podemos realizar una comprobación para ver si el particular
el bit correspondiente se establece en alto (1) o en bajo (0)
Antes de dar un código de ejemplo, necesito explicar solo dos registros más:
wy f.
W
El registro W es un registro general en el que puede poner cualquier valor que
tú deseas. Una vez que haya asignado un valor a W, puede agregarlo a
otro valor, o moverlo. Si asigna otro valor a W, su contenido
se sobrescriben.
Un código de ejemplo.
Les voy a dar un código de ejemplo sobre lo que acabamos de aprender.
No intente compilar esto todavía, lo haremos cuando lleguemos a nuestro primer
programa. Solo estoy tratando de mostrar cómo está realmente programado lo anterior.
e introduzca un par de instrucciones a lo largo del camino. Voy a configurar
Puerto A como en el ejemplo anterior.
Primero, tenemos que cambiar del banco 0 al banco 1. Hacemos esto configurando el
Registro STATUS, que se encuentra en la dirección 03h, bit 5 a 1.
BSF 03h, 5
El BSF significa el conjunto de bits F. La letra F significa que vamos a usar un
ubicación de la memoria o registro. Estamos usando dos números después de esto.
instrucción - 03h, que es la dirección del registro STATUS, y el número
5 que corresponde al número de bit. Entonces, lo que estamos diciendo es "Establecer bit
5 en dirección 03h a 1 ”.

Ahora estamos en el Banco 1.


MOVLW b'00110 '
Estamos poniendo el valor binario 00110 (la letra b significa que el número es
en binario) en nuestro registro de propósito general W.Podría, por supuesto, tener
hecho esto en hexadecimal, en cuyo caso nuestra instrucción sería:
MOVLW 06h
Cualquiera funciona. El MOVLW significa 'Mover valor literal en W', que en
Inglés significa poner el valor que sigue directamente en el registro W.
Ahora necesitamos poner este valor en nuestro registro TRISA para configurar el puerto:
MOVWF 85h
Esta instrucción significa "Mover el contenido de W al registro
Dirección que sigue ”, en este caso la dirección apunta a TRISA.
Nuestro registro TRISA ahora tiene el valor 00110, o se muestra gráficamente:
Puerto A Pin RA4 RA3 RA2 RA1 RA0
Binario
0
0
1
1
0
Entrada / salida OOI
yo
O
Ahora que hemos configurado nuestros pines del Puerto A, tenemos que volver al Banco 0 para
manipular cualquier dato.
BCF 03h, 5
Esta instrucción hace lo contrario de BSF. Significa "Bit Clear F". los
dos números que siguen son la dirección del registro, en este caso el
STATUS y el número de bit, en este caso el bit 5. Entonces, lo que tenemos
hecho ahora se establece el bit 5 en nuestro registro STAUS en 0
Ahora estamos de vuelta en el Banco 0.
Aquí está el código en un solo bloque:

BSF
03h, 5
; Ir al banco 1
MOVLW
06h
; Ponga 00110
en W
MOVWF
85h
; Mover 00110
en TRISA
BCF
03h, 5
;Vuelve a
Banco 0
Lea esto un par de veces, hasta que pueda seguirlo. Hasta ahora nosotros
he mirado 4 instrucciones. ¡Solo quedan 31!

Tutorial 3
Escribiendo a los puertos.
En el último tutorial, le mostré cómo configurar los pines del puerto IO en el
PIC para ser entrada o salida. En este tutorial, te voy a mostrar
cómo enviar datos a los puertos. En el siguiente tutorial, terminaremos por
parpadeando un LED encendido y apagado que incluirá una lista completa de programas y un
diagrama de circuito simple para que pueda ver el PIC haciendo exactamente lo que nosotros
esperar que lo haga. No intente compilar y programar su PIC con los listados
aquí, ya que son solo ejemplos.
Primero, configuremos el puerto A bit 2 como salida:
bsf
03h, 5
; Ir al banco 1
movlw
00h
; Ponga 00000 en W
movwf
85h
; Mueva 00000 a TRISA - todos los pines
configurado para salida
bcf
03h, 5
; Vuelve al Banco 0

Esto debería resultarle familiar desde el último tutorial. La única diferencia es que yo
han configurado todos los pines en el puerto A como salida, enviando 0h al tri-estado
Registrarse.
Ahora lo que tiene que hacer es encender un LED. Hacemos esto haciendo uno de
los pines (el que tiene el LED conectado) en alto. En otras palabras, nosotros
envíe un '1' al pin. Así es como se hace (observe los comentarios para un
explicación de cada línea):
movlw
02h; escriba 02h en el registro W. En binario es 00010, que
; pone un '1' en el bit 2 (pin 18) mientras mantiene los otros pines en '0'
movwf
05h; Ahora mueva el contenido de W (02h) al PortA, cuyo
; la dirección es 05h
Entonces, ahora que nuestro LED está encendido, ahora debemos apagarlo:
movlw
00h; escriba 00h en el registro W. Esto pone un '0' en todos los pines.
movwf
05h; Ahora mueva el contenido de W (0h) al Puerto A, cuyo
; la dirección es 05h
Entonces, lo que hemos hecho es encender y apagar el LED una vez.
Lo que queremos es que el LED se encienda y luego se apague continuamente.
Nosotros hacemos esto
haciendo que el programa vuelva al principio. Hacemos esto primero
definir una etiqueta al comienzo de nuestro programa, y luego decirle al programa que
sigue volviendo allí.
Definimos una etiqueta de manera muy simple. Escribimos un nombre, decimos EMPEZAR, luego
escribimos
el código:
comienzo
movlw
02h; escriba 02h en el registro W. En binario esto es
; 00010, que pone un '1' en el pin 2 mientras se mantiene
; los otros pines a '0'
movwf
05h; Ahora mueva el contenido de W (02h) al
; PortA, cuya dirección es 05h
movlw
00h; escriba 00h en el registro W. Esto pone un '0' en
; todos los pines.
movwf
05h; ahora mueva el contenido de W (0h) al puerto
; A, cuya dirección es 05h
ir
Inicio; Ir a donde decimos Inicio
Como puede ver, primero dijimos la palabra 'Inicio' justo al comienzo del
programa. Luego, justo al final del programa, simplemente dijimos 'goto
Comienzo'. La instrucción 'goto' hace exactamente lo que dice.
Este programa encenderá y apagará continuamente el LED tan pronto como
Enciende el circuito, y se detendrá cuando quitemos la energía.
Creo que deberíamos mirar nuestro programa nuevamente:
bsf
03h, 5
movlw
00h
movwf
85h
bcf
03h, 5
comienzo
movlw
02h
movwf
05h
movlw
00h
movwf
05h
ir
comienzo
OK, sé que he dejado los comentarios. Pero, ¿te das cuenta de que todos
puede ver son instrucciones y números? Esto puede resultar un poco confuso si
está intentando depurar el programa más tarde, y también cuando escribe el
código tienes que recordar todas las direcciones. Incluso con el
comentarios en su lugar, puede ser un poco complicado. Lo que necesitamos es dar estos
nombres de números. Esto se logra con otra instrucción: 'equ'.

La instrucción 'equ' simplemente significa que algo es igual a otra cosa. Eso
no es una instrucción para el PIC, sino para el ensamblador. Con este
instrucción podemos asignar un nombre a una ubicación de dirección de registro, o en
los términos de programación asignan una constante. Establezcamos algunas constantes para
nuestro programa, entonces verá cuánto más fácil de leer es el programa.
ESTADO
equ 03h
; esto asigna la palabra ESTADO al valor de 03h,
; que es la dirección del registro STATUS.
TRISA
equ 85h
; Esto asigna la palabra TRISA al valor de 85h,
; que es la dirección del registro tri-estatal para PortA
PORTA
equ 05h
; Esto asigna la palabra PORTA a las 05h que es la
; dirección del puerto A.
Entonces, ahora que hemos establecido nuestros valores constantes, pongámoslos en nuestro
programa. Los valores constantes deben definirse antes de que podamos usarlos,
así que para estar seguro, colóquelos siempre al comienzo del programa. Voy a reescribir
el programa sin comentarios de nuevo, para que pueda comparar el
listado anterior al nuevo:
ESTADO
equ 03h
TRISA
equ 85h
PORTA
equ 05h
bsf
ESTADO, 5
movlw
00h
movwf
TRISA
bcf
ESTADO, 5
comienzo
movlw
02h
movwf
PORTA
movlw
00h
movwf
PORTA
ir
comienzo
Con suerte, puede ver que las constantes facilitan un poco el seguimiento del programa,
aunque todavía no hemos incluido los comentarios. Sin embargo, no hemos terminado del todo.

Tutorial 4
Bucles de retardo.
Hay un pequeño inconveniente en nuestro programa de LED parpadeantes. Cada
la instrucción tarda un ciclo de reloj en completarse. Si usamos un 4MHz
crystal, entonces cada instrucción tomará 1 / 4MHz o 1uS para completarse. Como
Estamos usando solo 5 instrucciones, el LED se encenderá y luego se apagará en 5uS. Esta
es demasiado rápido para que lo veamos, y parecerá que el LED está permanentemente
en. Lo que tenemos que hacer es provocar un retraso entre el encendido del LED
y apagando el LED.
El principio del retraso es que contamos hacia atrás desde un conjunto previamente
número, y cuando llega a cero, dejamos de contar. El valor cero
indica el final de la demora, y continuamos nuestro camino por el
programa.
Entonces, lo primero que debemos hacer es definir una constante para usar como nuestro
mostrador. A esta constante la llamaremos COUNT. A continuación, debemos decidir cómo
un número grande para empezar a contar. Bueno, el mayor número que podamos
tener es 255, o FFh en hexadecimal. Ahora, como mencioné en el último tutorial, el
La instrucción equ asigna una palabra a una ubicación de registro. Esto significa que
cualquier número que asignemos a nuestro COUNT, será igual al contenido de un
Registrarse.
Si intentamos asignar el valor FFh, obtendremos un error cuando lleguemos a
compila el programa. Esto se debe a que la ubicación FFh está reservada, por lo que
no podemos acceder a él. Entonces, ¿cómo asignamos un número real? Así que
requiere un poco de pensamiento lateral. Si asignamos nuestro COUNT al
dirección 08h, por ejemplo, esto apuntará a un registro de propósito general
ubicación. De forma predeterminada, las ubicaciones no utilizadas se establecen en FFh. Por tanto, si
COUNT puntos a las 08h, tendrá el valor de FFh cuando cambiemos por primera vez
en.
Pero, te escucho llorar, ¿cómo configuramos COUNT en un número diferente? Bien,
todo lo que hacemos es 'mover' un valor a esta ubicación primero. Por ejemplo, si quisiéramos
COUNT para tener un valor de 85h, no podemos decir COUNT equ 85h porque
esa es la ubicación de nuestro registro tri-estatal para el puerto A. Lo que hacemos es esto:
movlw 85h
; Primero ponga el valor de 85h en el registro W
movwf 08h
; Ahora muévalo a nuestro registro de las 08h.

Ahora, cuando decimos COUNT equ 08h, COUNT será igual al valor 85h.
Sutil, ¿no es así?
Entonces, primero definimos nuestra constante:
CONTAR
equ 08h
A continuación, debemos disminuir este CONTAR en 1 hasta que llegue a cero. Es solo
sucede que hay una única instrucción que hará esto por nosotros, con
la ayuda de un 'goto' y una etiqueta. La instrucción que usaremos es:
RECUENTO DE DECFSZ, 1
Esta instrucción dice 'Disminuir el registro (en este caso COUNT) por el
número que sigue a la coma. Si llegamos a cero, salta dos lugares
adelante.' Muchas palabras, para una sola instrucción. Veámoslo en acción
primero, antes de ponerlo en nuestro programa.
CONTAR
equ 08h
ETIQUETA
decfsz COUNT, 1
ir a LABEL
Continúe aquí.
:
:
:
Lo que hemos hecho es configurar primero nuestra constante COUNT en 255. El siguiente
line pone una etiqueta, llamada LABEL junto a nuestra instrucción decfsz. El decfsz
COUNT, 1 disminuye el valor de COUNT en 1 y almacena el resultado
de nuevo a COUNT. También comprueba si COUNT tiene un valor de cero. Si
no lo hace, entonces hace que el programa se mueva a la siguiente línea. Aquí nosotros
tiene una declaración 'goto' que nos devuelve a nuestra instrucción decfsz. Si
el valor de COUNT es igual a cero, entonces la instrucción decfsz causa
nuestro programa para saltar dos lugares hacia adelante, y va a donde he dicho
'Continúa aquí'. Entonces, como puede ver, hemos provocado que el programa se quede
en un lugar durante un tiempo predeterminado antes de continuar. Esto se llama
bucle de retardo. Si necesitamos un retraso mayor, podemos seguir un bucle por otro.

Cuantos más bucles, mayor será el retraso. Vamos a necesitar al menos dos
si queremos ver el LED parpadear ...
Pongamos estos bucles de retardo en nuestro programa y terminemos haciéndolo
un programa real agregando comentarios:
; ***** Configurar las constantes ****
ESTADO equ 03h
; Dirección del registro STATUS
TRISA
equ 85h
; Dirección del registro triestado para el puerto A
PORTA
equ 05h
; Dirección del puerto A
COUNT1 equ 08 h
; Primer contador para nuestros bucles de retardo
COUNT2 equ 09h
; Segundo contador para nuestros bucles de retardo
; **** Configurar el puerto ****
bsf
ESTADO, 5; Cambiar al Banco 1
movlw
00h
; Establecer los pines del puerto A
movwf
TRISA
; a la salida.
bcf
ESTADO, 5; Regrese al Banco 0
; **** Encienda el LED ****
comienzo
movlw
02h
; Encienda el LED poniendo primero
movwf
PORTA
; en el registro w y luego
; en el puerto
; **** Inicio del bucle de retardo 1 ****
Loop1
decfsz
COUNT1,1; Restar 1 de 255
ir
Loop1
; Si COUNT es cero, continúe.
decfsz
COUNT2,1; Restar 1 de 255
ir
Loop1
; Regrese al inicio de nuestro ciclo.
; Este retraso cuenta regresivamente desde
; 255 a cero, 255 veces
; **** Retraso finalizado, ahora apague el LED ****
movlw
00h
; Apague el LED poniendo primero
movwf
PORTA
; en el registro w y luego en
;el puerto
; **** Agregar otro retraso ****

Loop2 decfsz
COUNT1,1
; Este segundo bucle mantiene el
ir
Loop2
; LED apagado el tiempo suficiente para
decfsz
COUNT2,1
; nosotros para verlo apagado
ir
Loop2
;
; **** Ahora vuelve al inicio del programa
ir
comienzo
; vuelve a Inicio y enciende el LED
;otra vez
; **** Fin del programa ****
fin
; Necesitado por algunos compiladores,
; y también por si nos perdemos
; la instrucción goto.
Puede compilar este programa y luego programar el PIC. Por supuesto tú
querrá probar el circuito para ver si realmente funciona. Aquí hay un circuito
diagrama para que lo construya una vez que haya programado su PIC.

Felicitaciones, acaba de escribir su primer programa PIC y ha creado un


circuito para encender y apagar un LED. Hasta ahora, si ha seguido estos
tutoriales, ha aprendido un total de 7 instrucciones de 35 y, sin embargo, ya
usted está controlando los puertos de E / S!
¿Por qué no intentar alterar los bucles de retardo para hacer que el LED parpadee más rápido?
Cuál es el valor mínimo de COUNT para ver realmente el parpadeo del LED? O por qué
No agregue un tercio o incluso más bucles de retardo después del primero para ralentizar el
Llevado abajo. Necesitará una constante diferente para cada bucle de retardo. usted
Entonces podría incluso ajustar sus bucles de retardo para hacer que el LED parpadee en un determinado
tasa, por ejemplo, una vez por segundo.
En el siguiente tutorial veremos cómo podemos usar una cosa llamada subrutina
para ayudar a mantener el programa pequeño y simple.

Tutorial 5
Subrutinas
Una subrutina es una sección de código o programa que se puede llamar como y
Cuándo lo necesitas. Se utilizan subrutinas si está realizando el mismo
funciona más de una vez, por ejemplo, creando un retraso. Las ventajas
de usar una subrutina es que será más fácil alterar el valor una vez
dentro de una subrutina en lugar de, digamos, diez veces a lo largo de su programa,
y también ayuda a reducir la cantidad de memoria que ocupa tu programa
dentro del PIC.
Veamos una subrutina:
RUTINA
CONTAR
equ 255
ETIQUETA
decfsz
CUENTA, 1
Ir
ETIQUETA
REGRESO
Primero, tenemos que darle un nombre a nuestra subrutina, y en este caso tengo
RUTINA elegida. Luego escribimos el código que queremos realizar como
normal. En este caso, he elegido el retardo en nuestro led intermitente
programa. Finalmente, finalizamos la subrutina escribiendo el RETORNO
instrucción.

Para iniciar la subrutina desde cualquier lugar de nuestro programa, simplemente escribimos el
instrucción CALL seguida del nombre de la subrutina.
Veamos esto con un poco más de detalle. Cuando llegamos a la parte de nuestro
programa que dice CALL xxx, donde xxx es el nombre de nuestra subrutina,
el programa salta al lugar donde reside la subrutina xxx. los
se llevan a cabo las instrucciones dentro de la subrutina. Cuando la instrucción
Cuando se alcanza RETURN, el programa vuelve a nuestro programa principal al
instrucción inmediatamente después de nuestra instrucción CALL xxx.
Puede llamar a la misma subrutina tantas veces como desee, que es
por qué el uso de subrutinas reduce la duración total de nuestro programa.
Sin embargo, hay dos cosas que debe tener en cuenta. Primero, como en nuestro
programa principal, las constantes deben declararse antes de ser utilizadas.
Estos pueden ser declarados dentro de la propia subrutina, o directamente en el
inicio del programa principal. Te recomendaria que declares
todo al comienzo de su programa principal, ya que entonces sabrá que
todo está en el mismo lugar. En segundo lugar, debe asegurarse de que la
programa salta la subrutina. Lo que quiero decir con esto es que si pones el
subrutina justo al final de su programa principal, a menos que use un 'Goto'
declaración para saltar lejos de donde está la subrutina, el programa
continúe y ejecute la subrutina lo desee o no. los
PIC no diferencia entre una subrutina y el programa principal.
Echemos un vistazo a nuestro programa de led parpadeante, pero esta vez usaremos un
subrutina para el bucle de retardo. Con suerte, verá cuánto más simple
el programa se ve, y también verá cómo funciona la subrutina para
real.
; ***** Configurar las constantes ****
ESTADO
equ 03h
; Dirección del registro STATUS
TRISA
equ 85h
; Dirección del registro triestado para el puerto A
PORTA
equ 05h
; Dirección del puerto A
COUNT1 equ 08 h
; Primer contador para nuestros bucles de retardo
COUNT2 equ 09h
; Segundo contador para nuestros bucles de retardo
; **** Configurar el puerto ****
bsf
ESTADO, 5; Cambiar al Banco 1
movlw
00h
; Establecer los pines del puerto A
movwf
TRISA
; a la salida.
bcf
ESTADO, 5; Regrese al Banco 0
; **** Encienda el LED ****
comienzo
movlw
02h
; Encienda el LED colocándolo primero
movwf
PORTA
; en el registro w y luego en el puerto

; **** Agregar un retraso


llamada
Retrasar
; **** Retraso finalizado, ahora apague el LED ****
movlw
00h
; Apague el LED colocándolo primero
movwf
PORTA
; en el registro w y luego en el puerto
; **** Agregar otro retraso ****
llamada
Retrasar
; **** Ahora vuelve al inicio del programa
ir
comienzo
; vuelve a Inicio y enciende el LED de nuevo
; **** Aquí está nuestra subrutina
Retrasar
Loop1
decfsz
COUNT1,1; Este segundo bucle mantiene el LED
ir
Loop1
; apagado el tiempo suficiente para que podamos
decfsz
COUNT2,1; verlo apagado
ir
Loop1
;
regreso
; **** Fin del programa ****
fin
; Necesario por algunos compiladores, y también
; en caso de que perdamos la instrucción goto.
Con suerte, puede ver que al usar una subrutina para nuestro bucle de retardo,
han reducido el tamaño del programa. Cada vez que queremos un retraso, ya sea
cuando el LED está encendido o apagado, simplemente llamamos a la subrutina de retardo. Al final
de la subrutina, el programa vuelve a la línea que sigue a nuestra 'Llamada'
instrucción. En el ejemplo anterior, encendemos el LED. Luego llamamos al
subrutina. Luego, el programa regresa para que podamos apagar el LED.
Llamamos a la subrutina nuevamente, y cuando la subrutina ha terminado, el
El programa regresa y la siguiente instrucción que ve es 'goto Start'.
Para aquellos de ustedes que estén interesados, nuestro programa original era de 120 bytes.
largo. Al usar la subrutina, hemos reducido el tamaño de nuestro programa
a 103 bytes. Esto puede no parecer tan bueno, pero viendo que solo
tener 1024 bytes en total dentro del PIC, todo ayuda.
En el siguiente tutorial, veremos la lectura de los puertos.

Tutorial 6
Lectura de los puertos de E / S.
Hasta ahora, hemos estado escribiendo en el puerto A para que podamos encender un LED
y fuera. Ahora, veremos cómo podemos leer los pines de E / S en
los puertos. Esto es para que podamos conectar un circuito externo y actuar en
cualquier salida que da.
Si recuerda nuestros tutoriales anteriores, para configurar los puertos de E / S,
Tuve que cambiar del Banco 0 al Banco 1. Hagamos eso primero:
ESTADO
equ 03h
; Dirección del registro STATUS
TRISA
equ 85h
; Dirección del registro triestado para el puerto A
PORTA
equ 05h
; Dirección del puerto A
bsf
ESTADO, 5
; Cambiar al banco 1
Ahora, para configurar el puerto para que sea una salida, enviamos un 0 al registro TrisA.
Para configurar un pin en un puerto para que sea una entrada, enviamos un 1 al registro TisA.
movlw
01h
; Establecer los pines del puerto A
movwf
TRISA
; para ingresar.
bcf
ESTADO, 5; Regrese al Banco 0
Ahora hemos configurado el bit 0 del puerto A como entrada. Lo que tenemos que hacer ahora es
compruebe si el pin es alto o bajo. Para esto, podemos usar uno de dos
instrucciones: BTFSC y BTFSS.
La instrucción BTFSC significa 'Haga una prueba de bit en el registro y bit we
especificar. Si es un 0, saltamos la siguiente instrucción '. BTFSS significa 'Hacer
un poco de prueba en el registro y el bit que especificamos. Si se establece en 1, saltamos
la siguiente instrucción. '
Cuál usemos, depende de cómo queremos que nuestro programa reaccione cuando
leemos la entrada. Por ejemplo, si simplemente estamos esperando que la entrada
sea un 1, entonces podríamos usar la instrucción BTFSS así:
Código aquí
:
BTFSS
PortA, 0
Ir a empezar
Continuar aquí
:
:

El programa solo pasará a 'Continuar aquí' solo si el bit 0 en el puerto A está


establecido en 1.
Escribamos ahora un programa que hará parpadear un LED a una velocidad, pero si
el interruptor está cerrado, el LED parpadeará dos veces más lento. Probablemente puedas
elabore este programa usted mismo, pero de todos modos he incluido la lista.
Puede intentar escribir el programa completo, solo para ver si tiene
comprendió los conceptos. Estamos usando el mismo circuito que antes, con el
adición de un interruptor RA0 conectado del PIC y el carril positivo de nuestro
suministro.
; ***** Configurar las constantes ****
ESTADO
equ 03h
; Dirección del registro STATUS
TRISA
equ 85h
; Dirección del registro triestado para el puerto A
PORTA
equ 05h
; Dirección del puerto A
COUNT1 equ 08 h
; Primer contador para nuestros bucles de retardo
COUNT2 equ 09h
; Segundo contador para nuestros bucles de retardo
; **** Configurar el puerto ****
bsf
ESTADO, 5; Cambiar al Banco 1
movlw
01h
; Establecer los pines del Puerto A:
movwf
TRISA
; bit 1 a salida, bit 0 a entrada.
bcf
ESTADO, 5; Regrese al Banco 0
; **** Encienda el LED ****
comienzo
movlw
02h
; Encienda el LED colocándolo primero
movwf
PORTA
; en el registro w y luego en el puerto
; **** Compruebe si el interruptor está cerrado
BTFSC
PORTA, 0
; Obtenga el valor del PUERTO A
; BIT 0. Si es cero
llamada
Retrasar
; un cero, continuar con normalidad.
; Si es un 1, agregue un
; rutina de retraso adicional
; **** Agregar un retraso
retraso de llamada
; **** Retraso finalizado, ahora apague el LED ****
movlw
00h
; Apague el LED colocándolo primero
movwf
PORTA
; en el registro w y luego en el puerto

; **** Compruebe si el interruptor todavía está cerrado


BTFSC
PORTA, 0; Obtener el valor del PUERTO A
; BIT 0. Si es cero,
llamada
Retrasar
; continuar con normalidad.
; Si es un 1, agregue un
; rutina de retraso adicional
; **** Agregar otro retraso ****
retraso de llamada
; **** Ahora vuelve al inicio del programa
ir
comienzo
; vuelve a Inicio y enciende el LED de nuevo
; **** Aquí está nuestra subrutina
Retrasar
Loop1
decfsz
COUNT1,1; Este segundo bucle mantiene el LED
ir
Loop1
; apagado el tiempo suficiente para que podamos
decfsz
COUNT2,1; verlo apagado
ir
Loop1
;
regreso
; **** Fin del programa ****
fin
; Necesario por algunos compiladores, y también
; en caso de que perdamos la instrucción goto.
Lo que he hecho aquí es encender el LED. Luego verifico si el
el interruptor está cerrado. Si está cerrado, hago una llamada a nuestra subrutina de retardo.
Esto nos da el mismo retraso que antes, pero ahora lo llamamos dos veces.
Lo mismo ocurre cuando el LED está apagado. Si el interruptor no está cerrado, entonces
tenemos nuestros viejos tiempos de encendido y apagado.
Puede compilar y ejecutar este programa. Sin embargo, una advertencia. los
El circuito y el código finales no parecerán impresionantes para alguien que no es
interesado en programar microcontroladores. Entonces, no se enoje si, cuando
le muestra a su familia y amigos cómo puede cambiar la velocidad de un
LED parpadeando con un interruptor, muestran muy poco interés, estoy hablando
por experiencia personal, aquí!
Si ha seguido estos tutoriales desde el principio, es posible que
interesado en saber que ya ha aprendido 10 de las 35 instrucciones para
el PIC 16F84! Y todos estos se han aprendido simplemente girando
un LED encendido y apagado.

Tutorial 7
Hasta ahora, hemos hecho que el PIC parpadee con un LED encendido y apagado. Entonces fuimos
capaz de interactuar con nuestro PIC agregando un interruptor, y así alterando el flash
Velocidad. El único problema es que el programa es muy largo y desperdicia mucho
memoria. Estuvo bien cuando estaba introduciendo los comandos por primera vez
tiempo, pero debe haber una mejor manera de hacerlo. Bueno, hay (lo sabías
que venía, ¿verdad?).
Examinemos cómo en realidad estábamos encendiendo y apagando el LED.
movlw
02h
movwf
PORTA
movlw
00h
movlw
PORTA
Primero cargamos nuestro registro w con 02h, luego lo movimos a nuestro PortA
registrarse para encender el LED. Para apagarlo, cargamos w con 00h y luego
lo movió a nuestro registro PortA. Entre estas rutinas tuvimos que llamar a un
subrutina para que pudiéramos ver el LED parpadeando. Entonces, tuvimos que movernos
dos conjuntos de datos dos veces (una vez en el registro w y luego en PORTA) y llamar a un
subrutina dos veces (una vez para encender y otra para apagar).
Entonces, ¿cómo podemos hacer esto de manera más eficiente? Sencillo. Usamos otro
instrucción llamada XORF.
La instrucción XORF realiza una función OR exclusiva en el registro
que especificamos con los datos que le damos. Creo que necesito explicar en qué
tierra, un OR exclusivo es antes de continuar.
Si tenemos dos entradas y una salida, la salida solo será 1 si, y
sólo si las dos entradas son diferentes. Si son iguales, entonces la salida
será 0. Aquí hay una tabla de verdad, para aquellos que prefieren mirar estos:
UNA
BF
0
0
0
0
1
1
1
0
1
1
1
0
Veamos ahora qué sucede si hacemos que B sea igual a nuestro anterior
salida, y simplemente cambiando el valor de A:
AB
F
0
0
0
0
0
0
1
0
1

1
1
0
1
0
1
Si mantenemos el valor de A igual a 1, y lo ponemos en O exclusivo con el
salida, la salida alternará. Para aquellos que no pueden ver esto de la verdad
tabla, aquí está usando binario:
0
Salida de corriente
EX-OR con 1 1
Nueva salida
EX-OR Con 1 0
Nueva salida
Es de esperar que pueda ver que al realizar un O exclusivo en la salida con 1, estamos
ahora alternando la salida de 0 a 1 a 0.
Entonces, para encender y apagar nuestro LED, solo necesitamos dos líneas:
MOVLW 02h
XORWF PORTA, 1
Lo que estamos haciendo es cargar nuestro registro w con 02h. Somos entonces
OR exclusivo para este número con lo que esté en nuestro PortA. Si el bit 1 es un 1,
cambiará a 0. Si el bit 1 es 0, cambiará a 1.
Repasemos este código un par de veces para mostrar cómo funciona en
binario:
PORTA
00010
xorwf
00000
xorwf
00010
xorwf
00000
xorwf
00010
Ni siquiera necesitamos cargar el mismo valor en nuestro registro w cada vez,
para que podamos hacer esto una vez al principio, y simplemente volver a nuestro conmutador
mando. Además, no necesitamos configurar un valor en nuestro registro PortA.
¿Por qué? Bueno, porque si al encenderlo es un 1, lo cambiaremos. Yo, en el
Por otro lado, es un 0 al encender, aún lo cambiaremos.
Entonces, veamos ahora nuestro nuevo código. El primero es nuestro LED parpadeante original, y el
el segundo es donde agregamos un interruptor:
LED intermitente
; ***** Configurar las constantes ****
ESTADO
equ 03h
; Dirección del registro STATUS
TRISA
equ 85h
; Dirección del registro triestado para el puerto A
PORTA
equ 05h
; Dirección del puerto A

COUNT1 equ 08 h
; Primer contador para nuestros bucles de retardo
COUNT2 equ 09h
; Segundo contador para nuestros bucles de retardo
; **** Configurar el puerto ****
bsf
ESTADO, 5; Cambiar al Banco 1
movlw
00h
; Establecer los pines del puerto A
movwf
TRISA
; a la salida.
bcf
ESTADO, 5; Regrese al Banco 0
movlw
02h
; Configurar nuestro registro w con 02h
; **** Enciende y apaga el LED ****
comienzo
xorwf
PORTA, 1; Alternar el LED
; **** Agregar un retraso
retraso de llamada
; **** Ahora vuelve al inicio del programa
ir
comienzo
; vuelve a Inicio y enciende el LED de nuevo
; **** Aquí está nuestra subrutina
Retrasar
Loop1
decfsz
COUNT1,1; Este segundo bucle mantiene el LED
ir
Loop1
; apagado el tiempo suficiente para que podamos
decfsz
COUNT2,1; verlo apagado
ir
Loop1
;
regreso
; **** Fin del programa ****
fin
; Necesario por algunos compiladores, y también
; en caso de que perdamos la instrucción goto.
LED intermitente con interruptor:
; ***** Configurar las constantes ****
ESTADO
equ 03h
; Dirección del registro STATUS
TRISA
equ 85h
; Dirección del registro triestado para el puerto A
PORTA
equ 05h
; Dirección del puerto A

COUNT1 equ 08 h
; Primer contador para nuestros bucles de retardo
COUNT2 equ 09h
; Segundo contador para nuestros bucles de retardo
; **** Configurar el puerto ****
bsf
ESTADO, 5; Cambiar al Banco 1
movlw
01h
; Establecer los pines del Puerto A:
movwf
TRISA
; bit 1 a salida, bit 0 a entrada.
bcf
ESTADO, 5; Regrese al Banco 0
movlw
02h
; Configure nuestro registro con 02h
; **** Enciende y apaga el LED ****
comienzo
xorwf
PORTA, 1; Alternar el LED
; **** Compruebe si el interruptor está cerrado
BTFSC
PORTA, 0; Obtenga el valor del PUERTO A
; BIT 0. Si es cero,
llamada
Retrasar
; continuar con normalidad.
; Si es un 1, agregue un
; rutina de retraso adicional
; **** Agregar un retraso
retraso de llamada
; **** Compruebe si el interruptor todavía está cerrado
BTFSC
PORTA, 0; Obtener el valor del PUERTO A
; BIT 0. Si es cero,
llamada
Retrasar
; continuar con normalidad.
; Si es un 1, agregue un
; rutina de retraso adicional
; **** Agregar otro retraso ****
retraso de llamada
; **** Ahora vuelve al inicio del programa
ir
comienzo
; vuelve a Inicio y enciende el LED de nuevo
; **** Aquí está nuestra subrutina
Retrasar

Loop1
decfsz
COUNT1,1; Este segundo bucle mantiene el LED
ir
Loop1
; apagado el tiempo suficiente para que podamos
decfsz
COUNT2,1; verlo apagado
ir
Loop1
;
regreso
; **** Fin del programa ****
fin
; Necesario por algunos compiladores, y también
; en caso de que perdamos la instrucción goto.
Espero que pueda ver que con solo usar una instrucción simple, tenemos
redujo el tamaño de nuestro programa. De hecho, solo para mostrar cuánto tenemos
reducido nuestros programas por, he mostrado los dos programas, qué cambios
se hicieron, y sus tamaños en la siguiente tabla:
Programa
Cambio
Tamaño (Bytes)
LED intermitente
Original
120
LED intermitente
Subrutina agregada 103
LED intermitente
Función XOR utilizada 91
LED Con Interruptor Original
132
LED con función de interruptor XOR utilizada 124.
Entonces, no solo hemos aprendido algunas instrucciones nuevas, también hemos reducido
el tamaño de nuestra codificación!
Operadores lógicos y aritméticos
Tutorial 8
Aquí, vamos a examinar cómo manipular bits individuales, realizar
algunas aritméticas simples y tablas de datos.
Operadores logicos
En el último tutorial presenté la función OR exclusivo. El ExOR
La función se conoce como operador lógico. En este tutorial voy a
explique los otros operadores lógicos que admite el PIC. No habrá
cualquier programa de ejemplo, pero explicaré cómo usar los operadores por

utilizando pequeñas secciones de código.


Y
La función AND simplemente compara dos bits y produce un 1 si son
lo mismo, y un 0 si son diferentes. Por ejemplo, si dijimos 1 Y 1,
el resultado es 1, mientras que si dijimos 1 Y 0 el resultado será 0. Por supuesto,
también podemos comparar palabras, y todo lo que hace la función AND es comparar
las dos palabras poco a poco. El siguiente ejemplo muestra dos palabras de 8 bits
Y junto con el resultado:
11001011
Y 10110011
Es igual a 10000011
Como puede ver, el resultado solo tendrá un 1 cuando dos 1 coincidan con
entre sí en las dos palabras. Podemos usar la función AND para verificar el
puertos, por ejemplo. Si estamos monitoreando algunos pines de E / S que son
conectado a un circuito, y necesitamos monitorear una cierta condición donde
solo algunos de los pines son altos, entonces simplemente podemos leer el puerto y
luego Y el resultado con la condición que estamos verificando, al igual que el
ejemplo anterior.
El PIC nos da dos sabores para AND. Son ANDLW y ANDWF.
ANDLW nos permite realizar una función AND con el contenido de la W
registro, y un número que especifiquemos. La sintaxis es:
ANDLW
<número> donde <número> es lo que haremos Y el
contenido de W con. El resultado de la función AND se volverá a almacenar
en el registro W.
ANDWF nos permite realizar una función AND en el registro W y
otro registro, como un PUERTO. La sintaxis es:
ANDWF
<register>, d donde <register> es el registro que estamos
interesado en, por ejemplo, PORTA, yd le dice al PIC dónde colocar el resultado. Si
d = 0, el resultado se coloca en el registro W, y de d = 1 el resultado se almacena
en el registro que especificamos.
Las dos secciones de código siguientes muestran un ejemplo de cada función AND.
El primero es verificar el estado del PORTA, donde necesitamos ver si
las entradas son 1100. Volveremos a poner el resultado en el registro W:

movlw
1100
ANDWF
05h, 0
El segundo ejemplo ahora verificará el contenido del registro W:
ANDLW
1100
O
Ya nos hemos encontrado con una función OR, a saber, el XOR. Esta
produjo un 1 si dos bits son diferentes, pero no iguales. Hay un segundo
Función OR llamada IOR, que es la OR inclusiva. Esta función
producir un 1 si cualquiera de los bits es un 1, pero también si ambos bits son 1. A continuación se muestra
un
tabla de verdad simple para demostrar esto:
ABO / P
000
011
101
111
Operadores aritméticos
AÑADIR
Esta función hace exactamente lo que dice. ¡Agrega dos números! Si el resultado
de sumar los dos números supera los 8 bits, se establecerá una bandera CARRY.
La bandera CARRY se encuentra en la dirección 03h bit 0. Si este bit está establecido, entonces el
dos números excedieron los 8 bits. Si es un 0, entonces el resultado está dentro de los 8 bits.
Nuevamente, el PIC nos da dos sabores de ADD, a saber, ADDLW y
ADDWF. Como habrás adivinado, esto es muy similar al anterior.
función. ADDLW agrega el contenido del registro W a un número que
especificamos. La sintaxis es:
ADDLW <número>
ADDWF agregará el contenido del registro W y cualquier otro registro que
especificamos. La sintaxis es:
ADDWF <register>, d donde <register es el registro que especificamos yd
le dice al PIC dónde colocar el resultado. Si d = 0, el resultado se coloca en el
W registro, y es d = 1 lo colocó en el registro que especificamos.

SUB
¡Apuesto a que no puedes adivinar qué hace esta función! Sí, lo adivinaste
esta función resta un bit de otro. Una vez más el PIC nos da
dos sabores: SUBLW y SUBWF. La sintaxis es exactamente la misma que para
la función ADD, excepto que, por supuesto, escribe SUB en lugar de ADD!
Incremento
Si quisiéramos agregar 1 a un número en el PIC, simplemente podríamos usar
la función AGREGAR, y use el número 1. ~ El problema con esto es que
primero tenemos que poner el número en el registro W, luego usar ADDLW 1
comando para incrementarlo. Si quisiéramos agregar 1 a un registro, es incluso
peor. Primero tenemos que poner el número 1 en el registro W, luego usar
ADDWF <registro>, 1. Entonces, por ejemplo, para agregar 1 a la ubicación 0C, digamos,
tendría que tener la siguiente sección de código:
movlw 01
addwf 0c, 1
Hay una forma mejor de hacer esto. Podemos usar el comando INCF. los
la sintaxis es:
INCF <registro>, d donde <register> es el registro, o la ubicación, que
están interesados, y d le dice al PIC dónde colocar el resultado. Si d = 0, el
el resultado está en el registro W, y si d = 1, el resultado se coloca en el registro
especificamos. Al usar esta única instrucción podemos literalmente la mitad de
codificación. Si quisiéramos que el resultado se volviera a colocar en el registro W, entonces usando
el ejemplo anterior, habríamos tenido que agregar otro comando a
mueva el contenido de 0C nuevamente al registro W, y luego coloque el 0C
Regístrese de nuevo a lo que fuera.
Hay otro comando de incremento. Es INCFSZ. Este comando
Incrementamos el registro que especificamos, pero si el registro es igual a 0 después
el incremento (que sucederá cuando agreguemos 1 a 127) entonces el PIC
omita la siguiente instrucción. La sección de código a continuación demuestra esto:
Bucle incfsz
0C
Ir a bucle
:
:
Resto del programa.
En la sección de código anterior, 0C se incrementará en 1. Entonces tenemos
una instrucción que le dice al PIC que vuelva a nuestra etiqueta llamada Loop, y

incrementar 0C en 1 de nuevo. Esto continúa hasta que 0C es igual a 127. Esta vez,
cuando incrementamos 0C en 1, 0C ahora será igual a 0. Nuestro INCFSZ
La instrucción le dirá al PIC que omita la siguiente instrucción, que en este
caso es la sentencia goto, por lo que el PIC continuará con el resto de
el programa.
Decremento
Ya he cubierto la función de disminución en tutoriales anteriores, así que
no me repetiré aquí.
Cumplido
La última instrucción de este grupo invertirá todos los bits del registro que
especificamos. La sintaxis es:
COMF <registro>, d donde <registro es el registro que queremos invertir,
y d le dirá al PIC dónde almacenar el resultado. Si d = 0, el resultado se almacena
en el registro W. Id d = 1, el resultado se almacena de nuevo en el registro que
especificado. El siguiente ejemplo muestra esta instrucción en acción:
0C = 11001100
COMF 0C, 1
0C = 00110011
Esto podría usarse, por ejemplo, para convertir rápidamente los pines de un puerto
salida a entrada y viceversa.
Tutorial 9
Operaciones BIT
Las operaciones de bits nos permiten manipular un solo bit dentro de una palabra. Ellos
nos permiten mover, establecer y borrar bits individuales en registros o números que
especificar. Al final de este tutorial, le mostraré un programa que
producir un conjunto de luces de marcha que van en una dirección y luego en la otra. Nosotros
vi esto hecho anteriormente cuando miramos la función OR exclusiva,
donde utilizamos exclusivamente ORed los puertos con una palabra.

Ya hemos visto un par de operaciones de bits cuando configuramos el


puertos en el PIC, y repetiré su uso aquí.
BCF
Esta instrucción borrará un poco que especifiquemos en un registro que
especificar. La sintaxis es:
BCF <registro>, <bit>
Usamos esto anteriormente para cambiar de la página 1 a la página 0 borrando un poco
en el registro STATUS. También podemos usarlo para establecer un bit en 0 en cualquier otro
registro / ubicación. Por ejemplo, si quisiéramos establecer el tercer bit en
11001101 almacenado en la ubicación 0C a 0, ingresaríamos:
BCF 0C, 03
BSF
Esta instrucción establecerá cualquier bit que especifiquemos en 1 en cualquier registro que
especificar. Usamos esto anteriormente para ir de la página 0 a la página 1. El
la sintaxis es:
BSF <register>, <bit>, y se utiliza en
exactamente de la misma manera que el BCF anterior.
BTFSC
Hasta ahora hemos puesto o borrado un bit en un registro. Pero y si queremos
simplemente pruebe si un bit es un 1 o un 0 en un registro? Bueno, podemos usar
BTFSC. Dice Bit Test Register F y Omitir si está despejado. Esta
La instrucción probará el bit que especificamos en el registro. Si el bit es un 0, el
La instrucción le indicará al PIC que se salte la siguiente instrucción. Usaríamos esto
instrucción si quisiéramos probar una bandera, como la bandera de acarreo. Esto salva
tener que leer el registro STATUS y mirar los bits individuales
para ver qué banderas están colocadas. Por ejemplo, si quisiéramos probar si el Carry
la bandera se ha establecido en 1 después de haber agregado dos números, entonces
introduzca la siguiente:
BTFSC
03h, 0
continuar aquí si se establece en 1
o aquí si se establece en 0

Si el estado del bit es 1, entonces la instrucción que sigue inmediatamente


Se realizará BTFSC. Si se establece en 0, entonces la siguiente instrucción es
omitido. La siguiente sección de código muestra dónde podría usarse:
Lazo :
:
:
BTFSC 03,0
Ir a bucle
En el código anterior, el PIC solo saldrá del bucle si el bit 0 del
El registro STATUS (o la bandera de acarreo) se establece en 0. De lo contrario, el goto
se ejecutará el comando.
BTFSS
Esta instrucción dice Bit Test Register F y Skip If Set. Esto es similar
a la instrucción BTFSC, excepto que el PIC omitirá la siguiente instrucción
si el bit que estamos probando se establece en 1, en lugar de 0.
CLRF
Esta instrucción establecerá todo el contenido de un registro en 0. La sintaxis
es:
CLRF <registro>
Usamos esto anteriormente para establecer la salida de los puertos en 0, usando
CLRF 85h. También lo usamos para configurar los puertos para que todos los pines salgan por
utilizando CLRF 05h.
CLRW
Esto es similar a la instrucción CLRF, excepto que solo borra la W
Registrarse. La sintaxis es bastante simple:
CLRW
RLF y RRF

Estos comandos se moverán un poco en un registro un lugar a la izquierda (RLF)


o el derecho (RRF) en un registro. Por ejemplo, si tuviéramos 00000001 y
usamos RLF, entonces tendríamos 00000010. Ahora, ¿qué sucede si
¿Tiene 10000000 y ha realizado la instrucción RLF? Bueno, el 1 sera
colocado en la bandera de transporte. Si llevamos a cabo la instrucción RLF nuevamente, el 1
reaparecerá al principio. Pasa lo mismo, pero al revés,
para la instrucción RRF. El siguiente ejemplo demuestra esto para
Instrucción RLF, donde he mostrado los 8 bits de un registro y el acarreo
bandera:
C 76543210
0 00000001
RLF 0 00000010
RLF 0 00000100
RLF 0 00001000
RLF 0 00010000
RLF 0 00100000
RLF 0 01000000
RLF 0 10000000
RLF 1 00000000
RLF 0 00000001
Programa de ejemplo
Ahora le voy a dar un código de ejemplo que puede compilar y
correr. Producirá una luz de marcha comenzando en PortA bit 0, yendo a PortB
bit 8 y luego de nuevo. Conecte los LED a todos los pines del puerto. Vas a
vea algunas de las operaciones de bits mencionadas en este tutorial.
TIEMPO EQU 9FH
; Variable para el bucle de retardo.
PORTB EQU 06H
; Dirección del puerto B.
TRISB EQU 86H
; Dirección del puerto B Tristate.
PORTA EQU 05H
; Dirección del puerto A.
TRISA EQU 85H
; Dirección del puerto A Tristate.
ESTADO EQU 03H
; Registro de selección de página.
COUNT1 EQU 0CH
; Registro de bucle.
COUNT2 EQU 0DH
; Registro de bucle.
ESTADO BSF, 5
; Ir a la página 1
MOVLW 00H
; y configurar
MOVWF TRISB
; ambos puertos A y B
MOVLW 00H
; a la salida,

MOVWF TRISA
; luego regresa a
ESTADO BCF, 5
; página 0.
MOVLW 00H
; Limpiar el puerto A.
MOVWF PORTA
;
; Inicio del programa principal
CORRER
MOVLW 01H
; Establecer el primer bit
MOVWF PORTB
; en el puerto B.
RETRASO DE LLAMADA
; Espera un momento
RETRASO DE LLAMADA
;
; Mueva el bit en el puerto B hacia la izquierda, luego haga una pausa.
PUERTO RLF, 1
RETRASO DE LLAMADA
RETRASO DE LLAMADA
PUERTO RLF, 1
RETRASO DE LLAMADA
RETRASO DE LLAMADA
PUERTO RLF, 1
RETRASO DE LLAMADA
RETRASO DE LLAMADA
PUERTO RLF, 1
RETRASO DE LLAMADA
RETRASO DE LLAMADA
PUERTO RLF, 1
RETRASO DE LLAMADA
RETRASO DE LLAMADA
PUERTO RLF, 1
RETRASO DE LLAMADA
RETRASO DE LLAMADA
PUERTO RLF, 1
RETRASO DE LLAMADA
RETRASO DE LLAMADA
PUERTO RLF, 1
; Esto mueve el bit a la bandera de acarreo
; Ahora pase al puerto A y mueva el bit a la izquierda.
RLF PORTA, 1
; Esto mueve el bit de la bandera cero a PortA
RETRASO DE LLAMADA
RETRASO DE LLAMADA
RLF PORTA, 1
RETRASO DE LLAMADA
RETRASO DE LLAMADA
RLF PORTA, 1
RETRASO DE LLAMADA
RETRASO DE LLAMADA
RLF PORTA, 1
RETRASO DE LLAMADA
RETRASO DE LLAMADA
; Mueva la broca hacia atrás en el puerto A
RRF PORTA, 1
RETRASO DE LLAMADA
RETRASO DE LLAMADA
RRF PORTA, 1
RETRASO DE LLAMADA
RETRASO DE LLAMADA
RRF PORTA, 1
RETRASO DE LLAMADA
RETRASO DE LLAMADA
RRF PORTA, 1
; Esto mueve el bit a la bandera cero

; Ahora mueva el bit hacia atrás en el puerto B


PUERTO RRF, 1
RETRASO DE LLAMADA
RETRASO DE LLAMADA
PUERTO RRF, 1
RETRASO DE LLAMADA
RETRASO DE LLAMADA
PUERTO RRF, 1
RETRASO DE LLAMADA
RETRASO DE LLAMADA
PUERTO RRF, 1
RETRASO DE LLAMADA
RETRASO DE LLAMADA
PUERTO RRF, 1
RETRASO DE LLAMADA
RETRASO DE LLAMADA
PUERTO RRF, 1
RETRASO DE LLAMADA
RETRASO DE LLAMADA
PUERTO RRF, 1
RETRASO DE LLAMADA
RETRASO DE LLAMADA
; Ahora estamos de vuelta donde empezamos
;
IR A CORRER
; vamos otra vez.
; Subrutina para dar un retraso entre movimientos de bits.
RETRASAR
TIEMPO MOVLW
; Obtenga el tiempo de retraso
RECUENTO DE MOVWF1
; y ponerlo en una variable.

LOOP1
;
DECFSZ COUNT1; Disminuya 1 desde el tiempo de retardo hasta que
IR
LOOP1
; llega a cero.
RECUENTO DE MOVWF1
; Obtenga el tiempo de retraso de nuevo
LOOP2
; y repita la cuenta atrás.
DECFSZ COUNT1;
GOTO LOOP2;
REGRESO
; Fin de subrutina.
FIN
;

Tutorial 10
Tablas de datos
Hay una característica interesante en el conjunto de instrucciones que le permite utilizar datos
mesa. Una tabla de datos es simplemente una lista de valores de datos, donde se lee cada uno
dependiendo de algunos criterios. Por ejemplo, puede tener un circuito que
utiliza un PIC donde cuenta el número de veces que un pin de entrada sube en
1 segundo. A continuación, puede mostrar el número en una pantalla de 7 segmentos.
Una vez que ha comenzado el cronometraje, el PIC cuenta el número de veces que el pin
va alto. Después de 1 segundo va a la mesa y busca el
información que necesita para mostrar el número en la pantalla que
corresponde al número de veces que el pin subió. Esto es útil,
porque no sabemos cuál será el número hasta que el PIC haya
completó su conteo. Al usar una tabla, podemos dejar que el PIC decida qué
número para mostrar.
Ahora, antes de continuar explicando cómo funciona la tabla de datos, tengo que
Explique cómo el PIC realiza un seguimiento del paradero en el programa cuando
el programa se está ejecutando. Ayuda si ha realizado alguna programación en
BÁSICO. Si no es así, no se preocupe, aún debería poder ver el concepto.
Imagina que tenemos un programa BÁSICO como el que se muestra a continuación:
10
DEJE K = 0
11
K=K+1
12
SI K> 10 ENTONCES GOTO 20 ELSE GOTO 11
20
IMPRIMIR K
21
FIN

El programa comienza en la línea 10. Una vez que K se establece en 0, procede a la línea
11. Después de haber agregado 1 a K, pasamos a la línea 12. Aquí estamos
preguntando si K es mayor que 10. Si lo es, entonces vamos a la línea 20, si no, vamos
volver a la línea 11. La línea 20 imprime el valor de K, y la línea 21 termina el
programa. BASIC utiliza números de línea para ayudar al programador a realizar un seguimiento de
donde están las cosas, ya que las etiquetas no están permitidas.
El PIC usa etiquetas para saltar entre ubicaciones, ¿o no? Usamos el
etiquetas para que sepamos dónde están las cosas, y también para que podamos decir la
PIC de una manera fácil a dónde ir. Lo que realmente sucede es que el PIC usa
un contador de línea interno llamado Contador de programa. El contador de programas
(abreviado como PC) realiza un seguimiento de la ubicación de la memoria donde
la instrucción actual es. Cuando le decimos al PIC que vaya a una etiqueta en particular,
conocer la ubicación de la memoria y, por lo tanto, aumentar la PC hasta que lea que
ubicación de la memoria. Esta es exactamente la misma forma en que leemos el BÁSICO
programa anterior. A continuación se muestra una sección de código, con las ubicaciones de memoria, o
el contenido de la PC, junto a cada instrucción:
ordenador personal
Instrucción
0000
movlw 03
0001
movwf 0C
0002 Lazo decfsc 0C
0003
Ir a bucle
0004 fin
En el ejemplo anterior, configuré la PC en 0000. En esta ubicación
tiene la instrucción movlw 03. Cuando el PIC ha ejecutado esto
instrucción, incrementa la PC para que se lea la siguiente instrucción. aquí
el PIC ve movwf 0C. La PC se incrementa nuevamente. Ahora el PIC
lee decfsc 0C. Si el contenido de 0C no es 0, entonces la PC es
incrementado en 1, y la siguiente instrucción, goto Loop, le dice a la PC que vaya
de regreso a la ubicación 0003, que es donde hemos dicho Loop. Si el contenido
de 0C es 0, entonces se le dice al PC que se incremente en 2, en otras palabras, omita el
siguiente instrucción. Esto coloca la PC en la ubicación 0004, donde el programa
termina. Las ubicaciones las establece el ensamblador y normalmente no
debe preocuparse por lo que está haciendo la PC. Hasta que es necesario controlarlo como
estamos a punto de hacer cuando usemos tablas de datos.
La mejor manera de explicar cómo funciona una tabla de datos es comenzar con una
ejemplo.
PC equ 02
movlw 03
tabla de llamadas

:
mesa addwf PC
retlw 01
retlw 02
retlw 03
retlw 04
retlw 05
retlw 06
retlw 07
regreso
La primera instrucción es asignar la etiqueta PC con la dirección del
Contador de programas (02h). Luego colocamos el valor de 03h en el w
Registrarse. Luego hacemos una llamada a la mesa. La primera línea de la subrutina
La tabla agrega el contenido del registro W (03h) al contador del programa.
Esto hace que el contador del programa aumente en 3, o lo ponga en otro
forma, hace que el contador del programa se mueva hacia abajo 3 líneas. Cuando el
El contador llega a 3 líneas más abajo, el PIC ve la instrucción retlw. Esta
El comando pasa el valor que le sigue al registro W, y luego
regresa de la subrutina. RETLW en realidad significa Retorno, literal a
W. Observe que puse una coma después de la palabra Retorno. Como estamos en un
subrutina, necesitamos una instrucción de retorno para salir de ella. Por lo tanto, la
RET en la instrucción. Después de la instrucción RETLW hay un número, y este
es lo que se coloca en el registro W. En este caso es el número 3.
Podemos asignar cualquier número al registro W, siempre y cuando este
se agrega un número al Contador de programa en la subrutina de la tabla,
encontrar una instrucción retlw. En el ejemplo anterior, esto significa que podemos tener
cualquier número del 1 al 7. Si pasamos la subrutina, podríamos terminar
ejecutando otra parte del programa. Debido a esto, siempre es un
Es una buena idea poner la tabla de datos al final del programa PIC, así que si
si nos sobrepasamos, llegaremos al final del programa de todos modos.

Tutorial 11
Interrupciones - Introducción
El tema de las interrupciones probablemente será el más largo y el más
difícil de atravesar. No hay una forma sencilla de explicar las interrupciones, pero
con suerte, al final de esta sección podrá implementar
interrumpe en sus propios programas. He dividido la sección en dos partes.
Esto es para ayudar a dividir el tema y darle a usted, el lector, un descanso.

Entonces, ¿qué es una interrupción? Bueno, como sugiere el nombre, una interrupción es una
proceso o una señal que detiene un microprocesador / microcontrolador de lo que
lo está haciendo para que pueda suceder algo más. Déjame darte una
ejemplo de día. Suponga que está sentado en su casa, charlando con alguien.
De repente suena el teléfono. Dejas de charlar y coges el
teléfono para hablar con la persona que llama. Cuando haya terminado su teléfono
conversación, vuelve a charlar con la persona antes del teléfono
sonó. Puede pensar en la rutina principal mientras charla con alguien, el
El timbre del teléfono hace que interrumpas tu conversación, y la interrupción
La rutina es el proceso de hablar por teléfono. Cuando el telefono
la conversación ha terminado, luego vuelve a tu rutina principal de
charlando. Este ejemplo es exactamente cómo una interrupción hace que un procesador
Actuar. El programa principal se está ejecutando, realizando alguna función en un circuito,
pero cuando ocurre una interrupción, el programa principal se detiene mientras que otra rutina
se lleva a cabo. Cuando finaliza esta rutina, el procesador vuelve al
rutina principal de nuevo.
El PIC tiene 4 fuentes de interrupción. Se pueden dividir en dos grupos.
Dos son fuentes de interrupciones que se pueden aplicar externamente al PIC,
mientras que los otros dos son procesos internos. Te voy a explicar los dos
los externos aquí. Los otros dos se explicarán en otros tutoriales.
cuando llegamos a mirar temporizadores y almacenar datos.
Si observa el pin-out del PIC, verá que el pin 6 muestra que está
RB0 / INT. Ahora, RB0 es, obviamente, el puerto B bit 0. El INT simboliza que
también se puede configurar como un pin de interrupción externo. Además, el puerto B bits 4 a
7 (pines 10 a 13) también se puede utilizar para interrupciones. Antes de que podamos usar el
INT u otros pines del Puerto B, tenemos que hacer dos cosas. Primero tenemos que decir
el PIC que vamos a utilizar interrumpe. En segundo lugar, necesitamos especificar
qué pin del puerto B usaremos como una interrupción y no como un pin de E / S.
Dentro del PIC hay un registro llamado INTCON, y está en la dirección 0Bh.
Dentro de este registro hay 8 bits que se pueden habilitar o deshabilitar. Poco 7
de INTCON se llama GIE. Esta es la habilitación de Interrngupt Global. Ajuste
esto a 1 le dice al PIC que vamos a usar una interrupción. Bit 4 de
INTCON se llama INTE, que significa INTerrupt Enable. Configurando este bit
a 1 le dice al PIC que RB0 será un pin de interrupción. Configuración del bit 3, llamado
RBIE, le dice al PIc que usaremos los bits del puerto B 4 a 7. Ahora el PIC
sabe cuando este pin sube o baja, deberá detener lo que está haciendo
y seguir con una rutina de interrupción. Ahora, tenemos que decirle al PIC
si la interrupción va a estar en el flanco ascendente (0V a + 5V) o en el
transición de flanco descendente (+ 5V a 0V) de la señal. En otras palabras,
quiere que el PIC interrumpa cuando la señal pasa de baja a alta, o de
de alto a bajo. De forma predeterminada, está configurado para estar en el borde ascendente. El borde
'disparo' se configura en otro registro llamado registro OPCIÓN, en
dirección 81h. El bit que nos interesa es el bit 6, que se llama
INTEDG. Establecer esto en 1 hará que el PIC se interrumpa en el aumento
edge (estado predeterminado) y establecerlo en 0 hará que el PIC se interrumpa
el borde descendente. Si desea que el PIC se dispare en el flanco ascendente, entonces

no necesitas hacer nada con este bit. Ahora, lamentablemente, la Opción


El registro está en el Banco 1, lo que significa que tenemos que cambiar del banco 0 al
banco 1, establezca el bit en el registro de opciones y luego vuelva al banco 0.
El truco aquí es hacer todos los registros del Banco 1 de un solo golpe, como configurar
los pines del puerto, luego regresa al Banco 0 cuando hayas terminado.
Ok, ahora le hemos dicho al PIC qué pin será la interrupción,
y en qué borde disparar, qué sucede en el programa y el PIC
cuando ocurre la interrupción? Suceden dos cosas. Primero, se establece una 'bandera'. Esta
le dice al procesador interno del PIC que ha ocurrido una interrupción.
En segundo lugar, el contador del programa (que mencioné en el último tutorial)
apunta a una dirección particular dentro del PIC. Veamos rápidamente cada uno de
estos por separado.
Bandera de interrupción
En nuestro registro INTCON, el bit 1 es la bandera de interrupción, llamada INTF. Ahora, cuando
se produce cualquier interrupción, este indicador se establecerá en 1. Si bien no hay un
interrumpir, la bandera se pone a 0. Y eso es todo lo que hace. Ahora probablemente eres
pensando '¿cuál es el punto?' Bueno, mientras esta bandera se establece en 1, el PIC
no puede y no responderá a ninguna otra interrupción. Entonces, digamos que nosotros
causar una interrupción. La bandera se establecerá en 1 y el PIC irá a nuestro
rutina para procesar la interrupción. Si esta bandera no se estableció en 1, y el
Se le permitió a PIC seguir respondiendo a la interrupción, luego continuamente
pulsar el pin mantendrá el PIC volviendo al inicio de nuestra interrupción
rutina, y nunca terminarla. Volviendo a mi ejemplo del
teléfono, es como levantar el teléfono, y tan pronto como empiezas
para hablar empieza a sonar de nuevo porque alguien más quiere hablar con
tú. Es mucho mejor terminar una conversación y luego levantar el teléfono.
de nuevo para hablar con la segunda persona.
Hay un pequeño inconveniente en esta bandera. Aunque el PIC automáticamente
establece esta bandera en 1, ¡no la vuelve a establecer en 0! Esa tarea debe ser realizada por
el programador, es decir, usted. Esto se hace fácilmente, como estoy seguro de que puedes
adivinar, y debe hacerse después de que el PIC haya ejecutado la interrupción
rutina.
Ubicación de la memoria
Cuando enciende el PIC por primera vez, o si hay un reinicio, el programa
El contador apunta a la dirección 0000h, que está justo al comienzo del programa
memoria. Sin embargo, cuando hay una interrupción, el contador de programa
apunte a la dirección 0004h. Entonces, cuando estamos escribiendo nuestro programa, es
van a tener interrupciones, primero tenemos que decirle al PIC que salte
dirección 0004h, y mantenga la rutina de interrupción que comienza en la dirección
0004h separados del resto del programa. Esto es muy fácil de hacer.

Primero, iniciamos nuestro programa con un comando llamado ORG. Este comando significa Origen,
o empezar. Lo seguimos con una dirección. Debido a que el PIC comenzará en la dirección 0000h,
tipo ORG 0000h. A continuación, debemos omitir la dirección 0004h. Hacemos esto colocando un
Instrucción GOTO, seguida de una etiqueta que apunta a nuestro programa principal. Luego seguimos
este comando GOTO con otro ORG, esta vez con la dirección 0004h. Es despues de esto
comando que ingresemos a nuestra rutina de interrupción. Ahora, podríamos escribir nuestra interrupción
rutina directamente siguiendo el segundo comando ORG, o podemos colocar un GOTO
declaración que apunta a la rutina de interrupción. Realmente es una cuestión de elección en su
parte. Para decirle al PIC que ha llegado al final de la rutina de interrupción, debemos colocar
el comando RTFIE al final de la rutina. Este comando significa volver del
interrumpir la rutina. Cuando el PIC ve esto, el contador de programa apunta a la última ubicación
el PIC estaba en antes de que ocurriera la interrupción. He mostrado a continuación un segmento corto de
código para mostrar lo anterior:
ORG 0000h; PIC comienza aquí al encender y reiniciar
GOTO start; Goto nuestro programa principal
ORG 0004h; El PIC vendrá aquí en una interrupción
:
; Esta es nuestra rutina de interrupción que
:
; desea que el PIC lo haga cuando reciba
:
; una interrupción
RETFIE
; Fin de la rutina de interrupción
comienzo
; Este es el comienzo de nuestro programa principal.
Hay dos cosas que debe tener en cuenta al utilizar interrupciones. los
primero es que si está utilizando el mismo registro en su programa principal y
la rutina de interrupción, tenga en cuenta que el contenido del registro
probablemente cambie cuando ocurra la interrupción. Por ejemplo, vamos a ser
utilizando el registro w para enviar datos al puerto A en el programa principal, y
también están usando el registro w en la rutina de interrupción para mover datos desde
de un lugar a otro. Si no tiene cuidado, el registro w contendrá
el último valor que tenía cuando estaba en la rutina de interrupción, y cuando
volver de la interrupción, estos datos se enviarán al puerto A en lugar de al
valor que tenía antes de que ocurriera la interrupción. La forma de rodear esto es
almacenar temporalmente el contenido del registro w antes de volver a utilizarlo en
la rutina de interrupción. La segunda es que hay un retraso entre cuando
ocurre una interrupción y cuándo puede ocurrir la siguiente. Como sabes, el
PIC tiene un reloj externo, que puede ser un cristal o puede ser un
combinación de resistencia y condensador. Cualquiera que sea la frecuencia de este reloj, el
PIC lo divide por 4 y luego lo usa para su sincronización interna. Por ejemplo
si tiene un cristal de 4MHz conectado a su PIC, entonces el PIC llevará
las instrucciones a 1MHz. Esta sincronización interna se llama Instrucción
Ciclo. Ahora, la hoja de datos dice (ciertamente en letra muy pequeña) que usted
debe permitir de 3 a 4 ciclos de instrucción entre interrupciones. Mi consejo es
permita 4 ciclos. El motivo del retraso es que el PIC necesita tiempo para saltar a

la dirección de interrupción, establezca la bandera y vuelva a salir de la interrupción


rutina. Por lo tanto, tenga esto en cuenta si está utilizando otro circuito para activar un
interrumpir para el PIC.
Ahora, un punto para recordar es que si usa los bits 4 a 7 del puerto B como un
interrumpir. No puede seleccionar pines individuales en el puerto B para que sirvan como
interrumpir. Entonces, si habilita estos pines, todos estarán disponibles. Entonces, para
ejemplo, no puede tener los bits 4 y 5; los bits 6 y 7 se habilitarán como
bien. Entonces, ¿cuál es el punto de tener cuatro bits para actuar como una interrupción? Bien,
podría tener un circuito conectado al PIC, y si alguna de las cuatro líneas
ir alto, entonces esta podría ser una condición en la que necesita que el PIC actúe
con rapidez. Un ejemplo de esto sería la alarma de una casa, donde cuatro
los sensores están conectados al puerto B bits 4 a 7. Cualquier sensor puede activar el
PIC para hacer sonar una alarma, y la rutina de sonido de la alarma es la interrupción
rutina. Esto ahorra examinar los puertos todo el tiempo y permite que el PIC
seguir con otras cosas.
En el siguiente tutorial, escribiremos un programa para manejar una interrupción.

Tutorial 12
Interrupciones: escribir el código
Cubrimos bastante terreno en el último tutorial, así que creo que es
momento en que escribimos nuestro primer programa. El programa que vamos a escribir
contará el número de veces que encendemos un interruptor, y luego mostrará el
número. El programa contará de 0 a 9, mostrado en 4 LED en
forma binaria, y la entrada o interrupción estará en RB0.
Lo primero que debemos hacer es decirle al PIC que salte la dirección
donde el Contador de programa apunta a cuando ocurre una interrupción. Vas a
observe que estoy usando una forma diferente de expresar hexadecimal
números. Antes solía usar F9h donde h denotaba hexadecimal. Nosotros
puedo escribir esto como 0xF9, y este es el formato que voy a usar a partir de ahora
en.
org
0x00
; Aquí es donde apunta la PC al encender y reiniciar
ir
principal
; Ir a nuestro programa principal
org
0x04
; Aquí es donde comenzará nuestra rutina de interrupción
retfie
; Esto le dice al PIC que la rutina de interrupción ha
; terminado y la PC apuntará de nuevo a la
;programa
principal
; Este es el comienzo de nuestro programa principal
Ahora necesitamos decirle al PIC que vamos a usar interrupciones, y estamos usando RB0
pin 6 como pin de interrupción:
bsf
INTCON, 7; GIE - Habilitación de interrupción global (1 = habilitada)
bsf
INTCON, 4; INTE - Habilitación de interrupción RB0 (1 = habilitación)
Voy a borrar la bandera de interrupción por si acaso (¡nunca confío en nada!)
bcf
INTCON, 1; INTF - Borrar bit de bandera por si acaso
Ahora necesitamos configurar nuestros dos puertos. Recuerde que como estamos usando RB0 como
pin de interrupción, esto debe configurarse como una entrada:
bsf
ESTADO, 5; Cambiar al Banco 1
movw
0x01
;
movwf
TRISB
; Establecer RB0 como entrada
movlw
0x10
;
movwf
TRISA
; Configure los primeros 4 pines en PortA como salida
bcf
ESTADO, 5; Vuelva al Banco 0
Vamos a usar una variable llamada COUNT para almacenar el número de
cambiar recuentos. Simplemente podríamos incrementar el valor en el puerto A, pero
verá por qué estoy usando una variable cuando escribimos nuestra rutina de interrupción.
lazo
movf
COUNT, 0
; Mover el contenido de
COUNT en W
movwf
PORTA
; Ahora muévalo al puerto A
ir
lazo
; Sigue haciendo esto

fin
; Fin de nuestro programa
Entonces, nuestro programa principal está escrito, y ahora necesitamos decirle al PIC qué
hacer cuando ocurre una interrupción. En este caso, nuestra interrupción va a
ser el cambio. Lo que queremos que haga el PIC es agregar uno a la variable
CUENTA cada vez que se cierra el interruptor. Sin embargo, solo queremos mostrar
la cantidad de veces que el interruptor se cierra de 0 a 9. Arriba, dije que podríamos
simplemente incrementaron el valor en el puerto A cada vez que hubo un
interrumpir. Pero, el puerto A tiene 5 bits, y si simplemente incrementamos el
puerto, tendremos un recuento máximo de 31. Hay dos razones por las que
eligió no subir a 31. Primero, usaremos una pantalla de 7 segmentos,
que como mucho solo puede ir de 0 a 15 (0 a F en hexadecimal). En segundo lugar, yo
también quiero mostrarte algunos de los comandos aritméticos que viniste
en los últimos dos tutoriales.
Así que sigamos con nuestra rutina de interrupciones.
Ahora, lo primero que debemos hacer es almacenar temporalmente el contenido de nuestro
w registro, ya que estamos usando esto para transferir el contenido de COUNT a
PORTA. Si no lo almacenamos, podríamos enviar un mensaje completamente diferente.
número como resultado de nuestra aritmética. Así que hagamos eso primero:
movwf
TEMPERATURA
; Almacenar w registrar en una ubicación temporal
A continuación, queremos agregar 1 a nuestra variable COUNT:
incf
COUNT, 1; Incrementar COUNT en 1 y poner el resultado
; volver a COUNT
A continuación, queremos hacer una comprobación de COUNT para comprobar si hemos pasado
valor de 9. La forma en que podemos hacer esto es restarlo de 10.
movlw
0x0A
; Mueva el valor 10 en w
subwf
COUNT, 0; Reste w de COUNT y ponga el
; resultado en w
Del tutorial 8 vimos que si restamos un número grande de un pequeño
número se establecerá una bandera de transporte. Esta bandera también se establecerá si los números
son iguales, y los restamos.
btfss
ESTADO, 0; Verifique la bandera de acarreo. Se establecerá si

; COUNT es igual o mayor que w,


; y se establecerá como resultado del subwf
;instrucción
Ahora sabemos si el valor de COUNT es 9 o más. Que queremos hacer
ahora es si COUNT es mayor que 9, vuelva a ponerlo en 0; de lo contrario, vuelva a
el programa principal para que podamos enviarlo al puerto A. El comando BTFSS
como usted sabe, se saltará la siguiente instrucción si la bandera de acarreo está configurada, es decir,
COUNT
= 10:
ir
Continua
; Si COUNT es <10, entonces podemos continuar
ir
claro
; Si COUNT es> 9, entonces debemos borrarlo
Continua
bcf
INTCON, 0x01
; Necesitamos borrar esta bandera para habilitar
; más interrupciones
movfw
TEMPERATURA
; Restablezca w al valor anterior al
interrumpir
retfie
; Sal de la rutina de interrupción
claro
clrf
CONTAR
; Establecer COUNT de nuevo a 0
bcf
INTCON, 1
; Necesitamos borrar esta bandera para habilitar
; más interrupciones
retfie
; Sal de la rutina de interrupción
Todo lo que queda por hacer ahora es juntar todo y también definir valores
a nuestras constantes, lo que podemos hacer desde el principio de nuestro programa.
A continuación se muestra la lista completa del programa. El circuito se muestra después de la
listado de programas. Cada vez que enciende el interruptor, los LED contarán
en binario de 0000 a 1010 y luego de nuevo a 0000.

org 0x00
; Aquí es donde entramos en el encendido y reinicio
; ******************* CONSTANTES DE CONFIGURACIÓN *******************
INTCON
EQU 0x0B; Registro de control de interrupciones
PORTB
EQU 0x06; Dirección de registro del puerto B
PORTA
EQU 0x05; Dirección de registro del puerto A
TRISA
EQU 0x85; Dirección de registro TrisA
TRISB
EQU 0x86; Dirección de registro TrisB
ESTADO
EQU 0X03; Dirección de registro de estado
CONTAR
EQU 0x0c; Esta será nuestra variable de conteo
TEMPERATURA
EQU 0x0d; Almacenamiento temporal para w
Registrarse
ir a principal
; Saltar la dirección de interrupción
; *************** RUTINA DE INTERRUPCIÓN ***************
org
0x04
; Aquí es donde la PC apunta a una interrupción
movwf
TEMPERATURA
; Almacene el valor de w temporalmente
incf
COUNT, 1; Incrementar COUNT en 1 y poner el resultado
; volver a COUNT
movlw 0x0A
; Mueva el valor 10 en w
subwf
COUNT, 0; Reste w de COUNT y ponga el
; resultado en w
btfss
ESTADO, 0; Verifique la bandera de acarreo. Se establecerá si
; COUNT es igual o mayor que w,
; y se establecerá como resultado del subwf
;instrucción

ir
Continua
; Si COUNT es <10, entonces podemos continuar
ir
claro
; Si COUNT es> 9, entonces debemos borrarlo
Continua
bcf
INTCON, 0x01; Necesitamos borrar esta bandera para habilitar
; más interrupciones
movfw
TEMPERATURA
; Restaura w al valor antes de la interrupción
retfie
; Sal de la rutina de interrupción
claro
clrf
CONTAR
; Establecer COUNT de nuevo a 0
bcf
INTCON, 1; Necesitamos borrar esta bandera para habilitar
; más interrupciones
retfie
; Sal de la rutina de interrupción
;*******************Programa principal*********************
principal
; ******************* Configurar los registros de interrupción ****
bsf
INTCON, 7; GIE - Habilitación de interrupción global (1 = habilitada)
bsf
INTCON, 4; INTE - Habilitación de interrupción RB0 (1 = habilitado)
bcf
INTCON, 1; INTF - Bit de bandera clara por si acaso
; ******************* Configurar los puertos ******************
bsf
ESTADO, 5; Cambiar al Banco 1
movlw 0x01

movwf TRISB
; Establecer RB0 como entrada
movlw 0x10
movwf TRISA
; Establecer R 0 en RA3 en PortA como salida
bcf
ESTADO, 5; Vuelva al Banco 0
; ******************* Ahora envíe el valor de COUNT al puerto A
lazo
movf
COUNT, 0; Mueve el contenido de Count a W
movwf
PORTA
; Ahora muévalo al puerto A
ir
lazo
; Sigue haciendo esto
fin
; Fin del programa
El diagrama de circuito
A continuación se muestra el diagrama de circuito que funcionará para el código anterior. Existen
dos cosas en el diagrama que pueden confundirte. Primero, no he incluido un
condensador de sincronización en el circuito del oscilador. Este es un pequeño truco inteligente que
puede probar si se queda sin condensadores. La capacitancia proviene del
capacitancia parásita entre el pin del oscilador y tierra. entonces, con el
resistor y la capacitancia parásita, tenemos un oscilador RC. Esta bien, esto
no es una forma precisa de hacerlo, ya que la capacitancia parásita variará de
circuito a circuito. Pero, pensé que podría estar interesado en ver este tipo de
cosa. En segundo lugar, he incluido un circuito de rebote en el interruptor.
Esto es necesario porque cada vez que pulsas un interruptor, los contactos
rebotar. Esto hará que el PIC piense que ha habido más de una
interruptores. Con el circuito de rebote, cuando el interruptor sube, el
el condensador se carga. no importa cuántas veces el interruptor vaya a + 5V,
el condensador solo se cargará una vez. El condensador se descarga cuando el
el interruptor se lanza hacia el otro lado. Si quieres ver los efectos de cambiar
rebote, luego desconecte el condensador y la resistencia a través del interruptor.

Tutorial 13
El temporizador del perro guardián
Ahora veremos un temporizador interno, llamado temporizador de vigilancia.
Entonces, ¿qué es un temporizador de vigilancia?
Suponga que ha escrito un programa que se ejecuta continuamente en un
FOTO. Ahora, desea asegurarse de que este programa siempre se esté ejecutando,
y que pase lo que pase nunca se detendrá. Lo primero que tu
tendría, por supuesto, un bucle al final del programa que
nos trae de vuelta al inicio del programa. Pero considere este caso. Nos deja
decir que el PIC está monitoreando una entrada. Cuando esta entrada es alta,
salta a otra parte del programa y espera a que otro pin suba.
Si el segundo pin no sube, el PIC simplemente se sentará allí y esperará. Va a
solo salga si el segundo pin va alto. Consideremos otro ejemplo.
Suponga que ha escrito un programa. Lo ha compilado con éxito,
e incluso lo ha simulado una y otra vez usando un simulador
como MPLAB. Todo parece funcionar bien. Programa el PIC
y colóquelo en un circuito. Sin embargo, después de un largo período de tiempo, la
El programa se atasca en alguna parte y el PIC queda atrapado en un bucle.
Lo que se necesita en ambos casos es algún tipo de reinicio si el programa se
atascado. Este es el propósito de un circuito de vigilancia.
Un circuito de vigilancia no es nada nuevo. Muchos microprocesadores y
los microcontroladores los tienen. pero como funciona? Bueno, dentro del PIC
hay una red de resistencias / condensadores. Esto proporciona un reloj único, que
es independiente de cualquier reloj externo que proporcione en su circuito. Ahora,
cuando el temporizador de vigilancia (abreviado como WDT) está habilitado, un contador
comienza en 00 y se incrementa en 1 hasta llegar a FF. Cuando pasa de
FF a 00 (que es FF + 1), el PIC se restablecerá, independientemente de lo
está haciendo. La única forma en que podemos evitar que el WDT reinicie el PIC es
para restablecer periódicamente el WDT a 00 a lo largo de nuestro programa. Ahora
puede ver que si nuestro programa se atasca por alguna razón, entonces el
No se establecerá WDT. El WDT luego reiniciará el PIC, causando que nuestro
programa para reiniciar desde el principio.
Para utilizar el WDT, necesitamos saber tres cosas. Primero, cuanto tiempo
¿Tenemos antes de que necesitemos restablecer el WDT? En segundo lugar, ¿cómo borramos
eso. Finalmente, tenemos que decirle al software de programación PIC que habilite el
WDT dentro del PIC. Miremos estos por separado.
Tiempos WDT

La hoja de datos del PIC especifica que el WDT tiene un período de inicio a
acabado de 18mS. Esto depende de varios factores, como la oferta
voltaje, temperatura del PIC, etc. La razón de la aproximación es
porque el reloj WDT es suministrado por una red RC interna. El tiempo
la carga de una red RC depende de la tensión de alimentación. También
depende de los valores de los componentes, que cambiarán ligeramente según
en su temperatura. Así que, en aras de la simplicidad, suponga que el
WDT se reiniciará cada 18 ms. Sin embargo, podemos hacer esto más largo. Dentro
el PIC es algo llamado Prescaler. Podemos programar este preescalador para
dividir el reloj RC. Cuanto más dividimos el reloj RC, más tiempo
tarda el WDT en restablecerse.
El preescalador está ubicado en el registro OPCIÓN en la dirección 81h, bits 0 a
2 inclusive. A continuación se muestra una tabla que muestra las asignaciones de bits con la división
tarifas y el tiempo de espera del WDT:
Recuerde que estos tiempos son independientes de la frecuencia de su reloj externo.
Piense en estos tiempos como tiempo real, en lugar de tiempos de reloj. Para ayudar a hacer
así de claro, supongamos que queremos que el WDT restablezca nuestro PIC después de aproximadamente
medio segundo a prueba de fallos. Lo más cercano que tenemos es 576 mS, o 0,576
segundos. Todo lo que hacemos es enviar b'101 'a nuestro registro de OPCIONES, de la siguiente manera:
movlw
b'101 '; Esto es 0x05 en hexadecimal
movwf
81h; este es el registro de opciones
Realmente simple. Ahora, hay una trampa. Por defecto, el preescalador es
asignado al otro temporizador interno. Esto significa que tenemos que cambiar
el preescalador al WDT. Primero, tenemos que reiniciar el otro contador
a 0 primero. Luego tenemos que cambiar al Banco 1 para asignar el preescalador a
WDT y para configurar la hora, y luego vuelva al Banco 0. El
el código está debajo, donde xx es el tiempo del preescalador:
bcf
ESTADO, 0; asegúrese de que estamos en el banco 0
clrf
01h
; dirección del otro temporizador - TMR0
Poco
2,1,0
Velocidad
Hora WDT
0,0,0 1: 1
18 mS
0,0,1 1: 2
36 mS
0,1,0 1: 4
72 mS
0,1,1 1: 8
144 mS
1,0,0 1:16
288 mS
1,0,1 1:32
576 mS
1,1,0 1:64 1,1 Segundos
1,1,1 1: 128 2,3 segundos

bsf
ESTADO, 0; cambiar al banco 1
clrwdt
; restablecer el WDT y el preescaler
movlw
b'1xxx '
; Seleccione el nuevo valor del preescaler y asigne
movwf
OPCIÓN
; a WDT
bcf
STATUS, 0; vuelve al banco 0
El comando CLRWDT anterior es cómo borramos el WDT antes de que se reinicie
la foto. Entonces, todo lo que tenemos que hacer es calcular en qué parte de nuestro programa
WDT expirará y luego ingresará el comando CLRWDT justo antes de este
punto para asegurarse de que el PIC no se reinicia. Si su programa es largo, espere
tenga en cuenta que es posible que necesite más de un CLRWDT. Por ejemplo, si nosotros
use el tiempo predeterminado de 18 mS, luego debemos asegurarnos de que el
El programa verá CLRWDT cada 18 mS.
Así que ahora llegamos al punto en el que necesitamos calcular cuánto tiempo
el código toma tiempo real. El principio es muy simple, pero podría causarle
para arrancarte el pelo!
Tiempo de instrucción
Como probablemente ya sepa, el PIC toma el reloj externo
tiempo y lo divide por 4. Este tiempo interno se llama ciclo de instrucción.
Ahora, si tenemos, digamos, un xtal de 4MHz conectado al PIC, internamente el PIC
funcionará a 1MHz. En términos de tiempo, esto es 1 / (4MHz / 4) = 1uS. Ahora, algunos
las instrucciones toman solo un ciclo de instrucción para completarse, es decir, 1 uS usando un
Cristal de 4MHz, mientras que otros tardan dos ciclos, 2uS, en completarse. Los datos
La hoja nos dice cuántos ciclos toma cada instrucción. La forma más fácil
recordar esto es bastante simple. Suponga que TODAS las instrucciones toman 1 ciclo.
Pero, si una instrucción hace que el programa vaya a otra parte, entonces
tomará 2 ciclos. Dejame darte un par de ejemplos. El movwf
El comando toma solo un ciclo, porque solo mueve datos de un
lugar a otro. El comando goto tarda 2 ciclos, porque es
haciendo que el Contador de programa (PC) vaya a otra parte del programa. los
El comando RETURN tarda 2 ciclos, porque hace que la PC se apague.
de nuevo en el programa. Creo que puedes ver el patrón aquí. Sin embargo,
hay cuatro comandos que pueden tomar 1 o 2 ciclos. Estos son
DECFSZ, INCFSZ, BTFSC y BTFSS. Estos comandos tienen uno
cosa en común. Omitirán la siguiente instrucción si hay una condición determinada
se cumple. Si no se cumple esa condición, se llevará a cabo la siguiente instrucción
afuera. Por ejemplo, el comando DECFSZ disminuirá el valor
almacenado en el registro F por 1. Si el resultado no es 0, entonces la siguiente instrucción
será ejecutado. Por tanto, esta instrucción tarda 1 ciclo. Si el resultado es
0, se omitirá la siguiente instrucción y la siguiente
ser ejecutado. En este caso, la instrucción tarda 2 ciclos. La razón
es que la instrucción altera el valor de la PC. Necesita un ciclo para
realizar la función, y necesitará otra para alterar la PC por un extra
uno.

Para aclarar esto, veamos un código de muestra y averigüemos cuántos


ciclos de instrucción necesarios.
movlw
02
movwf
CONTAR
bucle decfsz
CONTAR
ir
lazo
fin
Nuestra primera instrucción simplemente mueve el valor 02 a w. Esto no lo hace
hace que el programa se desvíe del curso, por lo tanto, es solo 1 ciclo. El siguiente
instrucción es similar, en la medida en que mueve el contenido de la w
registrarse en COUNT. Nuevamente, será 1 ciclo. Ahora, el siguiente
La instrucción primero disminuirá COUNT en 1. Esto es 1 ciclo. Entonces será
haz una prueba para ver si COUNT es igual a 0. En esta etapa no es así, por lo que
pasamos a la siguiente instrucción. La siguiente instrucción es un goto
declaración, y por lo tanto tiene 2 ciclos de duración. Volvemos a nuestro decfsz
instrucción, que vuelve a reducir COUNT en 1. Este es otro
ciclo de instrucción. Realiza una prueba para ver si COUNT es igual a 0. Esta vez
hace, por lo que se omite la siguiente instrucción. Para omitir la siguiente instrucción
requiere otro ciclo. Llegamos al final del programa. Entonces en total,
con el valor 02 colocado en COUNT, este programa tomará un total de 7
ciclos. Si usáramos un cristal de 4 MHz para nuestro reloj, entonces el programa
tomará:
1 / (4MHz / 4) = 1uS por ciclo, por lo tanto, 7 ciclos toman 7 x 1uS = 7uS.
Entonces puede ver que puede resultar un poco confuso cuando tiene
instrucciones como DECFSZ.
Software de programación
Dentro del PIC hay cosas llamadas 'Fusibles'. Estos no son lo mismo
como los fusibles que encontraría en un enchufe de red, pero interruptores electrónicos que
son "soplados" por el programador. Ahora, uno de estos fusibles tiene que ser
'soplado' para que el WDT funcione. Hay dos formas de hacer
esta. Una forma es escribir un par de líneas al comienzo de su
programa para decirle al software de programación PIC que habilite o deshabilite ciertos
fusibles. La otra forma es decirle al software de programación PIC manualmente
qué fusibles habilitar. Buscaremos que su programa instruya al
software de programación en un tutorial posterior, cuando analizamos la inclusión de otros
archivos y macros. Para decirle al software de programación manualmente, varía de
programa a programar. La documentación que vino con el programador
debería decirte cómo hacer esto. Como estoy usando el software PICALLW,
que está vinculado en mi página principal, explicaré cómo cambiar los fusibles
dentro de este programa. Los fusibles se configuran presionando la tecla F3, o
haciendo clic en el botón 'Configurar'. Entonces puede seleccionar el fusible que desee
habilitado, en este caso el WDT, haciendo clic en la casilla junto a él.

Programa de muestra
Escribamos un programa, donde encenderemos el WDT y dejaremos que el PIC
realizar una función. Primero que nada borraremos periódicamente el WDT, para mostrar
que el programa funciona, y luego elimine el comando CLRWDT para
muestra que el PIC se reiniciará.
El programa que he elegido es el que usamos en el tutorial 9 donde causamos
una fila de LED para iluminarse uno por uno de izquierda a derecha, luego de derecha a izquierda.
El circuito se muestra a continuación, y con los valores de RC mostrados nos dará un
Frecuencia de reloj de 8 KHz. Esta velocidad de reloj nos permitirá ver realmente
los LED se mueven uno por uno. Elegí este programa porque es lento
suficiente para que juguemos con el WDT, y puedes ver fácilmente cuando el PIC
se reinicia. Eliminé los comentarios originales y reemplacé
ellos con una descripción de las líneas WDT, un total acumulado del tiempo desde
el inicio (asumiendo un reloj de 8 KHz), y el número de ciclos de reloj en
cada línea.

HORA
equ 9FH
; Variable para el bucle de retardo.
PORTB
equ 06H
; Dirección del puerto B.
TRISB
equ 86H
; Dirección del puerto B Tristate.
PORTA
equ 05H
; Dirección del puerto A.
TRISA
equ 85H
; Dirección del puerto A Tristate.
ESTADO equ 03H
; Registro de selección de página.
COUNT1 equ 0CH
; Registro de bucle.
COUNT2 equ 0DH
; Registro de bucle.
ESTADO bsf, 5
; 1 ciclo, 0,5 mS
movlw 00H
; 1 ciclo, 1,0 mS
movwf TRISB
; 1 ciclo, 1,5 mS
movlw 00H
; 1 ciclo, 2,0 mS
movwf TRISA
; 1 ciclo, 2,5 mS
bcf ESTADO, 5
; 1 ciclo, 3,0 mS
movlw 00H
; 1 ciclo, 3,5 mS
movwf PORTA
; 1 ciclo, 4.0 mS
; Inicio del programa principal
CORRER
movlw 01H
; 1 ciclo, 4,5 mS
movwf PORTB
; 1 ciclo, 5,0 mS
llamar DELAY
; 2 ciclos, 486 mS
llamar DELAY
; 2 ciclos, 967 mS
; Mueva el bit en el puerto B hacia la izquierda, luego haga una pausa.
rlf PORTB, 1
; 1 ciclo, 967,5 mS
llamar DELAY
; 2 ciclos, 1,45 S
llamar DELAY
; 2 ciclos, 1,93 S
rlf PORTB, 1
; 1 ciclo, 1,93 S
llamar DELAY
; 2 ciclos, 2,41 S
llamar DELAY
; 2 ciclos, 2,89 S
rlf PORTB, 1
; 1 ciclo, 2,89 S
llamar DELAY
; 2 ciclos, 3.37S
llamar DELAY
; 2 ciclos, 3,85 S
rlf PORTB, 1
; 1 ciclo, 3,85 S
llamar DELAY
; 2 ciclos, 4.34S
llamar DELAY
; 2 ciclos, 4.82S
rlf PORTB, 1
; 1 ciclo, 4.82S
llamar DELAY
; 2 ciclos, 5.30S
llamar DELAY
; 2 ciclos, 5.78S
rlf PORTB, 1
; 1 ciclo, 5.78S
llamar DELAY
; 2 ciclos, 6.26S
llamar DELAY
; 2 ciclos, 6.74S
rlf PORTB, 1
; 1 ciclo, 6.74S
llamar DELAY
; 2 ciclos, 7.22S

llamar DELAY
; 2 ciclos, 7.70S
rlf PORTB, 1
; 1 ciclo, 7.70S
; Ahora pase al puerto A y mueva el bit a la izquierda.
rlf PORTA, 1
; 1 ciclo, 7.70S
llamar DELAY
; 2 ciclos, 8.19S
llamar DELAY
; 2 ciclos, 8.67S
rlf PORTA, 1
; 1 ciclo, 8.67S
llamar DELAY
; 2 ciclos, 9.15S
llamar DELAY
; 2 ciclos, 9,63 S
rlf PORTA, 1
; 1 ciclo, 9,63 S
llamar DELAY
; 2 ciclos, 10.11S
llamar DELAY
; 2 ciclos, 10,59 S
rlf PORTA, 1
; 1 ciclo, 10.59S
llamar DELAY
; 2 ciclos, 11.07S
llamar DELAY
; 2 ciclos, 11,55 S
; Mueva la broca hacia atrás en el puerto A
rrf PORTA, 1
; 1 ciclo, 11.55S
llamar DELAY
; 2 ciclos, 12.04S
llamar DELAY
; 2 ciclos, 12,52 S
rrf PORTA, 1
; 1 ciclo, 12.52S
llamar DELAY
; 2 ciclos, 12,99 S
llamar DELAY
; 2 ciclos, 13.48S
rrf PORTA, 1
; 1 ciclo, 13.48S
llamar DELAY
; 2 ciclos, 13,96 S
llamar DELAY
; 2 ciclos, 14.44S
rrf PORTA, 1
; 1 ciclo, 14.44S
; Ahora mueva el bit hacia atrás en el puerto B
rrf PORTB, 1
; 1 ciclo, 14.44S
llamar DELAY
; 2 ciclos, 14,92 S
llamar DELAY
; 2 ciclos, 15.40S
rrf PORTB, 1
; 1 ciclo, 15.40S
llamar DELAY
; 2 ciclos, 15,89 S
llamar DELAY
; 2 ciclos, 16,37 S
rrf PORTB, 1
; 1 ciclo, 16,37 S
llamar DELAY
; 2 ciclos, 16.84S
llamar DELAY
; 2 ciclos, 17,33 S
rrf PORTB, 1
; 1 ciclo, 17.33S
llamar DELAY
; 2 ciclos, 17,81 S
llamar DELAY
; 2 ciclos, 18.29S
rrf PORTB, 1
; 1 ciclo, 18.29S
llamar DELAY
; 2 ciclos, 18,77 S
llamar DELAY
; 2 ciclos, 19,25 S
rrf PORTB, 1
; 1 ciclo, 19.25S
llamar DELAY
; 2 ciclos, 19,73 S

llamar DELAY
; 2 ciclos, 20.22S
rrf PORTB, 1
; 1 ciclo, 20.22S
llamar DELAY
; 2 ciclos, 20,70S
llamar DELAY
; 2 ciclos, 21.18S
ir a correr
; 2 ciclos, 21.18S
; Subrutina para dar un retraso entre movimientos de bits.
; Total de 957 ciclos, 480 mS
RETRASAR
movlw TIME
; 1 ciclo
movwf COUNT1
; 1 ciclo
LOOP1
;
decfsz COUNT1
; 9F x 1 ciclo + 1 ciclo = 160 ciclos
ir a LOOP1
; 9E x 2 ciclos = 316 ciclos
movwf COUNT1
; 1 ciclo
LOOP2
;
decfsz COUNT1
; 9F x 1 ciclo + 1 ciclo = 256 ciclos
ir a LOOP2
; 9E x 2 ciclos = 316 ciclos
regreso
; 2 ciclos
FIN
;
Con un reloj de 8 KHz, el próximo LED tarda menos de 1 segundo
se ilumina y tarda un total de 21 segundos en ejecutarse desde un extremo
al otro y viceversa, es decir, realizar la rutina una sola vez. los
La rutina de retardo tarda 480 ms, y la llamamos dos veces antes de mover el
poco en los puertos. Ahora, necesitamos restablecer periódicamente el WDT. los
el tiempo más grande que podemos configurar el WDT es de 2,3 segundos, y el siguiente hacia abajo
forma esto es 1,1 segundos. Tenemos dos opciones aquí. Podríamos hacer un
llamar a una subrutina para borrar el WDT después de que hayan terminado las dos demoras,
o podríamos incorporar el CLRWDT dentro del propio retraso. yo tengo
decidió, sin ninguna razón real, incorporar el CLRWDT dentro del
bucle de retardo.
HORA
equ 9FH
; Variable para el bucle de retardo.
PORTB
equ 06H
; Dirección del puerto B.
TRISB
equ 86H
; Dirección del puerto B Tristate.
PORTA
equ 05H
; Dirección del puerto A.
TRISA
equ 85H
; Dirección del puerto A Tristate.
ESTADO
equ 03H
; Registro de selección de página.
COUNT1 equ 0CH
; Registro de bucle.
COUNT2 equ 0DH
; Registro de bucle.
OPTAR
equ 81h
; Opción Registro para controlar el
WDT
; ************* Configurar los puertos, WDT y pre-escalador ******************
clrf
01h
; Borrar TMR0
ESTADO bsf, 5
; Cambiar al banco 1
clrwdt
; restablecer el WDT y el preescaler
movlw
b'1101 '
; Seleccione el nuevo valor de preescalador y
asignar
movwf
OPTAR
; a WDT
movlw 00H
; Ahora configura los puertos
movwf TRISB
;
movlw 00H
;
movwf TRISA
;
bcf ESTADO, 5
; Vuelve al banco 0
movlw 00H
;
movwf PORTA
;
; ************* Inicio del programa principal ****************************
CORRER
movlw 01H
;
movwf PORTB
;
llamar DELAY
;
llamar DELAY
;
; ************* Mueva el bit en el puerto B hacia la izquierda, luego haga una pausa. **************
rlf PORTB, 1
;
llamar DELAY
;
llamar DELAY
;
rlf PORTB, 1
;
llamar DELAY
;
llamar DELAY
;
rlf PORTB, 1
;
llamar DELAY
;
llamar DELAY
;
rlf PORTB, 1
;
llamar DELAY
;

llamar DELAY
;
rlf PORTB, 1
;
llamar DELAY
;
llamar DELAY
;
rlf PORTB, 1
;
llamar DELAY
;
llamar DELAY
;
rlf PORTB, 1
;
llamar DELAY
;
llamar DELAY
;
rlf PORTB, 1
;
; ************* Ahora muévase al puerto A y mueva el bit a la izquierda. ***********
rlf PORTA, 1
;
llamar DELAY
;
llamar DELAY
;
rlf PORTA, 1
;
llamar DELAY
;
llamar DELAY
;
rlf PORTA, 1
;
llamar DELAY
;
llamar DELAY
;
rlf PORTA, 1
;
llamar DELAY
;
llamar DELAY
;
; ************** Mover el bit al puerto A ***********************
rrf PORTA, 1
;
llamar DELAY
;
llamar DELAY
;
rrf PORTA, 1
;
llamar DELAY
;
llamar DELAY
;
rrf PORTA, 1
;
llamar DELAY
;
llamar DELAY
;
rrf PORTA, 1
;
; ****************** Ahora mueva el bit hacia atrás en el puerto B ******************
rrf PORTB, 1
;
llamar DELAY
;
llamar DELAY
;
rrf PORTB, 1
;
llamar DELAY
;
llamar DELAY
;
rrf PORTB, 1
;
llamar DELAY
;

llamar DELAY
;
rrf PORTB, 1
;
llamar DELAY
;
llamar DELAY
;
rrf PORTB, 1
;
llamar DELAY
;
llamar DELAY
;
rrf PORTB, 1
;
llamar DELAY
;
llamar DELAY
;
rrf PORTB, 1
;
llamar DELAY
;
llamar DELAY
;
ir a correr
;
; ****************** Subrutina para dar un retraso entre bit
movimientos. ******
RETRASAR
movlw TIME
;
movwf COUNT1
;
LOOP1
;
decfsz COUNT1
;
ir a LOOP1
;
movwf COUNT1
;
LOOP2
;
decfsz COUNT1
;
ir a LOOP2
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;
;; Esta parte reinicia el WDT
;;
;; Comente o elimine este comando para ver el WDT
;;
;; en acción. Debería restablecer el PIC
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;
clrwdt
; Esto simplemente restablece el WDT.
; *************** Retorno de nuestra rutina DELAY original ***************
regreso
;
FIN
;
Si comenta o elimina el comando CLRWDT, encontrará que
el PIC no pasará de encender el segundo LED. Esto es porque el
WDT está restableciendo el PIC. Con CLRWDT en su lugar, el programa funciona
como debería.

También podría gustarte