क्या कोई इस अजीब दिखने वाले कोड की व्याख्या कर सकता है, जिसका उपयोग टाइमर सेटअप करने के लिए किया जाता है?


10

अन्य लोगों ने जो रेखाचित्र लिखे हैं, उन्हें देखते हुए, मुझे कभी-कभी कोड आता है जो कुछ इस तरह दिखता है:

TCCR1A = 0;
TCCR1B = 0;

TCNT1 = 34286;
TCCR1B |= (1 << CS12);
TIMSK1 |= (1 << TOIE1);

मुझे केवल इतना पता है कि टाइमिंग / टाइमर्स (मुझे लगता है) के साथ कुछ है। मैं इस तरह कैसे समझ सकता हूं और कोड बना सकता हूं? क्या हैं TCCR1A, TCCR1B, TCNT1, CS12, TIMSK1, और TOIE1?


जवाब देने के लिए पर्याप्त नहीं पता लेकिन: Electronics.stackexchange.com/questions/92350/… , forum.arduino.cc/index.php?topic=134602.0 , और stackoverflow.com/questions-9475482/… । अगर आपने ये पहले से ही देख लिया है तो न जानें।
बेनामी पेंगुइन

1
Atmel वेबसाइट से अपने डिवाइस के लिए "पूर्ण" डेटशीट डाउनलोड करें और टाइमर के बारे में अध्याय पढ़ें। डेटाशीट आश्चर्यजनक रूप से मेरी राय में पढ़ना अच्छा है।
जिप्पी

जवाबों:


15

यह अजीब नहीं है। यह सामान्य MCU कोड वास्तव में कैसा दिखता है।

यहां आपके पास स्मृति-मैप किए गए बाह्य उपकरणों की अवधारणा का एक उदाहरण है । मूल रूप से, MCU हार्डवेयर में SRU पता स्थान है जिसे MCU को सौंपा गया है। यदि आप इन पतों को लिखते हैं, तो बाइट के बिट्स एन पता परिधीय एम के व्यवहार को नियंत्रित करते हैं ।

मूल रूप से, मेमोरी के कुछ बैंकों में शाब्दिक रूप से SRAM सेल से हार्डवेयर तक चलने वाले छोटे तार होते हैं। यदि आप उस बाइट में इस बिट को "1" लिखते हैं, तो यह इस SRAM सेल को तार्किक उच्च पर सेट करता है, जो तब हार्डवेयर के कुछ हिस्से को चालू करता है।

यदि आप MCU के लिए शीर्षलेखों में देखते हैं, तो कीवर्ड की बहुत बड़ी तालिकाएँ हैं - <पते की मैपिंग। इस तरह TCCR1Bआदि चीजों को ... संकलन समय पर हल किया जाता है।

यह मेमोरी-मैपिंग तंत्र MCUs में अत्यंत व्यापक रूप से उपयोग किया जाता है। Arduino में ATmega MCU इसका उपयोग करते हैं, जैसे PIC, ARM, MSP430, STM32 और STM8 MCU सीरीज़, साथ ही बहुत सारे MCUs से मैं तुरंत परिचित नहीं हूँ।


Arduino कोड एक अजीब सामान है, जिसमें उन कार्यों के साथ होता है जो एमसीयू नियंत्रण रजिस्टरों को अप्रत्यक्ष रूप से एक्सेस करते हैं। हालांकि यह कुछ हद तक "अच्छा" है, यह बहुत धीमा है, और बहुत अधिक कार्यक्रम स्थान का उपयोग करता है।

रहस्यमय स्थिरांक सभी को ATmega328P डेटाशीट में बहुत विस्तार से वर्णित किया गया है , जिसे आपको वास्तव में पढ़ना चाहिए यदि आप कुछ और करने में रुचि रखते हैं तो एक आर्डिनो पर रोषपूर्ण रूप से टॉगल कर रहे हैं।

उपरोक्त लिंक की गई डेटाशीट के अंश चुनें:

यहां छवि विवरण दर्ज करें यहां छवि विवरण दर्ज करें यहां छवि विवरण दर्ज करें

इसलिए, उदाहरण के लिए, TIMSK1 |= (1 << TOIE1);बिट को TOIE1अंदर सेट करें TIMSK1। यह बिट्स 0b00000001द्वारा बाइनरी 1 ( ) को बाईं ओर शिफ्ट करके हासिल किया जाता TOIE1है, TOIE1हेडर फ़ाइल में 0. के रूप में परिभाषित किया गया है। यह तब के वर्तमान मूल्य में बिटवाइड ओर किया जाता है TIMSK1, जो प्रभावी रूप से इस एक बिट को सेट करता है।

बिटकॉइन के लिए दस्तावेज़ीकरण TIMSK1को देखते हुए , हम देख सकते हैं कि यह वर्णित है

जब यह बिट एक को लिखा जाता है, और स्टेटस रजिस्टर में आई-फ्लैग सेट किया जाता है (वैश्विक रूप से सक्षम बाधित होता है), टाइमर / काउंटर 1 ओवरफ्लो बाधित सक्षम होता है। संबंधित इंटरप्ट वेक्टर (पृष्ठ 57 पर "इंटरप्ट" देखें) को तब निष्पादित किया जाता है, जब TIFR1 में स्थित TOV1 फ्लैग को सेट किया जाता है।

अन्य सभी पंक्तियों की एक ही तरीके से व्याख्या की जानी चाहिए।


कुछ नोट:

आप जैसी चीजें भी देख सकते हैं TIMSK1 |= _BV(TOIE1);_BV()एक आम तौर पर इस्तेमाल किया जाने वाला मैक्रो है जो मूल रूप से AVR libc कार्यान्वयन से आता है । बेहतर पठनीयता के लाभ के साथ _BV(TOIE1)कार्यात्मक रूप से समान (1 << TOIE1)है।

इसके अलावा, आप लाइनों को भी देख सकते हैं जैसे: TIMSK1 &= ~(1 << TOIE1);या TIMSK1 &= ~_BV(TOIE1);। यह इसके विपरीत कार्य करता है TIMSK1 |= _BV(TOIE1);, इसमें यह बिट को अनिश्चित बनाताTOIE1 है TIMSK1। इसके द्वारा उत्पादित बिट-मास्क को प्राप्त करके _BV(TOIE1), उस पर एक बिटवाइज़ ~नॉट ऑपरेशन ( ) का प्रदर्शन किया जाता है , और फिर TIMSK1इस नोट मूल्य (जो 0b11111110 है) द्वारा एंडिंग किया जाता है।

ध्यान दें कि इन सभी मामलों में, जैसी चीजों का मूल्य (1 << TOIE1)या _BV(TOIE1)पूरी तरह से हल कर रहे हैं संकलन समय है, इसलिए वे कार्यात्मक एक सरल लगातार को कम करने, और इसलिए कार्यावधि में गणना करने के लिए कोई निष्पादन समय लगता है।


उचित रूप से लिखे गए कोड में आम तौर पर उस कोड के साथ टिप्पणी इनलाइन होगी जो यह बताती है कि रजिस्टर क्या करने के लिए सौंपा जा रहा है। यहाँ एक काफी सरल नरम-एसपीआई दिनचर्या है जो मैंने हाल ही में लिखा है:

uint8_t transactByteADC(uint8_t outByte)
{
    // Transfers one byte to the ADC, and receives one byte at the same time
    // does nothing with the chip-select
    // MSB first, data clocked on the rising edge

    uint8_t loopCnt;
    uint8_t retDat = 0;

    for (loopCnt = 0; loopCnt < 8; loopCnt++)
    {
        if (outByte & 0x80)         // if current bit is high
            PORTC |= _BV(ADC_MOSI);     // set data line
        else
            PORTC &= ~(_BV(ADC_MOSI));  // else unset it

        outByte <<= 1;              // and shift the output data over for the next iteration
        retDat <<= 1;               // shift over the data read back

        PORTC |= _BV(ADC_SCK);          // Set the clock high

        if (PINC & _BV(ADC_MISO))       // sample the input line
            retDat |= 0x01;         // and set the bit in the retval if the input is high

        PORTC &= ~(_BV(ADC_SCK));       // set clock low
    }
    return retDat;
}

PORTCवह रजिस्टर है जो PORTCATmega328P के भीतर आउटपुट पिन के मूल्य को नियंत्रित करता है । PINCवह रजिस्टर है जहां इनपुट मान PORTCउपलब्ध हैं। मौलिक रूप से, इस तरह की चीजें आंतरिक रूप से तब होती हैं जब आप digitalWriteया digitalReadकार्यों का उपयोग करते हैं। हालांकि, एक लुक-अप ऑपरेशन है जो arduino "पिन नंबर" को वास्तविक हार्डवेयर पिन नंबर में परिवर्तित करता है, जो कहीं-कहीं 50 घड़ी चक्रों के दायरे में आता है। जैसा कि आप शायद अनुमान लगा सकते हैं, यदि आप तेजी से जाने की कोशिश कर रहे हैं, तो एक ऑपरेशन पर 50 घड़ी चक्र बर्बाद करना चाहिए जो केवल 1 की आवश्यकता होनी चाहिए वह थोड़ा हास्यास्पद है।

उपरोक्त फ़ंक्शन शायद 8 बिट्स को स्थानांतरित करने के लिए 100-200 घड़ी चक्रों के दायरे में कहीं ले जाता है। यह 24 पिन-लिखता है, और 8 पढ़ता है। यह कई, कई बार तेजी से digital{stuff}फ़ंक्शंस का उपयोग करता है।


ध्यान दें कि इस कोड को Atmega32u4 (लियोनार्डो में प्रयुक्त) के साथ भी काम करना चाहिए क्योंकि इसमें ATmega32uP की तुलना में अधिक टाइमर शामिल हैं।
jfpoilpret

1
@ रिकार्डो - छोटे-एमसीयू एम्बेडेड कोड का संभवतः 90% + प्रत्यक्ष रजिस्टर हेरफेर करता है। अप्रत्यक्ष उपयोगिता कार्यों के साथ चीजें करना IO / बाह्य उपकरणों में हेरफेर करने का सामान्य तरीका नहीं है। हार्डवेयर नियंत्रण को दूर करने के लिए कुछ टूलकिट हैं (उदाहरण के लिए एटलम एएसएफ), लेकिन यह आमतौर पर रनटाइम ओवरहेड को कम करने के लिए जितना संभव हो उतना दूर संकलित करने के लिए लिखा जाता है, और लगभग हमेशा डेटाशीट को पढ़कर बाह्य उपकरणों को समझने की आवश्यकता होती है।
कॉनर वुल्फ

1
असल में, arduino सामान, कह कर, "यहाँ कार्यों ऐसा एक्स रहे हैं" वास्तव में हार्डवेयर है वास्तविक दस्तावेज या कैसे संदर्भित करने के लिए परेशान कर के बिना कर बातें यह होता है, बहुत बहुत सामान्य नहीं है। मैं समझता हूं कि यह एक परिचयात्मक उपकरण के रूप में मूल्य है, लेकिन त्वरित प्रोटोटाइप के अलावा, यह वास्तव में वास्तविक पेशेवर वातावरण में कभी नहीं किया गया है।
कॉनर वुल्फ

1
स्पष्ट होने के लिए, एम्बेडेड MCU फर्मवेयर के लिए arduino कोड को असामान्य बनाने वाली बात arduino कोड के लिए अद्वितीय नहीं है , यह समग्र दृष्टिकोण का एक कार्य है। असल में, एक बार जब आपको वास्तविक एमसीयू की अच्छी समझ हो जाती है , तो चीजों को ठीक से करना (जैसे सीधे हार्डवेयर रजिस्टरों का उपयोग करना) कम अतिरिक्त समय नहीं लेता है। जैसे, यदि आप वास्तविक MCU देव सीखना चाहते हैं, तो यह बेहतर है कि आप बस बैठें और समझें कि आपका MCU वास्तव में क्या कर रहा है, बल्कि फिर किसी और के अमूर्त होने पर भरोसा करना , जो टपका हुआ है।
कॉनर वुल्फ

1
ध्यान दें कि मैं यहां थोड़ा निंदक हो सकता हूं, लेकिन बहुत सारे व्यवहार जो मैं आर्डूइनो समुदाय में देखता हूं, वे विरोधी पैटर्न प्रोग्रामिंग कर रहे हैं। मैं बहुत सारे "कॉपी-पेस्ट" प्रोग्रामिंग, पुस्तकालयों के ब्लैक-बॉक्स के रूप में व्यवहार करता हूं, और बड़े पैमाने पर समुदाय में सिर्फ सामान्य गरीब डिजाइन प्रथाओं को देखता हूं। बेशक, मैं EE.stackexchange पर काफी सक्रिय हूं, इसलिए मेरे पास कुछ धीमा उपकरण हो सकता है, क्योंकि मेरे पास कुछ मॉडरेटर उपकरण हैं, और जैसे कि बहुत सारे बंद प्रश्न देखते हैं। वहाँ निश्चित रूप से arduino सवालों में एक पूर्वाग्रह है कि मैंने वहाँ देखा है "मुझे बताओ कि C & P को ठीक करने के लिए क्या है", बल्कि फिर "यह काम क्यों नहीं कर रहा है"।
कॉनर वुल्फ

3

TCCR1A टाइमर / काउंटर 1 नियंत्रण रजिस्टर ए है

TCCR1B टाइमर / काउंटर 1 नियंत्रण रजिस्टर बी है

TCNT1 टाइमर / काउंटर 1 का काउंटर मूल्य है

CS12 टाइमर / काउंटर 1 के लिए 3 घड़ी का चयन बिट है

TIMSK1 टाइमर / काउंटर 1 का अंतरायन मास्क रजिस्टर है

TOIE1 टाइमर / काउंटर 1 अतिप्रवाह बाधा सक्षम है

तो, कोड 62.5 किलोहर्ट्ज़ पर टाइमर / काउंटर 1 को सक्षम करता है और मूल्य को 34286 पर सेट करता है। फिर यह ओवरफ्लो को बाधित करने में सक्षम करता है, इसलिए जब यह 65535 तक पहुंचता है, तो यह रुकावट फ़ंक्शन को ट्रिगर करेगा, सबसे अधिक संभावना के रूप में लेबल किया गया। ISR(timer0_overflow_vect)


1

CS12 का मान 2 है क्योंकि यह TCCR1B रजिस्टर के बिट 2 का प्रतिनिधित्व करता है।

(1 << CS12) मान 1 (0b00000001) लेता है और इसे प्राप्त करने के लिए 2 बार छोड़ दिया जाता है (0b00000101)। संचालन का क्रम निर्धारित करता है कि चीजें पहले () में होती हैं, इसलिए इसका मूल्यांकन "= =" से पहले किया जाता है।

(1 << CS10) मान 1 (0b00000001) लेता है और इसे प्राप्त करने के लिए 0 बार छोड़ दिया जाता है (0b00000001)। संचालन का क्रम निर्धारित करता है कि चीजें पहले () में होती हैं, इसलिए इसका मूल्यांकन "= =" से पहले किया जाता है।

तो अब हम TCCR1B | = 0b00000101, जो TCCR1B = TCCR1B के समान है 0b00000101।

चूंकि "|" "OR" है, TCCR1B में CS12 के अलावा सभी बिट्स अप्रभावित हैं।

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