यह अजीब नहीं है। यह सामान्य 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
वह रजिस्टर है जो PORTC
ATmega328P के भीतर आउटपुट पिन के मूल्य को नियंत्रित करता है । PINC
वह रजिस्टर है जहां इनपुट मान PORTC
उपलब्ध हैं। मौलिक रूप से, इस तरह की चीजें आंतरिक रूप से तब होती हैं जब आप digitalWrite
या digitalRead
कार्यों का उपयोग करते हैं। हालांकि, एक लुक-अप ऑपरेशन है जो arduino "पिन नंबर" को वास्तविक हार्डवेयर पिन नंबर में परिवर्तित करता है, जो कहीं-कहीं 50 घड़ी चक्रों के दायरे में आता है। जैसा कि आप शायद अनुमान लगा सकते हैं, यदि आप तेजी से जाने की कोशिश कर रहे हैं, तो एक ऑपरेशन पर 50 घड़ी चक्र बर्बाद करना चाहिए जो केवल 1 की आवश्यकता होनी चाहिए वह थोड़ा हास्यास्पद है।
उपरोक्त फ़ंक्शन शायद 8 बिट्स को स्थानांतरित करने के लिए 100-200 घड़ी चक्रों के दायरे में कहीं ले जाता है। यह 24 पिन-लिखता है, और 8 पढ़ता है। यह कई, कई बार तेजी से digital{stuff}
फ़ंक्शंस का उपयोग करता है।