Cuarta publicación sobre Microcontroladores Programables PIC, en
la veremos como trabajar con bits, tablas y su aplicación
práctica.
OPERACIONES CON BITS.
Las operaciones con bits nos permiten manipular un solo bit dentro de una
palabra “Word”. Con ellos podemos mover, activar o desactivar bits individualmente en
registros o números que especifiquemos. Veamos las instrucciones para
ello.
BCF
La instrucción BCF pone a cero un bit que especifiquemos en el
registro que especifiquemos. La sintaxis es la siguiente:
BCF <registro>,<bit>
Puede que resulte familiar, ya que la hemos utilizado previamente para
cambiar del Banco 1 al Banco 0, cuando poníamos a 0 el bit 5 del registro
STATUS. También podemos utilizarla para poner a 0 cualquier bit de
cualquier otro registro o posición de memoria.
Por ejemplo, si queremos poner a 0 el tercer bit de 11001101 que está
almacenado en la posición de memoria 0Ch, introduciríamos:
1
BCF 0Ch,2
Recordar que en binario, los Bytes están formados por 8 bits que van de
0 a 7, donde 0 es el bit más a la derecha del número en binario. En la
siguiente tabla, se muestra un ejemplo de número en binario, y el
resultado tras aplicar la instrucción BCF anterior:
BSF
La instrucción BSF pone a 1 el bit que especifiquemos en
cualquier registro que especifiquemos. También nos tiene que
resultar familiar, porque la hemos utilizado para cambiar del Banco
0 al Banco 1. Su sintaxis es:
BSF <registro>,<bit>
Y se utiliza exactamente de la misma forma que la BCF, vista
anteriormente.
BTFSC
La instrucción BTFCS se utilizar para hacer la comprobación
de un bit en un registro. Literalmente dice "Comprueba un bit
en el registro o posición de memoria (F), y salta si es 0".
Así que comprobará el bit que le especifiquemos en el registro. Si
el bit es 0, la instrucción le dice al PIC que se salte la
instrucción que viene a continuación.
Por ejemplo, si queremos comprobar si el flag de
CARRY ha sido puesto a 1 cuando hayamos sumado dos números,
haremos lo siguiente:
1
2
3
4
;
BTFSC 803h,0 ; Dirección del Registro Puerto A
<Intrucción A> ; Continua por aquí, si CARRY está a 1.
<Instrución B> ; o continua aquí, si CARRY está a 0.
Si el valor del bit es 1, entonces BTFSC continuará por la
instrucción inmediatamente siguiente. Si está a 0, entonces se salta
esa instrucción. Este podría ser un ejemplo de aplicación:
1
2
3
4
Bucle
:
BTFSC 03,0
Goto Bucle
Aquí, el PIC solo saldrá de bucle del “goto”, si el bit 0 del
registro STATUS (o el flag de CARRY) está puesto a 0.
BTFSS
La instrucción BTFSS, ”Comprueba el bit del registro o
posición de memoria (F), y salta si está a 1". Como se puede
comprobar, es similar a la instrucción BTFSC, a excepción que
el PIC se saltará la siguiente instrucción si el bit que estamos
comprobando está a 1, en lugar de a 0.
CLRF
La instrucción CLRF, pondrá todos los bits del contenido de
un registro a 0. La sintaxis es:
CLRF <registro>
También tiene que sonarnos, ya que la hemos usado anteriormente
para poner todos los pines de un puerto como salidas, haciendo "CLRF 85h" o para poner los pines de un puerto que estaban como salidas
todos a 0, haciendo "CLRF 05h".
CLRW
La instrucción CLRW es similar a la instrucción CLRF,
pero solo pone a 0 el registro W.
RLF y RRF
Las instrucciones RLF y RRF desplazan los bits del
contenido de un registro un lugar hacia la izquierda (RLF), o
un lugar hacia la derecha (RRF).
Por ejemplo, si tenemos 00000001 y utilizamos la instrucción
RLF, el resultado sería 00000010. Pero si tenemos 10000000 y
empleamos RLF, el bit 1 será desplazado al flag CARRY. Y si empleamos RLF una vez más, el 1
reaparecerá justo al principio, o dicho de otro modo en el
bit0.
Lo mismo ocurre con la instrucción RRF pero de manera
inversa. En la siguiente tabla, vemos el resultado de aplicar la
instrucción RLF, donde mostramos los 8 bits del contenido de
un registro, y el flag de CARRY:
La sintaxis para estas dos instrucciones es la siguiente:
RLF <registro>,d
RRF <registro>,d
En ambos casos, d le dice al PIC donde almacenar el
resultado. Si d=0, el resultado se almacena en el registro
W, y si d=1 el resultado se almacena en ese registro
especificado.
Con todo lo visto hasta ahora, vamos a realizar un programa de
ejemplo. Este código hace que una luz se desplace, comenzando en
el bit 0 del puerto B hasta el bit 8 del mismo, y después
siguiendo al bit 0 del puerto A hasta el bit 5. Al terminar hace
el mismo camino a la inversa, hasta llegar de nuevo al principio.
Este sería el circuito:
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
;**********************************************************;
; PROGRAMA LEDS.asm FECHA: XX XXXXX 2022 ;
; Programa para hacer desplazar LEDS por los puertos A y B ;
; Usa el puerto RA 1 (Pin 18) ;
; Revisión: 1.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 *******
TIEMPO equ 9Fh ; Variable para el bucle de retardo
PORTB equ 06h ; Dirección del Port B
TRISB equ 86h ; Dirección registro Port B
PORTA equ 05h ; Dirección del Port A
TRISA equ 85h ; Dirección registro Port A
STATUS equ 03h ; Registro para seleccionar el banco
CONTADOR1 equ 0Ch ; Registro para el bucle1
CONTADOR2 equ 0Dh ; Registro para el bucle2
;
bsf STATUS,5 ; vamos al Banco 0.
movlw 00h ; y configura
movwf TRISB ; los puertos A y B
movlw 00h ; como salidas,
movwf TRISA ; después vuelve
bcf STATUS,5 ; al Banco 0.
movlw 00h ; Ponemos a 0 el Puerto A.
movwf PORTA ;
;
; Inicio del Programa
CorreLuz
movlw 01h ; Ponemos a 1 el primer bit
movwf PORTB ; del Puerto B. PORTB = 00000001
call Retardo ; y hacemos un retardo.
call Retardo ;
;
; Desplaza el bit a la izquierda, y después pausa.
rlf PORTB,1 ; PORTB = 00000010, C = 0
call Retardo ; y hacemos un retardo.
call Retardo
rlf PORTB,1 ; PORTB = 00000100, C = 0
call Retardo ; y hacemos un retardo
call Retardo
rlf PORTB,1 ; PORTB = 00001000, C = 0
call Retardo
call Retardo
rlf PORTB, ; PORTB = 00010000, C = 0
call Retardo
call Retardo
rlf PORTB,1 ; PORTB = 00100000, C = 0
call Retardo
call Retardo
rlf PORTB,1 ; PORTB = 01000000, C = 0
call Retardo
call Retardo
rlf PORTB,1 ; PORTB = 10000000, C = 0
call Retardo
call Retardo
rlf PORTB,1 ; desplaza el bit al "flag" CARRY.
; PORTB = 00000000, C = 1
; Ahora se moverá al puerto A, desplazando el bit hacia la izquierda.
rlf PORTA,1 ; movemos bit CARRY al puerto A.
; PORTA = 00001, C = 0
call Retardo
call Retardo
rlf PORTA,1 ; PORTA = 00010, C = 0
call Retardo
call Retardo
rlf PORTA,1 ; PORTA = 01000, C = 0
call Retardo
call Retardo
rlf PORTA,1 ; PORTA = 10000, C = 0
call Retardo
call Retardo
; Desplaza el bit de vuelta por el puerto A
rrf PORTA,1 ; PORTA = 01000, C = 0
call Retardo
call Retardo
rrf PORTA,1 ; PORTA = 00100, C = 0
call Retardo
call Retardo
rrf PORTA,1 ; PORTA = 00010, C = 0
call Retardo
call Retardo
rrf PORTA,1 ; PORTA = 00001, C = 0
call Retardo
call Retardo
rrf PORTA,1 ; desplaza el bit al "flag" CARRY
; PORTA = 00000, C = 1;
; Ahora desplaza el bit de vuela al Puerto B
rrf PORTB,1 ; PORTB = 10000000, C = 0
call Retardo
call Retardo
rrf PORTB,1 ; PORTB = 01000000, C = 0
call Retardo
call Retardo
rrf PORTB,1 ; PORTB = 00100000, C = 0
call Retardo
call Retardo
rrf PORTB,1 ; PORTB = 00010000, C = 0
call Retardo
call Retardo
rrf PORTB,1 ; PORTB = 00001000, C = 0
call Retardo
call Retardo
rrf PORTB,1 ; PORTB = 00000100, C = 0
call Retardo
call Retardo
rrf PORTB,1 ; PORTB = 00000010, C = 0
call Retardo
call Retardo
rrf PORTB,1 ; PORTB = 00000001, C = 0
call Retardo
call Retardo ; hemos llegado donde empezamos
;
goto CorreLuz ; y volvemos al inicio.
;
; Subrutina para hacer el retardo entre los movimientos de bits.
;
Retardo
movlw TIEMPO ; Cogemos el tiempo de retardo,
movwf CONTADOR1 ; y lo ponemos en una variable.
Bucle1 ;
decfsz CONTADOR1 ; Decremento del tiempo de retardo
goto Bucle1 ; hasta que llegue a cero.
movwf CONTADOR2 ; Cogemos el tiempo de retardo,
Bucle2 ; y repetimos la cuenta atrás.
decfsz CONTADOR2 ;
goto Bucle2 ;
return ; Fin de la subrutina.
;**** Fin del Programa****
end ;
; Algunos compiladores necesitan esta instrucción,
; O por si nos olvidamos poner la instrucción 'goto'.
TABLAS DE DATOS.
En el conjunto de instrucciones del PIC, dispone de una propiedad
interesante, que nos va a permitir realizar tablas de datos.
Para el quien no este habituado, una tabla de datos es una lista simple
de valores de datos, donde cada uno de ellos puede ser leído,
dependiendo de algún criterio.
Un ejemplo práctico, podría ser realizar un circuito que cuente de 0 a 9 y se pueda visualizar el número en un display de 7 segmentos. El display de 7 segmentos se conecta al puerto B, de manera que cada pin encienda un LED del display. Este sería el esquema de conexiones:
Es decir, el pin RB7 no lo conectaríamos al display. De este modo tendremos la siguiente tabla de correspondencias entre los números a representar y el valor binario que debe de tomar el puerto B para que se enciendan los diodos LED correspondientes:
Con estas premisas, la tabla se podría crear utilizando el siguiente
código:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
PC equ 02h
:
:
tabla addwf PC
retlw 41h
retlw 3Bh
retlw 6Bh
retlw 4Dh
retlw 6Eh
retlw 7Eh
retlw 43h
retlw 7Fh
retlw 6Fh
retlw 77h
return
Vamos a Usando parte del código que hemos empleado anteriormente para
crear otro nuevo. Por eso, hay partes que serán familiares. Este es el
código completo para hacer que se muestre en el display una cuenta
ascendente de 0 a 9 y luego volver a empezar:
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
;**********************************************************;
; PROGRAMA DISPLAY.asm FECHA: XX XXXXX 2022 ;
; Programa para contar de 0 a 9 y mostrar en un dispay 7seg;
; Usa el puerto RB (Pines 6 al 12) ;
; Revisión: 1.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 *******
PC equ 02h ; Dirección Contador de Programa(PC)
TIEMPO equ 9Fh ; Dirección del Bucle de Retardo.
PORTB equ 06h ; Dirección del Puerto B.
TRISB equ 86h ; Dirección del registro Puerto B.
.
STATUS equ 03h ; Registro para selecciona el Banco.
CONTADOR1 equ 0Ch ; Registro para el Bucle1 de Retardo.
CONTADOR2 equ 0Dh ; Registro para el Bucle2 de Retardo.
;
bsf STATUS,5 ; Vamos al Banco 1.
movlw 00h ; Y configura
movwf TRISB ; los puertos A y B
movlw 00h ; como salidas,
movwf TRISA ; después vuelve
bcf STATUS,5 ; al Banco 0.
movlw 00h ; Ponemos a 0 el Puerto A
movwf PORTA ;
;
; Configuración del Puerto B.
bsf STATUS,5 ; Vamos al Banco 1.
movlw 00h ; Configura todos los pines del Puerto B.
movwf TRISB ; como salidas.
bcf STATUS,5 ; Vuelta al Banco 0.
movlw 00h ; pone al 0 el Puerto B.
movwf PORTB ; Es decir, Display apagado.
;**** Comienzo del Programa ****
Inicio movlw 0Ah ; Carga el valor 10 en W.
call tabla ; Llamada a la tabla para encender el valor 0.
movwf PORTB ; w=77h, y representa 0 en el display.
;
call Retardo ; Hacemos un retardo...
call Retardo ; ...para que se pueda ver el Nº0.
;
movlw 01h ; Carga el valor 1 en W.
call tabla ; Llamada a la tabla para encender el valor 1.
movwf PORTB ; y representar 1 en el display.
;
call Retardo
call Retardo
;
movlw 02h ; Carga el valor 2 en W
call tabla ; Llamada a la tabla para encender el valor 2.
movwf PORTB ; y representa 2 en el display.
;
call Retardo
call Retardo
;
movlw 03h ; Cargar el valor 3 en W
call tabla ; Llamada a la tabla para encender el valor 3.
movwf PORTB ; y representa 3 en el display.
;
call Retardo
call Retardo
;
movlw 04h ; Carga el valor 4 en W
call tabla ; Llamada a la tabla para encender el valor 4.
movwf PORTB ; y representa 4 en el display.
;
call Retardo
call Retardo
;
movlw 05h ; Carga el valor 5 en W
call tabla ; Llamada a la tabla para encender el valor 5.
movwf PORTB ; y representa 5 en el display.
;
call Retardo
call Retardo
;
movlw 06h ; Carga el valor 6 en W
call tabla ; Llamada a la tabla para encender el valor 4.
movwf PORTB ; y representa 6 en el display.
;
call Retardo
call Retardo
;
movlw 07h ; Carga el valor 7 en W
call tabla ; Llamada a la tabla para encender el valor 5.
movwf PORTB ; y representa 7 en el display.
;
movlw 08h ; Carga el valor 8 en W
call tabla ; Llamada a la tabla para encender el valor 5.
movwf PORTB ; y representa 8 en el display.
;
call Retardo
call Retardo
;
movlw 06h ; Carga el valor 9 en W
call tabla ; Llamada a la tabla para encender el valor 4.
movwf PORTB ; y representa 9 en el display.
;
call Retardo
call Retardo
goto Inicio ; Y regresamos al Inicio
; Aquí empieza la subrutina para hacer el retardo.
Retardo
movlw TIEMPO
movwf CONTADOR1 ; Tomamos el Tiempo de retardo y lo ponemos en una variable.
Bucle1
decfsz CONTADOR1
goto Bucle1 ; Decremeto del tiempo hasta llegar a 0
movwf CONTADOR2
Bucle2
decfsz CONTADOR2 ;
goto Bucle2
return ; Fin de la Subrutina
; *****TABLA ***
; Aqui situamos la configuracio para representar los nuemros
; en el display de 7 segmentos, segun el esquema de conexiones.
tabla addwf PCPORTA
retlw 41h ; Carga 41h en W (Nº1) y retorna.
retlw 3Bh ; Carga 3Bh en W (Nº2) y retorna.
retlw 6Bh ; Carga 6Bh en W (Nº3) y retorna.
retlw 4Dh ; Carga 4Dh en W (Nº4) y retorna.
retlw 6Eh ; Carga 6Eh en W (Nº5) y retorna.
retlw 7Eh ; Carga 7Eh en W (Nº6) y retorna.
retlw 43h ; Carga 43h en W (Nº7) y retorna.
retlw 7Fh ; Carga 7Fh en W (Nº8) y retorna.
retlw 6Fh ; Carga 6Fh en W (Nº9) y retorna.
retlw 77h ; Carga 77h en W (Nº0) y retorna.
return
;
; **** Fin del Programa ****
end
; Algunos compiladores necesitan esta instrucción, o por si olvidamos poner la instrucción "goto".
Este código, es un simple ejemplo que puede ser optimizado con los conceptos explicados anteriormente. Por ejemplo, se pueden aplicar subrutinas para procesos repetidos, como este:
1
2
3
4
5
6
7
8
call DISPLAY ;Llamada a la rutina
:
:
DISPLAY call Tabla ; Llamada a la Tabla
movwf PORTB ; y representamos en el display
call Retardo
call Retardo
return
En cualquier caso, como aprendizaje, es una forma muy clara de ver el proceso.
En la siguiente y última publicación, continuaremos con las interrupciones y el "Watchdog":
Microcontroladores Programables PIC (V)
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.
No hay comentarios:
Publicar un comentario