I'm doing a project based on Atmel 32u4 (Leonardo board) to measure 1 micro seconds time interval. When I use micros() function(micros() is used 8 bit timer 0 register), it only gives 4us precision. That precision is not enough for my project. Therefore I tried to write my own timer function using 16 bit timer register with 0.01 precision and compare it with micros() values. But I couldn't get proper result.
What I want to know is how to write below T1_micros() code using 16 bit timer?
You seem to have attached a picture. Please post your code either directly in your next Reply using the code button </> or by attaching your .ino file
You can use a HardwareTimer to get high precision but the reason micros() increments in steps of 4 is because it would use up too many CPU cycles if it updated every microsecond. You also need to keep that in mind for your own code.
If you want to measure HIGH pulses, LOW pulses, frequency, or duty cycle on a single pin, you might be able to adapt this sketch, which I wrote for the Arduino UNO, which uses the Timer1 Input Capture Register:
// Measures the HIGH width, LOW width, frequency and duty-cycle of a pulse train
// on Arduino UNO Pin 8 (ICP1 pin).
// Should work up to 65535 clock cycles (4095 microseconds)
// Note: Since this uses Timer1, Pin 9 and Pin 10 can't be used for
// analogWrite().
void setup()
{
Serial.begin(115200);
// For testing, uncomment one of these lines and connect
// Pin 3 or Pin 5 to Pin 8
//analogWrite(3, 64); // 512.00, 1528.00, 2040.00, 25.10%, 490.20 Hz
//analogWrite(5, 64); // 260.00, 764.00, 1024.00, 25.39%, 976.56 Hz
noInterrupts (); // protected code
// reset Timer 1
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
TIFR1 |= (1 << ICF1); // clear Input Capture Flag so we don't get a bogus interrupt
// start Timer 1, no prescaler
TCCR1B |= (1 << CS10); // plus Input Capture Edge Select (rising on D8)
TCCR1B |= (1 << ICES1); // Input Capture Edge Select (1=Rising, 0=Falling)
TIMSK1 |= (1 << ICIE1); // Enable Timer 1 Input Capture Interrupt Enable
interrupts ();
}
volatile uint16_t PulseHighTime = 0;
volatile uint16_t PulseLowTime = 0;
ISR(TIMER1_CAPT_vect)
{
static uint16_t firstRisingEdgeTime = 0;
static uint16_t fallingEdgeTime = 0;
static uint16_t secondRisingEdgeTime = 0;
if (PulseLowTime == 0)
{
if (TCCR1B & (1 << ICES1))
{
// Rising Edge
if (firstRisingEdgeTime)
{
secondRisingEdgeTime = ICR1;
PulseLowTime = secondRisingEdgeTime - fallingEdgeTime;
firstRisingEdgeTime = 0;
}
else
{
firstRisingEdgeTime = ICR1;
TCCR1B &= ~(1 << ICES1); // Switch to Falling Edge
}
}
else
{
// Falling Edge
fallingEdgeTime = ICR1;
TCCR1B |= (1 << ICES1); // Switch to Rising Edge
PulseHighTime = fallingEdgeTime - firstRisingEdgeTime;
}
}
}
void loop()
{
noInterrupts();
uint16_t pulseHighTime = PulseHighTime;
uint16_t pulseLowTime = PulseLowTime;
interrupts();
// If a sample has been measured
if (pulseLowTime)
{
// Display the pulse length in microseconds
Serial.print("High time (microseconds): ");
Serial.println(pulseHighTime / 16.0, 2);
Serial.print("Low time (microseconds): ");
Serial.println(pulseLowTime / 16.0, 2);
Serial.print("Cycle time (microseconds): ");
Serial.println((pulseHighTime / 16.0) + (pulseLowTime / 16.0), 2);
uint32_t cycleTime = pulseHighTime + pulseLowTime;
float dutyCycle = pulseHighTime / (float)cycleTime;
Serial.print("Duty cycle (%): ");
Serial.println(dutyCycle * 100.0, 2);
float frequency = 16000000.0 / cycleTime;
Serial.print("Frequency (Hz): ");
Serial.println(frequency, 2);
Serial.println();
delay(1000); // Slow down output
// Request another sample
noInterrupts();
PulseLowTime = 0;
interrupts();
}
}
Robin2:
You can use a HardwareTimer to get high precision but the reason micros() increments in steps of 4 is because it would use up too many CPU cycles if it updated every microsecond. You also need to keep that in mind for your own code.
Are you sure? I always thought it was because they wanted a millis() update and PWM frequency near 1 kHz. The lowest frequency you can get on an 8-bit timer without prescale is 62.5 kHz. You could do it but the PWM output is going to generate a lot of radio noise. By using a prescale of 64 they get the millis() update period, and PWM frequency, near 1 kHz (976.5625 Hz). With that prescale the clock is 250 kHz (4 microseconds per clock tick) so having the micros() clock share Timer0 with the millis() clock they have limited themselves to a 4-microsecond timer.
Using any other timer, you can set the prescale to 1 and get 16 counts per microsecond.