Click here to load reader
Upload
rickypina
View
240
Download
4
Embed Size (px)
Citation preview
PROGRAMACIÓN DEL TEMPORIZADOR COMO CONTADOR DE EVENTOS En la sección anterior, hemos utilizado los temporizadores del AVR para generar
retardos de tiempo. El temporizador del AVR también puede ser usado para contar,
detectar y medir el tiempo de los acontecimientos que suceden fuera del AVR
Cuando el temporizador se utiliza como un contador de tiempo, la frecuencia del
cristal del AVR se usa como fuente de reloj. Cuando se utiliza como un contador, sin
embargo, se trata de una salida de impulsos del lado del AVR que incrementa el
registro TCNTx. Observe que, en el modo de contador, los registros TCCR, OCR0, y
TCNT son los mismos que para el temporizador discutido en la sección anterior.
Los bits CS00, CS01, and CS02 en el registr0 TCCR0 Recuerde que en la sección anterior que los bits de CS (clock selector) en el registro
TCCR0 sirven para seleccionar la fuente de para el temporizador. If CS02:CS00 está
entre 1 y 5, el temporizador recibe impulsos del oscilador de cristal. En contraste,
cuando CS02:CS00 es 6 o 7, el temporizador se utiliza como un contador de impulsos y
obtiene los pulsos desde una fuente externa al chip AVR. Vea la Figura.
Por lo tanto, cuando CS02:CS00 es 6 o 7, el registro contador TCNT0 incrementa su
cuenta cuando los pulsos se alimentan por el pin T0 (entrada externa del reloj del
Timer / Contador 0).
Ejemplo
Encuentra el valor de TCCR0 si queremos programar Timer 0 como contador en modo
Normal. Utiliza un reloj externo para la fuente de reloj y el incremento es con el flanco
positivo.
Solución:
TCCR0 = 0000 0111 Normal; fuente de reloj externa, no prescaler
T0 es un pin de función alternativa de PORTB bit 0.En el caso del Timer 0, cuando
CS02:CS00 es 6 o 7, el pin T0 proporciona el pulso de reloj y el contador cuenta hacia
arriba después de cada pulso de reloj procedente de pin, para el Timer 1, cuando CS12:
10 es 6 o 7, el pulso de reloj viene por el pin T1 (entrada de reloj externa del Timer /
Contador 1) hace que el contador TCNT1 incremente. Cuando CS12:CS10 es 6, el
contador cuenta hacia arriba en el flanco negativo. Cuando CS12:CS10 es 7, el
contador cuenta hacia arriba en el flanco positivo. T1 es un pin de función alternativa
de PORTB bit 1.
Ejemplo
Suponiendo que un pulso de reloj de 1 Hz se alimenta en el pin T0 (PD4), escriba un
programa para que Contador 0 cuente en el modo normal contando los pulsos en el
flanco descendente y mostrar el estado de la cuenta TCNT0 en PORTC.
#include <avr\io.h>
int main () {
PORTD|=(1<<PD4); //Pullup activada
DDRC = 0xFF; //PORTC como salida
TCCR0 = 0x6; //Timer 0, contador, flanco bajada
while (1) {
PORTC = TCNT0;
if((TIFR&(1<<TOV0))==1)//desbordamiento
TIFR |=(1<<TOV0); //Borra el indicador
}//repite por siempre
}
En el Ejemplo de arriba, estamos utilizando Timer 0 como un contador de eventos que
cuenta los pulsos de reloj que se alimentan en PD4. Estos pulsos de reloj podría
representar el número de personas que pasan a través de una entrada, o de rotaciones
de una rueda, o cualquier otro evento que se puede convertir en pulsos.
Los datos de TCNT0 se muestran en binario.
Antes de terminar esta sección, es necesario establecer un punto importante. Se
podría pensar que monitorear las banderas TOV y OCR el microcontrolador pierde
tiempo. Eso es cierto pero hay una solución para esto: el uso de las interrupciones.
Usando interrupciones nos permite hacer otras tareas con el microcontrolador.
Ejemplo
Supongamos que un reloj externo de 1hz se alimenta en el pin T1 (PD5). Escriba un
programa en C para que el contador 1 con flanco ascendente se incremente para
contar los pulsos y mostrar los registros TCNT1H y TCNT1L en PORTB y PORTC,
respectivamente.
Solución:
#include "avr/io.h"
int main () {
PORTD |= (1<<PD5); //activa pull-up de PD5 = T1
DDRC = 0xFF; //PORTC salida
DDRB = 0xFF; //PORTB salida
TCCR1A = 0x00; //Fuente de reloj configurada
TCCR1B = 0x06; //como contador con flanco desendente
TCNT1H = 0x00; //Inicia en cero
TCNT1L = 0x00; //Inicia en cero
while (1) {
do {
PORTC = TCNT1L;
PORTB = TCNT1H; //escribe el valor en los puertos
}while ((TIFR&(1<<TOV1))==0);//espera desbordamiento
TIFR |=(1<<TOV1); //Borra el indicador
}
}
PROGRAMACIÓN DE INTERRUPCIONES DEL TEMPORIZADOR
Desbordamiento del temporizador y bandera de interrupción La bandera de desbordamiento del temporizador se pone a uno cuando el
temporizador se desborda, vimos cómo monitorear la bandera del temporizador. En el
monitoreo de TOV0, tenemos que esperar hasta TOV0 sea uno. El problema con este
método es que el microcontrolador tiene que esperar hasta que TOV0 se coloque a
uno, y no se puede hacer nada más. Usando las interrupciones evitamos atar al
microcontrolador en este tiempo. Si la interrupción del temporizador está habilitada
en el registro de interrupción, TOV0 se pone a uno cada vez que el temporizador se
desborda y el microcontrolador salta a la tabla de vectores de interrupción para dar
servicio a la ISR. De esta manera, el microcontrolador puede hacer otras cosas hasta
que sea notificado de que el temporizador se ha desbordado. Para utilizar una
interrupción en lugar de un monitoreo constante de TOV, primero debemos activar la
interrupción porque todas las interrupciones están enmascaradas en el reset. El bit
TOIEx permite la interrupción para un temporizador determinado. Los bits TOIEx están
en el registro TIMSK como se muestra en la Tabla.
Bits bandera de interrupción de temporizador y registros asociados
Interrupción Bandera Registro Bit Habilitación Registro Timer 0 TOV0 TIFR TOIE0 TIMSK Timer 1 TOV1 TIFR TOlE1 TIMSK Timer 2 TOV2 TIFR TOIE2 TIMSK
Ejemplo
Uso del Timer 0 para generar una onda cuadrada en el pin PORTB bit 1, mientras que al
mismo tiempo transfiere datos del PORTC a PORTD.
#include "avr/io.h"
#include "avr/interrupt.h"
int main (){
DDRB |= 0x02;//DDRB 1 = output
TCNT0= -32; //valor del timer para 4uS
TCCR0 =0x01; //Normal mode, int clk, no prescaler
TIMSK=(1<<TOIE0) ; //enable TimerO overflow interrupt
sei (); //enable interrupts
DDRC= 0x00; //make PORTC input
DDRD=0xFF; //make PORTD output
while (1) PORTD=PINC; //wait here
}
ISR(TIMER0_OVF_vect) { //ISR for TimerO overflow
TCNT0 = -32;
PORTB ^= 0x2;
}
Ejemplo
Usando las interrupciones Timer 0 y Timer 1 y cristal de 8Mhz, escriba un programa en
el que:
(a) PORTC se incrementa cada vez que el Timer 1 se desborda una vez por segundo.
(b) Un pulso se alimenta al Timer 0 y se usa como contador. Cada vez que el contador
llegue a 200 se cambiará el estado del pin PORTB bit 4.
Solución:
Para preescalar = 256 tenemos TClock= (1/ 8 MHz) x 256 = 32 uS y 1 s/32 us = 31250. De
manera que TCNT1 = 31250 = 0x7A12
#include "avr/io.h"
#include "avr/interrupt.h"
int main (){
DDRB |= 0x10;//DDRB 4 = salida
PORTB |= 0x10;// activa pullup
TCNT0= -200; //carga el TimerO con -200
TCNT1H=(-31250) >>8; //byte alto para Timer 1
TCNT1L = (-31250)&0xFF;//se desborda despues de 31250 pulsos
TCCR1A= 0x00; //modo Normal
TCCR1B= 0x04; //,reloj interno, prescaler 1:256
TCCR0 =0x06; //Modo Normal , flanco descendente, no prescaler
TIMSK=(1<<TOIE0)|(1<<TOIE1) ; //habilta las interrupciones del TimerO y del
Timer 1
sei (); //habilita todas las interrupciones
PORTD|=(1<<PD2); //Pullup activada
DDRC=0xFF; // PORTC como salida
while (1) ; //wait here
}
ISR(SIG_OVERFLOW0) { //ISR para TimerO
TCNT0 = -200;
PORTB ^= 0x10;
}
ISR (SIG_OVERFLOW1) {//ISR para Timer1
TCNT1H=(-31250) >>8; //byte alto para Timer 1
TCNT1L = (-31250)&0xFF;//se desborda despues de 31250 pulsos
PORTC ++; //incrementa PORTC
}