c++ - studio - Comparaciones de temporizador seguro(tick)
timer visual studio c# (8)
Tengo un contador en hardware que puedo observar por consideraciones de tiempo. Cuenta milisegundos y se almacena en un valor sin firmar de 16 bits. ¿Cómo puedo verificar de forma segura si un valor del temporizador ha pasado un cierto tiempo y manejar de forma segura la inevitable transferencia?
//this is a bit contrived, but it illustrates what I''m trying to do
const uint16_t print_interval = 5000; // milliseconds
static uint16_t last_print_time;
if(ms_timer() - last_print_time > print_interval)
{
printf("Fault!/n");
last_print_time = ms_timer();
}
Este código fallará cuando ms_timer se desborde a 0.
A veces lo hago así:
#define LIMIT 10 // Any value less then ULONG_MAX
ulong t1 = tick of last event;
ulong t2 = current tick;
// This code needs to execute every tick
if ( t1 > t2 ){
if ((ULONG_MAX-t1+t2+1)>=LIMIT){
do something
}
} else {
if ( t2 - t1 >= LIMT ){
do something
}
Descubrí que usar una API de temporizador diferente funciona mejor para mí. Creé un módulo de temporizador que tiene dos llamadas API:
void timer_milliseconds_reset(unsigned index);
bool timer_milliseconds_elapsed(unsigned index, unsigned long value);
Los índices de temporizador también se definen en el archivo de encabezado del temporizador:
#define TIMER_PRINT 0
#define TIMER_LED 1
#define MAX_MILLISECOND_TIMERS 2
Utilizo unsigned long int para mis contadores de temporizador (32 bits) ya que ese es el entero de tamaño nativo en mi plataforma de hardware, y eso me da tiempos transcurridos desde 1 ms hasta aproximadamente 49.7 días. Podría tener contadores de temporizador de 16 bits que le darían tiempos transcurridos de 1 ms a aproximadamente 65 segundos.
Los contadores de temporizador son una matriz y se incrementan con el temporizador de hardware (interrupción, tarea o sondeo del valor del contador). Pueden limitarse al valor máximo del tipo de datos en la función que maneja el incremento para un temporizador de no volcado.
/* variable counts interrupts */
static volatile unsigned long Millisecond_Counter[MAX_MILLISECOND_TIMERS];
bool timer_milliseconds_elapsed(
unsigned index,
unsigned long value)
{
if (index < MAX_MILLISECOND_TIMERS) {
return (Millisecond_Counter[index] >= value);
}
return false;
}
void timer_milliseconds_reset(
unsigned index)
{
if (index < MAX_MILLISECOND_TIMERS) {
Millisecond_Counter[index] = 0;
}
}
Entonces tu código se convierte en:
//this is a bit contrived, but it illustrates what I''m trying to do
const uint16_t print_interval = 5000; // milliseconds
if (timer_milliseconds_elapsed(TIMER_PRINT, print_interval))
{
printf("Fault!/n");
timer_milliseconds_reset(TIMER_PRINT);
}
En realidad, no necesitas hacer nada aquí. El código original que figura en su pregunta funcionará ms_timer()
, suponiendo que ms_timer()
devuelve un valor de tipo uint16_t.
(También suponiendo que el temporizador no se desborda dos veces entre cheques ...)
Para convencerse de que este es el caso, intente la siguiente prueba:
uint16_t t1 = 0xFFF0;
uint16_t t2 = 0x0010;
uint16_t dt = t2 - t1;
dt
será igual a 0x20
.
Esto parece funcionar para intervalos de hasta 64 k / 2, que es adecuado para mí:
const uint16_t print_interval = 5000; // milliseconds
static uint16_t last_print_time;
int next_print_time = (last_print_time + print_interval);
if((int16_t) (x - next_print_time) >= 0)
{
printf("Fault!/n");
last_print_time = x;
}
Utiliza la naturaleza de los enteros con signo. ( complemento a dos )
Probablemente la forma más segura de evitar el problema sería usar un valor firmado de 32 bits. Para usar tu ejemplo:
const int32 print_interval = 5000;
static int32 last_print_time; // I''m assuming this gets initialized elsewhere
int32 delta = ((int32)ms_timer()) - last_print_time; //allow a negative interval
while(delta < 0) delta += 65536; // move the difference back into range
if(delta < print_interval)
{
printf("Fault!/n");
last_print_time = ms_timer();
}
Simplemente verifique si ms_timer <last_print_time y si es así agregue 2 ^ 16 no?
Editar: también puede necesitar hasta uint32 para esto si puede.
Solía escribir código como el siguiente para ese caso.
Probé con el caso de prueba y aseguro que funciona al 100%.
Además, cambie a uint32_t
desde uint16_t
y 0xFFFFFFFF
desde 0xFFFF
en el código siguiente con el 0xFFFFFFFF
del temporizador de 32 bits.
uint16_t get_diff_tick(uint16_t test_tick, uint16_t prev_tick)
{
if (test_tick < prev_tick)
{
// time rollover(overflow)
return (0xFFFF - prev) + 1 + test_tick;
}
else
{
return test_tick - prev_tick;
}
}
/* your code will be.. */
uint16_t cur_tick = ms_timer();
if(get_diff_tick(cur_tick, last_print_time) > print_interval)
{
printf("Fault!/n");
last_print_time = cur_tick;
}
Uso este código para ilustrar el error y la posible solución usando una comparación firmada.
/* ========================================================================== */
/* timers.c */
/* */
/* Description: Demonstrate unsigned vs signed timers */
/* ========================================================================== */
#include <stdio.h>
#include <limits.h>
int timer;
int HW_DIGCTL_MICROSECONDS_RD()
{
printf ("timer %x/n", timer);
return timer++;
}
// delay up to UINT_MAX
// this fails when start near UINT_MAX
void delay_us (unsigned int us)
{
unsigned int start = HW_DIGCTL_MICROSECONDS_RD();
while (start + us > HW_DIGCTL_MICROSECONDS_RD())
;
}
// works correctly for delay from 0 to INT_MAX
void sdelay_us (int us)
{
int start = HW_DIGCTL_MICROSECONDS_RD();
while (HW_DIGCTL_MICROSECONDS_RD() - start < us)
;
}
int main()
{
printf ("UINT_MAX = %x/n", UINT_MAX);
printf ("INT_MAX = %x/n/n", INT_MAX);
printf ("unsigned, no wrap/n/n");
timer = 0;
delay_us (10);
printf ("/nunsigned, wrap/n/n");
timer = UINT_MAX - 8;
delay_us (10);
printf ("/nsigned, no wrap/n/n");
timer = 0;
sdelay_us (10);
printf ("/nsigned, wrap/n/n");
timer = INT_MAX - 8;
sdelay_us (10);
}
Muestra de salida:
bob@hedgehog:~/work2/test$ ./timers|more
UINT_MAX = ffffffff
INT_MAX = 7fffffff
unsigned, no wrap
timer 0
timer 1
timer 2
timer 3
timer 4
timer 5
timer 6
timer 7
timer 8
timer 9
timer a
unsigned, wrap
timer fffffff7
timer fffffff8
signed, no wrap
timer 0
timer 1
timer 2
timer 3
timer 4
timer 5
timer 6
timer 7
timer 8
timer 9
timer a
signed, wrap
timer 7ffffff7
timer 7ffffff8
timer 7ffffff9
timer 7ffffffa
timer 7ffffffb
timer 7ffffffc
timer 7ffffffd
timer 7ffffffe
timer 7fffffff
timer 80000000
timer 80000001
bob@hedgehog:~/work2/test$