Based on PWM frequency and duty cycle using input capture on ATmega2560 - #5 by MasterT I wrote the following test. I hope to measure frequency and duty cycle from 1Hz to 1Mhz but the technics used mesure from 1Hz to ~ 86KHz only. Any idea about how to extend the range of frequency and duty from 1Hz to 1MHz ? thanks.
//
// Frequency & duty cycle measurement (input D48 -ICP5- on mega)
// -------------------------------------------------------------
//
volatile int32_t period_hi = 0;
volatile int32_t period_lo = 0;
volatile uint8_t tmr_overf = 0;
volatile boolean end_capture = 0;
float duty_cycl;
float freq_cntr;
void setup()
{
Serial.begin(115200);
init_T5();
}
void loop()
{
if (end_capture){
duty_cycl = float(period_hi) / float(period_hi + period_lo) * 100.0;
freq_cntr = 16000000.0 / float(period_hi + period_lo);
Serial.print("Freq: ");
Serial.print(freq_cntr, 2);
Serial.print(" - duty: ");
Serial.println(duty_cycl, 1);
end_capture = false;
}
delay(500);
}
void init_T5(void)
{
TCCR5A = 0;
TCCR5B = 0;
TCCR5B |= (1<< CS50); // set prescaler to 16 MHz
TCCR5B |= (1<<ICNC5); // input noise canceler on
TCCR5B |= (1<<ICES5); // input capture edge select (lo-hi)
TIMSK5 |= (1<<TOIE5); // Overflow Interrupt Enable
TIMSK5 |= (1<<ICIE5); // InCaptureInterrupt Enable
}
ISR(TIMER5_OVF_vect) {
tmr_overf++;
}
ISR(TIMER5_CAPT_vect) {
static uint16_t last_v = 0;
uint16_t curr_v = ICR5;
uint32_t accuml = 0;
accuml = curr_v + tmr_overf *65536UL;
accuml -= last_v;
last_v = curr_v;
tmr_overf = 0;
if(TCCR5B & (1<<ICES5)) { // lo-hi
TCCR5B &= ~(1<<ICES5); // input capture edge select (hi-lo) next
period_lo = accuml;
end_capture = true;
}
else { // hi-lo
TCCR5B |= (1<<ICES5); // input capture edge select (lo-hi) next
period_hi = accuml;
}
}