Continuamos con la siguiente publicación a cerca de Microcontroladores
Programables PIC. Hoy empezaremos a redactar nuestro código, y algunos
ejemplos prácticos.
EJEMPLO DE CÓDIGO.
Vamos a ver un ejemplo de código, en el que aplicaremos lo que acabamos de
aprender. Este ejemplo no es necesario compilar todavía, ya que lo haremos
cuando hagamos el primer programa. Ver esto simplemente como muestra de cómo
se hace la programación de lo explicado anteriormente y de paso veremos un
par de instrucciones.
Empecemos. Y vamos a poner el Puerto A como en el ejemplo anterior. Lo
primero, necesitamos cambiar del banco 0 al banco 1. Hacemos esto
modificando el registro STATUS, que está en la dirección 03h,
poniendo el bit 5 a 1.
1
BSF 03h,5
La instrucción BSF significa en ingles "Bit Set F" (Poner a 1
un bit de la Memoria). La letra F significa que vamos a utilizar una
posición de memoria, o un registro en memoria. Vamos a utilizar dos números
después de esta instrucción. 03h, que se refiere a la dirección del registro
STATUS, y el número 5 que corresponde al número de bit. Por tanto, lo
que estamos diciéndole al PIC es "pon a 1 el bit 5 de la dirección de
memoria 03h". Ahora ya estamos en el banco 1.
1
MOVLW b'00110'
En esta instrucción, estamos poniendo el valor binario 00110 en
nuestro registro de propósito general W (la letra 'b' significa
que el número está escrito en binario). Si preferimos hacerlo en
hexadecimal, la instrucción hubiese sido así:
1
MOVLW 06h
En las dos tenemos el mismo resultado. La instrucción MOVLW significa
en inglés "Move Literal Value into W", es decir, mover un valor
literal directamente al registro W.
El siguiente paso es poner este valor en el registro TRISA para
configurar el puerto:
1
MOVWF 85h
Esta instrucción significa "poner los contenidos de W en el registro
cuya dirección viene a continuación", en este caso la dirección 85h,
que apunta a TRISA. Es decir, ahora tiene el valor 00110 o
visto gráficamente:
Ahora tenemos que configurar los pines del Puerto A, y para eso necesitamos
volver al banco 0 para poder manejar cualquier dato.
1
BCF 03h,5
Con la instrucción BCF hacemos lo contrario a BSF. Significa "Bit Clear F",
o poner a 0 un bit de la memoria. Los dos números que le siguen son, la
dirección del registro, en este caso del registro STATUS (03h), y el número
de bit, es este caso el 5. Así que lo que hemos hecho ahora es poner a 0 el
bit 5 del registro STATUS.
Este es el código en un solo bloque:
1
2
3
4
BSF 03h,5 ; Vamos al banco 1
MOVLW 06h ; Poner 00110 en W
MOVWF 85h ; Mueve 00110 a TRISA
BCF 03h,5 ; Vuelve al Banco 0
ESCRIBIR EN LOS PUERTOS.
El anterior código, realmente no vemos un resultado, ya que muestra
como configurar los pines de un puerto del PIC como entradas o como
salidas. Pero ahora, vamos a mostrar como enviar datos a los puertos.
Es decir, veremos como resultado que un LED parpadea. Será como el
típico “Hello World!” de todos los programadores, en el que
veremos el listado completo y el esquema del circuito, para poder ver
nuestro PIC haciendo exactamente lo que esperamos que
haga.
Vamos a ir escribiendo el código, y explicando que hace. Así que
hasta el final, no deberíamos compilar nada, ya que son ejemplos:
1
2
3
4
BSF 03h,5 ; Vamos al banco 1
MOVLW 00h ; Poner 00000 en W
MOVWF 85h ; Mueve 00110 a TRISA, colocando todos los pines como salidas.
BCF 03h,5 ; Vuelve al Banco 0
Como vemos, esto es muy similar a lo expuesto en el capítulo
anterior. La única diferencia es que hemos puesto todos los pines del
Puerto A como salidas, poniendo 0h en el registro tri-estado
(TRISA). Y que hemos escrito todo en minúsculas, para evitar
posibles errores de compilación.
Ahora lo que tenemos que hacer es encender el LED. Y para ello
tenemos que colocar el pin donde irá conectado el LED, a nivel alto.
Es decir, enviamos un 1 al pin:
1
2
movlw 02h ; Escribe 02h en el registro W. En binario sería 00010.Con esto ponemos a 1 el bit 2 (Pin 18) y mantiene los otros pines a 0.
movwf 05h ; Ahora mueve los contenidos de W (02h) al puerto A, cuya dirección en 05h.
En este punto, nuestro LED estará encendido, y como queremos que
parpadee, ahora vamos a apagarlo:
1
2
movlw 00h ; Escribe 002h en el registro W. Esto pone todos los pines a 0.
movwf 05h ; Ahora mueve los contenidos de W (00h) al puerto A, cuya dirección en 05h.
De esta forma, lo que hemos hecho, ha sido encender y apagar el LED
una vez. Pero nuestro objetivo es que nuestro LED se encienda y se
apague continuamente. Para conseguir esto, tenemos que volver al
principio del programa.
Esto lo podemos hacer, colocando lo que se llama una etiqueta al
comienzo de nuestro programa, y luego diciéndole al programa que
vaya a ese punto constantemente. Esta sería la forma de
hacerlo:
1
2
3
4
5
6
Inicio ; Esta es la etiqueta que indica Inicio
movlw 02h ; Escribe 02h en el registro W. En binario sería 00010. Esto pone a 1 el bit 2 (pin 18), y mantiene el resto a 0.
movwf 05h ; Ahora mueve los contenidos de W (02h) al puerto A, cuya dirección en 05h.
movlw 00h ; Escribe 00h en el registro W. Esto pone todos los pines a 0
movwf 05h ; Ahora mueve el contenido de W (00h)al puerto A, cuya dirección es 05h.
goto Inicio ; va a la etiqueta de Inicio.
Así pues, primero establecemos la etiqueta 'Inicio' justo al
comienzo del programa. Después, justo al final del programa decimos
simplemente 'goto Inicio', es decir, ve a Inicio. Esta
instrucción 'goto' significa 'ir a', y eso es lo que
hace.
Este programa encenderá y apagará el LED constantemente, desde el
momento que le demos alimentación al circuito, y se detendrá cuando
le quitemos la alimentación.
Ahora bien, si nos fijamos, todo lo que hay son son instrucciones y
números. Y esto puede ser algo confuso a la hora de depurar el
programa, o cuando se escribes código y hemos de recordar todas las
direcciones de memoria. Incluso con los comentarios puestos, puede
ser un poco lioso. Así que lo que necesitamos es dar nombres a estos
números. Y esto se consigue con otra instrucción:
"equ"
La instrucción "equ" simplemente significa que algo equivale
a algo, literalmente del término inglés "equivalence", es
decir, equivalencia. Esta no es una instrucción del PIC, sino para
el ensamblador. Con esta instrucción podemos asignar un nombre a la
dirección de localización de un registro, o en términos de
programación asignar una constante. Vamos a establecer algunas
constantes para nuestro programa, y será más sencillo de leer.
1
2
3
STATUS equ 03h ; Asigna a STATUS el valor 03h, que es la dirección del registro STATUS.
TRISA equ 85h ; Asigna a la palabra TRISA el valor 85h, que corresponde a la dirección del registro tri-estado del puerto A.
PORTA equ 05h ; Asigna a la palabra PORTA el valor 05h, que corresponde a la dirección del puerto A.
Así que ahora que hemos establecido nuestros valores constantes,
vamos a ponerlos en nuestro programa. Los valores constantes deben
ser definidos antes de que los usemos.
Para estar seguros de ello los ponemos siempre al comienzo del
programa. Vamos a reescribir nuestro código sin comentarios, y se
puede ver que las constantes hacen el programa un poco más
sencillo. Sin embargo, no hemos terminado todavía:
1
2
3
4
5
6
7
8
9
10
11
12
13
STATUS equ 03h
TRISA equ 85h
PORTA equ 05h
bsf STATUS,5
movwf 00h
movlw TRISA
bcf STATUS,5
Inicio
movlw 02h
movwf PORTA
movlw 00h
movwf PORTA
goto Inicio
BUCLES DE RETARDO.
Pero si compilamos este código, y lo cargamos en nuestro PIC,
observaremos que hay un inconveniente en nuestro programa del
LED parpadeante. Y es que cada instrucción necesita un ciclo
de reloj para ser completada. Si utilizamos un cristal de 4
Mhz, cada instrucción tardará 1 microsegundo en ser
completada. Como solo estamos usando 5 instrucciones, el LED
se encenderá y apagará en 5 microsegundos, y parecerá que el
LED está permanentemente encendido, ya que esto es demasiado
rápido para que lo podamos ver.
En ese caso lo que necesitamos hacer, es introducir un
retardo entre el momento de encendido y apagado y
viceversa.
El principio para hacer retardos es, contar hacia atrás
desde un número previamente establecido y cuando llegue a
cero, paramos de contar. El valor cero indica el fin del
retardo y continuamos nuestro camino a través del
programa.
Así que lo primero que necesitamos hacer es definir una
constante que usaremos como contado y la llamaremos
CONTADOR. Luego necesitamos decidir el tamaño del
número desde el que contar y el número mayor que podemos
tener es 255 o FFh en hexadecimal. Ahora, como
hemos mencionado en el apartado anterior, la instrucción
equ asigna una palabra a una localización de un
registro. Esto significa que cualquiera que sea el número
que asignemos a CONTADOR, será igual al contenido de
un registro.
Pero nos encontramos que, si asignamos el valor FFh,
el compilador entenderá que estamos asignando la dirección
de memoria FFh a la constante, y obtendremos un error
cuando vayamos a compilar el programa. Esto es debido a que
la localización FFh está reservada, y por tanto no
podemos acceder a ella. Así que, ¿Cómo hacemos para
asignar un número real?
Pues hemos de asignar a nuestro CONTADOR, por
ejemplo, a la dirección 08h, este apuntará a un
registro de propósito general. Las posiciones de memoria
tienen un valor por defecto de FFh. De este modo, si
CONTADOR apunta a 08h, tendrá un valor de
FFh la primera vez que lo pongamos en
marcha.
Y si deseamos asignar un valor distinto en CONTADOR,
todo lo que tenemos que hacer es primero 'mover' un valor a
esta posición.
Por ejemplo, si queremos que CONTADOR tenga un valor
de 85h, no podemos decir 'CONTADOR equ 85h' porque esta es la localización del registro tri-estado
del puerto A (TRISA). Así que lo que haremos es
esto:
1
2
movlw 85h ; Ponemos el valor 85h en el registro W.
movwf 08h ; y lo movemos a nuestro registro 08h.
Ahora si podemos decir 'CONTADOR equ 08h', y nuestro
CONTADOR será igual al valor 85h. Así que lo primero de todo
es definir nuestra constante:
1
CONTADOR equ 08h
Y a continuación necesitamos disminuir este
CONTADOR en 1 hasta alcanzar cero. Y disponemos de
una sola instrucción que hace esto por nosotros, con la
ayuda de un 'goto' y una etiqueta. La instrucción que
usaremos es:
1
decfsz CONTADOR,1
Esta instrucción hace "resta 1 al registro (en este caso CONTADOR). Y si llegamos a cero, salta 2 posiciones hacia delante".
El valor que le sigue a la coma, indica donde debe almacenarse el resultado de la operación. Si es 1, como en el ejemplo anterior, el resultado se almacena en el mismo registro indicado en la instrucción, y si es 0 el resultado se almacena en el registro w:
1
2
3
4
5
6
7
CONTADOR equ 08h ;Asignamos el valor de CONTADOR
BUCLE decfsz COMNTADOR,1 ;Restamos 1 a CONTADOR, y...
goto BUCLE ;Si <> 0, sigue aquí.
;Continua por aquí ;Si = 0, sigue aquí.
:
:
:
Lo que hemos hecho es, primero poner nuestra constante
CONTADOR a 255.
La siguiente línea pone una etiqueta, llamada
BUCLE seguida de nuestra instrucción decfsz.
La instrucción decfsz CONTADOR,1 disminuye el valor
de CONTADOR en 1, y almacena el resultado de
vuelta en CONTADOR. También comprueba si
CONTADOR tiene valor 0. Si no lo tiene, hace
que el programa salte a la siguiente línea. Aquí tenemos
una instrucción de 'goto' que nos envía de vuelta a
nuestra instrucción decfsz. Cuando el valor de
CONTADOR sea igual a cero, entonces la instrucción
decfsz hace que el programa salte dos lugares hacia
adelante, y se sitúe donde hemos escrito "Continua por
aquí".
Así que, lo que hemos hecho es que el programa permanezca
en este punto durante un tiempo predeterminado antes de
seguir adelante. A esto se le llama bucle de retardo. En
el caso de necesitar un retardo mayor, podemos poner un
bucle detrás de otro o uno dentro de otro. Por tanto,
cuantos más bucles pongamos, mayor será el retardo. Para
nuestro ejemplo si queremos ver parpadear al LED, vamos a
necesitar por lo menos dos.
Así que vamos a poner los bucles de retardo y terminaremos haciendo un programa real añadiendo
los comentarios. Este es el código completo (Usar las barras de desplazamiento para ver todo el código):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
;**********************************************************;
; PROGRAMA LED1.asm FECHA: XX XXXXX 2022 ;
; Programa para hacer parpadear un LED ;
; Usa el puerto RA 1 (Pin 18) ;
; Revisión: 2.0 Programa para PIC16F48A ;
; Velocidad de Reloj: XTAL externo 4Mhz (1Mhz=1us) ;
; WatchDog = OFF Tipo Reloj: Cristal ;
; Autor: XMG Por: XANUR2001/ ACME 2022 ;
; Compilado en : MPLAB X IDE v2.05 (MICROCHIP) ;
; *********************************************************;
;
;*****Establecimiento de constantes *******
STATUS equ 03h ; Dirección del registro STATUS
TRISA equ 85h ; Dirección del registro Puerto A.
PORTA equ 05h ; Dirección del Puerto A.
CONTADOR1 equ 08h ; Primer contador para bucles de retardo.
CONTADOR2 equ 09h ; Segundo contador para bucles de retardo
;
;****Configuración del Puerto****
bsf STATUS,5 ; Cambiamos al banco 1
movlw 00h ; Ponemos pines del puerto A ...
movwf TRISA ; ...como salidas.
bcf STATUS,5 ; Y volvemos al Banco 0.
;
;****Encendido del LED ****
Inicio movlw 02h ; Encendemos el LED poniendo primero el valor...
movwf PORTA ;... en el registro W y después al puerto
;
;****Inicio del buble de retardo 1****
Bucle1 decfsz CONTADOR1,1 ; Restamos 1 a 255.
goto Bucle1 ; Si CONTADOR=0 continuamos.
decfsz CONTADOR2,1 ; Restamos 1 a 255
goto Bucle1 ; Volvemos al inicio de nuestro bucle
; Este retardo cuenta hacia atrás desde 255 a 0, 255 veces.
;
;****Retardo terminado, ahora apagamos el LED ****
movlw 00h ; Apaga el LED poniendo primero el alor ...
movwf PORTA ; en el registro w y después al puerto
;
;****Añadimos otro retardo****
Bucle2 decfsz CONTADOR1,1 ; segundo bucle mantiene el LED apagado...
goto Bucle2 ; el tiempo suficiente...
decfsz CONTADOR2,1 ; ...para poder verlo
goto Bucle2 ;
;
;****Ahora volvemos al inicio del programa
goto Inicio ; Vuelve al principio y enciende el LED.
;****Termina el Programa****
end
; Algunos compiladores necesitan esta instrucción. O por si acaso olvidamos poner la instrucción 'goto'.
Este código se puede compilar y programar el PIC con él,
para poder probar el circuito y ver cómo funciona.
Este es el sencillo esquema del circuito, para poder
construirlo y probar el PIC con nuestro primer programa:
Con esto, acabamos de escribir nuestro primer
programa y construir el circuito para hacer
parpadear un LED. Nuestro “Hello World!” para
PIC.
Hasta este punto, hemos visto 7 instrucciones de las 35, y hemos visto como controlar los puertos de entrada/salida.
Con esta base, se pude intentar modificar los
bucles de retardo, para hacer que el LED parpadee
más rápido, o más lento, añadir más bucles, incluso
ajustar los bucles de retardo para hacer que el LED
parpadease con un ritmo definido, por ejemplo una
vez por segundo.
En la siguiente publicación, continuaremos con las subrutinas para optimizarlo:
También, podéis consultar la publicación anterior:
ENLACES.
Y a continuación, una serie de enlaces útiles sobre lo expuesto:
Hoja de características (Datasheet) del PIC 16F84A®:
Web del Fabricante Microchip®:
MPLAB de Microchip®:
Software PICKit2 Programmer (y otros recursos en Microchip):
NotePad++:
WinPic800:
IC-PROG:
Programador JDM, en Blog Xanur:
Programador PicKit, en Blog Xanur:
Electrónica Digital, en Blog Xanur:
Esperamos que os haya gustado esta publicación. Si es así, no
dudes en compartirla.
© Se permite reproducción total o parcial de este contenido, siempre y cuando se reconozca la fuente de información utilizada y se incluya el enlace a este artículo.
Equipo Xanur©2022.
© Se permite reproducción total o parcial de este contenido, siempre y cuando se reconozca la fuente de información utilizada y se incluya el enlace a este artículo.
Equipo Xanur©2022.