एक रुकावट दिनचर्या के अंदर मिलिस () और माइक्रो () का उपयोग करना


13

के लिए प्रलेखन attachInterrupt()कहता है:

... millis()गिनती करने के लिए व्यवधान पर निर्भर करता है, इसलिए यह एक ISR के अंदर वृद्धि नहीं करेगा। चूँकि delay()काम करने के लिए इंटरप्ट की आवश्यकता होती है, अगर यह ISR के अंदर कहा जाता है तो यह काम नहीं करेगा। micros()शुरू में काम करता है, लेकिन 1-2 एमएस के बाद गलती से व्यवहार करना शुरू कर देगा। ...

कैसे micros()भिन्न होता है millis()(उनकी शुद्धता के लिए पाठ्यक्रम को छोड़कर)? क्या उपरोक्त चेतावनी का मतलब है कि micros()एक रुकावट के अंदर का उपयोग करना हमेशा एक बुरा विचार है?

संदर्भ - मैं कम पल्स ऑक्यूपेंसी को मापना चाहता हूं , इसलिए जब मेरा इनपुट सिग्नल बदलता है और वर्तमान समय रिकॉर्ड करता है, तो मुझे अपनी दिनचर्या को ट्रिगर करना होगा।

जवाबों:


16

अन्य उत्तर बहुत अच्छे हैं, लेकिन मैं इस बात पर विस्तार से बताना चाहता हूं कि कैसे micros()काम करता है। यह हमेशा वर्तमान हार्डवेयर टाइमर (संभवतः TCNT0) को पढ़ता है जो लगातार हार्डवेयर द्वारा अद्यतन किया जा रहा है (वास्तव में, 64 के प्रीस्कूलर के कारण हर 4 current)। इसके बाद टाइमर 0 ओवरफ्लो काउंट में जोड़ा जाता है, जिसे टाइमर ओवरफ्लो इंटरप्ट (256 से गुणा) द्वारा अपडेट किया जाता है।

इस प्रकार, एक ISR के अंदर भी, आप micros()अपडेट करने पर भरोसा कर सकते हैं । हालाँकि यदि आप बहुत अधिक प्रतीक्षा करते हैं तो आप अतिप्रवाह अद्यतन को याद करते हैं, और फिर वापस लौटा हुआ परिणाम नीचे चला जाएगा (अर्थात आपको 253, 254, 255, 0, 1, 2, 3 आदि मिलेंगे)

यह है micros()- अन्य प्रोसेसर के लिए परिभाषित हटाने के लिए थोड़ा सरल:

unsigned long micros() {
    unsigned long m;
    uint8_t oldSREG = SREG, t;
    cli();
    m = timer0_overflow_count;
    t = TCNT0;
    if ((TIFR0 & _BV(TOV0)) && (t < 255))
        m++;
    SREG = oldSREG;
    return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
}

उपरोक्त कोड ओवरफ्लो के लिए अनुमति देता है (यह TOV0 बिट की जांच करता है) इसलिए यह ओवरफ्लो से सामना कर सकता है जबकि बीच में आना बंद है लेकिन केवल एक बार - दो ओवरफ्लो से निपटने के लिए कोई प्रावधान नहीं है।


TLDR;

  • एक ISR के अंदर देरी मत करो
  • यदि आप उन्हें करना चाहिए, तो आप समय के साथ कर सकते हैं micros()लेकिन नहीं millis()delayMicroseconds()एक संभावना भी है।
  • 500 so या इससे अधिक देरी न करें, या आपको एक टाइमर अतिप्रवाह याद होगा।
  • यहां तक ​​कि छोटी देरी से आपको आने वाले सीरियल डेटा की कमी हो सकती है (115200 बॉड पर आपको हर 87) पर एक नया चरित्र मिलेगा)।

नीचे दिए गए कथन को समझने में सक्षम नहीं है जो कि माइक्रोस () में उपयोग किया जाता है। क्या आप कृपया विस्तार से बता सकते हैं? जब से ISR लिखा गया है, ISR में प्रवेश करते ही TOV0 का झंडा साफ हो जाएगा और इसलिए नीचे की स्थिति सच नहीं हो सकती है!। अगर ((TIFR0 & _BV (TOV0)) && (t <255)) m ++;
राजेश

micros()ISR नहीं है। यह एक सामान्य कार्य है। TOV0 ध्वज आपको यह देखने के लिए हार्डवेयर का परीक्षण करने देता है कि टाइमर ओवरफ़्लो हुआ है (लेकिन अभी तक संसाधित नहीं हुआ है)।
निक गैमन

चूँकि परीक्षण बंद हो जाता है इसलिए आपको पता है कि परीक्षण के दौरान झंडा नहीं बदलेगा।
निक गैमन

तो आपके कहने का मतलब है कि माइक्रो (अंदर) फ़ंक्शन के बाद क्ली (), यदि कोई अतिप्रवाह होता है, तो उसे जांचने की आवश्यकता है? उसका कुछ मतलब है। अन्यथा भले ही माइक्रोएस एक फ़ंक्शन नहीं है, TIMER0_OVF_vect ISR TIFR0 में TOV0 को साफ कर देगा, जो मेरा संदेह था।
राजेश

यह भी कि TCNT0 की तुलना 255 से क्यों की जाती है, यह देखने के लिए कि क्या यह 255 से कम है? Cli () के बाद यदि TCNT0 255 तक पहुँच गया तो क्या होगा?
राजेश

8

एक रुकावट दिनचर्या में या इसका उपयोग करना गलत नहीं हैmillis()micros()

यह है उन्हें गलत तरीके से उपयोग करने के लिए गलत।

यहाँ मुख्य बात यह है कि जब आप एक बाधा दिनचर्या में होते हैं "घड़ी टिक नहीं रही है"। millis()और micros()नहीं बदलेगा (अच्छी तरह से, micros()शुरू में, लेकिन एक बार यह उस जादू मिलीसेकंड बिंदु से आगे निकल जाएगा जहां एक मिलीसेकंड टिक की आवश्यकता होती है, यह सब अलग हो जाता है।)

तो आप निश्चित रूप से पर कॉल कर सकते हैं millis()या micros()अपने ISR के भीतर मौजूदा समय पता लगाने के लिए है, लेकिन परिवर्तन के लिए उस समय उम्मीद नहीं है।

यह है कि आपके द्वारा प्रदान किए जाने वाले उद्धरण के बारे में चेतावनी दी जा रही समय में परिवर्तन की कमी है। यह जानने के लिए कि समय कितना बीत चुका है, delay()पर निर्भर करता है millis()। चूंकि यह नहीं बदलता है, delay()कभी खत्म नहीं हो सकता।

इसलिए अनिवार्य रूप से millis()और micros()आपको उस समय को बताएगा जब आपके ISR को कोई फर्क नहीं पड़ता था जब आपके ISR में आप उनका उपयोग करते हैं।


3
नहीं, micros()अद्यतन। यह हमेशा हार्डवेयर टाइमर रजिस्टर पढ़ता है।
निक गैमन

4

उद्धृत वाक्यांश एक चेतावनी नहीं है, यह केवल एक बयान है कि चीजें कैसे काम करती हैं।

सही तरीके से लिखे गए इंटरप्ट रूटीन का उपयोग करने millis()या उसके micros()भीतर आंतरिक रूप से कुछ भी गलत नहीं है।

दूसरी ओर, अनुचित तरीके से लिखी गई बाधित दिनचर्या में कुछ भी करना परिभाषा के अनुसार गलत है।

एक बाधा दिनचर्या जो अपना काम करने के लिए कुछ माइक्रोसेकंड से अधिक समय लेती है, सभी संभावना में, अनुचित रूप से लिखा गया है।

संक्षेप में: एक ठीक से लिखा बाधा दिनचर्या का कारण या के साथ मुठभेड़ मुद्दों नहीं होगा millis()या micros()

संपादित करें: "क्यों micros ()" गलत तरीके से व्यवहार करना शुरू करता है ", जैसा कि" Arduino micros function " की परीक्षा में बताया गया है , वेबपेज, micros()एक साधारण Uno पर कोड कार्यात्मक रूप से इसके बराबर है

unsigned long micros() {
  return((timer0_overflow_count << 8) + TCNT0)*(64/16);
}

यह एक चार-बाइट से रहित लंबी रिटर्न देता है जिसमें timer0_overflow_countटाइमर और 0 काउंट रजिस्टर से तीन सबसे कम बाइट शामिल हैं ।

बाधित हैंडलर timer0_overflow_countद्वारा प्रति मिलीसेकंड के बारे में एक बार वृद्धि की जाती है TIMER0_OVF_vect, जैसा कि arduino millis webpage की एक परीक्षा में बताया गया है ।

एक बाधा हैंडलर शुरू होने से पहले, AVR हार्डवेयर बाधित होता है। यदि (उदाहरण के लिए) एक बाधा हैंडलर को पांच मिलीसेकंड के लिए चलाना था, तो अभी भी अक्षम होने के साथ, कम से कम चार टाइमर 0 ओवरफ्लो छूट जाएंगे। [Arduino सिस्टम में C कोड में लिखी गई रुकावटें रीएंन्टेंट (एक ही हैंडलर के भीतर कई ओवरलैपिंग निष्पादन को सही ढंग से संभालने में सक्षम) नहीं हैं, लेकिन एक रीइंक्रैंट असेंबली लैंग्वेज हैंडलर लिख सकता है, जो रीइनवेबल्स को बाधित करता है, इससे पहले कि यह समय लेने वाली प्रक्रिया शुरू हो।]

दूसरे शब्दों में, टाइमर ओवरफ्लो "स्टैक अप" नहीं करता है; जब भी पिछले ओवरफ्लो से बाधित होने से पहले एक अतिप्रवाह होता है, millis()काउंटर एक मिलीसेकंड खो देता है, और timer0_overflow_countबदले में विसंगति micros()एक मिलीसेकंड भी गलत बनाता है।

व्यवधान प्रसंस्करण के लिए एक ऊपरी समय सीमा के रूप में "500 μs से कम" के बारे में, "बहुत लंबे समय के लिए टाइमर की रुकावट को रोकने के लिए", आप 1024 μs (जैसे 1020 μs) के नीचे जा सकते हैं और millis()अभी भी काम करेंगे, अधिकांश समय। हालाँकि, मैं एक बाधा हैंडलर के बारे में सोचता हूं जो एक सुस्ती के रूप में 5 μs से अधिक लेता है, सुस्ती के रूप में 10 μs से अधिक, घोंघा की तरह 20 μs से अधिक।


क्या आप "कैसे चीजें काम करती हैं" पर विस्तार से बता सकते हैं, विशेष रूप से micros()"गलती से व्यवहार क्यों शुरू करें"? और "सही ढंग से लिखित रुकावट दिनचर्या" से आपका क्या मतलब है? मुझे लगता है कि इसका मतलब है "500us से छोटा" (बहुत लंबे समय तक टाइमर की रुकावट को रोकने के लिए), "संचार के लिए अस्थिर चर का उपयोग करना" और "लाइब्रेरी कोड को कॉल न करना" जितना संभव हो, क्या कुछ और है?
पेट्र पुडलक

@ पेट्रूडलाक, संपादित देखें
जेम्स वाल्डबी - jwpat7
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.