Está en la página 1de 58

INSTITUTO TECNOLGICO DE MORELIA

CURSO AVANZADO DE
PROGRAMACIN EN C DE
MICROCONTROLADORES AVR

POR DAVID INFANTE SNCHEZ

dinfante29@hotmail.com
dinfante@itmorelia.edu.mx

Revisin 8.0
Septiembre del 2008
Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez
e-mail: dinfante29@hotmail.com www.comunidadatmel.com
CAPTULO III. TPICOS AVANZADOS
3.1 Manejo de las Interrupciones INT0 e INT1

Una interrupcin, como su nombre lo indica, interrumpe el programa principal y ejecuta


una subrutina de interrupcin donde se ejecuta el cdigo que el programador desea, el
ejemplo mas representativo es el RESET de una PC cuando se presiona ese botn se
interrumpe el programa principal y vuelve a iniciar el programa.

Existen dos tipos de interrupcin las internas o de software y las externas o de hardware,
por ejemplo la de reset es una externa ya que est asociada a una terminal. Las de software
son generadas por alguna condicin en los perifricos, por ejemplo podemos habilitar una
interrupcin cuando el ADC termine de hacer la conversin, o cuando suceda overflow en
el timer, etc.

El programa CodeVision en la parte de la configuracin del chip se hace la configuracin


de la interrupcin ah se habilita la interrupcin y se programa la forma en que funcionar
la interrupcin, y el CodeVision generar una subrutina de interrupcin para esa
interrupcin en particular.

Por ejemplo hay interrupciones que son por flanco de bajada en un pin, entonces, suceder
una interrupcin cuando haya un flanco de bajada en el pin. Las subrutinas de interrupcin
son como las funciones que hemos realizado, con la excepcin de que las subrutinas de
interrupcin SON LLAMADAS POR HARDWARE, es decir el microcontrolador llama a
la subrutina de interrupcin cuando el evento sucede y que puede ser en cualquier
momento, en cambio las funciones que define el usuario son llamadas por el software segn
donde haya escrito el programador el llamado de la funcin.

Figura 3.1 Ubicacin de las interrupciones externas

En la figura 3.1 apreciamos las interrupciones externas INT0 e INT1 que estn en los pines
4 y 5 del microcontrolador. Estas interrupciones las podemos configurar para que cuando
exista un 0 (low level) se genere una interrupcin, si cuando salga de la interrupcin sigue

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
estando en 0 el pin volver a saltar a la interrupcin. Los otros modos de configurar esas
interrupciones es por flanco de subida (rising edge) o por flanco de bajada (falling edge) o
ambos flancos (any change).

Si se habilita la interrupcin externa INT0 el codevision generar la siguiente subrutina, si


se configura que la INT0 funcione en flanco de bajada, cada vez que en ese pin exista un
cambio de 1 a 0 saltar a esta interrupcin donde el programador deber colocar el cdigo
que deber ejecutarse en ese evento.

//External Interrupt 0 service routine


interrupt [EXT_INT0] void ext_int0_isr(void)
{
// Place your code here
}

Si se habilita la interrupcin externa INT1 el codevision generar la siguiente subrutina.

// External Interrupt 1 service routine


interrupt [EXT_INT1] void ext_int1_isr(void)
{
// Place your code here
}

Importante. Vimos que la INT0 e INT1 son los pines 4 y 5, y que a su vez son los puertos
D2 y D3; as que si habilitamos las funciones de interrupcin INT0 y la INT1, debemos
seleccionar esos pines para que sean de entrada; no debemos habilitarlos como salida
porque ahora ya no funcionan como pines de entrada/salida sino como pines de entrada
donde detectarn un evento (flanco de bajada, subido, ambos o nivel 0 lgico) y en ese
momento saltar a la subrutina de interrupcin.

Para probar las interrupciones de INT0 e INT1 se realizarn algunos programas para
entender su funcionamiento.

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
Programa 11. Disee un programa que cada vez que haya un flanco de bajada en la INT0
(pin 4) incremente el valor de un display conectado al puerto B, el cual podr contar de 0 a
9.
Configuracin: PORTB de salida, Pin D2 de entrada con resistencia de pull-up interna
activada y la INT0 que est asociada a ese pin D2 activada y funcionando para generar
interrupcin al detectar cambios de flanco de 1 a 0, es decir de bajada.

Figura 3.2 Conexin para el programa 11


/*****************************************************
This program was produced by the
CodeWizardAVR V2.03.6 Evaluation
Automatic Program Generator
Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :
Version :
Date : 16/09/2008
Author : Freeware, for evaluation and non-commercial use only
Company :
Comments:

Chip type : ATmega48


Clock frequency : 1,000000 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 128
*****************************************************/

#include <mega48.h>

const char tabla7segmentos [10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7c,0x07,0x7f,0x6f};


unsigned char var;

// External Interrupt 0 service routine


interrupt [EXT_INT0] void ext_int0_isr(void)
{

var++;
if (var>9)
var=0;
// Place your code here

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
// Declare your global variables here

void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 8


#pragma optsize-
CLKPR=0x80;
CLKPR=0x03;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization


// Port B initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTB=0x00;
DDRB=0xFF;

// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0x00;
DDRC=0x00;

// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=P State1=T State0=T
PORTD=0x04;
DDRD=0x00;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;

// External Interrupt(s) initialization


// INT0: On
// INT0 Mode: Falling Edge
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x02;
EIMSK=0x01;
EIFR=0x01;
PCICR=0x00;

// Timer/Counter 0 Interrupt(s) initialization


TIMSK0=0x00;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x00;

// Analog Comparator initialization


// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;

// Global enable interrupts


#asm("sei")

while (1)
{

PORTB=tabla7segmentos [var];
// Place your code here

};
}
Cuando programe el microcontrolador y conecte el microcontrolador notar que cuando se
presiona el interruptor el display se incrementa en varias unidades y es por la razn de los
rebotes que se generan y que se explicaron en los primeros programas del curso.

Programa 12. Disee un programa que cada vez que haya un flanco de subida o bajada en
la INT1 (pin 5) incremente el valor de un display conectado al puerto B, el cual podr
contar de 0 a 9.

Configuracin: PORTB de salidas, PIN D3 de entrada con resistencia de pull-up interna


activada y la INT1 que est asociada al pin D3 configurado est habilitada y funcionando
para que genere interrupcin en cambio de flanco de 1 a 0 y de 0 a 1.

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
Figura 3.3 Conexiones para el programa 12
/*****************************************************
This program was produced by the
CodeWizardAVR V2.03.6 Evaluation
Automatic Program Generator
Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :
Version :
Date : 16/09/2008
Author : Freeware, for evaluation and non-commercial use only
Company :
Comments:

Chip type : ATmega48


Clock frequency : 1,000000 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 128
*****************************************************/

#include <mega48.h>
const char tabla7segmentos [10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7c,0x07,0x7f,0x6f};
unsigned char var;

// External Interrupt 1 service routine


interrupt [EXT_INT1] void ext_int1_isr(void)
{
// Place your code here
var++;
if (var>9)
var=0;

// Declare your global variables here

void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 8


#pragma optsize-
CLKPR=0x80;
CLKPR=0x03;
#ifdef _OPTIMIZE_SIZE_

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
#pragma optsize+
#endif

// Input/Output Ports initialization


// Port B initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTB=0x00;
DDRB=0xFF;

// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0x00;
DDRC=0x00;

// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=P State2=T State1=T State0=T
PORTD=0x08;
DDRD=0x00;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
// External Interrupt(s) initialization
// INT0: Off
// INT1: On
// INT1 Mode: Any change
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x04;
EIMSK=0x02;
EIFR=0x02;
PCICR=0x00;

// Timer/Counter 0 Interrupt(s) initialization


TIMSK0=0x00;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x00;

// Analog Comparator initialization


// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;

// Global enable interrupts


#asm("sei")

while (1)
{

PORTB=tabla7segmentos [var];
// Place your code here

};
}

Programa 14. Disee un programa que cuando haya un flanco de subida en INT0 se
incremente el conteo del display que podra contar de 0 a 9, y que cuando haya un nivel
lgico de 0 en INT1 se decremente el valor del display.

3.2 Interrupciones externas PCINT0-PCINT23

Adems de las interrupciones INT0 e INT1 existen otras interrupciones externas


denominadas PCINTX (Pin Change Interrupt) que son 24 interrupciones desde PCINT0 a
PCINT23, pero existen dos diferencias con respecto a las de INT0 e INT1 que son:

1. Las interrupciones PCINTX se activan unicamente en cambios de nivel, es decir


cuando el pin cambia de 1 a 0 y de 0 a 1. No pueden configurarse en ninguna otra
opcin como las INT0 e INT1 que pueden configurarse para funcionar en flanco de
subida, bajada, en ambos o nivel lgico 0.
2. Las interrupciones PCINTX solo tienen tres subrutinas de interrupcin.

Cualquier interrupcin generada de PCINT0 a PCINT7 ejecutar la siguiente subrutina de


interrupcin.

// Pin change 0-7 interrupt service routine


Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez
e-mail: dinfante29@hotmail.com www.comunidadatmel.com
interrupt [PCINT0] void pin_change_isr0(void)
{
// Place your code here
}

Cualquier interrupcin generada de PCINT8 a PCINT14 ejecutar la siguiente subrutina de


interrupcin.

// Pin change 8-14 interrupt service routine


interrupt [PCINT1] void pin_change_isr1(void)
{
// Place your code here
}

Cualquier interrupcin generada de PCINT16 a PCINT23 ejecutar la siguiente subrutina


de interrupcin.

// Pin change 16-23 interrupt service routine


interrupt [PCINT2] void pin_change_isr2(void)
{
// Place your code here
}

Tomando como ejemplo esta ltima subrutina de interrupcin indica que cualquier
interrupcin generada de PCINT16 a PCINT23 ejecutar esa subrutina, pero no
necesariamente cuanda haya un cambio de nivel de 0 a 1 y de 1 a 0 en esos pines ejecutar
esa subrutina ya que podemos por el codevision habilitar solamente, por dar un ejemplo,
que se habiliten las interrupciones en PCINT16 y PCINT20. En este caso solamente cuando
haya cambio de nivel en esos pines se ejecutar la subrutina de interrupcin, es decir, que
podemos habilitar de manera individual cada pin.

En la figura 3.2 vemos que habilitamos la interrupcin de PCINT0-PCINT7, pero de todas


ellas indicamos que slo la PCINT1 y la PCINT5 generar la interrupcin.

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
Figura 3.2 Habilitacin de las interrupciones PCINT1 y PCINT5

Para probar estas interrupciones realizaremos el siguiente programa

Programa 14. Cuando exista cambio de nivel en PCINT0 o en PCINT7 que se incremente el
valor de un contador de 0 a 9 que se mostrar en un display conectado al puerto B, cuando
exista un cambio de nivel en PCINT8, PCINT9 o PCINT10 se decrementar el valor del
conteo y cuando exista
Por ejemplo, veamos un programa en el cual se desea detectar cada vez que haya un flanco
de bajada en el PIN 18 que es INT1 se incremente un contador BCD que estar conectado
al puerto B.

El pin 18 que es el pin A2 tiene como funcin alterna la de interrupcin externa INT1, lo
vamos a configurar como fuente de interrupcin para detectar flancos de bajada en el pin y
que se contabilice en un display conectado al puerto B.

Configuracin: Activacin de la Interrupcin externa INT1 (y por lo tanto el pin A2 de


entrada), pines B0 a B6 de salida que es donde se conectar el display.

Vea el video_P9 donde se muestra la forma de configurar el microcontrolador.


/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.7a Evaluation
Automatic Program Generator
Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :
Version :
Date : 04/05/2008

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
Author : Freeware, for evaluation and non-commercial use only
Company :
Comments:

Chip type : ATtiny461


Clock frequency : 1,000000 MHz
Memory model : Tiny
External SRAM size : 0
Data Stack size : 64
*****************************************************/

#include <tiny461.h>

unsigned char conteo;


const char tabla7segmentos [10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7c,0x07,0x7f,0x6f};
#define tra_u PINA.1
#define tra_d PINA.0

// External Interrupt 1 service routine


interrupt [EXT_INT1] void ext_int1_isr(void)
{ //Esta es la subrutina de interrupcin INT1
conteo++; //Note que no hay ninguna funcin que la llame
if (conteo==10) //Es porque la llama el hardware al detectar un flanco
conteo=0; //de bajada
// Place your code here

// Declare your global variables here

void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 1


#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization


// Port A initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTA=0x00;
DDRA=0x00;

// Port B initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTB=0x00;
DDRB=0xFF;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: 8bit top=FFh
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0H=0x00;
TCNT0L=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 1 initialization

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=OCR1C
// OC1A output: Discon.
// OC1B output: Discon.
// OC1C output: Discon.
// Fault Protection Mode: Off
// Fault Protection Noise Canceler: Off
// Fault Protection triggered on Falling Edge
// Fault Protection triggered by the Analog Comparator: Off
// Timer 1 Overflow Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
// Compare D Match Interrupt: Off
// Fault Protection Interrupt: Off
PLLCSR=0x00;
TCCR1A=0x00;
TCCR1B=0x00;
TCCR1C=0x00;
TCCR1D=0x00;
TCCR1E=0x00;
TC1H=0x00;
TCNT1=0x00;
OCR1A=0x00;
OCR1B=0x00;
OCR1C=0x00;
OCR1D=0x00;
DT1=0x00;

// External Interrupt(s) initialization


// INT0: Off
// INT1: On
// INT1 Mode: Falling Edge
// Interrupt on any change on pins PCINT0-7, 12-15: Off
// Interrupt on any change on pins PCINT8-11: Off
MCUCR=0x02;
PCMSK0=0x00;
GIMSK=0x80;
GIFR=0x80;

// Timer(s)/Counter(s) Interrupt(s) initialization


TIMSK=0x00;

// Universal Serial Interface initialization


// Mode: Disabled
// Clock source: Register & Counter=no clk.
// USI Counter Overflow Interrupt: Off
USICR=0x00;

// Analog Comparator initialization


// Analog Comparator: Off
ACSRA=0x80;
// Hysterezis level: 0 mV
ACSRB=0x00;

// Global enable interrupts


#asm("sei")

while (1)
{
// Place your code here
PORTB=tabla7segmentos [conteo];
};
}

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
Explicacin
Dentro del programa principal vemos que se queda de manera infinita ciclado
PORTB=tabla7segmentos [conteo];

while (1)
{
// Place your code here
PORTB=tabla7segmentos [conteo];
};

Pero dnde o cmo se incrementa la variable conteo? Recuerde que en la inicializacin


habilitamos la interrupcin INT1 y que iba ser por flancos de bajada, esto significa que
cada vez que se genere un flanco de bajada en la terminal INT1 el hardware va a llamar a la
subrutina de interrupcin de INT1, es decir, el programador no la puede llamar, sino es
cuando suceda el evento que genera la interrupcin. La subrutina de interrupcin de INT1
es la siguiente:

interrupt [EXT_INT1] void ext_int1_isr(void)


{ //Esta es la subrutina de interrupcin INT1
conteo++; //Note que no hay ninguna funcin que la llame
if (conteo==10) //Es porque la llama el hardware al detectar un flanco
conteo=0; //de bajada
// Place your code here
}

Tenga en cuenta que el codewizard genera la subrutina de interrupcin esperando que el


programador llene la funcin de interrupcin dependiendo de qu es lo que se desea que se
haga cuando sucede el evento de flanco de bajada. En nuestro caso queremos que cada vez
que se genera un flanco de bajada se incremente un contador es por ello que colocamos esas
instrucciones.

La interrupcines INT0 e INT1 tienen sus propias funciones de interrupcin y pueden


programarse para que genere una interrupcin por flanco de bajada, subida, ambos o por
nivel bajo; cuando se configura por nivel bajo significa que mientras est en nivel bajo se
generar la interrupcin, y si cuando sale de la subrutina de interrupcin sigue en nivel bajo
volver a saltar a la subrutina de interrupcin. Tambin hay que hacer notar que la INT0 e
INT1 son pines distintos, pero si habilita las dos interrupciones y una la habilita por flanco
de bajada la otra quedar habilitada con la misma condicin, esto es que no se puede
habilitar una por flanco de bajada y otra por flanco de subida ya que es la misma condicin
para las dos.

Importante. En el diagrama mostrado vemos que le pusimos una resistencia de pull-up


externo en el pin de la INT1 y esto es porque ya no le podemos activar la resistencia de
pull-up interna debido a que el pin ya no es de entrada/salida digital sino que funciona
Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez
e-mail: dinfante29@hotmail.com www.comunidadatmel.com
como una interrupcin externa, cuando pruebe en el circuito puede que se incremente el
conteo 1,2 o 3 veces cuando se presione el botn y es porque los interruptores mecnicos
generan rebotes, por lo que detectar varios flancos de subida y bajada cuando nosotros lo
presionemos una sla vez. Si en vez de conectar un botn conecta un generador de
funciones ya no se generaran rebotes y tampoco se necesitara la resistencia de pull-up
debido a que el generador no deja flotado el pin, ya que entrega 0 y 1 lgico.

Otra diferencia que podemos hacer con respecto a los PICs es que los PICs slo tienen un
vector de interrupcin y por tanto saltan a la misma subrutina donde el programador debe
checar cul interrupcin se gener, en cambio los AVR tienen vectores de interrupcin
distintos por lo que el manejo de interrupciones es decenas de veces ms rpido que los
PICs porque estos saltan al mismo vector que los manda a una sola subrutina donde debe
probar cada interrupcin para saber cul fue la que la gener.

Programa 20. Realizar un programa que cuando haya una interrupcin por flanco de subida
en la INT0 se prender un led, y cuando detecte un flanco de subida en INT1 se apagar. El
Led se conectar en el pin B0.

Interrupcin por cambio de estado en un pin (PIN Change Interrupt)

En el siguiente diagrama vemos que la terminal 20 tiene marcado PCINT0 hasta la terminal
10 que tiene PCINT15. Esto significa PIN CHANGE INTERRUPT X, es decir que se
puede generar una interrupcin cuando cambia de nivel lgico esos pines. Si conectaramos
a esos pines un interruptor se generara una interrupcin tanto cunado se presiona el
interruptor como cuando se suelta, ya que se generara un cambio de nivel en ambos casos.
A diferencia de las interrupciones INT0 e INT1 (pines 9 y18) los PCINTX slo funcionan
por cambio de nivel lgico es decir en flanco de subida y bajada; y los INT0 e INT1 si los
Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez
e-mail: dinfante29@hotmail.com www.comunidadatmel.com
podemos configurar para que funcionen por flanco de subida, bajada, ambos o por nivel
lgico 0.

La otra diferencia es que las INT0 e INT1 tienen una subrutina de interrupcin distinta. En
cambio e la interrupcin PCINT tiene una sla que es la siguiente :

// Pin change 0-15 interrupt service routine


interrupt [PCINT] void pin_change_isr(void)
{
// Place your code here
}

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
Captulo 4. Programacin del TIMER del ATMEGA48

El microcontrolador ATMEGA48 tiene 3 timers. El timer0 es de 8 bits, el timer1 es de 16


bits y el timer3 es de 8 bits.

El timer0 est asociado a los pines D5 y D6 (11 y 12), el timer1 est asociado a los pines
B1 y B2 (15 y 16) y el Timer2 est asociado a los pines D3 y B3 (5 y 17).

Indico que determinados pines estn asociados a un timer es por la razn de que cuando
sucede algn evento en el timer se pueden modificar esos pines ponindose a 1 a 0 o
cambiando de valor. Esto es que el Timer puede modificar directamente dos pines
asociados a l.

4.1 Partes del TIMER0

TCNT0. El corazn del timer0 es el contador TCNT0 (Counter of Timer 0) de 8 bits que
puede contar desde 0 hasta 255, el cual se va incrementando a la frecuencia interna del
microcontrolador dividido entre el preescalamiento de 1, 8, 64, 256 o 1024 seleccionado.
Es importante sealar que el preescalador divide nicamente la frecuencia de operacin del
timer y no la frecuencia del microcontrolador. Vea la siguiente figura, en ella se aprecia que
la frecuencia del oscilador interno es de 8 Mhz, el cual es dividido por 8, por lo que la
frecuencia de trabajo es de 1MHz. Esa frecuencia es para el CPU y los perifricos, pero a
su vez se puede dividir la frecuencia del timer por 1,8 64, 256 o 1024 pero esa divisin slo
afecta al timer y no a la frecuencia de operacin del CPU u otros perifricos del
microcontrolador. Esa frecuencia preescalada es la que determina cada cundo se va a
modificar el timer que es el TCNT0, el valor del TCNT0 se va comparando
automticamente con el OCR0A (Registro de Comparacin del Timer 0 salida A que es el
pin D6) y con el OCR0B (Registro de comparacin del Timer 0 salida B que es el pin D5),
cuando el TCNT0 es igual a uno de esos registros pueden programarse las acciones de: no

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
hacer nada sobre el pin, poner a 1 o a 0 el pin o intercambiar su valor, esto con la finalidad
de generar seales.

Figura Estructura del timer 0

OCROA. Este registro de comparacin del Timer0 salida A, es un registro de 8 bits


accesible para el programador que continuamente se compara de manera automtica con el
TCNT0 y cuando son idnticos se puede generar una accin al Pin D6 que es el pin
asociado a la salida A del timer0.

OCROB. Este registro de comparacin del Timer0 Salida B es un registro de 8 bits que
puede modificar el programador y que continuamente se compara de manera automtica
con el TCNT0 y cuando son idnticos se puede generar una accin al Pin D5 que es el pin
asociado a la salida B del timer0.

FRECUENCIA DE OPERACIN DEL TIMER. El timer se incrementa en una unidad


cada determinada cantidad de tiempo. Por ejemplo si la frecuencia del timer es de 1 MHz
entonces el periodo es de 1S, esto es que cada 1S se incrementar en 1 el contador.
Como el timer es de 8 bits puede contar desde 0 hasta 255 que son 256 cuentas por lo tanto
le tomar al TCNT0 256*1S=256S llegar desde 0 hasta 255.

El timer puede ser preescalado por 1, 8, 64, 256 o 1024 esto significa que si la frecuencia
de operacin del microcontrolador es de 1MHz, puede operar el timer a 1MHz, 125KHz,
15.625KHz, 3906.25 Hz y 976.5625Hz. Suponga que el microcontrolador est operando a
1MHz, entonces el timer trabajar a 1MHz (si est preescalado por 1), pero si se preescala
por 1024 entonces trabajar la frecuencia del timer ser 976.5625Hz. Pero recuerde que esa
frecuencia es la velocidad con la que se incrementar en una unidad el timer, y que el timer
cuenta 256 pulsos.

Lo primero que debe hacer el programador es identificar la velocidad de operacin del


microcontrolador para determinar las frecuencias del timer. Estos valores descritos son

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
considerando que el microcontrolador opera a 1MHz como es el caso de un
microcontrolador nuevo que viene de fbrica a 8MHz pero dividida la frecuencia de
operacin entre 8, por ello opera a 1MHz el microcontrolador, y a su vez puede
preescalarse la frecuencia del timer entre 1, 8, 64, 256 y 1024.

Si configuramos el timer para que se preescale entre 1024 entonces la frecuencia del timer
ser de 976.5625 Hz, y el periodo ser de 1.024 mS as que el timer se incrementar en 1
unidad cada 1.024mS. El tiempo que le llevar al timer ir desde 0 hasta 255 sern 256
cuentas*1.024mS=0.262144 Segundos.

Las siguientes tablas deber tenerlas en mente para los clculos usados para programar el
timer, y tambin tenga en cuenta que estas tablas son vlidas son para una frecuencia
interna de 1MHz, as que si coloca un cristal externo entonces deber recalcular estas tablas
a esa frecuencia usada.

Tabla de frecuencia y periodos del timer 0


Frecuencia Preescalamiento Frecuencia Tiempo que tarda en incrementarse en una
Interna del timer unidad el timer (1/Frecuencia Timer)
1 MHz 1 1 MHz 1 S
1 MHz 8 125KHz 8 S
1 MHz 64 15.625KHz 64 S
1 MHz 256 3906.25 Hz 256 S
1 MHz 1024 976.5625Hz 1.024 mS

Con los tiempos anteriores podemos calcular el tiempo que le tomar al timer ir de 0 hasta
255 (256 cuentas)

Tabla de conteo mximo del timer (256 Cuentas)


Periodo de una cuenta Tiempo que le llevar contar 256 cuentas
1 S (1 MHz) 256 S
8 S (125 KHz) 2.048 mS
64 S (15.625KHz) 16.284 mS
256 S (3906.25 Hz) 65.536 mS
1.024 mS (976.565 Hz) 0.262144 S

Importante. Recuerde que estas tablas son para una frecuencia de operacin del
microcontrolador de 1 Mhz y que si conecta otro cristal deber calcular los tiempos y
frecuencias.

Importante. El oscilador interno del microcontrolador es del tipo RC por lo que la


frecuencia NO ES EXACTA y VARA CON LA TEMPERATURA pero es cercana a 1
MHz. Para control de tiempos exactos deber conectarse un oscilador o cristal externo.

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
ACCIONES SOBRE EL PIN D5 Y PIN D6. Cuando el TCNT0 se iguala al valor del
OCR0A o el OCR0B se puede hacer que en el pin se ponga a 1 o 0, o que cambie de valor
en el pin D5 o D6.

OVERFLOW o SOBREFLUJO. El timer va incrementndose en una unidad cada


determinada cantidad de tiempo, segn la frecuencia y el preescalamiento, pero el timer
tiene un determinado ancho en bits por lo que el nmero mximo que puede almacenar est
limitado. Por ejemplo el timer0 es de 8 bits por lo que puede tener un nmero desde 0 hasta
255 (0 a FFh) pero cuando tiene 254 y cuenta una unidad ms, el timer se incrementa a 255,
y si cuenta un nmero ms ya no cabe el 256 en 8 bits, por lo que el timer se regresa a 0
esto se conoce como overflow, es decir llegar al valor mximo y contar un pulso ms que
hace que el timer regrese a cero.

SEALES PWM. Una seal PWM (Pulse Width Modulation) o modulacin por ancho de
pulso tiene las siguientes caractersticas: El periodo de la seal es fijo, lo que cambia es el
ancho de pulso.

PWM no invertida, en esta figura se aprecia que el periodo de la seal es fijo y lo que se
modifica es el ancho de pulso, en el primer ciclo la modulacin est al 50%, esto es que
durante todo el periodo de la seal estar en 1 el pulso, en el siguiente ciclo se encuentra la
modulacin es del 75%, as que estar en 1 durante partes del periodo de la seal, y en el
ltimo ciclo est al 100% la modulacin, as que est en 1 todo el tiempo que dura el
periodo de la seal.

Las seales PWM son muy utilizadas en control de energa de CA y CD. Si conectramos
un LED con un PWM al 50% veramos que est ligeramente encendido, si subimos el
ancho de pulso el LED prendera con mayor intensidad, y si la modulacin est al 100% el
LED prendera al mximo de intensidad lumnica.

PWM invertida. En una seal PWM invertida la modulacin es cunto tiempo estar en 0 la
seal. Cuando est al 75% significa que partes del periodo de la seal estar en 0. Vea la
siguiente figura de una seal PWM invertida al 50%, 75% y 100%.

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
PWM con Modulacin no invertida al centro. En determinados tipos de control de motores
la modulacin no se hace con respecto al inicio del periodo, sino con respecto al centro. En
la siguiente figura se aprecia PWM con modulacin no invertida al centro con modulacin
al 50%, 75% y 100%.

En la figura anterior se nota que el pulso va creciendo con respecto al centro, y que si la
modulacin es del 50% entonces durante 50% del tiempo del ciclo estar en 1 pero
centrado con respecto al periodo de la seal.

PWM con Modulacin invertida al centro. En este tipo de modulacin la modulacin es el


tiempo que est en 0 con respecto al centro del periodo, y en la siguiente figura se tienen
este tipo de modulacin al 50%, 75% y 100%.

Estos modos de modulacin del PWM se ilustraron y explicaron debido a que con el
TIMER del ATMEGA es posible generarlos con su timer.

En los siguientes subtemas se pondr el modo de funcionamiento del timer en ingls que es
como lo pone el wizard del codevision y en espaol no ser propiamente su traduccin, sino
ser una traduccin basada en su funcionamiento.

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
4.2 Modo Normal top=FFH (Modo Normal del Timer contando desde 0
hasta 255d)

Modo Normal top=FFh


En este modo el timer cuenta desde 0 hasta 255 cuando llega a 255 y se detecta un conteo
ms se regresa a 0. Esta accin se le conoce como sobreflujo (overflow) porque despus de
255 el valor correcto debera ser 256, pero como no cabe el 256 en 8 bits sucede el
sobreflujo por lo que se regresa a 0 y sigue acumulando pulsos el timer hasta llegar a 255
repitindose el 0 al siguiente pulso, esto es que cuenta de manera cclica de 0 a 255.

Registros de comparacin OCROA y OCROB, estos dos registros significan que dar una
salida a la comparacin con el timer (Output A Compare Register of Timer 0 y Output B
Compare Register of Timer 0), estos registros son accesibles para que el programador les
escriba un nmero y se comparan continuamente y de manera automtica con el timer
(TCNT0) y cuando se hacen iguales se genera una accin.

Por ejemplo si se les escribe lo siguiente:

OCR0A=100;
OCR0B=200;

Significa que cuando el timer (TCNT0) tenga el valor de 100 se generar una accin, y
cuando el timer (TCNT0) valga 200 se generar otra accin.

Tabla Acciones que se pueden programar a la comparacin


Las acciones que se pueden generar Descripcin
Disconnected No hay ningn efecto
Toggle on Compare match Conmuta el valor del pin
Clear on Compare match Se pone en 0 el pin

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
Set on compare match Se pone a 1 el pin

Note que el OCR0A est asociado al pin D6 y el OCR0B est asociado al pin D5.

Las acciones que se generarn a la comparacin con el OC0A y OC0B se configuran con el
wizard del codevision.

Suponga que el OCR0A=100; y el OCR0B=200; y se selecciona Set on Compare Match


en la salida A y se selecciona Toggle on Compare Match en la salida B, entonces cuando
el timer (TCNT0) sea igual al OCR0A, es decir 100, entonces el pin se pondr en 1, es por
eso que est en 0 el pin D6 (lnea roja) antes de 100 y despus de 100 se mantiene en 1.

Si la salida B se configura en Toggle on Compare Match, significa que al hacerse el


TCNT0 igual al OCR0B que es 200, entonces cambiar el estado del pin, as que la primera
vez cambia de 0 a 1, cuando se hace el TCNT0 igual al OCR0B que es igual a 200, entonces
cambia de 1 a 0 (lnea azul) y as sucesivamente como se ve en la figura siguiente.

Resumen del timer 0 en el modo de Normal Top = FFh

El timer0 usa el TCNT0 y se va incrementando este registro en cada pulso de reloj.


El timer0 puede preescalarse para que el conteo se haga ms lento y el
preescalamiento es de 1, 8, 64, 256 y 1024.
El timer0 es de 8 bits y cuenta desde 0 hasta 255 y regresa a 0 y as sucesivamente.
El timer0 tiene dos registros de comparacin OCR0A y OCR0B cuando esos
registros tienen el mismo valor que el TCNT0 se hace una accin que afecta al pin
D6 y D5 respectivamente
Las acciones que se pueden generar son: nada, ponerse a 1 el pin, ponerse a 0 el pin
o que conmute el estado del pin.

Note que si se selecciona la accin de que se ponga a 1 el pin, el pin se quedar en 1. Si se


selecciona que se ponga a 0 el pin se quedar en 0. El efecto que podemos ver es el
conmutacin (Toggle on Compare Match) porque el pin estar cambiando de estado
continuamente.

Programa timer1. Configure el timer0 de tal manera que en la salida B (pin D5) se genere
una seal cuadrada que dur 2.048 mS en bajo y 2.048 mS en alto. En este modo de
Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez
e-mail: dinfante29@hotmail.com www.comunidadatmel.com
operacin el periodo de la seal no se puede modificar porque el timer siempre cuenta
desde 0 hasta FF, y de los clculos antes vistos tenemos:

Tabla de frecuencia y periodos del timer 0


Frecuencia Preescalamiento Frecuencia Tiempo que tarda en incrementarse en una
Interna del timer unidad el timer (1/Frecuencia Timer)
1 MHz 1 1 MHz 1 S
1 MHz 8 125KHz 8 S
1 MHz 64 15.625KHz 64 S
1 MHz 256 3906.25 Hz 256 S
1 MHz 1024 976.5625Hz 1.024 mS

Con los tiempos anteriores podemos calcular el tiempo que le tomar al timer ir de 0 hasta
255 (256 cuentas)

Tabla de conteo mximo del timer (256 Cuentas)


Periodo de una cuenta Tiempo que le llevar contar 256 cuentas
1 S (1 MHz) 256 S
8 S (125 KHz) 2.048 mS
64 S (15.625KHz) 16.284 mS
256 S (3906.25 Hz) 65.536 mS
1.024 mS (976.565 Hz) 0.262144 S

Entonces debemos escoger el preescalamiento de 8 que es la frecuencia de 125KHz para


que nos d el periodo de 2.048mS.

Luego debemos configurara para que la accin a generar en la comparacin del TCNT0 con
el OCR0B sea Toggle on Compare Match para que cuando sean iguales el estado del pin
D5 se invierta de valor.

Qu valor debemos poner en OCR0B? No importa el valor que se ponga porque sin
importar el valor que tenga sucedern 256 pulsos ms para que cambie de valor. Vea la
siguiente figura:

Si en OCR0B coloca un 10, transcurrirn 256 cuentas para que suceda otro 10 e invierta el
estado del pin, si coloca un 20 sucedern 256 cuentas para que ocurar otro 20, as que no
importa el valor que le ponga al OCR0B. Para este ejemplo pondremos un 100d.

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
La configuracin debe ser as: Chip ATMEGA48 dividido por 8, luego en Timer0 deber
dar click en los siguientes puntos del timer0, cuando le indique que se va a guardar el
proyecto saldr la ventana de la derecha donde le dice que si activa el pin D5 como salida
ah deber decir que s porque el Pin debe ser configurado como salida para que muestre las
seales, note tambin que en la parte ms baja del Timero se coloc un 64h que es un 100
decimal.

Figura. Seleccin del timer 0 para el programa


Vea el vdeo timer1 donde se explica el programa y la inicializacin del timer para el
siguiente programa.

Grabe el programa en el microcontrolador y no deber agregar nada extra al programa


porque el asistente inicializ completamente el Timer0, alimente el microcontrolador y
conecte un osciloscopio en el pin D5 y ver la siguiente forma de onda:

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
En el programa anterior expliqu que no podemos modificar el periodo de la seal, pero
podemos actualizar continuamente los registros de comparacin para generar cualquier
periodo en la seal, primero veremos la tabla que ya se haba calculado:

Tabla de conteo mximo del timer (256 Cuentas) con una frecuencia de 1MHZ
Periodo de una cuenta Tiempo que le llevar contar 256 cuentas
1 S (1MHz) 256 S
8 S (125KHz) 2.048 mS
64 S (15.625KHz) 16.284 mS
256 S (3906.25 Hz) 65.536 mS
1.024 mS (976.565 Hz) 0.262144 S

Si quisiramos generar seales cuadradas con una frecuencia digamos de 2Khz, debemos
hacer lo siguiente:

El periodo de una seal de 2KHz es 0.5mS, con 0.25mS en alto y 0.25mS en bajo, por lo
que debemos escoger un preescalamiento que d ms de 0.5mS para que quepa la seal que
queremos generar, de esa forma vemos que podemos seleccionar cualquier preescalamiento
del segundo en adelante, porque en el primero el tiempo mximo que podemos medir son
256S y ocupamos que sea mayor a 0.5 mS, pero cul de todos es el ms adecuado? Para
ello pondr el siguiente ejemplo: Cuando va a medir 1.5 Volts Cul escala selecciona 2, 20
o 200 Volts? Selecciona el ms cercano es decir 2 Volts para una mayor resolucin; para el
timer razonamos de la misma forma, cul se encuentra ms cercano a 0.5mS la opcin sera
la frecuencia de 125 Khz que est resaltada en verde porque el periodo del timer a las 256
cuentas da 2.048 mS.

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
Es importante sealar que la frecuencia de 125 KHz es la velocidad con la que se
incrementa el timer en una unidad, que en tiempo corresponde a 8 S. Pero el ciclo del
timer se cumple cuando cuenta desde 0 hasta 255 (256 cuentas) que en tiempo corresponde
a 8 S *256=2.048 mS.

Una cuenta con la frecuencia de 125 Khz tarda 8uS, entonces queremos que la seal cambie
cada 0.25mS, as que traducido en cuentas sera 0.25mS/8uS=31.25 cuentas, pero no
podemos 31.25 as que lo redondeamos a 31.

El contador TCNT0 se comparar continuamente con el OCR0A y el OCR0B, si vamos a


utilizar la salida A (pin D6) en modo de toggle on compare match (conmutacin del pin a la
comparacin) entonces en el OCR0A le escribimos el 31 para que cambie el pin a los
0.25mS, pero los otros 0.25mS ocurrirn a las 62 cuentas, y los siguientes 0.25 mS
sucedern a las 93 cuentas y as sucesivamente. As que en este programa debemos
actualizar continuamente el OCR0A. El timer tiene la posibilidad de generar una
interrupcin a la comparacin del TCNT0 con el OCR0A y OCR0B. Cuando el TCNT0 sea
igual al OCR0A se generar una interrupcin y en la interrupcin lo que haremos es leer el
OCR0A para sumarle 31 para que la siguiente comparacin sea 31 cuentas despus o
0.25mS despus, cuando sea TCNT0 igual al OCR0A se generar otra interrupcin y
sumaremos otros 31 al OCR0A para que el siguiente cambio del pin sea 0.25mS despus.
Vea la grfica siguiente:

A las 31 cuentas conmutar el pin y se generar una interrupcin donde instrucciones para
actualizar el registro OCR0A a 62, cuando el TCNT0 sea igual a 62 cambiar el pin y se
generar una interrupcin para actualizar el OCR0A a 93 y as sucesivamente.

Ve el vdeo timer2 donde se explica la inicializacin del timer para el siguiente programa.

Programa timer2. Configure el timer para generar una seal cuadrada con una frecuencia
de 2KHz que se generar en el pin D6 (salida A del timer0).

Seleccione Chip ATMEGA48, 8 Mhz dividido por 8 y en el timer seleccione lo que se


muestra en la siguiente figura:

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
Note que estamos habilitando interrupcin por comparacin en el OCR0B con el TCNT0
(Compare Match B Interrupt) y el codewizard generar la siguiente subrutina de
interrupcin:

// Timer 0 output compare A interrupt service routine


interrupt [TIM0_COMPA] void timer0_compa_isr(void)
{
// Place your code here
}

Note que cuando nos genera la subrutina de interrupcin coloca como comentario en la
parte superior: // Timer 0 output compare A interrupt service routine Esto es til para que el
programador sepa de cul subrutina de interrupcin se trata. Ese comentario traducido es:
Subrutina de Interrupcin por Comparacin de la salida B del timer0. Recuerde que las
subrutinas de interrupcin no las llama el programador, sino el evento, que en este caso es
cuando el TCNT0=OCR0A si son iguales salta a esa subrutina de interrupcin.

Entonces cuando el OCR0A con el TCNT0 qu debemos hacer: leer el valor del OCR0A y
sumarle 31 para que se compare 31 cuentas despus que son 0.25mS.Es decir que el cdigo
que colocaremos en esa subrutina de interrupcin es:

OCR0A=CR0A+31;

Note tambin en la imagen anterior que se seleccion en el wizard Out:A Toggle on


Compare Match para que cada vez que el TCNT0 sea igual al OCR0A cambie de estado el
pin D6.

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
De acuerdo a lo que seleccionamos con el wizard del codevision se configur para que el
pin D6 (salida A del timer 0) cambie de estado cuando el TCNT0=OCR0A, y adems que
se genere una interrupcin, en esa subrutina de interrupcin actualizamos el valor del
OCR0A en 31 cuentas (0.25 ms) para que el siguiente cambio del pin suceda precisamente
a los 0.25 mS.

Recuerde que es importante indicar en la parte de chip que es el ATMEGA48 y que se est
trabajando a 8 MHz y dividido entre 8 como en todos los programas que hemos realizado.

El listado del programa genereado por el wizard es el siguiente, lo que deber agregar a su
programa es lo que est en azul.
/*****************************************************
This program was produced by the
CodeWizardAVR V2.03.6 Evaluation
Automatic Program Generator
Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :
Version :
Date : 02/11/2008
Author : Freeware, for evaluation and non-commercial use only
Company :
Comments:

Chip type : ATmega48


Clock frequency : 1,000000 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 128
*****************************************************/

#include <mega48.h>

// Timer 0 output compare A interrupt service routine


interrupt [TIM0_COMPA] void timer0_compa_isr(void)
{
OCR0A=OCR0A+31; // Place your code here
}

// Declare your global variables here

void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 8


#pragma optsize-
CLKPR=0x80;
CLKPR=0x03;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization


// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTB=0x00;
DDRB=0x00;

// Port C initialization

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0x00;
DDRC=0x00;

// Port D initialization
// Func7=In Func6=Out Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=0 State5=T State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x40;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 125,000 kHz
// Mode: Normal top=FFh
// OC0A output: Toggle on compare match
// OC0B output: Disconnected
TCCR0A=0x40;
TCCR0B=0x02;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;

// External Interrupt(s) initialization


// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;

// Timer/Counter 0 Interrupt(s) initialization

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
TIMSK0=0x02;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x00;

// Analog Comparator initialization


// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;

// Global enable interrupts


#asm("sei")

while (1)
{
// Place your code here

};
}

Lo nico que se agreg al programa generado por el codewizard es lo que se encuentra en


azul y esto fue:

OCR0B=OCR0B+31; // Place your code here

Cuando el TCNT0 se iguala al OCR0A cambia de estado el pin y se genera una


interrupcin para actualizar el OCR0A sumndole 31 cuentas que son equivalentes 0.25mS.

En la siguiente imagen se muestra una fotografa de la seal generada de este programa en


un osciloscopio.

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
4.3 Modo Phase Correct PWM top=FFh (Modo PWM con modulacin al
centro y con periodo fijo de 510 cuentas)

En este modo de funcionamiento el timer (TCNT0) cuenta de 0 hasta 255 y luego


decrementa su valor hasta llegar a 0 y despus vuelve a incrementarse hasta llegar a 255, y
as sucesivamente. Es decir, en este modo de operacin el timer es ascendente hasta llegar
al mximo y despus se hace descendente. El periodo del timer es 510 ya que cuenta de
manera ascendente y luego de manera descendente.

La traduccin de este modo sera PWM con correccin de fase y quizs no le d una idea
clara, pero en otras palabras y segn su funcionamiento es: PWM centrado con periodo de
510. La razn de este periodo doble es que un ciclo del timer es cuando va de 0 hasta 255 y
de ah regresa a 0, es por ello que el periodo se hace de 510 pulsos (2*255) de reloj.

Aqu tambin se utilizan los registros de 8 bits del timer 0 que son OCR0A y OCR0B, estos
dos registros se comparan de manera automtica con el timer (TCNT0) y cuando se hacen
iguales pueden suceder las siguientes acciones en los pines D6 y D5 que es donde estn
asociados los registros respectivamente:

1. Disconnected. No hay efecto sobre el pin


2. Non-inverted PWM. En esta configuracin al iniciar el timer comienza el pin en 0 al
hacerse igual al OCR0X el pin se pone a 1, despus el timer (TCNT0) llega al
mximo y comienza a decrementarse cuando son iguales el TCNT0 y el OCR0X el
pin se pone en 0.
3. Inverted PWM. En esta configuracin al iniciar el timer en 0 comienza el pin en 1
cuando se iguale el TCNT0 con el OCR0X el pin se pone a 0, al llegar el TCNT0 al
mximo regresa en un conteo descendente y al hacerse igual al OCR0X el pin se
pone nuevamente a 1, esto es que la seal generada es exactamente la inversin de
la seal del punto 2.

Las acciones 2 y 3 corresponden al PWM con Modulacin no invertida e invertida al centro


que se explic en la seccin 4.1

Ejemplo. Suponga que se configura el timer en el modo de Phase Correct PWM top=FFh
y se selecciona la salida A en Non Inverted PWM y se carga en OCR0A=100; y la salida
B en Inverted PWM y se carga en OCR0B en 200; en la siguiente figura se ilustra la
forma de la seal en el PIND6 que es la asociada a la salida A (OCR0A) y el PIND5 que es
la asociada a la salida B (OCR0B).

En la figura vea que el contador inicia en 0 y llega hasta 255 despus al siguiente pulso el
timer comienza a decrementarse por eso el siguiente conteo es 254 hasta llegar a 0 (el
periodo es 510 cuentas porque va de 0 al mximo y de ah se decrementa). En la salida A se
seleccion Non Inverted PWM, y se carg en el OCR0A un 100, entonces cuando el
TCNT se iguala al OCR0A se pone a 1 el pin D6 y cuando se vuelve hacer el TCNT igual
al OCR0A se pone en 0.

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
La lnea azul ilustra la seal en el PIN D5 que est asociada a la salida B del timer0, aqu se
ejemplifica el funcionamiento Inverted PWM, note que el pin inicia en 1, al igualarse el
OCR0B con el TCNT0 se pone a 0 y al volverse a igualar se pone nuevamente en 1.

Si ha cursado materias de control y de potencia notar que estas seales ilustradas son
tiles en control de motores.

Programa para ejemplificar el funcionamiento del PWM con modulacin al centro no


invertida.

Si la frecuencia interna de operacin es de 1MHz y los preescalamientos son 1, 8, 64, 256 y


1024. Tenemos las frecuencias de operacin del timer de:

Tabla de frecuencia y periodos del timer 0


Frecuencia Preescalamiento Frecuencia Tiempo que tarda en incrementarse en una
Interna del timer unidad el timer (1/Frecuencia Timer)
1 MHz 1 1 MHz 1 S
1 MHz 8 125KHz 8 S
1 MHz 64 15.625KHz 64 S
1 MHz 256 3906.25 Hz 256 S
1 MHz 1024 976.5625Hz 1.024 mS

Con los tiempos anteriores podemos calcular el tiempo que le tomar al timer ir de 0 hasta
255 y regresar a 0 (510 cuentas), esta tabla cambia con respecto a las antes vistas debido a
que el timer cuenta 510 pulsos.

Tabla de conteo mximo del timer (510 Cuentas)


Periodo de una cuenta Tiempo que le llevar contar 510 cuentas
1 S (1 Mhz) 510 S
8 S (125 KHz) 4.08 mS
64 S (15.625KHz) 32.64 mS
256 S (3906.25 Hz) 130.56 mS
1.024 mS (976.5625Hz) 0.52224 S
Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez
e-mail: dinfante29@hotmail.com www.comunidadatmel.com
Programa timer3. Escriba un programa con PWM no invertido con un ancho de pulso del
50%. Con un periodo de la seal de 32.64mS. La seal se generar en la salida B del
timer0. Vea la inicializacin del timer para este programa en el video timer3.

Note que no podemos modificar el periodo de la seal, ya que el nmero de cuentas es fijo
y es de 510 adems de que las frecuencias preescaladas es limitada 5 opciones.

Si queremos un ancho de pulso del 50% tenemos que cargar en el OCR0B un 127, porque
127 es la mitad del 255. Vea el siguiente diagrama para que vea el periodo de 510 pulsos y
que con 127 en el OCR0B se tiene el 50% del ancho de pulso.

Cuando el TCNT0 va incrementndose y se hace igual al 127 del OCR0B se pone a 1 el pin
D5 y se mantiene as hasta que el TCNT0 va decrementndose y se vuelve hacer igual a
127.

Seleccione el timer0 como se muestra en la siguiente figura

Configuracin del timero

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
Note que en la parte de abajo se escribi Compare B: 7fh que corresponde al 127 y este 127
es el valor que se cargar en el OCR0B.

El programa que genera el codewizard es el programa completo y no hay que agregar


ninguna instruccin.

Foto de la seal generada en el programa timer3

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
4.4 Modo Fast PWM top=FFh (PWM con periodo fijo de FFh cuentas)

En este modo el timer (TCNT0) cuenta desde 0 hasta 255, al siguiente pulso inicia en 0
hasta llegar a 255 cuentas y as sucesivamente. En este caso el periodo de la seal es de 256
cuentas. La salida A del timer0 (TCNT0) se iguala al valor del OCR0A o al OCR0B
pueden suceder las siguientes acciones sobre el pin D6 y D5 respectivamente:

1. Disconnected. No hay efecto sobre el pin


2. Non-inverted PWM. En esta configuracin al iniciar el timer comienza el pin en 0
al hacerse igual al OCR0X el pin se pone a 1 y se mantiene as hasta que el TCNT0
llega a 255, en el siguiente conteo el TCNT0 regresa 0 y el pin se pone a 0
nuevamente.
3. Inverted PWM. En esta configuracin al iniciar el timer en 0 comienza el pin en 1
cuando se iguale el TCNT0 con el OCR0X el pin se pone a 0 y se mantiene as hasta
que el TCNT0 llega a 255, en el siguiente conteo el TCNT0 regresa a 0 y el pin se
pone a 1 nuevamente.

En la siguiente figura vemos que el periodo es de 256 cuentas, ya que el timer0 (TCNT0 va
desde 0 hasta 255), el siguiente conteo a 255 es el 0 para iniciar nuevamente el conteo.

Suponga que la salida A del timer0 asociada al pin D6 se configura como Non-Inverted
PWM y se carga en el OCR0A un 100, entonces al inicio del conteo del timer el pin D6
(lnea roja) el pin est en 0, cuando el TCNT0 se hace igual al OCR0A se pone a 1 el pin, y
se mantiene en 1 hasta que el timer llega a 255, al siguiente pulso el timer regresa a 0
repitindose el ciclo del timer0 e iniciando el pin en 0.

Considere que la salida B del timer0 (asociada al pin D5) se configura como Inverted PWM
y que se carga en el OCR0B un 200, entonces al inciio del conteo del timer el pin D5 (lnea
azul) se pone en 1 y cuando el TCNT0=OCR0B que es 200 el pin se pone en 0 y se
mantiene en ese estado hasta que llega a 255, luego el timer inicia su ciclo en 0 y tambin el
pin se pone en 1 y se coloca en 0 hasta que nuevamente el TCNT0 se hace igual al OCR0B.

En materias de control y potencia se utilizan este tipo de seales para el control de la


energa en CD y AC, para el control de ngulos de disparo de tiristores.
Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez
e-mail: dinfante29@hotmail.com www.comunidadatmel.com
Programa Timer4. Controlar la energa lumnica de un LED mediante una seal PWM
que se generar en la salida B del timer0 (pin D5). EL ancho de pulso se controlar
mediante un potencimetro conectado al canal 0 del ADC (Pin C0) Este potencimetro
variar el voltaje desde 0 hasta 5 Volts. Vea el video timer4 donde se muestra la
configuracin del microcontrolador. En el circuito recuerde ponerle una resistencia de 330
Ohms al Led para limitar la corriente en el pin.

Importante. Recuerde que si va a utilizar un pin como entrada analgica del ADC deber
configurarlo como entrada y sin resistencia de pull-up ese pin. En caso de que lo configure
como salida el pin y le aplique un voltaje puede daar el pin.

Si la frecuencia del PWM es menor a 60Hz se ver parpadeando el LED, pero si la


frecuencia es mayor o igual a 60 Hz (periodo de 16.6 mS) no se ver el parpadeo del LED,
sino el promedio de voltaje aplicado a ste. Entonces se seleccionar un periodo de
16.284mS para 256 cuentas, que corresponde a una frecuencia de conteo de 15.625 KHz.

Tabla de conteo mximo del timer (256 Cuentas)


Periodo de una cuenta Tiempo que le llevar contar 256 cuentas
1 S (1 Mhz) 256 S
8 S (125 KHz) 2.048 mS
64 S (15.625KHz) 16.284 mS
256 S (3906.25 Hz) 65.536 mS
1.024 mS (976.5625Hz) 0.262144 S

La configuracin del timer y del ADC deber hacerla de la siguiente manera:

Figura. Inicializacin del timer y del ADC

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
Note que se est habilitando la interrupcin por sobreflujo (Ovreflow Interrupt) del timer,
entonces cuando el timer llegue al valor mximo de conteo que es FFh y se d un pulso ms
el timer se har cero y se generar la interrupcin por sobreflujo, y en esta interrupcin lo
que haremos es leer el canal 0 del ADC y ese valor se cargar en el OCR0B. Entonces a
mayor voltaje en el canal 0 del ADC se generar un ancho de pulso ms grande y por lo
tanto el LED emitir una mayor intensidad lumnica.
Vea que en la subrutina de interrupcin por sobreflujo del timer0 leemos el canal 0 del
ADC y lo cargamos en el OCR0B que es el registro que determina el ancho de pulso del
PWM. Esto se muestra en el siguiente cdigo:

// Timer 0 overflow interrupt service routine


interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
OCR0B=read_adc(0);
// Place your code here
}

Coloque el cdigo en azul en la subrutina de interrupcin como se muestra en el siguiente


listado y complelo y ver que marca un error.

Ese error es porque la subrutina del ADC est abajo de la subrutina de interrupcin de
sobreflujo, entonces al llamar la funcin de read_adc(0) no la encuentra porque la subrutina
est abajo. Entonces debe invertir esa dos subrutinas: copie el cdigo del ADC en la parte
superior y la del timer en la parte de abajo. (son los bloques de cdigo verde y rosa) y
debern quedar como se muestra en este listado.

/*****************************************************
This program was produced by the
CodeWizardAVR V2.03.6 Evaluation
Automatic Program Generator
Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :
Version :
Date : 27/10/2008
Author : Freeware, for evaluation and non-commercial use only
Company :
Comments:

Chip type : ATmega48


Clock frequency : 1,000000 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 128
*****************************************************/

#include <mega48.h>

#include <delay.h>

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
#define ADC_VREF_TYPE 0x60

// Read the 8 most significant bits


// of the AD conversion result
unsigned char read_adc(unsigned char adc_input)
{
ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=0x40;
// Wait for the AD conversion to complete
while ((ADCSRA & 0x10)==0);
ADCSRA|=0x10;
return ADCH;
}

// Timer 0 overflow interrupt service routine


interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
OCR0B=read_adc(0);
// Place your code here

// Declare your global variables here

void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 8


#pragma optsize-
CLKPR=0x80;
CLKPR=0x03;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization


// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTB=0x00;
DDRB=0x00;

// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0x00;
DDRC=0x00;

// Port D initialization
// Func7=In Func6=In Func5=Out Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=0 State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x20;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 15,625 kHz
// Mode: Fast PWM top=FFh
// OC0A output: Disconnected
// OC0B output: Non-Inverted PWM
TCCR0A=0x23;
TCCR0B=0x03;
TCNT0=0x00;

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;

// External Interrupt(s) initialization


// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;

// Timer/Counter 0 Interrupt(s) initialization


TIMSK0=0x01;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x00;

// Analog Comparator initialization


// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;

// ADC initialization
// ADC Clock frequency: 500,000 kHz
// ADC Voltage Reference: AVCC pin
// ADC Auto Trigger Source: None
// Only the 8 most significant bits of
// the AD conversion result are used
// Digital input buffers on ADC0: On, ADC1: On, ADC2: On, ADC3: On
// ADC4: On, ADC5: On

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
DIDR0=0x00;
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0x81;

// Global enable interrupts


#asm("sei")

while (1)
{
// Place your code here

};
}

Foto a) Modulacin con un ancho de pulso muy pequeo, note que el voltaje medio es de
64.2mV por lo que el led tendr una intensidad muy baja.

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
El ancho de pulso se incrementa y el voltaje promedio tambin sube, el led obtiene mayor
intensidad.

En la foto anterior el ancho de pulso es ms grande y por lo tanto el voltaje promedio sube.

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
En los modos vistos el periodo est fijo, ya que el TCNT0 cuenta desde 0 hasta 255 en los
modos Normal top=FFh y en el FAST PWM top=FFh; o de 0 hasta 255 y despus se
decrementa hasta llegar a 0 (510 cuentas) en el modo Phase correct PWM top=FFh.

Pero existen otros tres modos en los cuales el programador puede configurar el periodo de
la seal, recuerde que el periodo se fija en nmero de cuentas. Estos modos los veremos a
continuacin.

4.5 Modo CTC top =OCR0A (Timer contando desde 0 y con tope el valor de OCR0A)

Este modo Clear Timer on Compare with OCR0A o traducido segn su funcionamiento es:
reinicializacin del timer cuando se haga igual al OCR0A, es decir que si seleccionamos
este modo de operacin el OCR0A es el tope del timer0, entonces si OCR0A=100 entonces
el timer contar de 0 hasta 100 y al siguiente conteo regresar a 0 el timer para continuar su
conteo. Vemos que en este modo el programador fija el periodo de la seal a travs del
registro OCR0A.

El funcionamiento de este modo es exactamente igual al de Modo Normal top=FFh pero


con la diferencia de que el timer no cuenta hasta FFh sino hasta el valor del OCR0A, las
acciones que se pueden generar en los pines D5 y D6 son las definidas en el Modo Normal
top=FFh

Programa Timer5. Disear un programa que cada 10mS cambie de estado el pin B0. Para
ello se utilizar la interrupcin por comparacin con el OCR0A. Aqu notamos que el pin
B0 no est asociado a ningn timer, pero aqu usaremos el timer como un temporizador, no
como un generador de seales, as que cada 10mS se generar una interrupcin en la cual se
cambiar de estado el pin B0.

Para empezar necesitamos seleccionar una frecuencia del timer que multiplicada por 256
cuentas sea la ms cercana y mayor a 10mS. Los 10 mS caben en una frecuencia de conteo
de 15.625KHz.

Cuntas cuentas debe tener el timer para que genere una interrupcin cada 10mS?
10mS/64uS=156.25 pero como deben ser enteros sera un 156. El timer contar desde 0
hasta 156 y luego regresar a 0 hasta llegar a 156 y as continuamente. Cuando el timer
llegue a 156 sucedern dos cosas: el timer regresa a 0 al siguiente conteo y el timer ser
igual al OCR0A. En este programa activaremos la interrupcin por comparacin con el
OCR0A y en esa interrupcin cambiaremos de estado el pin B0. Note que la interrupcin
se generar cada 156 cuentas que corresponden a 10mS.

Quien define el valor mximo al que contar el timer en este modo es el OCR0A. Entonces
hacemos OCR0A=156d que en hexadecimal es 9Ch.

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
Figura Inicializacin del timer0 para el programa5

El wizard del codevision generar la siguiente subrutina de interrupcin por comparacin el


OCR0A con el timer0 (TCNT0).

// Timer 0 output compare A interrupt service routine


interrupt [TIM0_COMPA] void timer0_compa_isr(void)
{
// Place your code here
}

Esta subrutina de interrupcin ser llamada cada vez que el TCNT0 sea igual al OCR0A, y
esto suceder cada 156 cuentas, que en tiempo corresponde a 10mS, y en esa subrutina
deberemos colocar:

PORTB.0=~PORTB.0;

Y eso hace que el pin B0 cambie de valor, y esto suceder cada 10mS,

/*****************************************************
This program was produced by the
CodeWizardAVR V2.03.6 Evaluation
Automatic Program Generator
Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :
Version :
Date : 03/11/2008
Author : Freeware, for evaluation and non-commercial use only
Company :

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
Comments:

Chip type : ATmega48


Clock frequency : 1,000000 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 128
*****************************************************/

#include <mega48.h>

// Timer 0 output compare A interrupt service routine


interrupt [TIM0_COMPA] void timer0_compa_isr(void)
{
PORTB.0=~PORTB.0;
// Place your code here

// Declare your global variables here

void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 8


#pragma optsize-
CLKPR=0x80;
CLKPR=0x03;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization


// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=Out
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=0
PORTB=0x00;
DDRB=0x01;

// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0x00;
DDRC=0x00;

// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x00;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 15,625 kHz
// Mode: CTC top=OCR0A
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x02;
TCCR0B=0x03;
TCNT0=0x00;
OCR0A=0x9C;
OCR0B=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;

// External Interrupt(s) initialization


// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;

// Timer/Counter 0 Interrupt(s) initialization


TIMSK0=0x02;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x00;

// Analog Comparator initialization


// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;

// Global enable interrupts


#asm("sei")

while (1)
{
// Place your code here

};
}

La imagen de la seal generada se muestra en la siguiente fotografa:

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
Tabla de conteo mximo del timer (256 Cuentas)
Periodo de una cuenta Tiempo que le llevar contar 256 cuentas
1 S (1 MHz) 256 S
8 S (125 KHz) 2.048 mS
64 S (15.625KHz) 16.284 mS
256 S (3906.25 Hz) 65.536 mS
1.024 mS (976.565 Hz) 0.262144 S

4.6 Modo Fast PWM Top=OCR0A (PWM con ajuste de periodo dado por OCR0A)

En este modo el periodo de la seal PWM se ajusta con el registro OCR0A, por ejemplo si
OCR0A=100 significa que el timer contar desde 0 hasta 100 y despus regresar a 0.
Entonces el registro OCR0B se utiliza para ajustar el ancho de pulso del PWM.

Programa Timer6. Se desea una seal PWM con un periodo de 100S, con un ancho de
pulso del 75%, entonces en este modo si podemos ajustar el periodo del timer, para ello
vemos la siguiente tabla y con un preescalamiento de 1 el timer se incrementa cada 1S y el
timer puede contar hasta 256, por lo que si queremos 100S se escoge ese preescalamiento
y se coloca en OCR0A=100; y el ancho de pulso de 75% corresponde a un 75 que se
cargar en el OCR0B. Entonces la seal PWM se mostrar sobre la salida B. Note que en
este modo el OCR0A fija el periodo en cuentas del PWM y el OCR0B es para establecer el
ancho de pulso del PWM.

Tabla de frecuencia y periodos del timer 0


Frecuencia Preescalamiento Frecuencia Tiempo que tarda en incrementarse en una
Interna del timer unidad el timer (1/Frecuencia Timer)
1 MHz 1 1 MHz 1 S
1 MHz 8 125KHz 8 S
1 MHz 64 15.625KHz 64 S
1 MHz 256 3906.25 Hz 256 S
1 MHz 1024 976.5625Hz 1.024 mS

El wizard deber ajustarse de la siguiente manera:

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
Note que en la parte de abajo en Compare A se coloc 65h que es un 100d que corresponde
al periodo en cuentas, y en Compare B se coloc un 4b que coresponde a un 75d para fijar
el ancho de pulso en 75%.

El wizard generar el siguiente cdigo y no ser necesario agregar ms cdigo para que el
programa genere la seal deseada.
/*****************************************************
This program was produced by the
CodeWizardAVR V2.03.6 Evaluation
Automatic Program Generator
Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :
Version :
Date : 03/11/2008
Author : Freeware, for evaluation and non-commercial use only
Company :
Comments:

Chip type : ATmega48


Clock frequency : 1,000000 MHz
Memory model : Small
External RAM size : 0
Data Stack size : 128
*****************************************************/

#include <mega48.h>

// Declare your global variables here

void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 8


#pragma optsize-

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
CLKPR=0x80;
CLKPR=0x03;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization


// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTB=0x00;
DDRB=0x00;

// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0x00;
DDRC=0x00;

// Port D initialization
// Func7=In Func6=In Func5=Out Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=0 State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x20;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 1000,000 kHz
// Mode: Fast PWM top=OCR0A
// OC0A output: Disconnected
// OC0B output: Non-Inverted PWM
TCCR0A=0x23;
TCCR0B=0x09;
TCNT0=0x00;
OCR0A=0x64;
OCR0B=0x4b;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer 1 Stopped
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
OCR2A=0x00;
OCR2B=0x00;

// External Interrupt(s) initialization


// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;

// Timer/Counter 0 Interrupt(s) initialization


TIMSK0=0x00;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x00;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x00;

// Analog Comparator initialization


// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;

while (1)
{
// Place your code here

};
}

4.7 Modo Phase Correct PWM top=OCR0A

Este modo es idntico al modo Phase Correct PWM top=FFh pero la diferencia radica que
el timer no contar hasta FFh sino hasta el valor del OCR0A y cuando se iguala el TCNT0
al valor del OCR0A el timer se reinicializa a 0. Las acciones que pueden generarse en los
pines D5 y D6 son las descritas en el modo Phase Correct PWM top=FFh.

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
4.8 Programacin del timer 2

El timer 2 es idntico al timer 0 en el tipo de seales que genera, adems de que el contador
es de 8 bits, pero con las siguiente diferencias:

El contador del timer0 es el TCNT0


El contador del timer2 es el TCNT2

La salida A asociada al TIMER0 se llama OC0A y es el pin D6


La salida A asociada al TIMER2 se llama OC2A y es el pin B3

La salida B asociada al TIMER0 se llama OC0B y es el pin D5


La salida B asociada al TIMER2 se llama OC2B y es el pin D3

El timer0 puede preescalar la frecuencia entre 1,8,64,256 y 1024 por lo que para una
frecuencia interna de 1MHz se tienen las siguientes frecuencias del timer0.

Tabla de frecuencia y periodos del timer 0


Frecuencia Preescalamiento Frecuencia Tiempo que tarda en incrementarse en una
Interna del timer unidad el timer (1/Frecuencia Timer)
1 MHz 1 1 MHz 1 S
1 MHz 8 125KHz 8 S
1 MHz 64 15.625KHz 64 S
1 MHz 256 3906.25 Hz 256 S
1 MHz 1024 976.5625Hz 1.024 mS

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
El timer2 puede preescalar la frecuencia interna entre ms valores y stos son: 1, 8, 32, 64,
128, 256 y 1024.
Tabla de frecuencias y periodos del timer 2
Frecuencia Preescalamiento Frecuencia Tiempo que tarda en incrementarse en una
Interna del timer unidad el timer (1/Frecuencia Timer)
1 MHz 1 1 MHz 1 S
1 MHz 8 125KHz 8 S
1 MHz 32 31.250KHz 32 S
1 MHz 64 15.625KHz 64 S
1 MHz 128 7.813KHz 128 S
1 MHz 256 3906.25 Hz 256 S
1 MHz 1024 976.5625Hz 1.024 mS

Importante. cuando maneje el timer2 deber usar los registros de comparacin asociados a
l que son OCR2A y OCR2B que son los registros de comparacin del timer 2.

Importante. Los valores de frecuencias y periodos que se muestran en la Tabla del timer 2
son calculados considerando una frecuencia de operacin interna de 1MHz, pero si va usar
otro frecuencia de cristal distinta deber calcular esos datos.

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
4.9 Programacin de timer1

El timer1 es de 16 bits (TCNT1) por lo que puede contar desde 0 hasta 65535 (0 hasta
FFFFh), as que los registros asociados a l son de 16 bits.

Puede preescalarse la frecuencia del timer entre 1,8,64,256 y 1024 por lo que para una
frecuencia interna de 1MHz se tienen las siguientes frecuencias de operacin del timer1.

Tabla de frecuencia y periodos del timer 1


Frecuencia Preescalamiento Frecuencia Tiempo que tarda en incrementarse en una
Interna del timer unidad el timer (1/Frecuencia Timer)
1 MHz 1 1 MHz 1 S
1 MHz 8 125KHz 8 S
1 MHz 64 15.625KHz 64 S
1 MHz 256 3906.25 Hz 256 S
1 MHz 1024 976.5625Hz 1.024 mS

Pero la diferencia del timer0 y timer2 es que el timer1 es de 16 bits por lo que calculamos
la siguiente tabla para cuando el timer cuenta hasta FFFFh pulsos:

Tabla de conteo mximo del timer2 (65536 Cuentas)


Periodo de una cuenta Tiempo que le llevar contar 65536 cuentas
1 S (1 MHz) 65.536mS
8 S (125 KHz) 524.288 mS
64 S (15.625KHz) 4.194304 S
256 S (3906.25 Hz) 16.7772 S
1.024 mS (976.565 Hz) 67.108864 S

El timer1 tiene asociada la salida A al pin B3 y la salida B al pin B2

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
Los registros de comparacin son OCR1A y OCR1B los que tambin son de 16 bits, el
programador les escribe un dato y ese nmero se compara continua y automticamente con
el valor del timer1 (TCNT1) y cuando son iguales se puede generar las siguientes acciones
sobre esos pines: Ponerse a 1 a 0 o cambiar de estado.

4.9.1 Modo Normal top FFFFh (Modo de conteo desde 0 hasta FFFFh)

En este modo el timer va desde 0 hasta FFFF cuando el timer1 llega a FFFF el siguiente
conteo es cero (esto se conoce como sobreflujo y se puede programar una interrupcin cada
vez que llega al valor mximo).

Programa Timer7. Haga un programa que cada segundo cambie de estado el pin B1 donde
se conectar un LED, el led se prender y apagar una vez por segundo.

Se va a configurar la salida A del timer1 (pin B1) en el modo de toggle o de


conmutacin, as que cada vez que ocurra un segundo el pin cambiara de estado.

Primero vemos el preescalamiento que permita medir tiempos de 1 segundo y que est lo
mas cercano a l, as encontramos que se debe preescalar entre 64 la frecuencia del timer
para que opere a 15.625KHz la velocidad de incremento del timer1 y que le llevar
4.194304 Segundos contar desde 0 hasta FFFFh al timer1.

Tabla de conteo mximo del timer2 (65536 Cuentas)


Periodo de una cuenta Tiempo que le llevar contar 65536 cuentas
1 S (1 MHz) 65.536mS
8 S (125 KHz) 524.288 mS
64 S (15.625KHz) 4.194304 S
256 S (3906.25 Hz) 16.7772 S
1.024 mS (976.565 Hz) 67.108864 S

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
Cuntas cuentas corresponden a 1 segundo? Se resuelve as cuentas=1 Segundo/64S
Cuentas=15625. Entonces ese nmero debemos cargarlo en el OCR1A para que cuando el
TCNT1 se haga igual al OCR1A cambie de estado el pin, pero el siguiente segundo ocurrir
cuando OCR1A valga 15625+15625; as que debemos generar una interrupcin por
comparacin con el registro A para leer el valor del OCR1A sumarle 15625 y genere el
siguiente cambio de pin al segundo nmero dos y as sucesivamente.

La inicializacin del timer1 se muestra en la siguiente figura, note que en la parte de abajo
donde est COMP. A escribimos 3d09h que corresponde 15625d y que eso en tiempo es
1 segundo. Y tambin se dio click en Interrupcin por Compare Match A que significa
que se va a generar una interrupcin cuando el timer1 sea igual al registro A.

PENDIENTE DE COMPLETAR EL TIMER1

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
INSTITUTO TECNOLGICO DE MORELIA

TPICOS SELECTOS DE
PROGRAMACIN DE
MICROCONTROLADORES AVR

POR DAVID INFANTE SNCHEZ

dinfante29@hotmail.com
dinfante@itmorelia.edu.mx

Revisin 2.0
Abril del 2008

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com
Objetivos

Disear instrumentos virtuales como medidores y controladores de temperatura,


presin, nivel, voltaje, corriente, etc. Usando LABVIEW y los microcontroladores
de ATMEL.
Control y medicin de variables a travs de mdulos de radio frecuencia
Diseo de filtros digitales IIR usando MATLAB y su implementacin en
microcontroladores ATMEL usando matemtica de punto flotante.

Debido a la complejidad de esta parte es presencial y se incluyen los siguientes temas:

Instrumentacin Virtual

Con el software de LabView se hacen instrumentos virtuales para manipular,


alamacenas y desplegar datos en la PC usando una conexin con el puerto serie del
microcontrolador. (8 horas)

Programas
1. Osciloscopio digital con despliegue en PC
2. Medidor de temperatura y despliegue en instrumentos virtuales
3. Medidor de nivel a travs de sensores de ultrasonido y despliegue en
instrumentos virtuales

Telemetra

Control de puertos de entrada/salida del micrcontrolador a travs de mdulos de RF


(2 horas)

Adquisicin de datos y despliegue de informacin en la pantalla de la PC a travs de


instrumentos virtuales usando mdulos de radio frecuencia (2 horas).

Programas
1. Control de puertos de E/S a travs de radio frecuencia, manipulados a travs
de instrumentos virtuales diseados con LABVIEW
2. Control de la intensidad luminosa de un foco por radio frecuencia y
LABVIEW

Procesamiento digital de seales

Diseo de filtros digitales tipo IIR y su implementacin en microcontroladores de


ATMEL usando matemtica de punto flotante. El diseo de los filtros se hace a
travs del sofware de MATLAB (4 horas)
Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez
e-mail: dinfante29@hotmail.com www.comunidadatmel.com
Programas
1. Diseo de un filtro digital Butterworth e implementacin en un
microcontroladore ATMEL
2. Diseo de un filtro digital Chebyshev e implementacin en un
microcontroladore ATMEL

Para este curso es necesario contar con el sofware de MATLAB, LABVIEW y CodeVision,
y el curso consta de una introduccin a LABVIEW y teora de procesamiento de seales,
as como su programacin en MATLAB para el diseo de los filtros.

Es necesario haber cubierto los temas y prcticas de los cursos anteriores

Programacin en C de los microcontroladores ATMEL Autor: David Infante Snchez


e-mail: dinfante29@hotmail.com www.comunidadatmel.com

También podría gustarte