2008-09-14 13 views
6

मेरे पास हार्डवेयर में एक काउंटर है जिसे मैं समय पर विचारों के लिए देख सकता हूं। यह मिलीसेकंड की गणना करता है और 16 बिट हस्ताक्षरित मूल्य में संग्रहीत होता है। कैसे मैं सुरक्षित रूप से एक निश्चित समय अगर एक टाइमर मान प्रदान किया है जाँच करते हैं और सुरक्षित रूप से अपरिहार्य रोलओवर संभाल:रोलओवर सुरक्षित टाइमर (टिक) तुलना

//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(); 
} 

इस कोड को जब ms_timer 0.

उत्तर

1

को overflows असफल हो जायेगी बस की जाँच करता है, तो ms_timer < last_print_time और अगर तो 2^16 नंबर जोड़ें?

संपादित करें: यदि आप कर सकते हैं तो इसके लिए आपको एक uint32 तक भी जाना होगा।

1

शायद सबसे सुरक्षित तरीका समस्या से बचने के लिए एक हस्ताक्षरित 32-बिट मूल्य का उपयोग करने के लिए होगा।

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(); 
} 
1

यह 64k/2, जो मेरे लिए उपयुक्त है अप करने के लिए अंतराल के लिए काम करने के लिए लगता है::

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; 
} 

पर हस्ताक्षर किए पूर्णांकों की प्रकृति का उपयोग करता है अपने उदाहरण का उपयोग करें। (twos complement)

8

आप वास्तव में यहाँ कुछ भी करने की जरूरत नहीं है। आपके प्रश्न में सूचीबद्ध मूल कोड ठीक काम करेगा, मानते हैं कि ms_timer() uint16_t प्रकार का मान देता है।

uint16_t t1 = 0xFFF0; 
uint16_t t2 = 0x0010; 
uint16_t dt = t2 - t1; 

dt0x20 बराबर होगा:

(इसके अलावा यह सोचते हैं कि टाइमर जांचों के बीच दो बार अतिप्रवाह नहीं करता है ...)

खुद को समझाने के लिए यह मामला है, तो निम्न परीक्षण की कोशिश करो।

+0

जब मैं हर गिनती के लिए मूल कोड इस पर प्रवाह बिंदु तक काम करता है और फिर प्रिंट चलाते हैं। – JeffV

+4

मेरा अंतिम स्टैब-इन-द-डार्क, मूल व्यवहार और आपके प्रतिस्थापन समाधान को देखते हुए, यह है कि आपका एक्स वैरिएबल/ms_timer() फ़ंक्शन 16 बिट्स से अधिक int int/देता है, जो समय की गणना करते समय एक अनपेक्षित प्रकार का प्रचार करता है अंतर। – smh

0

मैंने पाया कि एक अलग टाइमर एपीआई का उपयोग मेरे लिए बेहतर काम करता है।

void timer_milliseconds_reset(unsigned index); 
bool timer_milliseconds_elapsed(unsigned index, unsigned long value); 

टाइमर सूचकांक भी टाइमर हेडर फाइल में परिभाषित कर रहे हैं:

#define TIMER_PRINT 0 
#define TIMER_LED 1 
#define MAX_MILLISECOND_TIMERS 2 

मैं अपने टाइमर काउंटरों के लिए अहस्ताक्षरित लंबे int का उपयोग (32-बिट मैं एक टाइमर मॉड्यूल दो API कॉल है कि बनाया) क्योंकि यह मेरे हार्डवेयर प्लेटफ़ॉर्म पर मूल आकार का पूर्णांक है, और यह मुझे 1 एमएस से लगभग 49.7 दिनों तक समाप्त कर देता है। आपके पास टाइमर काउंटर हो सकते हैं जो कि 16-बिट हैं जो आपको 1 एमएस से लगभग 65 सेकंड तक गुजरने का समय देगा।

टाइमर काउंटर एक सरणी हैं, और हार्डवेयर टाइमर (इंटरप्ट, कार्य, या काउंटर वैल्यू के मतदान) द्वारा बढ़ाए जाते हैं। वे फ़ंक्शन में डेटाटाइप के अधिकतम मूल्य तक सीमित हो सकते हैं जो नो-रोलओवर टाइमर के लिए वृद्धि को संभालता है।

/* 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; 
    } 
} 

फिर अपने कोड हो जाता है:

//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); 
} 
3

मैं एक हस्ताक्षरित तुलना का उपयोग करके बग और संभव समाधान को वर्णन करने के लिए इस कोड का उपयोग करें।

/* ========================================================================== */ 
/* 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); 

} 

नमूना उत्पादन:

[email protected]:~/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 
[email protected]:~/work2/test$ 
+0

INT_MAX के बगल में प्रदान की गई देरी की गलत लंबाई है, है ना? – AndresR

-1

कभी कभी मैं इस तरह यह कार्य करें:

#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 
} 
1

मैं इस तरह के मामले के लिए निम्नलिखित की तरह कोड लिखने के लिए इस्तेमाल किया।
मैंने परीक्षण मामले के साथ परीक्षण किया और आश्वासन दिया कि यह 100% काम करता है।
इसके अतिरिक्त, 3212 बिट टाइमर टिक के साथ 0xFFFF से uint16_t और 0xFFFFFFFF से uint32_t में से बदलें।

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; 
}