Curso Avanzado 8.0

58
INSTITUTO TECNOLÓGICO DE MORELIA CURSO AVANZADO DE PROGRAMACIÓN EN C DE MICROCONTROLADORES AVR POR DAVID INFANTE SÁNCHEZ [email protected] [email protected] Revisión 8.0 Septiembre del 2008 Programación en C de los microcontroladores ATMEL Autor: David Infante Sánchez e-mail: [email protected] www.comunidadatmel.com

Transcript of Curso Avanzado 8.0

Page 1: Curso Avanzado 8.0

INSTITUTO TECNOLÓGICO DE MORELIA

CURSO AVANZADO DE PROGRAMACIÓN EN C DE

MICROCONTROLADORES AVR

POR DAVID INFANTE SÁNCHEZ

[email protected]@itmorelia.edu.mx

Revisión 8.0 Septiembre del 2008Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 2: Curso Avanzado 8.0

CAPÍTULO III. TÓPICOS AVANZADOS

3.1 Manejo de las Interrupciones INT0 e INT1

Una interrupción, como su nombre lo indica, interrumpe el programa principal y ejecuta una subrutina de interrupción donde se ejecuta el código que el programador desea, el ejemplo mas representativo es el RESET de una PC cuando se presiona ese botón se interrumpe el programa principal y vuelve a iniciar el programa.

Existen dos tipos de interrupción 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 condición en los periféricos, por ejemplo podemos habilitar una interrupción cuando el ADC termine de hacer la conversión, o cuando suceda overflow en el timer, etc.

El programa CodeVision en la parte de la configuración del chip se hace la configuración de la interrupción ahí se habilita la interrupción y se programa la forma en que funcionará la interrupción, y el CodeVision generará una subrutina de interrupción para esa interrupción en particular.

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

Figura 3.1 Ubicación de las interrupciones externas

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

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 3: Curso Avanzado 8.0

estando en 0 el pin volverá a saltar a la interrupción. 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 interrupción 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 interrupción donde el programador deberá colocar el código que deberá ejecutarse en ese evento.

//External Interrupt 0 service routineinterrupt [EXT_INT0] void ext_int0_isr(void){// Place your code here}

Si se habilita la interrupción externa INT1 el codevision generará la siguiente subrutina.

// External Interrupt 1 service routineinterrupt [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 interrupción 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 detectarán un evento (flanco de bajada, subido, ambos o nivel 0 lógico) y en ese momento saltará a la subrutina de interrupción.

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

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 4: Curso Avanzado 8.0

Programa 11. Diseñe 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.Configuración: 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 interrupción al detectar cambios de flanco de 1 a 0, es decir de bajada.

Figura 3.2 Conexión para el programa 11

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

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

Chip type : ATmega48Clock frequency : 1,000000 MHzMemory model : SmallExternal RAM size : 0Data 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 routineinterrupt [EXT_INT0] void ext_int0_isr(void){

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

}

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 5: Curso Avanzado 8.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_#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: DisconnectedTCCR0A=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: OffTCCR1A=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

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 6: Curso Avanzado 8.0

// Clock value: Timer 2 Stopped// Mode: Normal top=FFh// OC2A output: Disconnected// OC2B output: DisconnectedASSR=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: OffEICRA=0x02;EIMSK=0x01;EIFR=0x01;PCICR=0x00;

// Timer/Counter 0 Interrupt(s) initializationTIMSK0=0x00;// Timer/Counter 1 Interrupt(s) initializationTIMSK1=0x00;// Timer/Counter 2 Interrupt(s) initializationTIMSK2=0x00;

// Analog Comparator initialization// Analog Comparator: Off// Analog Comparator Input Capture by Timer/Counter 1: OffACSR=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 razón de los rebotes que se generan y que se explicaron en los primeros programas del curso.

Programa 12. Diseñe 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.

Configuración: 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 interrupción en cambio de flanco de 1 a 0 y de 0 a 1.

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 7: Curso Avanzado 8.0

Figura 3.3 Conexiones para el programa 12

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

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

Chip type : ATmega48Clock frequency : 1,000000 MHzMemory model : SmallExternal RAM size : 0Data 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 routineinterrupt [EXT_INT1] void ext_int1_isr(void){// Place your code herevar++;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_

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 8: Curso Avanzado 8.0

#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: DisconnectedTCCR0A=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: OffTCCR1A=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: DisconnectedASSR=0x00;TCCR2A=0x00;TCCR2B=0x00;TCNT2=0x00;OCR2A=0x00;OCR2B=0x00;

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 9: Curso Avanzado 8.0

// 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: OffEICRA=0x04;EIMSK=0x02;EIFR=0x02;PCICR=0x00;

// Timer/Counter 0 Interrupt(s) initializationTIMSK0=0x00;// Timer/Counter 1 Interrupt(s) initializationTIMSK1=0x00;// Timer/Counter 2 Interrupt(s) initializationTIMSK2=0x00;

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

// Global enable interrupts#asm("sei")

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

};}

Programa 14. Diseñe 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 lógico de 0 en INT1 se decremente el valor del display.

3.2 Interrupciones externas PCINT0-PCINT23

Además 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 opción como las INT0 e INT1 que pueden configurarse para funcionar en flanco de subida, bajada, en ambos o nivel lógico 0.

2. Las interrupciones PCINTX solo tienen tres subrutinas de interrupción.

Cualquier interrupción generada de PCINT0 a PCINT7 ejecutará la siguiente subrutina de interrupción.

// Pin change 0-7 interrupt service routine

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 10: Curso Avanzado 8.0

interrupt [PCINT0] void pin_change_isr0(void){// Place your code here}

Cualquier interrupción generada de PCINT8 a PCINT14 ejecutará la siguiente subrutina de interrupción.

// Pin change 8-14 interrupt service routineinterrupt [PCINT1] void pin_change_isr1(void){// Place your code here}

Cualquier interrupción generada de PCINT16 a PCINT23 ejecutará la siguiente subrutina de interrupción.

// Pin change 16-23 interrupt service routineinterrupt [PCINT2] void pin_change_isr2(void){// Place your code here}

Tomando como ejemplo esta última subrutina de interrupción indica que cualquier interrupción 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 interrupción, es decir, que podemos habilitar de manera individual cada pin.

En la figura 3.2 vemos que habilitamos la interrupción de PCINT0-PCINT7, pero de todas ellas indicamos que sólo la PCINT1 y la PCINT5 generará la interrupción.

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 11: Curso Avanzado 8.0

Figura 3.2 Habilitación 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 función alterna la de interrupción externa INT1, lo vamos a configurar como fuente de interrupción para detectar flancos de bajada en el pin y que se contabilice en un display conectado al puerto B.

Configuración: Activación de la Interrupción 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 theCodeWizardAVR V1.25.7a EvaluationAutomatic Program Generator© Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.http://www.hpinfotech.com

Project : Version : Date : 04/05/2008

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 12: Curso Avanzado 8.0

Author : Freeware, for evaluation and non-commercial use onlyCompany : Comments:

Chip type : ATtiny461Clock frequency : 1,000000 MHzMemory model : TinyExternal SRAM size : 0Data 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 routineinterrupt [EXT_INT1] void ext_int1_isr(void){ //Esta es la subrutina de interrupción INT1 conteo++; //Note que no hay ninguna función 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=FFhTCCR0A=0x00;TCCR0B=0x00;TCNT0H=0x00;TCNT0L=0x00;OCR0A=0x00;OCR0B=0x00;

// Timer/Counter 1 initialization

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 13: Curso Avanzado 8.0

// 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: OffPLLCSR=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: OffMCUCR=0x02;PCMSK0=0x00;GIMSK=0x80;GIFR=0x80;

// Timer(s)/Counter(s) Interrupt(s) initializationTIMSK=0x00;

// Universal Serial Interface initialization// Mode: Disabled// Clock source: Register & Counter=no clk.// USI Counter Overflow Interrupt: OffUSICR=0x00;

// Analog Comparator initialization// Analog Comparator: OffACSRA=0x80;// Hysterezis level: 0 mVACSRB=0x00;

// Global enable interrupts#asm("sei")

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

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 14: Curso Avanzado 8.0

ExplicaciónDentro del programa principal vemos que se queda de manera infinita ciclado PORTB=tabla7segmentos [conteo];

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

¿Pero dónde o cómo se incrementa la variable conteo? Recuerde que en la inicialización habilitamos la interrupción 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 interrupción de INT1, es decir, el programador no la puede llamar, sino es cuando suceda el evento que genera la interrupción. La subrutina de interrupción de INT1 es la siguiente:

interrupt [EXT_INT1] void ext_int1_isr(void){ //Esta es la subrutina de interrupción INT1 conteo++; //Note que no hay ninguna función 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 interrupción esperando que el programador llene la función de interrupción 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 interrupciónes INT0 e INT1 tienen sus propias funciones de interrupción y pueden programarse para que genere una interrupción 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 interrupción, y si cuando sale de la subrutina de interrupción sigue en nivel bajo volverá a saltar a la subrutina de interrupción. También 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 condición, esto es que no se puede habilitar una por flanco de bajada y otra por flanco de subida ya que es la misma condición 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

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 15: Curso Avanzado 8.0

como una interrupción externa, cuando pruebe en el circuito puede que se incremente el conteo 1,2 o 3 veces cuando se presione el botón y es porque los interruptores mecánicos generan rebotes, por lo que detectará varios flancos de subida y bajada cuando nosotros lo presionemos una sóla vez. Si en vez de conectar un botón conecta un generador de funciones ya no se generarían rebotes y tampoco se necesitaría la resistencia de pull-up debido a que el generador no deja flotado el pin, ya que entrega 0 y 1 lógico.

Otra diferencia que podemos hacer con respecto a los PICs es que los PICs sólo tienen un vector de interrupción y por tanto saltan a la misma subrutina donde el programador debe checar cuál interrupción se generó, en cambio los AVR tienen vectores de interrupción distintos por lo que el manejo de interrupciones es decenas de veces más rápido que los PICs porque estos saltan al mismo vector que los manda a una sola subrutina donde debe probar cada interrupción para saber cuál fue la que la generó.

Programa 20. Realizar un programa que cuando haya una interrupción 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.

Interrupción 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 interrupción cuando cambia de nivel lógico esos pines. Si conectaramos a esos pines un interruptor se generaría una interrupción tanto cunado se presiona el interruptor como cuando se suelta, ya que se generaría un cambio de nivel en ambos casos. A diferencia de las interrupciones INT0 e INT1 (pines 9 y18) los PCINTX sólo funcionan por cambio de nivel lógico es decir en flanco de subida y bajada; y los INT0 e INT1 si los

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 16: Curso Avanzado 8.0

podemos configurar para que funcionen por flanco de subida, bajada, ambos o por nivel lógico 0.

La otra diferencia es que las INT0 e INT1 tienen una subrutina de interrupción distinta. En cambio e la interrupción PCINT tiene una sóla que es la siguiente :

// Pin change 0-15 interrupt service routineinterrupt [PCINT] void pin_change_isr(void){// Place your code here}

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 17: Curso Avanzado 8.0

Capítulo 4. Programación 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 están asociados a un timer es por la razón de que cuando sucede algún evento en el timer se pueden modificar esos pines poniéndose 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 corazón 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 señalar que el preescalador divide únicamente la frecuencia de operación 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 periféricos, pero a su vez se puede dividir la frecuencia del timer por 1,8 64, 256 o 1024 pero esa división sólo afecta al timer y no a la frecuencia de operación del CPU u otros periféricos del microcontrolador. Esa frecuencia preescalada es la que determina cada cuándo se va a modificar el timer que es el TCNT0, el valor del TCNT0 se va comparando automáticamente con el OCR0A (Registro de Comparación del Timer 0 salida A que es el pin D6) y con el OCR0B (Registro de comparación 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

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 18: Curso Avanzado 8.0

hacer nada sobre el pin, poner a 1 o a 0 el pin o intercambiar su valor, esto con la finalidad de generar señales.

Figura Estructura del timer 0

OCROA. Este registro de comparación del Timer0 salida A, es un registro de 8 bits accesible para el programador que continuamente se compara de manera automática con el TCNT0 y cuando son idénticos se puede generar una acción al Pin D6 que es el pin asociado a la salida A del timer0.

OCROB. Este registro de comparación del Timer0 Salida B es un registro de 8 bits que puede modificar el programador y que continuamente se compara de manera automática con el TCNT0 y cuando son idénticos se puede generar una acción al Pin D5 que es el pin asociado a la salida B del timer0.

FRECUENCIA DE OPERACIÓN 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 1µS, esto es que cada 1µS 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*1µS=256µS llegar desde 0 hasta 255.

El timer puede ser preescalado por 1, 8, 64, 256 o 1024 esto significa que si la frecuencia de operación 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 operación del microcontrolador para determinar las frecuencias del timer. Estos valores descritos son

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 19: Curso Avanzado 8.0

considerando que el microcontrolador opera a 1MHz como es el caso de un microcontrolador nuevo que viene de fábrica a 8MHz pero dividida la frecuencia de operación 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 serán 256 cuentas*1.024mS=0.262144 Segundos.

Las siguientes tablas deberá tenerlas en mente para los cálculos usados para programar el timer, y también tenga en cuenta que estas tablas son válidas 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 0Frecuencia

InternaPreescalamiento Frecuencia

del timerTiempo que tarda en incrementarse en una unidad el timer (1/Frecuencia Timer)

1 MHz 1 1 MHz 1 µS 1 MHz 8 125KHz 8 µS1 MHz 64 15.625KHz 64 µS1 MHz 256 3906.25 Hz 256 µS1 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 máximo del timer (256 Cuentas)Periodo de una cuenta Tiempo que le llevará contar 256 cuentas 1 µS (1 MHz) 256 µS8 µS (125 KHz) 2.048 mS64 µS (15.625KHz) 16.284 mS256 µS (3906.25 Hz) 65.536 mS1.024 mS (976.565 Hz) 0.262144 S

Importante. Recuerde que estas tablas son para una frecuencia de operación 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 VARÍA CON LA TEMPERATURA pero es cercana a 1 MHz. Para control de tiempos exactos deberá conectarse un oscilador o cristal externo.

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 20: Curso Avanzado 8.0

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 incrementándose en una unidad cada determinada cantidad de tiempo, según la frecuencia y el preescalamiento, pero el timer tiene un determinado ancho en bits por lo que el número máximo que puede almacenar está limitado. Por ejemplo el timer0 es de 8 bits por lo que puede tener un número desde 0 hasta 255 (0 a FFh) pero cuando tiene 254 y cuenta una unidad más, el timer se incrementa a 255, y si cuenta un número más 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 máximo y contar un pulso más que hace que el timer regrese a cero.

SEÑALES PWM. Una señal PWM (Pulse Width Modulation) o modulación por ancho de pulso tiene las siguientes características: El periodo de la señal es fijo, lo que cambia es el ancho de pulso.

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

Las señales PWM son muy utilizadas en control de energía de CA y CD. Si conectáramos un LED con un PWM al 50% veríamos que está ligeramente encendido, si subimos el ancho de pulso el LED prendería con mayor intensidad, y si la modulación está al 100% el LED prendería al máximo de intensidad lumínica. PWM invertida. En una señal PWM invertida la modulación es cuánto tiempo estará en 0 la señal. Cuando está al 75% significa que ¾ partes del periodo de la señal estará en 0. Vea la siguiente figura de una señal PWM invertida al 50%, 75% y 100%.

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 21: Curso Avanzado 8.0

PWM con Modulación no invertida al centro. En determinados tipos de control de motores la modulación no se hace con respecto al inicio del periodo, sino con respecto al centro. En la siguiente figura se aprecia PWM con modulación no invertida al centro con modulación al 50%, 75% y 100%.

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

PWM con Modulación invertida al centro. En este tipo de modulación la modulación es el tiempo que está en 0 con respecto al centro del periodo, y en la siguiente figura se tienen este tipo de modulación al 50%, 75% y 100%.

Estos modos de modulación 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 inglés que es como lo pone el wizard del codevision y en español no será propiamente su traducción, sino será una traducción basada en su funcionamiento.

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 22: Curso Avanzado 8.0

4.2 Modo Normal top=FFH (Modo Normal del Timer contando desde 0 hasta 255d)

Modo Normal top=FFhEn este modo el timer cuenta desde 0 hasta 255 cuando llega a 255 y se detecta un conteo más se regresa a 0. Esta acción se le conoce como sobreflujo (overflow) porque después de 255 el valor correcto debería 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 repitiéndose el 0 al siguiente pulso, esto es que cuenta de manera cíclica de 0 a 255.

Registros de comparación OCROA y OCROB, estos dos registros significan que dará una salida a la comparación 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 número y se comparan continuamente y de manera automática con el timer (TCNT0) y cuando se hacen iguales se genera una acción.

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 acción, y cuando el timer (TCNT0) valga 200 se generará otra acción.

Tabla Acciones que se pueden programar a la comparaciónLas acciones que se pueden generar DescripciónDisconnected No hay ningún efectoToggle on Compare match Conmuta el valor del pin Clear on Compare match Se pone en 0 el pin

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 23: Curso Avanzado 8.0

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 generarán a la comparación 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 (línea roja) antes de 100 y después 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 (línea 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 más 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 comparación OCR0A y OCR0B cuando esos

registros tienen el mismo valor que el TCNT0 se hace una acción 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 acción 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 conmutación (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 señal cuadrada que duré 2.048 mS en bajo y 2.048 mS en alto. En este modo de

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 24: Curso Avanzado 8.0

operación el periodo de la señal no se puede modificar porque el timer siempre cuenta desde 0 hasta FF, y de los cálculos antes vistos tenemos:

Tabla de frecuencia y periodos del timer 0Frecuencia

InternaPreescalamiento Frecuencia

del timerTiempo que tarda en incrementarse en una unidad el timer (1/Frecuencia Timer)

1 MHz 1 1 MHz 1 µS 1 MHz 8 125KHz 8 µS1 MHz 64 15.625KHz 64 µS1 MHz 256 3906.25 Hz 256 µS1 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 máximo del timer (256 Cuentas)Periodo de una cuenta Tiempo que le llevará contar 256 cuentas 1 µS (1 MHz) 256 µS8 µS (125 KHz) 2.048 mS64 µS (15.625KHz) 16.284 mS256 µS (3906.25 Hz) 65.536 mS1.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 acción a generar en la comparación 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 sucederán 256 pulsos más para que cambie de valor. Vea la siguiente figura:

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

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 25: Curso Avanzado 8.0

La configuración 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 señales, note también que en la parte más baja del Timero se colocó un 64h que es un 100 decimal.

Figura. Selección del timer 0 para el programaVea el vídeo timer1 donde se explica el programa y la inicialización 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:

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 26: Curso Avanzado 8.0

En el programa anterior expliqué que no podemos modificar el periodo de la señal, pero podemos actualizar continuamente los registros de comparación para generar cualquier periodo en la señal, primero veremos la tabla que ya se había calculado:

Tabla de conteo máximo del timer (256 Cuentas) con una frecuencia de 1MHZPeriodo de una cuenta Tiempo que le llevará contar 256 cuentas 1 µS (1MHz) 256 µS8 µS (125KHz) 2.048 mS64 µS (15.625KHz) 16.284 mS256 µS (3906.25 Hz) 65.536 mS1.024 mS (976.565 Hz) 0.262144 S

Si quisiéramos generar señales cuadradas con una frecuencia digamos de 2Khz, debemos hacer lo siguiente:

El periodo de una señal de 2KHz es 0.5mS, con 0.25mS en alto y 0.25mS en bajo, por lo que debemos escoger un preescalamiento que dé más de 0.5mS para que quepa la señal que queremos generar, de esa forma vemos que podemos seleccionar cualquier preescalamiento del segundo en adelante, porque en el primero el tiempo máximo que podemos medir son 256µS y ocupamos que sea mayor a 0.5 mS, ¿pero cuál de todos es el más adecuado? Para ello pondré el siguiente ejemplo: Cuando va a medir 1.5 Volts ¿Cuál escala selecciona 2, 20 o 200 Volts? Selecciona el más cercano es decir 2 Volts para una mayor resolución; para el timer razonamos de la misma forma, cuál se encuentra más cercano a 0.5mS la opción sería la frecuencia de 125 Khz que está resaltada en verde porque el periodo del timer a las 256 cuentas da 2.048 mS.

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 27: Curso Avanzado 8.0

Es importante señalar 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 señal cambie cada 0.25mS, así que traducido en cuentas sería 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 (conmutación del pin a la comparación) entonces en el OCR0A le escribimos el 31 para que cambie el pin a los 0.25mS, pero los otros 0.25mS ocurrirán a las 62 cuentas, y los siguientes 0.25 mS sucederán 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 interrupción a la comparación del TCNT0 con el OCR0A y OCR0B. Cuando el TCNT0 sea igual al OCR0A se generará una interrupción y en la interrupción lo que haremos es leer el OCR0A para sumarle 31 para que la siguiente comparación sea 31 cuentas después o 0.25mS después, cuando sea TCNT0 igual al OCR0A se generará otra interrupción y sumaremos otros 31 al OCR0A para que el siguiente cambio del pin sea 0.25mS después. Vea la gráfica siguiente:

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

Ve el vídeo timer2 donde se explica la inicialización del timer para el siguiente programa.

Programa timer2. Configure el timer para generar una señal 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:

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 28: Curso Avanzado 8.0

Note que estamos habilitando interrupción por comparación en el OCR0B con el TCNT0 (Compare Match B Interrupt) y el codewizard generará la siguiente subrutina de interrupción:

// Timer 0 output compare A interrupt service routineinterrupt [TIM0_COMPA] void timer0_compa_isr(void){// Place your code here}

Note que cuando nos genera la subrutina de interrupción coloca como comentario en la parte superior: // Timer 0 output compare A interrupt service routine Esto es útil para que el programador sepa de cuál subrutina de interrupción se trata. Ese comentario traducido es: Subrutina de Interrupción por Comparación de la salida B del timer0. Recuerde que las subrutinas de interrupción 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 interrupción.

Entonces cuando el OCR0A con el TCNT0 qué debemos hacer: leer el valor del OCR0A y sumarle 31 para que se compare 31 cuentas después que son 0.25mS.Es decir que el código que colocaremos en esa subrutina de interrupción es:

OCR0A=CR0A+31;

Note también 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.

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 29: Curso Avanzado 8.0

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 además que se genere una interrupción, en esa subrutina de interrupción 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 theCodeWizardAVR V2.03.6 EvaluationAutomatic Program Generator© Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.http://www.hpinfotech.com

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

Chip type : ATmega48Clock frequency : 1,000000 MHzMemory model : SmallExternal RAM size : 0Data Stack size : 128*****************************************************/

#include <mega48.h>

// Timer 0 output compare A interrupt service routineinterrupt [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

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 30: Curso Avanzado 8.0

// 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: DisconnectedTCCR0A=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: OffTCCR1A=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: DisconnectedASSR=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: OffEICRA=0x00;EIMSK=0x00;PCICR=0x00;

// Timer/Counter 0 Interrupt(s) initialization

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 31: Curso Avanzado 8.0

TIMSK0=0x02;// Timer/Counter 1 Interrupt(s) initializationTIMSK1=0x00;// Timer/Counter 2 Interrupt(s) initializationTIMSK2=0x00;

// Analog Comparator initialization// Analog Comparator: Off// Analog Comparator Input Capture by Timer/Counter 1: OffACSR=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 interrupción para actualizar el OCR0A sumándole 31 cuentas que son equivalentes 0.25mS.

En la siguiente imagen se muestra una fotografía de la señal generada de este programa en un osciloscopio.

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 32: Curso Avanzado 8.0

4.3 Modo Phase Correct PWM top=FFh (Modo PWM con modulación 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 después vuelve a incrementarse hasta llegar a 255, y así sucesivamente. Es decir, en este modo de operación el timer es ascendente hasta llegar al máximo y después se hace descendente. El periodo del timer es 510 ya que cuenta de manera ascendente y luego de manera descendente.

La traducción de este modo sería PWM con corrección de fase y quizás no le dé una idea clara, pero en otras palabras y según su funcionamiento es: PWM centrado con periodo de 510. La razón 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í también se utilizan los registros de 8 bits del timer 0 que son OCR0A y OCR0B, estos dos registros se comparan de manera automática con el timer (TCNT0) y cuando se hacen iguales pueden suceder las siguientes acciones en los pines D6 y D5 que es donde están asociados los registros respectivamente:

1. Disconnected. No hay efecto sobre el pin2. Non-inverted PWM. En esta configuración al iniciar el timer comienza el pin en 0 al

hacerse igual al OCR0X el pin se pone a 1, después el timer (TCNT0) llega al máximo y comienza a decrementarse cuando son iguales el TCNT0 y el OCR0X el pin se pone en 0.

3. Inverted PWM. En esta configuración 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 máximo regresa en un conteo descendente y al hacerse igual al OCR0X el pin se pone nuevamente a 1, esto es que la señal generada es exactamente la inversión de la señal del punto 2.

Las acciones 2 y 3 corresponden al PWM con Modulación no invertida e invertida al centro que se explicó en la sección 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 señal 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 después 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 máximo 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.

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 33: Curso Avanzado 8.0

La línea azul ilustra la señal 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 señales ilustradas son útiles en control de motores.

Programa para ejemplificar el funcionamiento del PWM con modulación al centro no invertida.

Si la frecuencia interna de operación es de 1MHz y los preescalamientos son 1, 8, 64, 256 y 1024. Tenemos las frecuencias de operación del timer de:

Tabla de frecuencia y periodos del timer 0Frecuencia

InternaPreescalamiento Frecuencia

del timerTiempo que tarda en incrementarse en una unidad el timer (1/Frecuencia Timer)

1 MHz 1 1 MHz 1 µS 1 MHz 8 125KHz 8 µS1 MHz 64 15.625KHz 64 µS1 MHz 256 3906.25 Hz 256 µS1 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 máximo del timer (510 Cuentas)Periodo de una cuenta Tiempo que le llevará contar 510 cuentas 1 µS (1 Mhz) 510 µS8 µS (125 KHz) 4.08 mS64 µS (15.625KHz) 32.64 mS256 µS (3906.25 Hz) 130.56 mS1.024 mS (976.5625Hz) 0.52224 S

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 34: Curso Avanzado 8.0

Programa timer3. Escriba un programa con PWM no invertido con un ancho de pulso del 50%. Con un periodo de la señal de 32.64mS. La señal se generará en la salida B del timer0. Vea la inicialización del timer para este programa en el video timer3.

Note que no podemos modificar el periodo de la señal, ya que el número de cuentas es fijo y es de 510 además 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 incrementándose y se hace igual al 127 del OCR0B se pone a 1 el pin D5 y se mantiene así hasta que el TCNT0 va decrementándose y se vuelve hacer igual a 127.

Seleccione el timer0 como se muestra en la siguiente figura

Configuración del timero

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 35: Curso Avanzado 8.0

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 instrucción.

Foto de la señal generada en el programa timer3

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 36: Curso Avanzado 8.0

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 señal 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 pin2. Non-inverted PWM. En esta configuración 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 configuración 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 (línea 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 repitiéndose 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 (línea 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 también 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 señales para el control de la energía en CD y AC, para el control de ángulos de disparo de tiristores.

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 37: Curso Avanzado 8.0

Programa Timer4. Controlar la energía lumínica de un LED mediante una señal PWM que se generará en la salida B del timer0 (pin D5). EL ancho de pulso se controlará mediante un potenciómetro conectado al canal 0 del ADC (Pin C0) Este potenciómetro variará el voltaje desde 0 hasta 5 Volts. Vea el video timer4 donde se muestra la configuración 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 analógica 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 dañar 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 máximo del timer (256 Cuentas)Periodo de una cuenta Tiempo que le llevará contar 256 cuentas 1 µS (1 Mhz) 256 µS8 µS (125 KHz) 2.048 mS64 µS (15.625KHz) 16.284 mS256 µS (3906.25 Hz) 65.536 mS1.024 mS (976.5625Hz) 0.262144 S

La configuración del timer y del ADC deberá hacerla de la siguiente manera:

Figura. Inicialización del timer y del ADC

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 38: Curso Avanzado 8.0

Note que se está habilitando la interrupción por sobreflujo (Ovreflow Interrupt) del timer, entonces cuando el timer llegue al valor máximo de conteo que es FFh y se dé un pulso más el timer se hará cero y se generará la interrupción por sobreflujo, y en esta interrupción 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 más grande y por lo tanto el LED emitirá una mayor intensidad lumínica.

Vea que en la subrutina de interrupción 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 código:

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

Coloque el código en azul en la subrutina de interrupción como se muestra en el siguiente listado y compílelo y verá que marca un error.

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

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

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

Chip type : ATmega48Clock frequency : 1,000000 MHzMemory model : SmallExternal RAM size : 0Data Stack size : 128*****************************************************/

#include <mega48.h>

#include <delay.h>

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 39: Curso Avanzado 8.0

#define ADC_VREF_TYPE 0x60

// Read the 8 most significant bits// of the AD conversion resultunsigned char read_adc(unsigned char adc_input){ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);// Delay needed for the stabilization of the ADC input voltagedelay_us(10);// Start the AD conversionADCSRA|=0x40;// Wait for the AD conversion to completewhile ((ADCSRA & 0x10)==0);ADCSRA|=0x10;return ADCH;}

// Timer 0 overflow interrupt service routineinterrupt [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 PWMTCCR0A=0x23;TCCR0B=0x03;TCNT0=0x00;

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 40: Curso Avanzado 8.0

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: OffTCCR1A=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: DisconnectedASSR=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: OffEICRA=0x00;EIMSK=0x00;PCICR=0x00;

// Timer/Counter 0 Interrupt(s) initializationTIMSK0=0x01;// Timer/Counter 1 Interrupt(s) initializationTIMSK1=0x00;// Timer/Counter 2 Interrupt(s) initializationTIMSK2=0x00;

// Analog Comparator initialization// Analog Comparator: Off// Analog Comparator Input Capture by Timer/Counter 1: OffACSR=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

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 41: Curso Avanzado 8.0

DIDR0=0x00;ADMUX=ADC_VREF_TYPE & 0xff;ADCSRA=0x81;

// Global enable interrupts#asm("sei")

while (1) { // Place your code here

};}

Foto a) Modulación con un ancho de pulso muy pequeño, note que el voltaje medio es de 64.2mV por lo que el led tendrá una intensidad muy baja.

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 42: Curso Avanzado 8.0

El ancho de pulso se incrementa y el voltaje promedio también sube, el led obtiene mayor intensidad.

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

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 43: Curso Avanzado 8.0

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 después 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 señal, recuerde que el periodo se fija en número de cuentas. Estos modos los veremos a continuación.

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 según su funcionamiento es: reinicialización del timer cuando se haga igual al OCR0A, es decir que si seleccionamos este modo de operación 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 señal a través 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. Diseñar un programa que cada 10mS cambie de estado el pin B0. Para ello se utilizará la interrupción por comparación con el OCR0A. Aquí notamos que el pin B0 no está asociado a ningún timer, pero aquí usaremos el timer como un temporizador, no como un generador de señales, así que cada 10mS se generará una interrupción 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 más cercana y mayor a 10mS. Los 10 mS caben en una frecuencia de conteo de 15.625KHz.

¿Cuántas cuentas debe tener el timer para que genere una interrupción cada 10mS? 10mS/64uS=156.25 pero como deben ser enteros sería 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 sucederán dos cosas: el timer regresa a 0 al siguiente conteo y el timer será igual al OCR0A. En este programa activaremos la interrupción por comparación con el OCR0A y en esa interrupción cambiaremos de estado el pin B0. Note que la interrupción se generará cada 156 cuentas que corresponden a 10mS.

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

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 44: Curso Avanzado 8.0

Figura Inicialización del timer0 para el programa5

El wizard del codevision generará la siguiente subrutina de interrupción por comparación el OCR0A con el timer0 (TCNT0).

// Timer 0 output compare A interrupt service routineinterrupt [TIM0_COMPA] void timer0_compa_isr(void){// Place your code here}

Esta subrutina de interrupción 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 theCodeWizardAVR V2.03.6 EvaluationAutomatic Program Generator© Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.http://www.hpinfotech.com

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

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 45: Curso Avanzado 8.0

Comments:

Chip type : ATmega48Clock frequency : 1,000000 MHzMemory model : SmallExternal RAM size : 0Data Stack size : 128*****************************************************/

#include <mega48.h>

// Timer 0 output compare A interrupt service routineinterrupt [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: DisconnectedTCCR0A=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.

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 46: Curso Avanzado 8.0

// 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: OffTCCR1A=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: DisconnectedASSR=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: OffEICRA=0x00;EIMSK=0x00;PCICR=0x00;

// Timer/Counter 0 Interrupt(s) initializationTIMSK0=0x02;// Timer/Counter 1 Interrupt(s) initializationTIMSK1=0x00;// Timer/Counter 2 Interrupt(s) initializationTIMSK2=0x00;

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

// Global enable interrupts#asm("sei")

while (1) { // Place your code here

};}

La imagen de la señal generada se muestra en la siguiente fotografía:

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 47: Curso Avanzado 8.0

Tabla de conteo máximo del timer (256 Cuentas)Periodo de una cuenta Tiempo que le llevará contar 256 cuentas 1 µS (1 MHz) 256 µS8 µS (125 KHz) 2.048 mS64 µS (15.625KHz) 16.284 mS256 µS (3906.25 Hz) 65.536 mS1.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 señal PWM se ajusta con el registro OCR0A, por ejemplo si OCR0A=100 significa que el timer contará desde 0 hasta 100 y después regresará a 0. Entonces el registro OCR0B se utiliza para ajustar el ancho de pulso del PWM.

Programa Timer6. Se desea una señal PWM con un periodo de 100µS, 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 1µS y el timer puede contar hasta 256, por lo que si queremos 100µS 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 señal 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 0Frecuencia

InternaPreescalamiento Frecuencia

del timerTiempo que tarda en incrementarse en una unidad el timer (1/Frecuencia Timer)

1 MHz 1 1 MHz 1 µS 1 MHz 8 125KHz 8 µS1 MHz 64 15.625KHz 64 µS1 MHz 256 3906.25 Hz 256 µS1 MHz 1024 976.5625Hz 1.024 mS

El wizard deberá ajustarse de la siguiente manera:

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 48: Curso Avanzado 8.0

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 código y no será necesario agregar más código para que el programa genere la señal deseada.

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

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

Chip type : ATmega48Clock frequency : 1,000000 MHzMemory model : SmallExternal RAM size : 0Data 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-

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 49: Curso Avanzado 8.0

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 PWMTCCR0A=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: OffTCCR1A=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: DisconnectedASSR=0x00;TCCR2A=0x00;TCCR2B=0x00;TCNT2=0x00;

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 50: Curso Avanzado 8.0

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: OffEICRA=0x00;EIMSK=0x00;PCICR=0x00;

// Timer/Counter 0 Interrupt(s) initializationTIMSK0=0x00;// Timer/Counter 1 Interrupt(s) initializationTIMSK1=0x00;// Timer/Counter 2 Interrupt(s) initializationTIMSK2=0x00;

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

while (1) { // Place your code here

};}

4.7 Modo Phase Correct PWM top=OCR0A

Este modo es idéntico 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.

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 51: Curso Avanzado 8.0

4.8 Programación del timer 2

El timer 2 es idéntico al timer 0 en el tipo de señales que genera, además de que el contador es de 8 bits, pero con las siguiente diferencias:

El contador del timer0 es el TCNT0El contador del timer2 es el TCNT2

La salida A asociada al TIMER0 se llama OC0A y es el pin D6La 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 D5La 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 0Frecuencia

InternaPreescalamiento Frecuencia

del timerTiempo que tarda en incrementarse en una unidad el timer (1/Frecuencia Timer)

1 MHz 1 1 MHz 1 µS 1 MHz 8 125KHz 8 µS1 MHz 64 15.625KHz 64 µS1 MHz 256 3906.25 Hz 256 µS1 MHz 1024 976.5625Hz 1.024 mS

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 52: Curso Avanzado 8.0

El timer2 puede preescalar la frecuencia interna entre más valores y éstos son: 1, 8, 32, 64, 128, 256 y 1024.

Tabla de frecuencias y periodos del timer 2Frecuencia

InternaPreescalamiento Frecuencia

del timerTiempo que tarda en incrementarse en una unidad el timer (1/Frecuencia Timer)

1 MHz 1 1 MHz 1 µS 1 MHz 8 125KHz 8 µS1 MHz 32 31.250KHz 32 µS1 MHz 64 15.625KHz 64 µS1 MHz 128 7.813KHz 128 µS1 MHz 256 3906.25 Hz 256 µS1 MHz 1024 976.5625Hz 1.024 mS

Importante. cuando maneje el timer2 deberá usar los registros de comparación asociados a él que son OCR2A y OCR2B que son los registros de comparación 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 operación interna de 1MHz, pero si va usar otro frecuencia de cristal distinta deberá calcular esos datos.

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 53: Curso Avanzado 8.0

4.9 Programación 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 operación del timer1.

Tabla de frecuencia y periodos del timer 1Frecuencia

InternaPreescalamiento Frecuencia

del timerTiempo que tarda en incrementarse en una unidad el timer (1/Frecuencia Timer)

1 MHz 1 1 MHz 1 µS 1 MHz 8 125KHz 8 µS1 MHz 64 15.625KHz 64 µS1 MHz 256 3906.25 Hz 256 µS1 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 máximo del timer2 (65536 Cuentas)Periodo de una cuenta Tiempo que le llevará contar 65536 cuentas 1 µS (1 MHz) 65.536mS8 µS (125 KHz) 524.288 mS64 µS (15.625KHz) 4.194304 S256 µS (3906.25 Hz) 16.7772 S1.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

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 54: Curso Avanzado 8.0

Los registros de comparación son OCR1A y OCR1B los que también son de 16 bits, el programador les escribe un dato y ese número se compara continua y automáticamente 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 interrupción cada vez que llega al valor máximo).

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 conmutación, 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 máximo del timer2 (65536 Cuentas)Periodo de una cuenta Tiempo que le llevará contar 65536 cuentas 1 µS (1 MHz) 65.536mS8 µS (125 KHz) 524.288 mS64 µS (15.625KHz) 4.194304 S256 µS (3906.25 Hz) 16.7772 S1.024 mS (976.565 Hz) 67.108864 S

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 55: Curso Avanzado 8.0

¿Cuántas cuentas corresponden a 1 segundo? Se resuelve así cuentas=1 Segundo/64µSCuentas=15625. Entonces ese número 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 interrupción por comparación con el registro A para leer el valor del OCR1A sumarle 15625 y genere el siguiente cambio de pin al segundo número dos y así sucesivamente.

La inicialización 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 también se dio click en Interrupción por “Compare Match A” que significa que se va a generar una interrupción cuando el timer1 sea igual al registro A.

PENDIENTE DE COMPLETAR EL TIMER1

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 56: Curso Avanzado 8.0

INSTITUTO TECNOLÓGICO DE MORELIA

TÓPICOS SELECTOS DE PROGRAMACIÓN DE

MICROCONTROLADORES AVR

POR DAVID INFANTE SÁNCHEZ

[email protected]@itmorelia.edu.mx

Revisión 2.0 Abril del 2008

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 57: Curso Avanzado 8.0

Objetivos

• Diseñar instrumentos virtuales como medidores y controladores de temperatura, presión, nivel, voltaje, corriente, etc. Usando LABVIEW y los microcontroladores de ATMEL.

• Control y medición de variables a través de módulos de radio frecuencia• Diseño de filtros digitales IIR usando MATLAB y su implementación en

microcontroladores ATMEL usando matemática de punto flotante.

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

Instrumentación Virtual

• Con el software de LabView se hacen instrumentos virtuales para manipular, alamacenas y desplegar datos en la PC usando una conexión con el puerto serie del microcontrolador. (8 horas)

Programas1. Osciloscopio digital con despliegue en PC2. Medidor de temperatura y despliegue en instrumentos virtuales3. Medidor de nivel a través de sensores de ultrasonido y despliegue en

instrumentos virtuales

Telemetría

• Control de puertos de entrada/salida del micrcontrolador a través de módulos de RF (2 horas)

• Adquisición de datos y despliegue de información en la pantalla de la PC a través de instrumentos virtuales usando módulos de radio frecuencia (2 horas).

Programas1. Control de puertos de E/S a través de radio frecuencia, manipulados a través

de instrumentos virtuales diseñados con LABVIEW2. Control de la intensidad luminosa de un foco por radio frecuencia y

LABVIEW

Procesamiento digital de señales

• Diseño de filtros digitales tipo IIR y su implementación en microcontroladores de ATMEL usando matemática de punto flotante. El diseño de los filtros se hace a través del sofware de MATLAB (4 horas)

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com

Page 58: Curso Avanzado 8.0

Programas1. Diseño de un filtro digital Butterworth e implementación en un

microcontroladore ATMEL2. Diseño de un filtro digital Chebyshev e implementación en un

microcontroladore ATMEL

Para este curso es necesario contar con el sofware de MATLAB, LABVIEW y CodeVision, y el curso consta de una introducción a LABVIEW y teoría de procesamiento de señales, así como su programación en MATLAB para el diseño de los filtros.

Es necesario haber cubierto los temas y prácticas de los cursos anteriores

Programación en C de los microcontroladores ATMEL Autor: David Infante Sáncheze-mail: [email protected] www.comunidadatmel.com