Accurate microseconds
Posted: 03 Nov 2020, 16:46
The micros() timer on our 8-bit Arduinos only resolves to 4-microsecond intervals - try Serial.print(micros()); The result is always a multiple of 4. And on 8 MHz models it's even worse as the resolution drops to 8 microseconds.
This isn't ideal for measuring or creating the sorts of pulse widths we tend to use. If you're not using Timer2 for anything else, then the snippet below provides a 1-microsecond resolution replacement for micros(). It works on all 16MHz and 8MHz ATmega328p chips - which covers most of the basic Arduinos. Just use accurateMicros() anywhere you would have previously used micros(). You can rename the function to something shorter, of course. The standard libraries, as far as I know, only use Timer2 for analogWrite() (PWM-simulated analog output) on pins 3 and 11, and for the tone() function.
This isn't ideal for measuring or creating the sorts of pulse widths we tend to use. If you're not using Timer2 for anything else, then the snippet below provides a 1-microsecond resolution replacement for micros(). It works on all 16MHz and 8MHz ATmega328p chips - which covers most of the basic Arduinos. Just use accurateMicros() anywhere you would have previously used micros(). You can rename the function to something shorter, of course. The standard libraries, as far as I know, only use Timer2 for analogWrite() (PWM-simulated analog output) on pins 3 and 11, and for the tone() function.
Code: Select all
void setup() {
// put your setup code here, to run once:
TCCR2A = 0x00;
TCCR2B = 0x02; // /8 clock prescale
TIMSK2 |= 0x01;
}
volatile uint32_t timer2cycles = 0UL;
ISR(TIMER2_OVF_vect) {
++timer2cycles;
}
uint32_t accurateMicros(void) {
uint8_t sreg = SREG;
cli();
uint32_t u = timer2cycles;
uint8_t t = TCNT2;
if (TIFR2 & 0x01) {
t = TCNT2;
timer2cycles = ++u;
TIFR2 |= 0x01;
}
SREG = sreg;
return F_CPU <= 8000000 ? (u << 8) | t : (u << 7) | (t >> 1);
}
void loop() {
// put your main code here, to run repeatedly:
}