Diagramas y SeudoEsquemas para implementar los Microcontroladores PIC16X84 en circuitos reales o protoboards + Programas en ASM y C
¡¡¡Put0 título tan largo que me he inventado xD!!! Nada, decir que obviamente los programas no los he inventado yo, sino que son la recopilación de los "ejemplos práticos" más usados. Los he sacado de unos cuantos libros cuyo nombre no me sé (en realidad son unas fotocopias que encontré por casualidad). Y aclarar que los dibujos los hice yo en Visio, y que talvez tengan uno que otro fallo, la verdad es que me costó un huevo hacer esos put0s dibujos; en fín, si encontrais algún fallo me lo comunicas por privado. Sino conoceis como es este rollo de los Microcontroladores PIC, podeis hecharle un vistazo a este post: Introducción a microcontroladores PIC [simulando nuestro programas en ASM y C] (no te demoras sino 20 o 30 minutillos leyéndolo).
Primer Ejemplo: Explorando interruptores y encendiendo luces.
SeudoEsquema de Montaje
Descripción: Lee el número binario introducido mediante 3 interruptores conectados a la puerta A, luego suma 2 unidades a ese valor y visualiza el resultado mediante 4 diodos led conectados a la puerta B.
Programa en Assembler:
Código:
;----------------------------------------------------------------------------
LIST P=16C84 ;Comando que indica el PIC usado
RADIX HEX ;Los valores se representar n en hexadecimal
;----------------------------------------------------------------------------
PUERTAA EQU 0X05 ;La etiqueta "PUERTAA" queda identificada con
;la dirección 0x05, que si corresponde con el
;banco 0 es el valor de PUERTAA y si es del
;banco 1 con el de TRISA.
PUERTAB EQU 0X06 ;Equivalencia de la etiqueta PUERTAB
ESTADO EQU 0X03 ;Estado corresponde con el valor 0x03.
W EQU 0 ;Identifica W con el valor 0.
;----------------------------------------------------------------------------
ORG 0 ;Comando que indica al Ensamblador la
;dirección de la memeoria donde se
;situar la instrución siguiente
;----------------------------------------------------------------------------
bsf ESTADO,5 ;Pone a 1 el bit 5 de ESTADO para direccionar
;la p gina 1 de la memoria de datos.
movlw 0xff ;W <-- FF(Hex)
movwf PUERTAA ;W --> TRISA
movlw 0x00 ;W <-- 0
movwf PUERTAB ;W --> TRISB (Las líneas de PB salidas)
bcf ESTADO,5 ;Pone a 0 el bit 5 de ESTADO pasando a
;acceder al banco 0.
inicio movf PUERTAA,W ;W <-- PUERTAA. Se introduce el valor binario
;de los interruptores.
addlw 2 ;W <-- W + 2
movwf PUERTAB ;W --> PUERTAB. El valor de W sale por las
;líneas de PB a los led.
goto inicio ;Salta a la instrucción precedida por la
;etiqueta de inicio.
END
Programa en C:
Código:
#INCLUDE <16C84.H>
void main(void)
{
int valor; /* Valor temporal */
int * p_puertaa= 0x05; /* Puntero a PuertaA */
int * p_puertab= 0x06; /* Puntero a PuertaB */
SET_TRIS_A (0xff); /* 0xff --> TRISA */
SET_TRIS_B (0x00); /* 0x00 --> TRISB */
do
{
valor = * p_puertaa;/* PuertaA --> valor */
valor += 2; /* se incrementa valor en 2 */
*p_puertab = valor; /* valor --> puertaB */
}while(true); /* Bucle infinito */
}
Segundo Ejemplo: Más interruptores y diodos led.
Esquema de Montaje
Descripción: Muestra por cinco diodos led en la puerta B la entrada que proporcionan cinco interruptores en la puerta A.
Programa en Assembler:
Código:
LIST p=16c84 ; Se usa el PIC16C84
RADIX hex ; Se emplea el sistema de numeración hexadecimal
; ZONA DE ETIQUETAS-----------------------------------------------------------------------
W EQU 0 ; Cuando el destino es W, d = 0
F EQU 1 ; Cuando el destino es el registro f, d = 1
PUERTAA EQU 0x05 ; La Puerta A (datos) ocupa la dirección 5 del
; banco 0 y el registro de configuración la
; dirección 5 del banco 1
PUERTAB EQU 0x06 ; La misma etiqueta para el registro de datos y el
; de configuración de la Puerta B
ESTADO EQU 0x03 ; El registro Estado ocupa dirección 3 de los dos bancos
; COMIENZO DEL PROGRAMA -----------------------------------------------------------------
ORG 0 ; El programa comienza en la dirección 0 (Vector Reset)
goto inicio ; Se salta a la etiqueta “inicio”
ORG 5 ; Se asigna la dirección 5 a la siguiente instrucción
inicio bsf ESTADO,5 ; Pone a 1 el bit 5 de Estado. Acceso al banco 1.
clrf PUERTAB ; Se configuran como salidas las líneas de la Puerta B
movlw 0xff ; El registro W se carga con unos
movwf PUERTAA ; Se configuran como entradas las líneas de la Puerta A
bcf ESTADO,5 ; Pone a 0 el bit 5 de Estado. Acceso al banco 0.
bucle movf PUERTAA,W; Carga el registro de datos de Puerta A en W
comf PUERTAA,W ; Complementa a 1 la entrada y la deposita en W
movwf PUERTAB ; El contenido de W se deposita en el registro de datos de
; la Puerta B
goto bucle ; Se crea un bucle cerrado e infinito
END ; Fin del programa
Programa en C:
Código:
#include <16c84.h>
#byte puertaa = 05 /* Posición de la puerta A */
#byte puertab = 06 /* Posición de la puerta B */
void main( void )
{
int temp;
set_tris_a( 0xFF ); /* Puerta A configurada para entrada */
set_tris_b( 0x00 ); /* Puerta B configurada para salida */
do
{
/* La variable temporal es necesaria porque */
temp = ~puertaa; /* la complementación se traduce en dos pasos: */
puertab = temp; /* a) Copia de puertaa en temp */
}
/* b) Complementación de temp */
/* De no hacerlo así los LED parpadearían */
while( TRUE );/* Repetir ininterrumpidamente */
}
Tercer Ejemplo: Contando y visualizando.
Esquema de Montaje
Descripción: Hace un conteo desde 0 hasta 0x5f y muestra en las patitas RB.
Programa en Assembler:
Código:
;----------------------------------------------------------------------------
LIST P=16C84
RADIX HEX
;----------------------------------------------------------------------------
W EQU 0x00 ; Comienzo del campo de etiquetas.
F EQU 0x01
PUERTAB EQU 0x06
ESTADO EQU 0x03
CONTA EQU 0x0C
;----------------------------------------------------------------------------
ORG 0 ; El programa comienza en la dirección 0 y
goto inicio ; salta a la dirección 5 para sobrepasar
ORG 5 ; el vector de interrupción.
;----------------------------------------------------------------------------
inicio bsf ESTADO,5 ; Seleciona el banco 1
movlw 0x00 ; Se configura PuertaB como salida
movwf PUERTAB
bcf ESTADO,5 ; Selección del banco 0
;----------------------------------------------------------------------------
clrf CONTA ; CONTA = 0
bucle1 incf CONTA,F ; CONTA + 1 --> CONTA
movf CONTA,W ; CONTA se carga en W
movwf PUERTAB ; W se carga en el registro de datos PB
movlw 0x5f ; W <-- 0x5f
subwf CONTA,W ; CONTA - W --> W
btfss ESTADO,2 ; Explora Z y si vale 1 se produce "brinco"
goto bucle1 ; Si Z = 0 se vuelve a bucle1
bucle2 goto bucle2 ; si Z = 1 se produce un bucle infinito
end
Programa en C:
Código:
#include <16c84.h> /* Tipo de PIC a usar */
#byte puertab=0x06
#byte conta=0x0C
void main(void)
{
set_tris_b(0x00); /* Configura la PB como salida */
for (conta=0;conta<=0x5f;++conta) /* Bucle que incrementa CONTA de 0 */
puertab=conta; /* a 0x5f */
}
Cuarto Ejemplo: Controlando el tiempo.
SeudoEsquema de Montaje
Descripción: Programa que ilustra cómo realizar una temporización sin emplear interrupciones.
Programa en Assembler:
Código:
LIST P=16C84
RADIX HEX
; ------------------------------------------------------------------------
PUERTAA EQU 0x06
OPTION EQU 0x01
ESTADO EQU 0x03
TMR EQU 0x01
; ------------------------------------------------------------------------
ORG 0 ; Inicio del programa en
; dirección 0
; ------------------------------------------------------------------------
bsf ESTADO,5 ; Banco 1
movlw b 1101 0110 ; Valor a cargar en
; OPTION
movwf OPTION
movlw 0x00
movwf PUERTAB ; La Puerta B salida
bcf ESTADO,5 ; Banco 0
clrf PUERTAB ; Las líneas de salida
; de PB a 0
parpa bsf PUERTAB,7 ; Enciende el led RB7 = 1
call retardo ; Llamada a subrutina de
; RETARDO
bcf PUERTAB,7 ; Apaga el led, RB7 = 0
call retardo
goto parpa
retardo clrf TMR0 ; TMR0 = 0 y empieza su
; incremento
explora btfss TMR0,4; TMR0<4> = 1?
goto explora ; No ha llegado TMR0 a 16d
return ; Ha llegado TMR0 al
; valor 16d y retorna
; al programa principal
END
Programa en C:
Código:
#include <16C84.H>
#use delay( clock = 1000000 ) /* Especifica reloj de 1 MHz */
#byte puertab = 06 /* Dirección de la puerta B */
void main( void )
{
set_tris_b( 0x00 );
puertab = 0;
do
{
delay_us( 8700 ); /* Crea un bucle de espera de 8700 microsegundos */
bit_set(puertab,7); /* Enciende el LED */
delay_us(8700); /* Espera */
bit_clear(puertab,7);/* Apaga el LED */
}while(true); /* Repetir siempre */
}
Quinto Ejemplo: Manejando Interrupciones.
SeudoEsquema de Montaje
Descripción: Refleja el estado de dos interruptores situados en RA0 y RA1 en RB0 y RB1 mientras hace parpadear un diodo en la línea RB7.
Programa en Assembler:
Código:
;----------------------------------------------------------------------------
LIST P=16C84
RADIX HEX
;----------------------------------------------------------------------------
W EQU 0
F EQU 1
TMR_OPT EQU 0x01 ; TMRO en banco 0 OPTION en banco 1
ESTADO EQU 0x03
PUERTAA EQU 0x05 ; PA en banco 0 TRISA en banco1
PUERTAB EQU 0x06 ; PB en banco 0 TRISB en banco1
INTCON EQU 0x0B ;
CONTA EQU 0x10 ; Contador auxiliar
;----------------------------------------------------------------------------
ORG 0 ; Vector de Reset
goto inicio
ORG 4 ; Vector de Interrupción
goto inter ; Salta a comienzo de rutina de interrupción
ORG 5
inicio bsf ESTADO,5 ; Selección del banco 1
clrf PUERTAB ; Configura PUERTA B como salida
movlw b'00000011' ; Configura RA0, RA1 como entradas
movwf PUERTAA
movlw b'00000111'
movwf TMR_OPT
bcf ESTADO,5 ; Banco 0
movlw b'10100000' ; Se permite interrupción del
movwf INTCON ; TMR0 y la globla (GIE)
movlw 0x10
movwf CONTA ; Se carga CONTA con 16 decimal
movlw 0x0c
movwf TMR_OPT ; Se carga TMR0 con 12 decimal
bucle btfsc PUERTAA,0 ; Explora RA0 y brinco si vale 0
goto ra0_1 ; salta a RA0_1
bcf PUERTAB,0 ; Si RA0 = 0 sa saca por RB0 un 0
goto ra1x ; A explorar RA1
ra0_1 bsf PUERTAB,0 ; Si RA0 = 1 se saca por RB0 un 1
ra1x btfsc PUERTAA,1 ; Examina ra1 y brinco si es 0
goto ra1_1 ; Salta si RA1 = 1
bcf PUERTAB,1 ; Si RA1 = 0, RB1 = 0
goto bucle2
ra1_1 bsf PUERTAB,1 ; Si RA1 = 1 , RB1 = 1
bucle2 goto bucle ; Bucle indefinido, se sale por la interupción
;----------------------------------------------------------------------------
inter decfsz CONTA,1 ; RSI. Decrementa CONTA y brinco si vale 0
goto seguir
conta_0 movlw 0x10 ; Si CONTA = 0 se carga
movwf CONTA
btfsc PUERTAB,7 ; Si RB7 = 0, brinco
goto rb7_1
bsf PUERTAB,7 ; Si RB7 = 0, se invierte
goto seguir
rb7_1 bcf PUERTAB,7 ; Si RB7 = 1 , se invierte
seguir movlw b'10100000' ; Se restaura INTCON por desactivar las
movwf INTCON ; interrupciones el procesador
movlw 0x0c
movwf TMR_OPT ; Se recarga TMR0 con 12
retfie
end
Programa en C:
Código:
#include <16c84.h> /* Selección del PIC a usar */
#use delay(clock= 4000000) /* Reloj de 4 MHz */
#BYTE puertab = 6
#define maximo 16 /* Constante: maximo = 16 */
byte conta;
/*--------------------------------------------------------------------------*/
/* SERVICIO DE LA INTERRUPCIóN */
#INT_RTCC /* Interrupción por desvordamiento del timer*/
clock_isr()
{
short valor;
short novalor;
valor = bit_test(puertab,7); /* El bit valor es igual al contenido */
/* de RB7 */
novalor = !valor;
if (--conta==0)
{
output_bit (PIN_B7,novalor); /* Voltea RB7 */
delay_us (5);
conta = maximo;
}
}
/* PROGRAMA PRINCIPAL */
main()
{
short ra0,ra1;
set_tris_b(0x00); /* Se inicializa PB */
conta=maximo;
set_rtcc(0); /* Se inicializa el timer a cero */
setup_counters(rtcc_internal,rtcc_div_256);
enable_interrupts(rtcc_zero); /* Se permite int del tmr0 */
enable_interrupts(GLOBAL); /* Se activa GIE */
/* Rutina de control de los leds e interruptores: */
do
{
ra0 = input(PIN_A0);
ra1 = input(PIN_A1);
output_bit (PIN_B0,ra0);
output_bit (PIN_B1,ra1);
}
while(true); /* Bucle infinito */
}
Séptimo Ejemplo: Proyecto para manejar un display de 7 segmentos.
SeudoEsquema de Montaje
Descripción: Programa que visualiza un número del 1 al 7 en un display de siete segmentos en la puerta B dependiendo del valor binario de tres interruptores situados en la puerta A.
Programa en Assembler:
Código:
LIST P=16C84
RADIX HEX
w EQU 0
f EQU 1
PCL EQU 02
PUERTAA EQU 05
PUERTAB EQU 06
ESTADO EQU 03
VALOR EQU 12 ; Registro auxiliar
; RUTINA PRINCIPAL: Lectura de los interruptores y c lculo del valor a visualizar
ORG 0
goto inicio
ORG 5 ; Para saltar el Vector de
; Interrupción
inicio bsf ESTADO,5 ; Selección del banco 1
clrw
movwf PUERTAB ; Puerta B salida
movlw 0xff
movwf PUERTAA ; puerta A entrada
bcf ESTADO,5 ; Selección banco 0
explora movf PUERTAA,w ; Se cargan los
; interruptores en W
movwf VALOR ; Se usa un registro auxiliar
comf VALOR,f ; Invertir los niveles de interuptores
clrw
btfss VALOR,0 ; Si RA0 = 1, brinca
goto bit_1 ; Salta a explorar el bit_1
addlw 0x01 ; Si RA0 =1, se suma
bit_1 btfss VALOR,1; Si RA1 = 1, brinca
goto bit_2 ; Salta a explorar el bit_2
addlw 0x02 ; Si RA1 = 1, se suman 2
bit_2 btfss VALOR,2; Si RA2 = 1, brinca
goto visual ; Salta al módulo del display
addlw 0x04 ; Si RA2 0 1, se suman 4
visual call display ; Salta al módulo del display
; DISPLAY: Rutina de visualización del acumulador en el display de 7 segmentos
movwf PUERTAB ; Al retornar de la subrutina
; el valor de W se saca por la
; Puerta B
bucle goto bucle ; bucle infinito
; TABLA DE CONVERSION---------------------------------------------------------
display addwf PCL,f ; pcl + W -> W
; El pcl se incrementa con el
; valor de W proporcionando un
; salto
retlw 0x3F ; Retorna con el valor del
; código del 0
retlw 0x06 ; Retorna con el código del 1
retlw 0x5b ; Retorna con el código del 2
retlw 0x4f ; Retorna con el código del 3
retlw 0x66 ; Retorna con el código del 4
retlw 0x6d ; Retorna con el código del 5
retlw 0x7d ; Retorna con el código del 6
retlw 0x07 ; Retorna con el código del 7
END
Programa en C:
Código:
#include <16C84.H>
#byte puertaa = 05 /* Posición de la puerta A */
#byte puertab = 06 /* Posición de la puerta B */
void main( void )
{
int temp = 0, tabla[8]={ 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07 };
int indice = 0;
set_tris_a( 0xFF ); /* Puerta A configurada para entrada */
set_tris_b( 0x00 ); /* Puerta B configurada para salida */
temp = ~puertaa; /* Se complementa la entrada de PA */
if ( bit_test( temp, 0 ) ) indice += 1;
if ( bit_test( temp, 1 ) ) indice += 2;
if ( bit_test( temp, 2 ) ) indice += 4;
puertab = tabla[indice];
}
Ejemplos básicos de programación de Microcontroladores PIC16X84 sin esquemas ni diagramas; enunciados de los ejemplos:
- Control de un dispositivo desde dos puntos: Se desea controlar una lámpara, en este caso un diodo LED desde dos interruptores, de forma que cuando los dos interruptores están abiertos el LED está apagado. A partir de esta situación, cada vez que cambie el estado de un interruptor, el estado del LED bascula (si está apagado se enciende y viceversa)
- Semáforo programabe: Se simula un semáforo con 3 diodos LED. Se dispone de 2 interruptores que según la combinación que adopten originan una secuencia de encendido de las luces del semáforo.
- Dado electrónico: Este programa simula el juego del dado. Un dado típico tiene 6 caras, en cada una de las cuales viene dibujado un número del 1 al 6. Cada vez que se presiona un pulsador se produce un número aleatorio entre 1 y 6, el cual se visualiza en un display de 7 segmentos.
- Temporizador programable: Con 3 microrruptores se selecciona un valor entre el 0 y el 7 (binario), que representa un tiempo en segundos y que ser visualizado por el display de 7 segmentos. Durante el tiempo que dura la temporización un LED rojo permanece activado, así como un zumbador. Al finalizar se desactivan ambos elementos y el display se pone a 0.
- Alarma: Se tienen 3 detectores digitales, cada uno de los cuales provocar la activación de un LED, diferente en cada caso. Uno de los detectores ser un optoacoplador y los otros 2 se simularán mediante 2 microrruptores. El programa consiste en poner en marcha un zumbador cuando la alarma salte por causa de la activación de cualquiera de los detectores. También se enciende el LED correspondiente al detector. La alarma sólo funcionará cuando el microrruptor I1 de conexión esté a nivel alto.
- Ejemplo tomado de Internet: (Autor: David Tait, david.tait@man.ac.uk) Este programa ilumina una serie de leds en secuencia principio-fin-principio (algo así como las luces del "El Coche Fantástico).
- Manejo del WatchDog (perro guardián): El objetivo de este programa es mostrar en la práctica el funcionamiento del Watchdog en el PIC 16c84. El programa entra en un bucle infinito del que sale tras cumplirse la temporización asiganada al watchdog, que en este caso ser n 36 ms, es decir 2 veces la temporización nominal.
En un futuro post talvez coloque un pequeño glosario de las instrucciones de Assembler para esta gama de microcontroladores, para los que no entienden mucho los códigos; por lo demás espero que les sea de ayuda Y anexo también el archivo donde tengo los (seudo)diagramas en formato *.vsd (Visio), por si lo necesitan o quisieran modificar algún put0 dibujito de esos.
Saludos!!!