Dado que una MCU de 8 bits no puede leer todo el temporizador de 16 bits en un ciclo, esto crea una condición de carrera en la que la palabra baja puede cambiar entre lecturas. ¿Tiene la comunidad un método preferido para evitar estas condiciones de carrera? Actualmente estoy considerando detener el temporizador durante las lecturas, pero me gustaría saber si existe una solución más elegante.
FYI, esto es para un PIC16F690 .
Windell tiene razón, si está hablando de PIC, la hoja de datos (y el hardware) ya manejan esto por usted.
Si no está usando un PIC, el método general que uso es hacer esto:
byte hi, lo;
word timer_value;
do {
hi = TIMER_HI;
lo = TIMER_LO;
} while(hi != TIMER_HI);
timer_value = (hi << 8) | lo;
Lo que esto hace es leer el byte superior seguido del byte inferior y continuar haciéndolo hasta que el byte alto no cambie. Esto maneja fácilmente el caso en el que el byte bajo del valor de 16 bits se desborda entre lecturas. Se supone, por supuesto, que no hay efectos secundarios al leer el registro TIMER_HI varias veces. Si su microprocesador en particular no lo permite, es hora de tirarlo y usar uno que no sea tan tonto. :-)
Este método TAMBIÉN asume que su temporizador no está cambiando tan rápidamente que corre el riesgo de desbordar los 8 bits bajos dentro de uno o dos ciclos de recuperación del procesador. Si está ejecutando un temporizador tan rápido (o un microprocesador tan lento), entonces es hora de repensar su implementación.
¡Consulta tu hoja de datos! Hablará de esto , con detalles sangrientos, para su chip en particular.
No estoy seguro de que esto sea cierto para todos los registros de contador/temporizador de 16 bits en todos los PIC (¡tal vez alguien más pueda responder eso!) pero al menos para el PIC 18F que uso, la hoja de datos habla específicamente sobre cómo se maneja esto .
Cuando lee el byte bajo, almacena el byte alto en un registro temporal para el byte alto, de modo que cuando lea el byte alto a continuación, le brinde una instantánea instantánea completa del valor del temporizador.
El mismo proceso básico se usa en AVR (y Arduino, por supuesto), y para la mayoría de los otros casos en los que necesita leer o escribir registros de dos bytes a la vez en MCU de 8 bits.
El texto al que se refirió en su comentario (Sección 6.5.1) se refiere a la operación del temporizador asíncrono, donde el temporizador se cronometra desde una fuente externa al microcontrolador.
El descargo de responsabilidad sugiere iniciar y detener el temporizador porque el método general de Andrew (realmente cualquier método) no funcionará porque puede haber muchos tics (más de 256, incluso) del reloj externo y, por lo tanto, el temporizador en un solo ciclo del procesador . Supongo que no estás corriendo con este caso extremo.
Si, en cambio, está utilizando el oscilador interno como referencia, estará bien. Incluso con un preescalador de 1, tiene hasta 255 ciclos después de leer el byte alto para leer el byte bajo. Esta debe ser una operación de 2 ciclos. Todavía necesita el ciclo do/while en caso de que su byte alto cambie (¿Cuál es la diferencia entre 'hi' y 'TIMER_HI' si el valor de 'lo' es 0?) entre estos tiempos. Con un prescaler de 2 o más, ya no necesita esta prueba. Es solo con prescalers mucho menores que 1 que comienza a ser un problema, y esto es imposible sin el reloj externo.
Hay un ejemplo en el Manual de referencia de la familia de MCU de rango medio PIC para leer y escribir Timer1 en modo de contador asíncrono.
Ejemplo: lectura de un temporizador de ejecución libre de 16 bits
; All interrupts are disabled
MOVF TMR1H, W ; Read high byte
MOVWF TMPH ;
MOVF TMR1L, W ; Read low byte
MOVWF TMPL ;
MOVF TMR1H, W ; Read high byte
SUBWF TMPH, W ; Sub 1st read with 2nd read
BTFSC STATUS,Z ; Is result = 0
GOTO CONTINUE ; Good 16-bit read
;
; TMR1L may have rolled over between the read of the high and low bytes.
; Reading the high and low bytes now will read a good value.
;
MOVF TMR1H, W ; Read high byte
MOVWF TMPH ;
MOVF TMR1L, W ; Read low byte
MOVWF TMPL ;
; Re-enable the Interrupt (if required)
CONTINUE ; Continue with your code
davidcary
stevenvh