No tengo mucha experiencia con interrupciones y he leído bastante pero no logro dar con una solución a lo siguiente:
Estoy probando un código en el Diecimilia que tiene el Timer0 generando 1Khz por el pin8 pero necesito que este se active cada 2 segundos.
Para eso estoy usando otra interrupción con el Timer1, el cual lo tengo configurado para que interrumpa cada 2 segundos precisamente.
Lo que no consigo es que desde la rutina de interrupción del Timer1, pueda des habilitar el Timer0.
Agradecido a cualquiera que pueda aportar, tal vez sea un tema de concepto, porque creo que el Timer0 tiene interrupciones mas rápidas que el Timer1 y algo pasa que esta última rutina no es tomado en consideración por el Timer0.
Mi idea es no usar el Delay y Tone propios del lenguaje Arduino, ya que lo que necesito es precisión.
Dejo el código para mejor comprensión.
//Interrupciones
//Timer setup para timer0, timer1, and timer2.
//timer0 will interrupt at 2kHz
//timer1 will interrupt at 1Hz
#include "avr/pgmspace.h"
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
//storage variables
boolean toggle0 = 0;
boolean toggle1 = 0;
void setup(){
//set pins as outputs
pinMode(8, OUTPUT);//Timer0
pinMode(13, OUTPUT);//Timer1
cli();//stop interrupts
//set timer0 interrupt at 2kHz
TCCR0A = 0;// set entire TCCR2A register to 0
TCCR0B = 0;// same for TCCR2B
TCNT0 = 0;//initialize counter value to 0
// set compare match register for 2khz increments
OCR0A = 124;// = (16*10^6) / (2000*64) - 1 (must be <256)
// turn on CTC mode
TCCR0A |= (1 << WGM01);
// Set CS11 and CS10 bits for 64 prescaler
TCCR0B |= (1 << CS11) | (1 << CS10);
// enable timer compare interrupt
TIMSK0 |= (1 << OCIE0A);
//set timer1 interrupt at 1Hz
TCCR1A = 0;// set entire TCCR1A register to 0
TCCR1B = 0;// same for TCCR1B
TCNT1 = 0;//initialize counter value to 0
// set compare match register for 1hz increments
OCR1A = 31248 ;// = 2*(16*10^6) / (1*1024) - 1 (must be <65536)
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS12 and CS10 bits for 1024 prescaler
TCCR1B |= (1 << CS12) | (1 << CS10);
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
//set timer2 interrupt at 8kHz
TCCR2A = 0;// set entire TCCR2A register to 0
TCCR2B = 0;// same for TCCR2B
TCNT2 = 0;//initialize counter value to 0
// set compare match register for 8khz increments
OCR2A = 249;// = (16*10^6) / (8000*8) - 1 (must be <256)
// turn on CTC mode
TCCR2A |= (1 << WGM21);
// Set CS11 bit for 8 prescaler
TCCR2B |= (1 << CS11);
// enable timer compare interrupt
TIMSK2 |= (1 << OCIE2A);
sei();//allow interrupts
}//end setup
ISR(TIMER0_COMPA_vect){//timer0 interrupt 2kHz toggles pin 8
//generates pulse wave of frequency 2kHz/2 = 1kHz (takes two cycles for full wave- toggle high then toggle low)
if (toggle0){
digitalWrite(8,HIGH);
toggle0 = 0;
}
else{
digitalWrite(8,LOW);
toggle0 = 1;
}
}
ISR(TIMER1_COMPA_vect){//timer1 interrupt 1Hz toggles pin 13 (LED)
//Genera pulsos de onda de frecuencia 2 segundos
if (toggle1){
digitalWrite(13,HIGH);
toggle1 = 0;
}
else{
digitalWrite(13,LOW);
toggle1 = 1;
}
}
void loop(){
while(true);
}
Entiendo que lo que está ocurriendo es que se genera tono y el led13 parpadea, pero no se para el tono, ¿no?.
Lo que deberías hacer, creo yo, en la interrupción del timer1 es quitar esto del setup (aunque también lo puedes dejar ahí):
y habilitar/deshabilitar el bit OCIE0A dentro del código de la interrupción de timer1.
No parece en tu caso que tenga consecuencias, pero es recomendable que las variables toggle0 y toggle1 las declares volatile. Así se recomienda siempre que una interrupción modifique una variable externa a ella, pues otra parte del código que la utilice puede no "enterarse" de que ha sido modificada por la interrupción. Si no la vas a utilizar en otras partes, yo prefiero declararlas como static dentro de la propia función y así evito problemas de poder toquetearla desde donde no debo, y además el código queda más "juntito" (es menos probable que te preguntes "¿para qué c**** uso esta variable?").
Espero que haya podido ayudarte.
Saludos.
OK Gracias, pero hice unos cambios, y lo que tenía que hacer era unos manejos a nivel de Bit del Timer 0.
Ahora lo modifique para que emita el tono de 2Khz por 1 segundo cada 5 segundos según el código siguiente:
//Interrupciones
//Timer setup para timer0, timer1.
//timer0 will interrupt at 2kHz
//timer1 will interrupt at 1Hz
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) // Aqui una definición del manejo del Bit para setearlo a 0
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) // Aqui una definición del manejo del Bit para setearlo a 1
//variables volatile en la RAM
volatile boolean toggle0 = 0;
volatile boolean toggle1 = 0;
volatile byte tiempoOFF = 0;
void setup(){
//set pins as outputs
pinMode(8, OUTPUT);//Timer0
pinMode(13, OUTPUT);//Timer1
cli();//stop interrupts
//set timer0 interrupt at 2kHz
TCCR0A = 0;// set entire TCCR2A register to 0
TCCR0B = 0;// same for TCCR2B
TCNT0 = 0;//initialize counter value to 0
// set compare match register for 2khz increments
OCR0A = 124;// = (16*10^6) / (2000*64) - 1 (must be <256)
// turn on CTC mode
TCCR0A |= (1 << WGM01);
// Set CS11 and CS10 bits for 64 prescaler
TCCR0B |= (1 << CS11) | (1 << CS10);
// enable timer compare interrupt
TIMSK0 |= (1 << OCIE0A);
//set timer1 interrupt at 1Hz
TCCR1A = 0;// set entire TCCR1A register to 0
TCCR1B = 0;// same for TCCR1B
TCNT1 = 0;//initialize counter value to 0
// set compare match register for 1hz increments
OCR1A = 15624 ;// = 2*(16*10^6) / (1*1024) - 1 (must be <65536)
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS12 and CS10 bits for 1024 prescaler
TCCR1B |= (1 << CS12) | (1 << CS10);
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
sei();//allow interrupts
}//end setup
ISR(TIMER0_COMPA_vect){//timer0 interrupt 2kHz toggles pin 8
//generates pulse wave of frequency 2kHz/2 = 1kHz (takes two cycles for full wave- toggle high then toggle low)
if (toggle0){
digitalWrite(8,HIGH);
toggle0 = 0;
}
else{
digitalWrite(8,LOW);
toggle0 = 1;
}
}
ISR(TIMER1_COMPA_vect){//timer1 interrupt 1Hz toggles pin 13 (LED)
//Genera pulsos de onda de frecuencia 2 segundos
tiempoOFF++;
if (tiempoOFF == 5) { //Des habilita el Timer0 por 5 Segundos
tiempoOFF = 0;
sbi (TIMSK0, OCIE0A); //Habilita Timer0
digitalWrite(13,HIGH);
}
else {
cbi (TIMSK0, OCIE0A); //Des Habilita Timer0
digitalWrite(13,LOW);
}
}
void loop(){
while(true);
}