Inicialización del temporizador 1, el temporizador de 16 bits en el ATmega328:
TCCR1A = 0; // normal operation
TCCR1B = bit(CS10); // no prescaling
OCR1A = 0;
OCR1B = 0;
TIMSK1 |= bit(TOIE1); // Timer/Counter 1, Overflow Interrupt Enable
Los desbordamientos de 16 bits incrementan un contador de desbordamiento:
ISR(TIMER1_OVF_vect) {
timer1OverflowCount ++;
}
En un bucle se comprueba si los dos contadores de 16 bits se incrementan correctamente:
void loop() {
static uint16_t lastOc = 0, lastC = 0;
uint16_t oc, c;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
oc = timer1OverflowCount;
c = TCNT1;
}
if (c < lastC && oc == lastOc) {
print(oc, c, lastOc, lastC);
}
lastOc = oc;
lastC = c;
}
Salida de muestra a la consola serie:
Bad overflow: oc = 31, c = 49, lastOc = 31, lastC = 65440
Bad overflow: oc = 58, c = 49, lastOc = 58, lastC = 65440
Bad overflow: oc = 66, c = 49, lastOc = 66, lastC = 65440
Bad overflow: oc = 118, c = 49, lastOc = 118, lastC = 65440
Bad overflow: oc = 127, c = 49, lastOc = 127, lastC = 65440
¿Por qué a veces el contador de desbordamiento no se incrementa?
Entiendo que el bucle accede mucho al contador de desbordamiento. Durante un acceso, las interrupciones se activan con ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
. Sin embargo, el acceso es rápido y espero que la interrupción por desbordamiento se ponga en cola para que nunca se pierda.
Código completo para Arduino Pro Mini ATmega328P (5V, 16MHz), compatible con Arduino IDE 1.8.1:
#include <util/atomic.h>
volatile uint16_t timer1OverflowCount = 0;
ISR(TIMER1_OVF_vect) {
timer1OverflowCount ++;
}
void setup() {
TCCR1A = 0; // normal operation
TCCR1B = bit(CS10); // no prescaling
OCR1A = 0;
OCR1B = 0;
TIMSK1 |= bit(TOIE1); // Timer/Counter 1, Overflow Interrupt Enable
Serial.begin(9600);
}
void print(uint16_t oc, uint16_t c, uint16_t lastOc, uint16_t lastC) {
Serial.print("Bad overflow: ");
Serial.print("oc = ");
Serial.print(oc);
Serial.print(", c = ");
Serial.print(c);
Serial.print(", lastOc = ");
Serial.print(lastOc);
Serial.print(", lastC = ");
Serial.println(lastC);
}
void loop() {
static uint16_t lastOc = 0, lastC = 0;
uint16_t oc, c;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
oc = timer1OverflowCount;
c = TCNT1;
}
if (c < lastC && oc == lastOc) {
print(oc, c, lastOc, lastC);
}
lastOc = oc;
lastC = c;
}