Está en la página 1de 8

Curso de Microcontroladores ndmunoz@elpoli.edu.

co 1

TUTORIAL

OBJETIVOS

• Hacer uso de las interrupciones.


• Conocer el problema de los rebotes en los pulsadores y plantear algunas
formas de solucionarlo.

INTRODUCCIÓN:

Utilizaremos dos importantes funciones que nos ofrecen los microcontroladores,


los temporizadores y las interrupciones externas, por medio de ellas
incrementaremos o decrementaremos un contador el cual será mostrado por
medio de displays de siete segmentos.

A continuación dividiremos el problema en dos, primero abordaremos el problema


del conteo utilizando el timer0 y las banderas de interrupción externa, luego
abordaremos la parte de la visualización complementando lo visto en la práctica
anterior.

FUNDAMENTOS TEÓRICOS:

Del funcionamiento del microcontrolador necesitamos conocer dos módulos muy


importantes: El timer0 y la interrupción externa (int).

• El timer0: Ya se ha trabajado tanto en el tutorial anterior como en la parte


teórica, en este caso lo usaremos como contador de eventos internos.
Refiérase a la guía anterior para los detalles referentes a este.

• La interrupción externa: Estas se manejan en el pin RB0, este pin puede


configurarse para que cuando se perciba un cambio de señal de alto a bajo
o de bajo a alto (flanco de bajada o de subida) se encenderá una bandera
(INTF del registro INTCON) y se disparará la interrupción si esta estaba
habilitada. Solo se puede configurar si la interrupción se disparará en el
flanco de subida o de bajada y se hace por medio del registro
OPTION_REG bit INTEDG en el cual con un 1 indicamos flanco de subida y
con un cero flanco de bajada.

REALIZACIÓN DEL CONTEO:

Recuérdese que tenemos un pulsador en el pin RA4 (TOCKI) el cual nos permitirá
incrementar la cuenta y otro pulsador en RB0 (INT) el cual nos permitirá

Curso de Microcontroladores ndmunoz@elpoli.edu.co 1


Curso de Microcontroladores ndmunoz@elpoli.edu.co 2

decrementarla, vamos por lo tanto a esperar interrupciones dadas por alguno de


estos eventos.

La estrategia que usaremos será la siguiente: Mantener el TMR0 en un valor de


255 de modo que al presionar el usuario el pulsador de incrementar se disparará
la interrupción de TMR0, en la interrupción por TMR0 se procederá a incrementar
la cuenta (en una variable contador), volver a cargar el TMR0 con 255 y a limpiar
la bandera TMR0IF.

Para el decremento simplemente al presionar el pulsador en RB0 se disparará una


interrupción externa INT y en esta interrupción decrementamos la variable y
colocamos de nuevo la bandera en cero.

INTERRUPCIONES:

Cuando usamos las interrupciones el microcontrolador responde automáticamente


a ciertos eventos haciendo saltar la ejecución del código del punto donde se
encuentre a un lugar conocido como vector de interrupción; en dicho punto se
debe encontrar el código necesario para atender el evento que genero la
interrupción, una vez terminado este código el microcontrolador automáticamente
devuelve la ejecución al lugar donde se encontraba cuando fue interrumpido.

En los micros de la familia 16 existe un solo vector de interrupción, es decir,


independiente de cual bandera de interrupción sea activada (TMR0IF, INTIF,
RBIF, ADIF, RCIF, etc) siempre el código será dirigido a la misma ubicación. En
las familias 18 y los DSPIC existen varios vectores de interrupción.

Cuando sucede una interrupción algunos registros (STATUS y W) deben ser


guardados para evitar interferencia con el código en ejecución en el momento que
sucede la interrupción, el guardado de dichos registros es realizado por el
programador en ensamblador, en C el compilador se encarga de agregar este
proceso.

Mientras el microcontrolador se encuentra atendiendo una interrupción no puede


atender otra, cualquier interrupción generada durante este tiempo encenderá la
bandera y esperará a que la interrupción anterior sea procesada antes de procesar
la actual.

Control de interrupciones:

Las interrupciones son controladas por medio de registros, en dichos registros se


encuentran dos bits por cada interrupción, uno de ellos es la bandera de
interrupción (XXIF) el otro es el habilitador de interrupción (XXIE) el cual sirve para
que dicha interrupción efectivamente se dispare si esta activo, si esta inactivo solo
se encenderá la bandera.

Curso de Microcontroladores ndmunoz@elpoli.edu.co 2


Curso de Microcontroladores ndmunoz@elpoli.edu.co 3

Aparte de estos bits existe el bit GIE y el PEIE, el GIE (Habilitador global de
interrupción) debe estar en uno para habilitar las interrupciones, si esta en cero no
permite la interrupción sin importar el estado de los habilitadores individuales. El
PEIE habilita las interrupciones por periféricos.

En los micros de la familia 16F88X las interrupciones se dividen en varios


registros, en el INTCON encontramos los bits GIE, PEIE y los habilitadores y
banderas de las interrupciones por TMR0, interrupción externa y por cambio en
puerto B. El resto de las 14 interrupciones son interrupciones por periféricos (A/D,
CCP, USART, etc) y se manejan en los registros PIE1, PIE2 (Habilitadores) PIR1 y
PIR2 (Banderas), El bit PEIE habilita las interrupciones controladas por los
registros PIE1 y PIE2.

En esta practica trabajaremos con las interrupciones de internas y las del TMR0
por lo tanto trabajaremos el registro INTCON, más adelante se podra trabajar
algunos periféricos con sus respectivas interrupciones.

Registro INTCON:

GIE Habilitador global de interrupciones.


PEIE Habilitador de interrupciones periféricas
T0IE Habilitador interrupción Timer 0
INTE Habilitador interrupción externa
RBIE Habilitador interrupción por cambio
T0IF Bandera de desbordamiento de TMR0
INTF Bandera de interrupción externa
RBIF Bandera de interrupción por cambio en RB

Para todos los bits del registro anterior la lógica es positiva es decir, un uno
habilita y un cero deshabilita.

Rutina de interrupciones en C.: En el compilador PICC la interrupción se trabaja


como una subrutina que hace las veces de un vector de interrupción, dicha
subrutina se codifica de la siguiente manera:

void interrupt nombre(void)


{

//Código de la rutina
//de servicio a interrupción

Normalmente dentro de esta rutina primero se preguntará que tipo de interrupción


fue la causante observando las banderas de interrupción, luego se ejecutará el
código correspondiente y luego se limpiara la bandera.

Curso de Microcontroladores ndmunoz@elpoli.edu.co 3


Curso de Microcontroladores ndmunoz@elpoli.edu.co 4

VISUALIZACIÓN DE LOS DATOS:

El hardware a implementar seria como sigue:

Obsérvese en dicho diagrama que cada línea de selección maneja un display,


cuando dicha línea se encuentra en cero se produce el encendido de dicho display
según los segmentos indicados en las líneas de datos, si dicha línea se encuentra
en uno se apagarán todos los segmentos del display correspondiente. Es
necesario entonces realizar un refrescamiento continuo de dichos displays, se
enciende el primer display con el dato de las decenas, luego este se apaga y se
enciende el segundo display con el dato de las unidades y se repite este proceso a
una frecuencia suficientemente alta de modo que el ojo humano no pueda detectar
los continuos prende apaga de los display.

Paso previo a la visualización: Como puede notarse, para poder visualizar un dato
numérico con displays de siete segmentos, es necesario primero dividirlo en
dígitos (en nuestro caso solo unidades y decenas) para luego enviar cada dígito al
display correspondiente usando los códigos correspondientes.

Necesitamos entonces una función que nos permita realizar dicha separación, el
compilador nos presenta una función que permite realizar divisiones y obtener en

Curso de Microcontroladores ndmunoz@elpoli.edu.co 4


Curso de Microcontroladores ndmunoz@elpoli.edu.co 5

distintos registros el cociente y el residuo. Dicha función se denomina div y se


explicará a continuación.

La función div recibe dos argumentos tipo entero (int aunque también funciona
para char) y realiza su división computando su cociente y su residuo, el resultado
se obtiene de una variable tipo estructura que contiene tanto el residuo como el
cociente y debe ser leído de manera especial.

1. Definimos la variable tipo estructura que va a recibir el resultado, el tipo


de esta estructura (div_t) está definida al igual que la función div en la
librería stdlib.h la cual debemos incluir. Para definir la variable
recurrimos a la siguiente sintaxis: div_t nombre_variable; donde
estamos diciendo que la variable nombre_variable es tipo div_t.
2. Ahora procedemos invocar la función, lo realizamos mediante la
siguiente sintaxis:
nombre_variable=div(dividendo,divisor); Donde estamos diciendo que
realice la función div con los argumentos dividendo y divisor, y que el
resultado de dicha función lo reciba en la variable nombre_variable.
3. En nombre_variable tenemos entonces tanto el cociente como el residuo
en forma de estructura, para poder leer dicha estructura lo hacemos de
la siguiente forma:
nombre_variable.quot; Nos devuelve el cociente.
nombre_variable.rem; Nos devuelve el residuo.
Los valores devueltos pueden ser guardados en variables para ser
usados más adelante en el código.

Curso de Microcontroladores ndmunoz@elpoli.edu.co 5


6

6
VCC
ESQUEMA DE CONEXIONES:

R1
10k
ndmunoz@elpoli.edu.co

ndmunoz@elpoli.edu.co
GND U1 RN1
1 15 1 16
RE3/MCLR/VPP RC0/T1OSO/T1CKI
16 2 15
RC1/T1OSI/CCP2
2 17 3 14
RA0/AN0/ULPWU/C12IN0- RC2/P1A/CCP1
3 18 4 13
RA1/AN1/C12IN1- RC3/SCK/SCL
4 23 5 12
RA2/AN2/VREF-/CVREF/C2IN+ RC4/SDI/SDA
5 24 6 11
RA3/AN3/VREF+/C1IN+ RC5/SDO
6 25 7 10
RA4/T0CKI/C1OUT RC6/TX/CK
7 26 8 9
RA5/AN4/SS/C2OUT RC7/RX/DT
14
RA6/OSC2/CLKOUT
13 19 330
RA7/OSC1/CLKIN RD0
R2 RD1
20
10k 33 21
RB0/AN12/INT RD2
34 22
RB1/AN10/C12IN3- RD3
35 27
RB2/AN8 RD4

Curso de Microcontroladores
36 28
Curso de Microcontroladores

RB3/AN9/PGM/C12IN2- RD5/P1B
37 29
RB4/AN11 RD6/P1C
38 30
RB5/AN13/T1G RD7/P1D
39
RB6/ICSPCLK
40 8
RB7/ICSPDAT RE0/AN5
9
RE1/AN6
10
RE2/AN7
PIC16F887
R3
10k
Curso de Microcontroladores ndmunoz@elpoli.edu.co 7

CODIFICACIÓN:

A continuación se ilustra un código posible que ilustra lo dicho anteriormente,


dicho código puede realizarse de varias formas, al código mostrado falta agregarle
validaciones para mantener el contador en dos dígitos (0-99) se propone que cada
uno diseñe y agregue esta parte y lo implemente.
#include <pic.h>
#include <stdlib.h>
#include "delay.h"
#include "delay.c"

unsigned char contador=0, unidades=0, decenas=0, bandera=0;


//unsigned char display[10]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x98};

unsigned char display[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};

div_t cocienteresiduo;

void main(void)
{ ADCON1=6; //Desactivo entradas analogas

ANSEL=0x00;
ANSELH=0x00;

TRISC=0b10000000; //Puerto C como salidas (7 segmentos)


TRISB=0b11111001; //Puerto B como entrada(RB7,RB6) y salida(RB1 y 2 7seg)
INTCON=0b10110000; //Habilito iterrupciones
OPTION=0b11100000; //Configuración del TMR0 y la interrupción externa.
TMR0=255;
while(1)
{ if(bandera==1)
{ cocienteresiduo=div(contador,10); //Actualizo los valores de decenas y unidades
unidades=cocienteresiduo.rem; //solo si la bandera es 1.
decenas=cocienteresiduo.quot;
bandera=0; //Devuelvo la bandera a su valor por defecto.
}

PORTC=display[unidades]; //Envio unidades.


RB1=0; //Activo display de unidades.
RB2=1;
DelayMs(50); //Retardo de visualización.
PORTC=display[decenas]; //Envio las decenas.
RB2=0; //Activo display de decenas.
RB1=1;
DelayMs(50); //Retardo de visualización.
}
}

Curso de Microcontroladores ndmunoz@elpoli.edu.co 7


Curso de Microcontroladores ndmunoz@elpoli.edu.co 8

void interrupt RSI(void)


{
if(T0IF==1) //Me aseguro que sea interrupción por cambio de TMR0
{
T0IF=0;
if(contador==99)
contador=0;
contador++;
bandera=1;
TMR0=255;
}
if(INTF==1)
{
INTF=0;
if(contador==0)
contador=99;
contador--;
bandera=1;

Curso de Microcontroladores ndmunoz@elpoli.edu.co 8

También podría gustarte