Estoy tratando de obtener la frecuencia de entrada de una onda cuadrada usando el registro de captura de entrada de un Atmega328p. Hasta ahora, funciona de forma esporádica, es decir, cuando ingreso una onda cuadrada de 75 kHz, la salida se ve así:
244 244 75117 74766 75117 75117 79207 80402 82051 82901 84656 85561 87431 244 244 244 88888 90395 244 244 244 -941176 -271186 244 -246153 244 244 244
¿Alguien sabe por qué este podría ser el caso? He intentado meterme con los tipos de datos, pero de lo contrario no estoy realmente seguro de cuál podría ser el problema. El código que he escrito está abajo.
// # of overflows
volatile long T1Ovs;
// timestamp variables (store TCNT at time of input capture interrupt)
volatile long Capt1, Capt2;
// capture flag
volatile uint8_t Flag;
volatile long ticks;
volatile double period;
volatile long frequency;
void initTimer1(void)
{
TCNT1 = 0;
// initialize timer to 0
//timer/counter1 control register b
TCCR1B |= (1<<ICES1);
// input capture edge select; rising edge triggers capture
//timer/counter1 interrupt mask register
TIMSK1 |= (1<<ICIE1);
// ICIE1: input capture interrupt enable
TIMSK1 |= (1<<TOIE1);
// timer/counter1 overflow interrupt enable
}
void startTimer1(void)
{
TCCR1B = (1<<CS10);
//start timer with pre-scaler = 1
sei();
//enable global interrupts
}
ISR(TIMER1_CAPT_vect) // interrupt handler on input capture match (rising edge in this case)
{
if (Flag == 0)
{
Capt1 = ICR1;
// save timestamp at interrupt (input capture is updated with the counter (TCNT1)
// value each time an event occurs on the ICP1 pin (digital pin 8, PINB0)
T1Ovs = 0;
// reset overflows
}
if (Flag ==1)
{
Capt2 = ICR1;
}
Flag ++;
}
ISR(TIMER1_OVF_vect) // interrupt handled on timer1 overflow
{
T1Ovs++; // increment number of overflows
}
void setup()
{
Serial.begin(9600);
initTimer1();
startTimer1();
}
void loop()
{
if (Flag == 2)
{
ticks = Capt2 - Capt1 + T1Ovs * 0x10000L;
// (second timestamp) - (first stamp) + (# of overflows) * (ticks/overflow = 65535)
frequency = 16000000/ticks;
// ticks * seconds/ticks = seconds
// 1/seconds = Hz
Flag = 0;
// reset flags
T1Ovs = 0;
// reset overflow count
TIFR1 = 0b00000000; // clear interrupt registers
Serial.println(frequency);
TIMSK1 |= (1 << ICIE1); // enable capture interrupt
TIMSK1 |= (1 << TOIE1); // enable overflow interrupt
}
}
Gracias de antemano!
ACTUALIZACIÓN ***********************************
La segunda iteración del código, que usa tipos enumerados para hacer una máquina de estado:
typedef enum {
CAPTURE_1,
CAPTURE_2,
WAIT
} timer_state_t;
timer_state_t flag = WAIT;
volatile long Capt1, Capt2;
volatile long T1Ovs;
void InitTimer1(void)
{
//Set Initial Timer value
TCNT1=0;
//First capture on rising edge
TCCR1B|=(1<<ICES1);
//Enable input capture and overflow interrupts
TIMSK1|=(1<<ICIE1)|(1<<TOIE1);
}
void StartTimer1(void)
{
//Start timer without prescaler
TCCR1B|=(1<<CS10);
//Enable global interrutps
sei();
}
ISR(TIMER1_CAPT_vect) {
switch(flag) {
case CAPTURE_1:
Capt1 = ICR1;
flag = CAPTURE_2;
break;
case CAPTURE_2:
Capt2 = ICR1;
flag = WAIT;
Serial.println(flag);
break;
}
}
ISR(TIMER1_OVF_vect)
{
T1Ovs++;
}
void setup()
{
Serial.begin(9600);
InitTimer1();
StartTimer1();
}
void loop() {
flag = CAPTURE_1;
while (flag != WAIT);
Serial.println("loop");
Serial.println(Capt2 - Capt1 + T1Ovs * 0x10000);
}