ATmega16 – Timer 0

Con un timer podemos realizar aplicaciones como el control de velocidad de un motor, el manejo de un teclado, un barrido de 7 segmentos, obtención de muestras mediante el ADC, etc.

El funcionamiento general de un timer consiste en guardar en un registro especial de almacenamiento un valor máximo al que llegará un contador, cuando el valor en el contador sea igual al registro almacenado un comparador puede realizar las siguientes acciones:

  • Se activa el flag de salida del timer iniciando así una interrupción.
  • Programamos un evento en el cual en el pin de salida se conmuta el nivel anterior, es decir, se ponga a nivel bajo o se ponga a nivel alto y así generar una señal PWM a determinada frecuencia.

Esquema del Timer 0

Entre los bloques podemos destacar son:

  • El TCCRn que es el registro que configura el timer en su modo de funcionamiento.
  • Tn es por donde se inyecta la señal de reloj para el modo de contador de eventos externos.
  • OCn es el pin por el cual se genera la señal digital.

Características del Timer 0:

  • Timer de 8 bits.
  • Contador con una unidad de comparación.
  • Modo de borrado de contador en la igualdad de la comparación CTC (Auto-recarga).
  • Modulador de ancho de pulso (PWM) de fase correcta y libre de glitches (Pulsos cortos).
  • Generador de frecuencia.
  • Pre-escalador de 10 bits (permite dividir la frecuencia).
  • Dos fuentes de interrupción: desbordamiento e igualdad en la comparación (TOV0 y OCF0).

Los registros que intervienen para la configuración del timer 0 son:

TCCR0: Este registro es el encargado de la configuración del timer.

Estos bits configuran los cuatro diferentes modos de trabajo del timer.

Para cada modo de trabajo estos bits configuran el modo de generación de la señal digital.

Estos tres bits configuran en que valor de pre-escalamiento será dividido la frecuencia del oscilador.

TIMSK: En este registro habilitamos el modo en que se generará la interrupción.

OCIE0 es la habilitación de la interrupción por igualdad en la comparación de salida y TOIE0 es la habilitación de la interrupción por desbordamiento.

TIFR: En este registro se encuentran los flags de las interrupciones.

Para el cálculo de los valores de OCR0 adjunto un documento en excel en donde solo modificando los valores en “ROJO” es decir la frecuencia de salida, la frecuencia de las interrupciones y el valor del Xtal obtenemos el valor adecuado de OCR0.

Las fórmulas para dichos cálculos se encuentran definidas en el Datasheet del uC.

Hay que tener en cuenta que solo se puede tener control de la frecuencia de salida en el modo CTC, en los modos PWM las frecuencias ya están definidas.

Ejemplo:

// * Author: Victor Dueñas Guardia
// * Info: www.netzek.com
// @Ejemplo1 – Timer en Modo Normal:
// Este programa es usado como contador de eventos externos.
// – Cada vez que se produce desbordamiento se incrementa una variable.
// – Al activar la interrupción 0 se guarda el valor de TCNT0.
// Pseudocódigo:
// – Configuro el Timer 0 en Modo Normal.
// – Al producirse 256 conteos enciendo el LED e incremento una variable.
// – Al producir la interrupción externa INT0 capturo el valor del contador.
.INCLUDE "M16DEF.INC" //Incluye definicion archivos ATmega16
.ORG $00
JMP PROGRAMA //Interrupcion Reset
.ORG $02
JMP INTER0 //Interrupcion 0
.ORG $12
JMP TIMER0_COM //Timer0 Compare Match
PROGRAMA:
LDI R16,HIGH(RAMEND)
OUT SPH,R16
LDI R16,LOW(RAMEND)
OUT SPL,R16
LDI R16,$01
OUT DDRD,R16 //PD0 como salida
LDI R16,0B00000110
OUT TCCR0,R16 //Normal Port – Normal – Flanco de bajada
LDI R16,0B00000001
OUT TIMSK,R16
LDI R16,0B00000010
OUT MCUCR,R16 //INT0 Flanco de Bajada
LDI R16,0B01000000
OUT GICR,R16 //INT0 Habilitada
SEI
BUCLE: RJMP BUCLE
//……INTERRUPCIONES
INTER0:
CALL RETARDO
IN R17,TCNT0
RETI
TIMER0_COM:
INC R19
IN R16,PORTD
LDI R18,$01
EOR R16,R18
OUT PORTD,R16
RETI
//……PROCEDIMIENTOS
RETARDO:
LDI R25,31 //Configurado Evitar Rebote
Bucle_Externo:
LDI R24,255
Bucle_Interno:
NOP
NOP
NOP
NOP
NOP
NOP
NOP
DEC R24
BRNE Bucle_Interno
DEC R25
BRNE Bucle_Externo
RET
view raw Timer0NM.asm hosted with ❤ by GitHub
/*
* Timer0NM.c
*
* Author: Victor Dueñas Guardia
* Info: www.netzek.com
@Ejemplo1 – Timer en Modo Normal:
Este programa es usado como contador de eventos externos.
– Cada vez que se produce desbordamiento se incrementa una variable.
– Al activar la interrupción 0 se guarda el valor de TCNT0.
Pseudocódigo:
– Configuro el Timer 0 en Modo Normal.
– Al producirse 256 conteos enciendo el LED e incremento una variable.
– Al producir la interrupción externa INT0 capturo el valor del contador.
*/
#include <avr/io.h>
//Incluyo las definiciones del ATmega16
#include <avr/interrupt.h>
//Incluyo las definiciones de las Interrupciones
#include "mdelay.h"
//Incluyo las definiciones de retardo
volatile unsigned char v_tcnt;
//Variables reservadas para lectura de registros en interrupciones
unsigned char contador;
//Variables temporales
//__INTERRUPCIONES
ISR(INT0_vect)
{
_delay_ms(300);
//Delay para evitar efecto rebote
v_tcnt=TCNT0;
//Guardo el valor de TCNT0 en la variable "v_tcnt"
}
ISR(TIMER0_OVF_vect)
{
contador++;
PORTD=PIND^0x01;
//Cambio el estado del LED
}
//__PROGRAMA PRINCIPAL
int main(void)
{
DDRD |= (1<<PD0);
//PD0 como salida
TCCR0 |= (1<<CS02) | (1<<CS01);
//Normal Port – Fuente externa de reloj en TO y en Flanco de Bajada
TIMSK |= (1<<TOIE0);
//Habilito Interrupción por desbordamiento
MCUCR |= (1<<ISC01);
//INT0 Flanco de Bajada
GICR |= (1<<INT0)
//INT0 Habilitada
sei();
//Interrupciones habilitadas
while (1)
{
}
}
view raw Timer0NM.c hosted with ❤ by GitHub

Ejemplo:

// * Author: Victor Dueñas Guardia
// * Info: www.netzek.com
// @Ejemplo2 – Timer en modo CTC:
// Este programa genera en OC0 una señal periódica de 5ms de nivel alto
// y 2ms de nivel bajo al presionar el pulsador.
// Pseudocódigo:
// – Al activar la interrupción externa configuro el timer en modo CTC.
// – Cada vez que se produce interrupción en el timer se cambia el valor de OCR.
.INCLUDE "M16DEF.INC" //Incluye definición archivos ATmega16
.EQU OCR_2ms=15
.EQU OCR_5ms=38
.ORG $00
JMP PROGRAMA //Interrupción Reset
.ORG $02
JMP INTER0 //Interrupcion 0
.ORG $26
JMP TIMER0 //Interrupcion Timer 0
PROGRAMA:
LDI R16,HIGH(RAMEND)
OUT SPH,R16
LDI R16,LOW(RAMEND)
OUT SPL,R16
LDI R16,0B00000010
OUT MCUCR,R16 //INT0 Flanco de Bajada
LDI R16,0B01000000
OUT GICR,R16 //INT0 Habilitada
LDI R17,$01
SEI
BUCLE: RJMP BUCLE
;…….INTERRUPCIONES
INTER0:
CALL RETARDO
LDI R16,0B00001000
OUT DDRB,R16 //Habilito salida OC0
LDI R16,0B00011101
OUT TCCR0,R16 //Toggle OC0 – CTC – CLK/1024
LDI R16,0B00000010
OUT TIMSK,R16 //Habilito OC0 por Igualdad en Comparacion
RETI
TIMER0:
EOR R0,R17 //Con cada EOR cambia el valor OCR
BREQ Escero
LDI R16,OCR_5ms
OUT OCR0,R16
RJMP Salida
Escero:
LDI R16,OCR_2ms
OUT OCR0,R16
Salida:
RETI
//……PROCEDIMIENTOS
RETARDO:
LDI R25,31 //Configurado Evitar Rebote
Bucle_Externo:
LDI R24,255
Bucle_Interno:
NOP
NOP
NOP
NOP
NOP
NOP
NOP
DEC R24
BRNE Bucle_Interno
DEC R25
BRNE Bucle_Externo
RET
view raw Timer0CTC.asm hosted with ❤ by GitHub
/*
* Timer0CTC.c
*
* Author: Victor Dueñas Guardia
* Info: www.netzek.com
@Ejemplo2 – Timer en modo CTC:
Este programa genera en OC0 una señal periódica de 5ms de nivel alto
y 2ms de nivel bajo al presionar el pulsador.
Pseudocódigo:
– Al activar la interrupción externa configuro el timer en modo CTC.
– Cada vez que se produce interrupción en el timer se cambia el valor de OCR.
*/
#include <avr/io.h>
//Incluyo las definiciones del ATmega16
#include <avr/interrupt.h>
//Incluyo las definiciones de las Interrupciones
#include "mdelay.h"
//Incluyo las definiciones de retardo
unsigned char temporal;
//__INTERRUPCIONES
ISR(INT0_vect)
{
_delay_ms(300);
//Delay para evitar efecto rebote
TCCR0 |= (1<<COM00) | (1<<WGM01) | (1<<CS02) | (1<<CS00);
//Toggle OC0 – CTC – CLK/1024
TIMSK |= (1<<OCIE0)
//Habilito Interrupción Compare Match
}
ISR(TIMER0_COMP_vect)
{
temporal =~ temporal;
if (temporal == 0)
OCR0 = 38;
else
OCR0 = 15;
}
//__PROGRAMA PRINCIPAL
int main(void)
{
DDRB |= (1<<PB3)
//PB3 como salida
MCUCR |= (1<<ISC01);
//INT0 Flanco de Bajada
GICR |= (1<<INT0);
//INT0 Habilitada
sei();
//Interrupciones habilitadas
while (1)
{
}
}
view raw Timer0CTC.c hosted with ❤ by GitHub

Ejemplo:

// * Author: Victor Dueñas Guardia
// * Info: www.netzek.com
// @Ejemplo3 – Timer en Fast PWM:
// Este programa genera en OC0 una señal periódica, cada vez que se presiona un pulsador aumenta
// el ciclo de trabajo y al presionar el otro pulsador disminuye el ciclo de trabajo.
// Pseudocódigo:
// – Configuro al timer en modo Fast PWM.
// – Cada vez que se inicia una interrupción externa se aumenta o disminuye el valor de OCR.
.INCLUDE "M16DEF.INC" //Incluye definicion archivos ATmega16
.EQU OCR_INICIAL=128
.ORG $00
JMP PROGRAMA //Interrupcion Reset
.ORG $02
JMP INTER0 //Interrupcion 0
.ORG $04
JMP INTER1 //Interrupcion 1
PROGRAMA:
LDI R16,HIGH(RAMEND)
OUT SPH,R16
LDI R16,LOW(RAMEND)
OUT SPL,R16
LDI R16,0B00001000
OUT DDRB,R16 //Habilito salida OC0
LDI R17,OCR_INICIAL
OUT OCR0,R17 //Coloco la señal al 50% ciclo de trabajo
LDI R16,0B01101101
OUT TCCR0,R16 //No invertido OC0 – Fast PWM – CLK/1024
LDI R16,0B00001010
OUT MCUCR,R16 //INT0 e INT1 Flanco de Bajada
LDI R16,0B11000000
OUT GICR,R16 //INT0 e INT1 Habilitada
SEI
BUCLE: RJMP BUCLE
//……INTERRUPCIONES
INTER0:
CALL RETARDO
CPI R17,0
BREQ Salir0
DEC R17
OUT OCR0,R17
Salir0:
RETI
INTER1:
CALL RETARDO
CPI R17,255
BREQ Salir1
INC R17
OUT OCR0,R17
Salir1:
RETI
//……PROCEDIMIENTOS
RETARDO: //Configurado Evitar Rebote
LDI R25,31
Bucle_Externo:
LDI R24,255
Bucle_Interno:
NOP
NOP
NOP
NOP
NOP
NOP
NOP
DEC R24
BRNE Bucle_Interno
DEC R25
BRNE Bucle_Externo
RET
/*
* Timer0FastPWM.c
*
* Author: Victor Dueñas Guardia
* Info: www.netzek.com
@Ejemplo3 – Timer en Fast PWM:
Este programa genera en OC0 una señal periódica, cada vez que se presiona un pulsador aumenta
el ciclo de trabajo y al presionar el otro pulsador disminuye el ciclo de trabajo.
Pseudocódigo:
– Configuro al timer en modo Fast PWM.
– Cada vez que se inicia una interrupción externa se aumenta o disminuye el valor de OCR.
*/
#include <avr/io.h>
//Incluyo las definiciones del ATmega16
#include <avr/interrupt.h>
//Incluyo las definiciones de las Interrupciones
#include "mdelay.h"
//Incluyo las definiciones de retardo
//__INTERRUPCIONES
ISR(INT0_vect)
{
_delay_ms(300);
//Delay para evitar efecto rebote
if(OCR0 == 0)
OCR0;
else
OCR0–;
}
ISR(INT1_vect)
{
_delay_ms(300);
//Delay para evitar efecto rebote
if(OCR0 == 255)
OCR0;
else
OCR0++;
}
//__PROGRAMA PRINCIPAL
int main(void)
{
DDRB |= (1<<PB3);
//PB3 como salida
MCUCR |= (1<<ISC11) | (1<<ISC01);
//INT0 e INT1 Flanco de Bajada
GICR |= (1<<INT1) | (1<<INT0);
//INT0 e INT1 Habilitada
TCCR0 |= (1<<WGM00) | (1<<COM01) | (1<<WGM01) | (1<<CS02) | (1<<CS00);
//No invertido OC0 – Fast PWM – CLK/1024
OCR0 = 128;
//50% de ciclo de trabajo
sei();
//Interrupciones habilitadas
while (1)
{
}
}

Ejemplo:

// * Author: Victor Dueñas Guardia
// * Info: www.netzek.com
// @Ejemplo4 – Timer en PWM Correcta:
// Este programa genera en OC0 una señal periódica, cada vez que se presiona
// un pulsador, aumenta el ciclo de trabajo, y al presionar el otro pulsador
// disminuye el ciclo de trabajo.
// Pseudocódigo:
// – Configuro al timer en modo PWM Correcta.
// – Cada vez que se inicia una interrupción externa se aumenta o disminuye el valor de OCR.
.INCLUDE "M16DEF.INC" //Incluye definición archivos ATmega16
.EQU OCR_INICIAL=128
.ORG $00
JMP PROGRAMA //Interrupción Reset
.ORG $02
JMP INTER0 //Interrupción 0
.ORG $04
JMP INTER1 //Interrupción 1
PROGRAMA:
LDI R16,HIGH(RAMEND)
OUT SPH,R16
LDI R16,LOW(RAMEND)
OUT SPL,R16
LDI R16,0B00001000
OUT DDRB,R16 //Habilito salida OC0
LDI R17,OCR_INICIAL
OUT OCR0,R17 //Coloco la señal al 50% ciclo de trabajo
LDI R16,0B01100101
OUT TCCR0,R16 //No invertido OC0 – PWM Correcta – CLK/1024
LDI R16,0B00001010
OUT MCUCR,R16 //INT0 e INT1 Flanco de Bajada
LDI R16,0B11000000
OUT GICR,R16 //INT0 e INT1 Habilitada
SEI
BUCLE: RJMP BUCLE
//……INTERRUPCIONES
INTER0:
CALL RETARDO
CPI R17,0
BREQ Salir0
DEC R17
OUT OCR0,R17
Salir0:
RETI
INTER1:
CALL RETARDO
CPI R17,255
BREQ Salir1
INC R17
OUT OCR0,R17
Salir1:
RETI
//……PROCEDIMIENTOS
RETARDO: //Configurado Evitar Rebote
LDI R25,31
Bucle_Externo:
LDI R24,255
Bucle_Interno:
NOP
NOP
NOP
NOP
NOP
NOP
NOP
DEC R24
BRNE Bucle_Interno
DEC R25
BRNE Bucle_Externo
RET
/*
* Timer0PWMCorrecta.c
*
* Author: Victor Dueñas Guardia
* Info: www.netzek.com
@Ejemplo4 – Timer en PWM Correcta:
Este programa genera en OC0 una señal periódica, cada vez que se presiona
un pulsador, aumenta el ciclo de trabajo, y al presionar el otro pulsador
disminuye el ciclo de trabajo.
Pseudocódigo:
– Configuro al timer en modo PWM Correcta.
– Cada vez que se inicia una interrupción externa se aumenta o disminuye el valor de OCR.
*/
#include <avr/io.h>
//Incluyo las definiciones del ATmega16
#include <avr/interrupt.h>
//Incluyo las definiciones de las Interrupciones
#include "mdelay.h"
//Incluyo las definiciones de retardo
//__INTERRUPCIONES
ISR(INT0_vect)
{
_delay_ms(300);
//Delay para evitar efecto rebote
if(OCR0 == 0)
OCR0;
else
OCR0–;
}
ISR(INT1_vect)
{
_delay_ms(300);
if(OCR0 == 255)
OCR0;
else
OCR0++;
}
//__PROGRAMA PRINCIPAL
int main(void)
{
DDRB |= (1<<PB3);
//PB3 como salida
MCUCR |= (1<<ISC11) | (1<<ISC01);
//INT0 e INT1 Flanco de Bajada
GICR |= (1<<INT1) | (1<<INT0);
//INT0 e INT1 Habilitada
TCCR0 |= (1<<WGM00) | (1<<COM01) | (1<<CS02) | (1<<CS00);
//No invertido OC0 – PWM Correcta – CLK/1024
OCR0 = 128;
//50% de ciclo de trabajo
sei();
//Interrupciones habilitadas
while (1)
{
}
}

Descargas: