visual tick studio propiedades formulario event ejemplo cronometro cerrar c++ c timer rollover embedded

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$