विषयसूची:

एवीआर असेंबलर ट्यूटोरियल 3: 9 कदम
एवीआर असेंबलर ट्यूटोरियल 3: 9 कदम

वीडियो: एवीआर असेंबलर ट्यूटोरियल 3: 9 कदम

वीडियो: एवीआर असेंबलर ट्यूटोरियल 3: 9 कदम
वीडियो: AVR Assembly Tutorial: Part 1 (Basic Commands) 2024, जुलाई
Anonim
एवीआर असेंबलर ट्यूटोरियल 3
एवीआर असेंबलर ट्यूटोरियल 3

ट्यूटोरियल नंबर 3 में आपका स्वागत है!

शुरू करने से पहले मैं एक दार्शनिक बिंदु बनाना चाहता हूं। सर्किट और कोड के साथ प्रयोग करने से डरो मत जो हम इन ट्यूटोरियल में बना रहे हैं। चारों ओर तार बदलें, नए घटक जोड़ें, घटकों को बाहर निकालें, कोड की लाइनें बदलें, नई लाइनें जोड़ें, लाइनें हटाएं, और देखें कि क्या होता है! कुछ भी तोड़ना बहुत मुश्किल है और अगर आप करते हैं, तो कौन परवाह करता है? माइक्रोकंट्रोलर सहित हम जो कुछ भी उपयोग नहीं कर रहे हैं, वह बहुत महंगा है और यह देखना हमेशा शैक्षिक होता है कि चीजें कैसे विफल हो सकती हैं। अगली बार न केवल आपको पता चलेगा कि क्या नहीं करना है, बल्कि इससे भी महत्वपूर्ण बात यह है कि आपको पता चल जाएगा कि ऐसा क्यों नहीं करना चाहिए। यदि आप मेरे जैसे कुछ भी हैं, जब आप एक बच्चे थे और आपको एक नया खिलौना मिला था, तो आपके पास यह देखने में बहुत समय नहीं था कि आपके पास यह देखने के लिए क्या सही है? कभी-कभी खिलौना अपूरणीय रूप से क्षतिग्रस्त हो जाता है लेकिन कोई बड़ी बात नहीं है। एक बच्चे को टूटे खिलौनों तक भी अपनी जिज्ञासा का पता लगाने की अनुमति देना ही उसे डिशवॉशर के बजाय वैज्ञानिक या इंजीनियर में बदल देता है।

आज हम एक बहुत ही सरल सर्किट को तार करने जा रहे हैं और फिर सिद्धांत में थोड़ा भारी हो रहे हैं। इसके बारे में क्षमा करें, लेकिन हमें उपकरणों की आवश्यकता है! मैं वादा करता हूं कि हम ट्यूटोरियल 4 में इसकी भरपाई करेंगे जहां हम कुछ और गंभीर सर्किट निर्माण करेंगे और परिणाम बहुत अच्छा होगा। हालाँकि, जिस तरह से आपको इन सभी ट्यूटोरियल्स को करने की आवश्यकता है, वह बहुत धीमे, चिंतनशील तरीके से है। यदि आप बस हल चलाते हैं, सर्किट बनाते हैं, कोड को कॉपी और पेस्ट करते हैं, और इसे चलाते हैं, तो निश्चित रूप से, यह काम करेगा, लेकिन आप कुछ नहीं सीखेंगे। आपको प्रत्येक पंक्ति के बारे में सोचने की जरूरत है। विराम। प्रयोग। आविष्कार। यदि आप इसे इस तरह से करते हैं तो ५वें ट्यूटोरियल के अंत तक आप अच्छी चीजें बनाना बंद कर देंगे और आपको अधिक शिक्षण की आवश्यकता नहीं होगी। अन्यथा आप सीखने और बनाने के बजाय बस देख रहे हैं।

किसी भी मामले में, पर्याप्त दर्शन, चलो शुरू करें!

इस ट्यूटोरियल में आपको आवश्यकता होगी:

  1. आपका प्रोटोटाइप बोर्ड
  2. एक एलईडी
  3. कनेक्टिंग तार
  4. 220 से 330 ओम के आसपास एक रोकनेवाला
  5. निर्देश सेट मैनुअल: www.atmel.com/images/atmel-0856-avr-instruction-se…
  6. डेटाशीट: www.atmel.com/images/Atmel-8271-8-bit-AVR-Microco…
  7. एक अलग क्रिस्टल थरथरानवाला (वैकल्पिक)

यहां ट्यूटोरियल के संपूर्ण संग्रह का लिंक दिया गया है:

चरण 1: सर्किट का निर्माण

सर्किट का निर्माण
सर्किट का निर्माण

इस ट्यूटोरियल में सर्किट बेहद सरल है। हम अनिवार्य रूप से "ब्लिंक" प्रोग्राम लिखने जा रहे हैं, इसलिए हमें केवल निम्नलिखित की आवश्यकता है।

एक LED को PD4 से, फिर एक 330 ओम रेसिस्टर से, फिर ग्राउंड में कनेक्ट करें। अर्थात।

पीडी4 - एलईडी - आर (330) - जीएनडी

और वह है!

हालांकि सिद्धांत कठिन नारा देने वाला है …

चरण 2: हमें टिप्पणियों और M328Pdef.inc फ़ाइल की आवश्यकता क्यों है?

मुझे लगता है कि हमें यह दिखाकर शुरू करना चाहिए कि फाइल और टिप्पणियां क्यों उपयोगी हैं। उनमें से कोई भी वास्तव में आवश्यक नहीं है और आप उनके बिना उसी तरह कोड लिख सकते हैं, इकट्ठा कर सकते हैं और अपलोड कर सकते हैं और यह पूरी तरह से अच्छी तरह से चलेगा (हालांकि फ़ाइल शामिल किए बिना आपको असेंबलर से कुछ शिकायतें मिल सकती हैं - लेकिन कोई त्रुटि नहीं)

यहाँ वह कोड है जिसे हम आज लिखने जा रहे हैं, सिवाय इसके कि मैंने टिप्पणियों और शामिल फ़ाइल को हटा दिया है:

.डिवाइस ATmega328P

.org 0x0000 jmp a.org 0x0020 jmp ईए: ldi r16, 0x05 0x25, r16 ldi r16, 0x01 sts 0x6e, r16 sei clr r16 0x26, r16 sbi 0x0a, 0x0 sbi 0x0b, 0x 0x04 कॉल करें cbi 0x0b, 0x04 rcall c rjmp bc: clr r17 d: cpi r17, 0x1e brne d ret e: inc r17 cpi r17, 0x3d brne PC+2 clr r17 रेटी

बहुत आसान है ना? हाहा। यदि आप इस फ़ाइल को असेंबल और अपलोड करते हैं, तो आप एलईडी को १ ब्लिंक प्रति सेकंड की दर से ब्लिंक करेंगे और १/२ सेकंड तक ब्लिंक करेंगे और ब्लिंक्स के बीच १/२ सेकंड तक रुकेंगे।

हालाँकि, इस कोड को देखना शायद ही ज्ञानवर्धक हो। यदि आप इस तरह से कोड लिखना चाहते हैं और इसे संशोधित करना चाहते हैं या भविष्य में इसका पुन: उपयोग करना चाहते हैं तो आपके लिए कठिन समय होगा।

तो चलिए टिप्पणियाँ डालते हैं और फ़ाइल को वापस शामिल करते हैं ताकि हम इसका कुछ अर्थ निकाल सकें।

चरण 3: ब्लिंक.asm

यहां वह कोड है जिस पर हम आज चर्चा करेंगे:

;************************************

; द्वारा लिखित: 1o_o7; दिनांक:; संस्करण: 1.0; फ़ाइल इस रूप में सहेजी गई: blink.asm; एवीआर के लिए: atmega328p; घड़ी की आवृत्ति: 16 मेगाहर्ट्ज (वैकल्पिक); ***********************; कार्यक्रम समारोह:---------------------; एक एलईडी को झपकाकर सेकंड गिनता है;; PD4 - LED - R (330 ओम) - GND;;-------------------------------------------------.nolist.include "./m328Pdef.inc" सूची;===============; घोषणाएँ:.def अस्थायी = r16.def अतिप्रवाह = r17.org 0x0000; मेमोरी (पीसी) रीसेट हैंडलर का स्थान rjmp रीसेट; jmp की लागत 2 cpu साइकिल और rjmp की लागत केवल 1 है; इसलिए जब तक आपको 8k बाइट्स से अधिक कूदने की आवश्यकता न हो; आपको केवल rjmp की आवश्यकता है। कुछ माइक्रोकंट्रोलर इसलिए ही; rjmp है न कि jmp.org 0x0020; Timer0 ओवरफ्लो हैंडलर की मेमोरी लोकेशन rjmp ओवरफ्लो_हैंडलर; अगर टाइमर0 ओवरफ्लो इंटरप्ट होता है तो यहां जाएं;============ रीसेट करें: एलडीआई अस्थायी, 0b00000101 टीसीसीआर0बी, अस्थायी; घड़ी चयनकर्ता बिट्स CS00, CS01, CS02 को 101 पर सेट करें; यह टाइमर काउंटर0, टीसीएनटी0 को एफसीपीयू/1024 मोड में डालता है; तो यह CPU freq/1024 ldi temp, 0b00000001 sts TIMSK0, temp पर टिक करता है; टाइमर ओवरफ्लो इंटरप्ट सक्षम करें (TOIE0) बिट सेट करें; टाइमर इंटरप्ट मास्क रजिस्टर (TIMSK0) सेई; ग्लोबल इंटरप्ट सक्षम करें -- "sbi SREG, I" clr temp out TCNT0, temp के बराबर; टाइमर/काउंटर को 0 एसबीआई डीडीआरडी, 4 में इनिशियलाइज़ करें; PD4 को आउटपुट पर सेट करें;=====================; कार्यक्रम का मुख्य भाग: ब्लिंक: sbi PORTD, 4; PD4 rcall देरी पर LED चालू करें; देरी होगी 1/2 सेकंड cbi PORTD, 4; PD4 rcall देरी पर LED बंद करें; देरी होगी १/२ सेकंड rjmp ब्लिंक; प्रारंभ विलंब पर वापस लूप करें: clr ओवरफ़्लो; ओवरफ्लो को 0 sec_count पर सेट करें: cpi ओवरफ्लो, 30; ओवरफ्लो की संख्या और 30 brne sec_count की तुलना करें; शाखा वापस sec_count पर यदि बराबर नहीं है तो ret; अगर 30 ओवरफ्लो हुए हैं तो ब्लिंक ओवरफ्लो_हैंडलर पर लौटें: इंक ओवरफ्लो; अतिप्रवाह चर में 1 जोड़ें सीपीआई अतिप्रवाह, ६१; ६१ बड़े पीसी+२ के साथ तुलना करें; प्रोग्राम काउंटर + 2 (अगली पंक्ति छोड़ें) यदि बराबर clr ओवरफ्लो नहीं है; यदि ६१ ओवरफ्लो होते हैं तो काउंटर को जीरो रेटी पर रीसेट करें; रुकावट से वापसी

जैसा कि आप देख सकते हैं, मेरी टिप्पणियाँ अब थोड़ी और संक्षिप्त हैं। एक बार जब हम जान जाते हैं कि निर्देश सेट में क्या आदेश हैं, तो हमें टिप्पणियों में यह समझाने की आवश्यकता नहीं है। हमें केवल यह समझाने की जरूरत है कि कार्यक्रम के दृष्टिकोण से क्या हो रहा है।

हम इस बात पर चर्चा करेंगे कि यह सब टुकड़े-टुकड़े क्या करता है, लेकिन पहले आइए एक वैश्विक परिप्रेक्ष्य प्राप्त करने का प्रयास करें। कार्यक्रम का मुख्य निकाय निम्नानुसार काम करता है।

पहले हम PORTD के बिट 4 को "sbi PORTD, 4" के साथ सेट करते हैं, यह PD4 को 1 भेजता है जो उस पिन पर वोल्टेज को 5V पर रखता है। इससे एलईडी चालू हो जाएगी। फिर हम "देरी" सबरूटीन पर कूद जाते हैं जो 1/2 सेकंड की गणना करता है (हम यह बताएंगे कि यह बाद में कैसे करता है)। हम फिर PORTD पर ब्लिंक और क्लियर बिट 4 पर लौटते हैं जो PD4 को 0V पर सेट करता है और इसलिए एलईडी को बंद कर देता है। फिर हम एक और 1/2 सेकंड के लिए देरी करते हैं, और फिर "rjmp ब्लिंक" के साथ फिर से ब्लिंक की शुरुआत में वापस कूद जाते हैं।

आपको यह कोड चलाना चाहिए और देखना चाहिए कि यह वही करता है जो इसे करना चाहिए।

आखिर तुमने इसे हासिल कर ही लिया है! यह सब कोड शारीरिक रूप से करता है। माइक्रोकंट्रोलर जो कर रहा है उसकी आंतरिक यांत्रिकी थोड़ी अधिक शामिल है और इसीलिए हम यह ट्यूटोरियल कर रहे हैं। तो आइए प्रत्येक खंड पर बारी-बारी से चर्चा करें।

चरण 4:.org असेंबलर निर्देश

हम पहले से ही जानते हैं कि.nolist,.list,.include, और.def असेंबलर निर्देश हमारे पिछले ट्यूटोरियल से क्या करते हैं, तो आइए पहले कोड की 4 पंक्तियों पर एक नज़र डालें जो उसके बाद आती हैं:

.org 0x0000

जेएमपी रीसेट.org 0x0020 जेएमपी ओवरफ्लो_हैंडलर

.org स्टेटमेंट असेंबलर को बताता है कि "प्रोग्राम मेमोरी" में अगला स्टेटमेंट कहां रखा जाए। जैसे ही आपका प्रोग्राम निष्पादित होता है, "प्रोग्राम काउंटर" (पीसी के रूप में संक्षिप्त) में निष्पादित की जा रही वर्तमान लाइन का पता होता है। तो इस मामले में जब पीसी 0x0000 पर है तो यह उस मेमोरी लोकेशन में रहने वाले कमांड "jmp Reset" को देखेगा। जिस कारण से हम उस स्थान पर jmp रीसेट करना चाहते हैं, क्योंकि जब प्रोग्राम शुरू होता है, या चिप रीसेट हो जाता है, तो पीसी इस स्थान पर कोड निष्पादित करना शुरू कर देता है। इसलिए, जैसा कि हम देख सकते हैं, हमने अभी इसे "रीसेट" लेबल वाले अनुभाग पर तुरंत "कूदने" के लिए कहा है। हमने ऐसा क्यों किया? इसका मतलब है कि ऊपर की अंतिम दो पंक्तियों को अभी छोड़ दिया जा रहा है! क्यों?

खैर, वहीं चीजें दिलचस्प हो जाती हैं। अब आपको पूर्ण ATmega328p डेटाशीट के साथ एक पीडीएफ व्यूअर खोलना होगा, जिसे मैंने इस ट्यूटोरियल के पहले पृष्ठ पर इंगित किया था (इसीलिए यह "आपको आवश्यकता होगी" अनुभाग में आइटम 4 है)। यदि आपकी स्क्रीन बहुत छोटी है, या आपके पास पहले से ही बहुत सारी खिड़कियां खुली हैं (जैसा कि मेरे साथ है) तो आप वह कर सकते हैं जो मैं करता हूं और इसे ईरीडर, या अपने एंड्रॉइड फोन पर रख सकता हूं। यदि आप असेंबली कोड लिखने की योजना बना रहे हैं तो आप हर समय इसका इस्तेमाल करेंगे। अच्छी बात यह है कि सभी माइक्रोकंट्रोलर बहुत समान तरीकों से व्यवस्थित होते हैं और इसलिए एक बार जब आप डेटाशीट पढ़ने और उनसे कोडिंग करने के अभ्यस्त हो जाते हैं, तो आपको एक अलग माइक्रोकंट्रोलर के लिए ऐसा करना लगभग तुच्छ लगेगा। इसलिए हम वास्तव में सीख रहे हैं कि सभी माइक्रोकंट्रोलर का एक अर्थ में उपयोग कैसे करें, न कि केवल atmega328p।

ठीक है, डेटाशीट में पृष्ठ 18 पर मुड़ें और चित्र 8-2 पर एक नज़र डालें।

इस प्रकार माइक्रोकंट्रोलर में प्रोग्राम मेमोरी सेट की जाती है। आप देख सकते हैं कि यह 0x0000 पते से शुरू होता है और दो खंडों में विभाजित होता है; एक एप्लिकेशन फ्लैश सेक्शन और एक बूट फ्लैश सेक्शन। यदि आप संक्षेप में पृष्ठ 277 तालिका 27-14 को देखें तो आप देखेंगे कि एप्लिकेशन फ्लैश अनुभाग 0x0000 से 0x37FF तक के स्थान लेता है और बूट फ्लैश अनुभाग शेष स्थानों को 0x3800 से 0x3FFF तक ले जाता है।

अभ्यास १: प्रोग्राम मेमोरी में कितने स्थान होते हैं? अर्थात। 3FFF को दशमलव में बदलें और 1 जोड़ें क्योंकि हम 0 पर गिनना शुरू करते हैं। चूंकि प्रत्येक मेमोरी लोकेशन 16 बिट्स (या 2 बाइट्स) चौड़ी है, मेमोरी के बाइट्स की कुल संख्या क्या है? अब इसे किलोबाइट में बदलें, याद रखें कि एक किलोबाइट में 2^10 = 1024 बाइट्स होते हैं। बूट फ्लैश सेक्शन 0x3800 से 0x37FF तक जाता है, यह कितने किलोबाइट है? हमारे प्रोग्राम को स्टोर करने के लिए हमारे पास कितनी किलोबाइट मेमोरी बची है? दूसरे शब्दों में, हमारा कार्यक्रम कितना बड़ा हो सकता है? अंत में, हमारे पास कोड की कितनी पंक्तियाँ हो सकती हैं?

ठीक है, अब जब हम फ्लैश प्रोग्राम मेमोरी के संगठन के बारे में सब कुछ जानते हैं, तो आइए.org कथनों की अपनी चर्चा जारी रखें। हम देखते हैं कि पहले मेमोरी लोकेशन 0x0000 में हमारे सेक्शन में जाने का हमारा निर्देश है जिसे हमने रीसेट लेबल किया है। अब हम देखते हैं कि ".org 0x0020" कथन क्या करता है। यह कहता है कि हम चाहते हैं कि अगली पंक्ति का निर्देश स्मृति स्थान 0x0020 पर रखा जाए। हमने जो निर्देश वहां रखा है, वह हमारे कोड में एक सेक्शन में कूद गया है जिसे हमने "ओवरफ्लो_हैंडलर" लेबल किया है … अब हम क्यों मांग करेंगे कि यह जंप मेमोरी लोकेशन 0x0020 पर रखा जाए? यह पता लगाने के लिए, हम डेटाशीट में पृष्ठ ६५ की ओर मुड़ते हैं और तालिका १२-६ पर एक नज़र डालते हैं।

तालिका 12-6 "रीसेट और इंटरप्ट वेक्टर" की एक तालिका है और यह ठीक से दिखाती है कि जब पीसी "इंटरप्ट" प्राप्त करता है तो पीसी कहां जाएगा। उदाहरण के लिए, यदि आप वेक्टर नंबर 1 को देखते हैं। रुकावट का "स्रोत" "रीसेट" है जिसे "बाहरी पिन, पावर-ऑन रीसेट, ब्राउन-आउट रीसेट, और वॉचडॉग सिस्टम रीसेट" के रूप में परिभाषित किया गया है, जिसका अर्थ है, यदि कोई हो वे चीजें हमारे माइक्रोकंट्रोलर के साथ होती हैं, पीसी प्रोग्राम मेमोरी लोकेशन 0x0000 पर हमारे प्रोग्राम को निष्पादित करना शुरू कर देगा। तब हमारे.org निर्देश के बारे में क्या? ठीक है, हमने मेमोरी लोकेशन 0x0020 पर एक कमांड रखा है और यदि आप टेबल को नीचे देखते हैं तो आप देखेंगे कि यदि टाइमर/काउंटर0 ओवरफ्लो होता है (TIMER0 OVF से आ रहा है) तो यह 0x0020 लोकेशन पर जो कुछ भी है उसे निष्पादित करेगा। इसलिए जब भी ऐसा होगा, पीसी उस स्थान पर पहुंच जाएगा जहां हमने "ओवरफ्लो_हैंडलर" का लेबल लगाया था। बिल्कुल सटीक? आप एक मिनट में देखेंगे कि हमने ऐसा क्यों किया, लेकिन पहले ट्यूटोरियल के इस चरण को एक तरफ से समाप्त करते हैं।

यदि हम अपने कोड को और अधिक साफ-सुथरा बनाना चाहते हैं तो हमें वास्तव में उन 4 पंक्तियों को बदलना चाहिए जिनकी हम वर्तमान में निम्नलिखित के साथ चर्चा कर रहे हैं (पृष्ठ 66 देखें):

.org 0x0000

आरजेएमपी रीसेट; पीसी = 0x0000 रेटी; पीसी = 0x0002 रेटी; पीसी = 0x0004 रेटी; पीसी = 0x0006 रेटी; पीसी = 0x0008 रेटी; पीसी = 0x000A … रेटी; पीसी = 0x001E जेएमपी ओवरफ्लो_हैंडलर: पीसी = 0x0020 रेटी: पीसी = 0x0022 … रेटी; पीसी = 0x0030 रेटी; पीसी = 0x0032

ताकि अगर कोई रुकावट आती है तो यह सिर्फ "रेती" होगा जिसका अर्थ है "बाधा से वापसी" और कुछ नहीं होता है। लेकिन अगर हम इन विभिन्न व्यवधानों को कभी "सक्षम" नहीं करते हैं, तो उनका उपयोग नहीं किया जाएगा और हम इन स्थानों में प्रोग्राम कोड डाल सकते हैं। हमारे वर्तमान "blink.asm" प्रोग्राम में हम केवल टाइमर0 ओवरफ्लो इंटरप्ट (और निश्चित रूप से रीसेट इंटरप्ट जो हमेशा सक्षम होता है) को सक्षम करने जा रहे हैं और इसलिए हम दूसरों के साथ परेशान नहीं होंगे।

हम टाइमर0 ओवरफ्लो इंटरप्ट को "सक्षम" कैसे करते हैं? … यह इस ट्यूटोरियल में हमारे अगले चरण का विषय है।

चरण 5: टाइमर / काउंटर 0

टाइमर / काउंटर 0
टाइमर / काउंटर 0

ऊपर दी गई तस्वीर पर एक नजर डालें। यह "पीसी" की निर्णय लेने की प्रक्रिया है जब कुछ बाहरी प्रभाव हमारे कार्यक्रम के प्रवाह को "बाधित" करते हैं। पहली बात यह है कि जब इसे बाहर से एक संकेत मिलता है कि एक रुकावट आ गई है, तो यह देखने के लिए जाँच करता है कि क्या हमने उस प्रकार के व्यवधान के लिए "इंटरप्ट इनेबल" बिट सेट किया है। यदि हमने ऐसा नहीं किया है, तो यह हमारे कोड की अगली पंक्ति को निष्पादित करना जारी रखता है। यदि हमने उस विशेष इंटरप्ट को सक्षम बिट सेट किया है (ताकि उस बिट स्थान में 0 के बजाय 1 हो) तो यह जांच करेगा कि हमने "ग्लोबल इंटरप्ट" को सक्षम किया है या नहीं, यदि नहीं तो यह फिर से अगली पंक्ति में जाएगा कोड और जारी रखें। यदि हमने ग्लोबल इंटरप्ट को भी सक्षम किया है, तो यह उस प्रकार के इंटरप्ट के प्रोग्राम मेमोरी लोकेशन पर जाएगा (जैसा कि तालिका 12-6 में दिखाया गया है) और जो भी कमांड हमने वहां रखा है उसे निष्पादित करें। तो आइए देखें कि हमने अपने कोड में यह सब कैसे लागू किया है।

हमारे कोड का लेबल रीसेट करें अनुभाग निम्नलिखित दो पंक्तियों से शुरू होता है:

रीसेट:

एलडीआई अस्थायी, 0b00000101 टीसीसीआर0बी से बाहर, अस्थायी

जैसा कि हम पहले से ही जानते हैं, यह तुरंत बाद की संख्या (यानी R16) में लोड हो जाता है, जो कि 0b00000101 है। फिर यह इस नंबर को "आउट" कमांड का उपयोग करके TCCR0B नामक रजिस्टर में लिखता है। यह रजिस्टर क्या है? खैर, आइए डेटाशीट के पेज 614 पर जाएं। यह सभी रजिस्टरों को सारांशित करने वाली तालिका के बीच में है। पते 0x25 पर आपको TCCR0B मिलेगा। (अब आप जानते हैं कि कोड के मेरे गैर-टिप्पणी वाले संस्करण में "आउट 0x25, r16" लाइन कहां से आई है)। हम ऊपर दिए गए कोड सेगमेंट से देखते हैं कि हमने 0 वां बिट और दूसरा बिट सेट किया है और बाकी सभी को साफ़ कर दिया है। तालिका को देखकर आप देख सकते हैं कि इसका मतलब है कि हमने CS00 और CS02 सेट किए हैं। अब "8-बिट टाइमर/पीडब्लूएम के साथ काउंटर0" नामक डेटाशीट में अध्याय पर जाने देता है। विशेष रूप से, उस अध्याय के पृष्ठ १०७ पर जाएँ। आपको "टाइमर/काउंटर कंट्रोल रजिस्टर बी" (TCCR0B) रजिस्टर का वही विवरण दिखाई देगा जो हमने अभी रजिस्टर सारांश तालिका में देखा था (इसलिए हम सीधे यहां आ सकते थे, लेकिन मैं चाहता था कि आप देखें कि सारांश तालिकाओं का उपयोग कैसे करें आगामी संदर्भ के लिए)। डेटाशीट उस रजिस्टर में प्रत्येक बिट्स का विवरण देना जारी रखती है और वे क्या करते हैं। हम अभी के लिए वह सब छोड़ देंगे और पृष्ठ को तालिका 15-9 में बदल देंगे। यह तालिका "घड़ी का चयन बिट विवरण" दिखाती है। अब उस तालिका को तब तक देखें जब तक आपको वह रेखा न मिल जाए जो बिट्स से मेल खाती है जिसे हमने अभी उस रजिस्टर में सेट किया है। लाइन कहती है "clk/1024 (prescaler से)"। इसका मतलब यह है कि हम चाहते हैं कि टाइमर/काउंटर0 (टीसीएनटी0) उस दर पर टिक करे जो सीपीयू आवृत्ति 1024 से विभाजित है। चूंकि हमारे पास 16 मेगाहट्र्ज क्रिस्टल ऑसीलेटर द्वारा हमारे माइक्रोकंट्रोलर को खिलाया जाता है, इसका मतलब है कि हमारे सीपीयू द्वारा निर्देशों को निष्पादित करने की दर है प्रति सेकंड 16 मिलियन निर्देश। तो हमारे टीसीएनटी0 काउंटर पर टिक करने की दर 16 मिलियन/1024 = 15625 बार प्रति सेकेंड है (इसे विभिन्न घड़ी चयन बिट्स के साथ आज़माएं और देखें कि क्या होता है - हमारे दर्शन को याद रखें?) आइए संख्या 15625 को बाद के लिए अपने दिमाग के पीछे रखें और कोड की अगली दो पंक्तियों पर आगे बढ़ें:

एलडीआई अस्थायी, 0b00000001

एसटीएस TIMSK0, अस्थायी

यह TIMSK0 नामक रजिस्टर का 0वां बिट सेट करता है और बाकी सभी को साफ करता है। यदि आप डेटाशीट में पृष्ठ 109 पर एक नज़र डालते हैं, तो आप देखेंगे कि TIMSK0 का अर्थ "टाइमर/काउंटर इंटरप्ट मास्क रजिस्टर 0" है और हमारे कोड ने 0वां बिट सेट किया है जिसका नाम TOIE0 है जो "टाइमर/काउंटर0 ओवरफ्लो इंटरप्ट इनेबल" के लिए है। … वहां! अब आप देखिए क्या है माजरा। अब हमारे पास "इंटरप्ट इनेबल बिट सेट" है जैसा कि हम शीर्ष पर अपनी तस्वीर में पहले निर्णय से चाहते थे। तो अब हमें केवल "वैश्विक व्यवधान" को सक्षम करना है और हमारा कार्यक्रम इस प्रकार के व्यवधानों का जवाब देने में सक्षम होगा। हम जल्द ही वैश्विक व्यवधानों को सक्षम करेंगे, लेकिन इससे पहले कि हम ऐसा करें कि आप किसी चीज़ से भ्रमित हो गए हों.. मैंने सामान्य "आउट" के बजाय TIMSK0 रजिस्टर में कॉपी करने के लिए "sts" कमांड का उपयोग क्यों किया?

जब भी आप मुझे एक निर्देश का उपयोग करते हुए देखते हैं जो आपने पहले नहीं देखा है तो आपको सबसे पहले डेटाशीट में पृष्ठ ६१६ की ओर मुड़ना चाहिए। यह "निर्देश सेट सारांश" है। अब "STS" निर्देश ढूंढें जिसका मैंने उपयोग किया है। यह कहता है कि यह एक आर रजिस्टर से एक नंबर लेता है (हमने आर 16 का इस्तेमाल किया) और "स्टोर डायरेक्ट टू एसआरएएम" लोकेशन k (हमारे मामले में TIMSK0 द्वारा दिया गया)। तो हमें "sts" का उपयोग क्यों करना पड़ा जो TIMSK0 में स्टोर करने के लिए 2 घड़ी चक्र (तालिका में अंतिम कॉलम देखें) लेता है और हमें केवल "आउट" की आवश्यकता होती है, जो पहले TCCR0B में स्टोर करने के लिए केवल एक घड़ी चक्र लेता है? इस प्रश्न का उत्तर देने के लिए हमें पृष्ठ 614 पर अपनी रजिस्टर सारांश तालिका पर वापस जाने की आवश्यकता है। आप देखते हैं कि TCCR0B रजिस्टर 0x25 पते पर है, लेकिन (0x45) दाईं ओर भी है? इसका मतलब है कि यह SRAM में एक रजिस्टर है, लेकिन यह एक निश्चित प्रकार का रजिस्टर भी है जिसे "पोर्ट" (या i/o रजिस्टर) कहा जाता है। यदि आप "आउट" कमांड के बगल में निर्देश सारांश तालिका को देखते हैं, तो आप देखेंगे कि यह R16 जैसे "वर्किंग रजिस्टरों" से मान लेता है और उन्हें एक पोर्ट पर भेजता है। इसलिए हम TCCR0B को लिखते समय "आउट" का उपयोग कर सकते हैं और अपने आप को एक घड़ी चक्र बचा सकते हैं। लेकिन अब रजिस्टर तालिका में TIMSK0 को देखें। आप देखते हैं कि इसका पता 0x6e है। यह बंदरगाहों की सीमा से बाहर है (जो एसआरएएम के केवल पहले 0x3F स्थान हैं) और इसलिए आपको एसटीएस कमांड का उपयोग करने और इसे करने के लिए दो सीपीयू घड़ी चक्र लेने के लिए वापस आना होगा। कृपया अभी पृष्ठ ६१५ पर निर्देश सारांश तालिका के अंत में नोट ४ पढ़ें। यह भी ध्यान दें कि हमारे सभी इनपुट और आउटपुट पोर्ट, जैसे PORTD टेबल के नीचे स्थित हैं। उदाहरण के लिए, 0x0b पते पर PD4 बिट 4 है (अब आप देख सकते हैं कि मेरे गैर-टिप्पणी किए गए कोड में सभी 0x0b सामान कहां से आए!).. ठीक है, त्वरित प्रश्न: क्या आपने "एसटी" को "आउट" में बदल दिया और देखें कि क्या ह ाेती है? हमारे दर्शन को याद रखें! इसे तोड़ दो! केवल बातों के लिए मेरी बात मत मानो।

ठीक है, इससे पहले कि हम आगे बढ़ें, एक मिनट के लिए डेटाशीट में पेज 19 पर जाएं। आप डेटा मेमोरी (SRAM) की एक तस्वीर देखते हैं। SRAM में पहले 32 रजिस्टर (0x0000 से 0x001F तक) R31 के माध्यम से "सामान्य प्रयोजन के काम करने वाले रजिस्टर" R0 हैं जिनका हम अपने कोड में हर समय चर के रूप में उपयोग करते हैं।अगले 64 रजिस्टर 0x005f तक के I/O पोर्ट हैं (अर्थात जिनके बारे में हम बात कर रहे थे, उनके पास रजिस्टर टेबल में उनके बगल में बिना ब्रैकेट वाले पते हैं, जिन्हें हम "sts" के बजाय "आउट" कमांड का उपयोग कर सकते हैं) अंत में SRAM के अगले भाग में 0x00FF को संबोधित करने के लिए सारांश तालिका में अन्य सभी रजिस्टर शामिल हैं, और अंत में शेष आंतरिक SRAM है। अब जल्दी से, एक सेकंड के लिए पेज १२ की ओर मुड़ें। वहां आपको "सामान्य प्रयोजन के काम करने वाले रजिस्टरों" की एक तालिका दिखाई देती है जिसे हम हमेशा अपने चर के रूप में उपयोग करते हैं। आप संख्या R0 से R15 और फिर R16 से R31 के बीच की मोटी रेखा देखते हैं? यही कारण है कि हम हमेशा सबसे छोटे के रूप में R16 का उपयोग करते हैं और मैं अगले ट्यूटोरियल में इसके बारे में कुछ और जानूंगा जहां हमें तीन 16-बिट अप्रत्यक्ष पता रजिस्टरों, X, Y, और Z की भी आवश्यकता होगी। अभी इसमें शामिल हों, हालांकि अभी हमें इसकी आवश्यकता नहीं है और हम यहां काफी फंस गए हैं।

डेटाशीट के पेज 11 पर एक पेज वापस फ्लिप करें। आपको ऊपर दाईं ओर SREG रजिस्टर का डायग्राम दिखाई देगा? आप देखते हैं कि उस रजिस्टर के बिट 7 को "I" कहा जाता है। अब पेज के नीचे जाएं और बिट 7 का विवरण पढ़ें…. वाह! यह ग्लोबल इंटरप्ट इनेबल बिट है। उपरोक्त हमारे आरेख में दूसरे निर्णय से गुजरने के लिए हमें यही सेट करने की आवश्यकता है और हमारे कार्यक्रम में टाइमर/काउंटर ओवरफ्लो इंटरप्ट की अनुमति दें। तो हमारे कार्यक्रम की अगली पंक्ति पढ़नी चाहिए:

एसबीआई एसआरईजी, आई

जो SREG रजिस्टर में "I" नामक बिट सेट करता है। हालाँकि, इसके बजाय हमने निर्देश का उपयोग किया है

सेइ

बजाय। यह बिट प्रोग्राम में इतनी बार सेट किया जाता है कि उन्होंने इसे करने का एक आसान तरीका बना दिया।

ठीक! अब हमारे पास ओवरफ्लो इंटरप्ट जाने के लिए तैयार है ताकि जब भी कोई हो तो हमारा "जेएमपी ओवरफ्लो_हैंडलर" निष्पादित हो जाएगा।

इससे पहले कि हम आगे बढ़ें, SREG रजिस्टर (स्टेटस रजिस्टर) पर एक नज़र डालें क्योंकि यह बहुत महत्वपूर्ण है। पढ़ें कि प्रत्येक ध्वज क्या दर्शाता है। विशेष रूप से, हमारे द्वारा उपयोग किए जाने वाले कई निर्देश इन फ़्लैग्स को हर समय सेट और चेक करेंगे। उदाहरण के लिए, बाद में हम "सीपीआई" कमांड का उपयोग करेंगे जिसका अर्थ है "तत्काल तुलना करें"। इस निर्देश के लिए निर्देश सारांश तालिका पर एक नज़र डालें और ध्यान दें कि यह "झंडे" कॉलम में कितने झंडे सेट करता है। ये सभी SREG में फ़्लैग हैं और हमारा कोड इन्हें सेट करेगा और इनकी लगातार जाँच करेगा। आप जल्द ही उदाहरण देखेंगे। अंत में कोड के इस खंड का अंतिम बिट है:

क्लियर टेम्प

बाहर टीसीएनटी0, अस्थायी एसबीआई डीडीआरडी, 4

यहाँ अंतिम पंक्ति बहुत स्पष्ट है। यह पोर्टडी के लिए डेटा डायरेक्शन रजिस्टर का चौथा बिट सेट करता है जिससे पीडी 4 आउटपुट हो जाता है।

पहला चर अस्थायी को शून्य पर सेट करता है और फिर उसे TCNT0 रजिस्टर में कॉपी करता है। TCNT0 हमारा टाइमर/काउंटर0 है। यह इसे शून्य पर सेट करता है। जैसे ही पीसी इस लाइन को निष्पादित करता है, टाइमर 0 शून्य से शुरू होगा और प्रति सेकंड 15625 बार की दर से गिना जाएगा। समस्या यह है: TCNT0 एक "8-बिट" रजिस्टर है, है ना? तो सबसे बड़ी संख्या क्या है जिसे 8-बिट रजिस्टर में रखा जा सकता है? खैर 0b11111111 है। यह संख्या 0xFF है। जो 255 है। तो आप देखिए क्या होता है? टाइमर एक सेकंड में 15625 गुना बढ़ रहा है और हर बार 255 तक पहुंचने पर यह "ओवरफ्लो" हो जाता है और फिर से 0 पर वापस चला जाता है। साथ ही जैसे ही यह शून्य पर वापस जाता है, यह टाइमर ओवरफ्लो इंटरप्ट सिग्नल भेजता है। पीसी को यह मिल जाता है और आप जानते हैं कि यह अब तक क्या करता है? हां। यह प्रोग्राम मेमोरी लोकेशन 0x0020 पर जाता है और वहां मिलने वाले निर्देश को निष्पादित करता है।

महान! अगर आप अभी भी मेरे साथ हैं तो आप एक अथक सुपरहीरो हैं! चलो ऐसे ही चलते रहें…

चरण 6: अतिप्रवाह हैंडलर

तो चलिए मान लेते हैं कि टाइमर/काउंटर0 रजिस्टर अभी-अभी ओवरफ्लो हुआ है। अब हम जानते हैं कि प्रोग्राम एक इंटरप्ट सिग्नल प्राप्त करता है और 0x0020 निष्पादित करता है जो प्रोग्राम काउंटर, पीसी को "ओवरफ्लो_हैंडलर" लेबल पर कूदने के लिए कहता है, निम्नलिखित वह कोड है जिसे हमने उस लेबल के बाद लिखा था:

अतिप्रवाह_हैंडलर:

इंक ओवरफ्लो सीपीआई ओवरफ्लो, 61 ब्रने पीसी + 2 क्लियर ओवरफ्लो रेटी

पहली चीज जो यह करती है वह चर "ओवरफ्लो" (जो सामान्य प्रयोजन के काम करने वाले रजिस्टर R17 के लिए हमारा नाम है) में वृद्धि करता है, फिर यह संख्या 61 के साथ ओवरफ्लो की सामग्री की "तुलना" करता है। जिस तरह से निर्देश सीपीआई काम करता है वह बस घटाता है दो नंबर और यदि परिणाम शून्य है तो यह SREG रजिस्टर में Z ध्वज सेट करता है (मैंने आपको बताया था कि हम इस रजिस्टर को हर समय देखेंगे)। यदि दो संख्याएँ समान हैं, तो Z ध्वज एक 1 होगा, यदि दो संख्याएँ समान नहीं हैं, तो यह 0 होगा।

अगली पंक्ति "ब्रन पीसी + 2" कहती है जिसका अर्थ है "बराबर नहीं तो शाखा"। अनिवार्य रूप से, यह SREG में Z ध्वज की जाँच करता है और यदि यह एक नहीं है (अर्थात दो संख्याएँ समान नहीं हैं, यदि वे समान थीं, तो शून्य ध्वज सेट किया जाएगा) PC शाखाओं को PC+2 पर, जिसका अर्थ है कि यह अगले को छोड़ देता है लाइन और सीधे "रेती" पर जाता है जो इंटरप्ट से वापस आने पर कोड में किसी भी स्थान पर वापस आ जाता है। यदि ब्रने निर्देश को शून्य ध्वज बिट में 1 मिला तो यह शाखा नहीं करेगा और इसके बजाय यह केवल अगली पंक्ति पर जारी रहेगा जो इसे 0 पर रीसेट करने के लिए अतिप्रवाह करेगा।

इन सबका शुद्ध परिणाम क्या है?

वैसे हम देखते हैं कि हर बार टाइमर ओवरफ्लो होने पर यह हैंडलर "ओवरफ्लो" के मान को एक से बढ़ा देता है। तो चर "अतिप्रवाह" अतिप्रवाह की संख्या की गणना कर रहा है जैसे वे होते हैं। जब भी संख्या 61 पर पहुंचती है तो हम इसे शून्य पर रीसेट कर देते हैं।

अब हम दुनिया में ऐसा क्यों करेंगे?

आइए देखते हैं। याद रखें कि हमारे CPU के लिए हमारी घड़ी की गति 16MHz है और हमने TCCR0B का उपयोग करके इसे "पूर्व-निर्धारित" किया है ताकि टाइमर केवल 15625 प्रति सेकंड की दर से गिना जाए? और हर बार जब टाइमर 255 की गिनती तक पहुंचता है तो यह ओवरफ्लो हो जाता है। तो इसका मतलब है कि यह प्रति सेकंड 15625/256 = 61.04 बार ओवरफ्लो करता है। हम अपने चर "ओवरफ्लो" के साथ ओवरफ्लो की संख्या का ट्रैक रख रहे हैं और हम उस संख्या की तुलना 61 से कर रहे हैं। इसलिए हम देखते हैं कि "ओवरफ्लो" हर सेकंड में एक बार 61 के बराबर होगा! तो हमारा हैंडलर हर सेकेंड में एक बार "ओवरफ्लो" को शून्य पर रीसेट कर देगा। इसलिए यदि हम केवल चर "ओवरफ्लो" की निगरानी करते हैं और हर बार शून्य पर रीसेट होने पर ध्यान देते हैं तो हम वास्तविक समय में दूसरे-से-सेकंड की गिनती करेंगे (ध्यान दें कि अगले ट्यूटोरियल में हम दिखाएंगे कि कैसे अधिक सटीक प्राप्त करें मिलीसेकंड में देरी उसी तरह से होती है जैसे कि Arduino "देरी" दिनचर्या काम करता है)।

अब हमने टाइमर ओवरफ्लो इंटरप्ट को "हैंडल" किया है। सुनिश्चित करें कि आप समझते हैं कि यह कैसे काम करता है और फिर अगले चरण पर जाएं जहां हम इस तथ्य का उपयोग करते हैं।

चरण 7: देरी

अब जब हमने देखा है कि हमारा टाइमर ओवरफ्लो इंटरप्ट हैंडलर "ओवरफ्लो_हैंडलर" रूटीन वैरिएबल "ओवरफ्लो" को हर सेकेंड में एक बार शून्य पर सेट कर देगा, हम इस तथ्य का उपयोग "देरी" सबरूटीन डिजाइन करने के लिए कर सकते हैं।

हमारे विलंब के अंतर्गत निम्नलिखित कोड पर एक नज़र डालें: लेबल

विलंब:

clr अतिप्रवाह sec_count: cpi अतिप्रवाह, 30 brne sec_count ret

जब भी हमें अपने कार्यक्रम में देरी की आवश्यकता होगी, हम इस सबरूटीन को कॉल करने जा रहे हैं। जिस तरह से यह काम करता है वह पहले चर "ओवरफ्लो" को शून्य पर सेट करता है। फिर यह "sec_count" लेबल वाले क्षेत्र में प्रवेश करता है और 30 के साथ अतिप्रवाह की तुलना करता है, यदि वे समान नहीं हैं तो यह शाखाएं sec_count लेबल पर वापस जाती हैं और फिर से, और फिर से, आदि की तुलना तब तक करती हैं जब तक कि वे अंत में समान न हों (याद रखें कि पूरे समय यह चल रहा है हमारे टाइमर इंटरप्ट हैंडलर पर वैरिएबल ओवरफ्लो में वृद्धि जारी है और इसलिए हर बार जब हम यहां घूमते हैं तो यह बदल रहा है। जब ओवरफ्लो अंत में 30 के बराबर होता है तो यह लूप से बाहर हो जाता है और जहां भी हम देरी कहते हैं, वहां वापस आ जाता है। शुद्ध परिणाम एक है 1/2 सेकंड की देरी

व्यायाम 2: ओवरफ्लो_हैंडलर रूटीन को निम्न में बदलें:

अतिप्रवाह_हैंडलर:

इंक अतिप्रवाह रेटी

और प्रोग्राम चलाएं। क्या कुछ अलग है? क्यों या क्यों नहीं?

चरण 8: झपकी

अंत में ब्लिंक रूटीन पर नजर डालते हैं:

झपकी:

एसबीआई PORTD, 4 rcall देरी cbi PORTD, 4 rcall देरी rjmp ब्लिंक

पहले हम PD4 चालू करते हैं, फिर हम अपने विलंब सबरूटीन को rcall करते हैं। हम rcall का उपयोग करते हैं ताकि जब PC एक "ret" स्टेटमेंट पर पहुंच जाए तो वह rcall के बाद की लाइन पर वापस आ जाए। फिर, जैसा कि हमने देखा है, अतिप्रवाह चर में ३० गिनती के लिए विलंब दिनचर्या में देरी होती है और यह लगभग १/२ सेकंड है, फिर हम पीडी४ को बंद कर देते हैं, एक और १/२ सेकंड की देरी करते हैं, और फिर शुरुआत में वापस जाते हैं।

शुद्ध परिणाम एक निमिष एलईडी है!

मुझे लगता है कि अब आप सहमत होंगे कि असेंबली भाषा में "ब्लिंक" शायद सबसे अच्छा "हैलो वर्ल्ड" प्रोग्राम नहीं है।

व्यायाम ३: कार्यक्रम में विभिन्न मापदंडों को बदलें ताकि एलईडी अलग-अलग दरों पर झपकाएं जैसे कि एक सेकंड या ४ बार एक सेकंड, आदि। व्यायाम ४: इसे बदलें ताकि एलईडी अलग-अलग समय के लिए चालू और बंद रहे। उदाहरण के लिए १/४ सेकंड के लिए चालू करें और फिर २ सेकंड के लिए बंद करें या ऐसा ही कुछ। व्यायाम ५: TCCR0B घड़ी के चयन बिट्स को १०० में बदलें और फिर तालिका में ऊपर जाना जारी रखें। ट्यूटोरियल 1 से हमारे "hello.asm" प्रोग्राम से यह किस बिंदु पर अप्रभेद्य हो जाता है? व्यायाम 6 (वैकल्पिक): यदि आपके पास एक अलग क्रिस्टल ऑसीलेटर है, जैसे 4 मेगाहर्ट्ज या 13.5 मेगाहर्ट्ज या जो कुछ भी, अपने 16 मेगाहट्र्ज ऑसीलेटर को बदलें नए के लिए अपने ब्रेडबोर्ड पर और देखें कि यह एलईडी की ब्लिंकिंग दर को कैसे प्रभावित करता है। अब आप सटीक गणना के माध्यम से जाने और भविष्यवाणी करने में सक्षम होना चाहिए कि यह दर को कैसे प्रभावित करेगा।

चरण 9: निष्कर्ष

आप में से उन लोगों के लिए जिन्होंने इसे यहां तक पहुंचाया है, बधाई हो!

मुझे एहसास है कि जब आप वायरिंग और प्रयोग करने की तुलना में अधिक पढ़ रहे हैं और देख रहे हैं तो यह बहुत कठिन नारा है, लेकिन मुझे आशा है कि आपने निम्नलिखित महत्वपूर्ण चीजें सीखी हैं:

  1. प्रोग्राम मेमोरी कैसे काम करती है
  2. एसआरएएम कैसे काम करता है
  3. रजिस्टर कैसे देखें
  4. निर्देशों को कैसे देखें और जानें कि वे क्या करते हैं
  5. इंटरप्ट्स को कैसे लागू करें
  6. CP कैसे कोड को निष्पादित करता है, SREG कैसे काम करता है, और इंटरप्ट के दौरान क्या होता है
  7. कोड में लूप और जंप और बाउंस कैसे करें
  8. डेटशीट को पढ़ना कितना जरूरी है!
  9. एक बार जब आप जानते हैं कि Atmega328p माइक्रोकंट्रोलर के लिए यह सब कैसे करना है, तो यह किसी भी नए नियंत्रक को सीखने के लिए एक सापेक्ष केक वॉक होगा जिसमें आप रुचि रखते हैं।
  10. CPU समय को वास्तविक समय में कैसे बदलें और इसे विलंब दिनचर्या में कैसे उपयोग करें।

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

व्यायाम 7: कोड को विभिन्न तरीकों से "तोड़ें" और देखें कि क्या होता है! वैज्ञानिक जिज्ञासा बेबी! कोई और बर्तन सही धो सकता है?व्यायाम 8: सूची फ़ाइल बनाने के लिए "-l" विकल्प का उपयोग करके कोड को इकट्ठा करें। अर्थात। "avra -l blink.lst blink.asm" और सूची फ़ाइल पर एक नज़र डालें। अतिरिक्त क्रेडिट: मैंने शुरुआत में जो टिप्पणी नहीं की थी और टिप्पणी कोड जिसे हम बाद में चर्चा करते हैं, भिन्न होते हैं! कोड की एक पंक्ति अलग है। क्या आप इसे ढूंढ सकते हैं? वह अंतर क्यों मायने नहीं रखता?

आशा हैं आपको मज़ा आया! मिलते हैं अगली बार…

सिफारिश की: