विषयसूची:

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

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

वीडियो: एवीआर असेंबलर ट्यूटोरियल 2: 4 कदम
वीडियो: Лекция 4. Архитектура AVR. Ассемблер 2024, नवंबर
Anonim
एवीआर असेंबलर ट्यूटोरियल 2
एवीआर असेंबलर ट्यूटोरियल 2

यह ट्यूटोरियल "एवीआर असेंबलर ट्यूटोरियल 1" की निरंतरता है

यदि आपने ट्यूटोरियल 1 नहीं पढ़ा है तो आपको अभी रुक जाना चाहिए और पहले उसे करना चाहिए।

इस ट्यूटोरियल में हम Arduino's में प्रयुक्त atmega328p की असेंबली भाषा प्रोग्रामिंग के अपने अध्ययन को जारी रखेंगे।

आपको चाहिये होगा:

  1. एक ब्रेडबोर्ड Arduino या सिर्फ एक सामान्य Arduino जैसा कि ट्यूटोरियल 1. में है
  2. एक एलईडी
  3. एक 220 ओम अवरोधक
  4. एक पुश बटन
  5. अपने ब्रेडबोर्ड पर सर्किट बनाने के लिए तारों को जोड़ना
  6. निर्देश सेट मैनुअल: www.atmel.com/images/atmel-0856-avr-instruction-s…
  7. डेटाशीट: www.atmel.com/images/Atmel-8271-8-bit-AVR-Microco…

मेरे ट्यूटोरियल का पूरा संग्रह यहां पाया जा सकता है:

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

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

सबसे पहले आपको उस परिपथ का निर्माण करना होगा जिसका अध्ययन हम इस ट्यूटोरियल में करेंगे।

यहाँ जिस तरह से यह जुड़ा हुआ है:

PB0 (डिजिटल पिन 8) - LED - R (220 ओम) - 5V

PD0 (डिजिटल पिन 0) - पुशबटन - GND

आप जांच सकते हैं कि आपका एलईडी PB0 के बजाय GND से कनेक्ट करके ठीक से उन्मुख है। अगर कुछ नहीं होता है तो ओरिएंटेशन को उल्टा कर दें और लाइट आनी चाहिए। फिर इसे PB0 से फिर से कनेक्ट करें और जारी रखें। चित्र दिखाता है कि मेरा ब्रेडबोर्ड arduino कैसे जुड़ा है।

चरण 2: असेंबली कोड लिखना

असेंबली कोड लिखना
असेंबली कोड लिखना

निम्नलिखित कोड को pushbutton.asm नामक टेक्स्ट फ़ाइल में लिखें और इसे avra के साथ संकलित करें जैसा आपने ट्यूटोरियल 1 में किया था।

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

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

; द्वारा लिखित: 1o_o7; दिनांक: अक्टूबर २३, २०१४;**********************

नोलिस्ट

.include "m328Pdef.inc".list.def temp = r16; कार्य रजिस्टर r16 को अस्थायी rjmp Init के रूप में नामित करें; पहली पंक्ति निष्पादित

में इस:

सेर अस्थायी; सभी बिट्स को अस्थायी रूप से 1 पर सेट करें। डीडीआरबी, अस्थायी; डेटा दिशा I/O पर 1 के रूप में थोड़ा सा सेट करना; पोर्टबी के लिए रजिस्टर करें, जो कि डीडीआरबी है, वह सेट करता है; आउटपुट के रूप में पिन करें, 0 उस पिन को इनपुट के रूप में सेट करेगा; तो यहां, सभी पोर्टबी पिन आउटपुट हैं (1 पर सेट करें) एलडीआई अस्थायी, 0b11111110; अस्थायी रजिस्टर में 'तत्काल' संख्या लोड करें; अगर यह सिर्फ एलडी थे तो दूसरा तर्क; डीडीआरडी, अस्थायी के बजाय स्मृति स्थान होना चाहिए; डीडीआरडी के लिए एमवी अस्थायी, परिणाम यह है कि पीडी0 इनपुट है; और बाकी आउटपुट clr temp हैं; अस्थायी में सभी बिट्स 0 के पोर्टबी, अस्थायी पर सेट हैं; पोर्टबी में सभी बिट्स (यानी पिन) को 0V ldi temp, 0b00000001 पर सेट करें; पोर्टडी, अस्थायी को अस्थायी करने के लिए तत्काल संख्या लोड करें; अस्थायी को पोर्टडी में ले जाएं। PD0 में एक पुल अप रेसिस्टर है; (अर्थात 5V पर सेट) क्योंकि उस बिट में 1 है; शेष 0 के बाद से 0V हैं।

मुख्य:

अस्थायी में, पिनडी; पिनडी पोर्टडी की स्थिति रखता है, इसे अस्थायी रूप से कॉपी करें; यदि बटन PD0 से जुड़ा है तो यह होगा; 0 जब बटन दबाया जाता है, 1 अन्यथा तब से; PD0 में एक पुल अप रेसिस्टर होता है जो सामान्य रूप से पोर्टबी, अस्थायी 5V पर होता है; 0 और 1 के ऊपर पढ़े गए पोर्टबी को भेजता है; इसका मतलब है कि हम चाहते हैं कि एलईडी PB0 से जुड़ा हो; जब PD0 कम होता है, तो यह PB0 को LOW पर सेट करता है और मुड़ता है; एलईडी पर (चूंकि एलईडी की दूसरी तरफ है; 5V से जुड़ा है और यह PB0 से 0V तक सेट हो जाएगा; करंट प्रवाहित होगा) rjmp Main; Main. की शुरुआत में वापस लूप

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

उपरोक्त कोड संकलित करने के बाद आपको इसे माइक्रोकंट्रोलर पर लोड करना चाहिए और देखना चाहिए कि यह काम करता है। जब आप बटन दबा रहे हों तो एलईडी चालू होनी चाहिए और जब आप जाने दें तो फिर से बंद कर दें। मैंने दिखाया है कि यह तस्वीर में कैसा दिखता है।

चरण 3: कोड का लाइन-बाय-लाइन विश्लेषण

मैं उन पंक्तियों को छोड़ दूंगा जो केवल टिप्पणियां हैं क्योंकि उनका उद्देश्य स्वयं स्पष्ट है।

नोलिस्ट

.include "m328Pdef.inc".list

इन तीन पंक्तियों में ATmega328P के लिए रजिस्टर और बिट परिभाषाओं वाली फ़ाइल शामिल है जिसे हम प्रोग्रामिंग कर रहे हैं।.nolist कमांड असेंबलर से कहता है कि वह इस फाइल को pushbutton.lst फाइल में शामिल न करे, जो आपके द्वारा इसे असेंबल करने पर उत्पन्न होती है। यह लिस्टिंग विकल्प को बंद कर देता है। फ़ाइल को शामिल करने के बाद हम.list कमांड के साथ लिस्टिंग विकल्प को वापस चालू करते हैं। हम ऐसा इसलिए करते हैं क्योंकि m328Pdef.inc फ़ाइल काफी लंबी है और हमें वास्तव में इसे सूची फ़ाइल में देखने की आवश्यकता नहीं है। हमारा असेंबलर, अवरा, स्वचालित रूप से एक सूची फ़ाइल उत्पन्न नहीं करता है और यदि हम एक चाहते हैं तो हम निम्नलिखित कमांड का उपयोग करके इकट्ठा करेंगे:

अवरा-एल पुशबटन.एलएसटी पुशबटन.एएसएम

यदि आप ऐसा करते हैं तो यह pushbutton.lst नामक एक फ़ाइल उत्पन्न करेगा और यदि आप इस फ़ाइल की जांच करते हैं तो आप पाएंगे कि यह अतिरिक्त जानकारी के साथ आपका प्रोग्राम कोड दिखाता है। यदि आप अतिरिक्त जानकारी को देखते हैं तो आप देखेंगे कि लाइनें सी से शुरू होती हैं: उसके बाद हेक्स में सापेक्ष पता जहां कोड स्मृति में रखा जाता है। अनिवार्य रूप से यह पहले कमांड के साथ 000000 से शुरू होता है और प्रत्येक बाद के कमांड के साथ वहां से बढ़ता है। मेमोरी में सापेक्ष स्थान के बाद दूसरा कॉलम कमांड के लिए हेक्स कोड है और उसके बाद कमांड के तर्क के लिए हेक्स कोड है। हम भविष्य के ट्यूटोरियल में सूची फाइलों पर आगे चर्चा करेंगे।

.def अस्थायी = r16; कार्य रजिस्टर r16 को अस्थायी के रूप में नामित करें

इस पंक्ति में हम कोडांतरक निर्देश ".def" का उपयोग चर "temp" को r16 "वर्किंग रजिस्टर" के बराबर परिभाषित करने के लिए करते हैं। हम रजिस्टर r16 का उपयोग करेंगे, जो उन नंबरों को संग्रहीत करता है जिन्हें हम विभिन्न बंदरगाहों और रजिस्टरों में कॉपी करना चाहते हैं (जिन्हें सीधे नहीं लिखा जा सकता है)।

अभ्यास 1: बाइनरी नंबर को सीधे पोर्ट या डीडीआरबी जैसे विशेष रजिस्टर में कॉपी करने का प्रयास करें और देखें कि जब आप कोड को इकट्ठा करने का प्रयास करते हैं तो क्या होता है।

एक रजिस्टर में एक बाइट (8 बिट) सूचना होती है। अनिवार्य रूप से यह आमतौर पर SR-Latches का एक संग्रह होता है, प्रत्येक एक "बिट" होता है और इसमें 1 या 0 होता है। हम इस श्रृंखला में बाद में इस पर चर्चा कर सकते हैं (और एक भी बना सकते हैं!)। आप सोच रहे होंगे कि "वर्किंग रजिस्टर" क्या है और हमने r16 को क्यों चुना। हम भविष्य के ट्यूटोरियल में इस पर चर्चा करेंगे जब हम चिप के इंटर्नल के दलदल में उतरेंगे। अभी के लिए मैं चाहता हूं कि आप समझें कि कोड कैसे लिखें और भौतिक हार्डवेयर प्रोग्राम करें। फिर आपके पास उस अनुभव से संदर्भ का एक फ्रेम होगा जो माइक्रोकंट्रोलर की मेमोरी और रजिस्टर गुणों को समझने में आसान बना देगा। मुझे एहसास है कि अधिकांश परिचयात्मक पाठ्यपुस्तकें और चर्चाएं इसे दूसरे तरीके से करती हैं, लेकिन मैंने पाया है कि निर्देश पुस्तिका पढ़ने से पहले वैश्विक परिप्रेक्ष्य प्राप्त करने के लिए कुछ समय के लिए वीडियो गेम खेलना पहले मैनुअल पढ़ने की तुलना में बहुत आसान है।

आरजेएमपी इनिट; पहली पंक्ति निष्पादित

यह पंक्ति "इनिट" लेबल के लिए एक "सापेक्ष छलांग" है और यहां वास्तव में आवश्यक नहीं है क्योंकि अगली कमांड पहले से ही इनिट में है लेकिन हम इसे भविष्य के उपयोग के लिए शामिल करते हैं।

में इस:

सेर अस्थायी; सभी बिट्स को अस्थायी रूप से 1 पर सेट करें।

इनिट लेबल के बाद हम "सेट रजिस्टर" कमांड निष्पादित करते हैं। यह "अस्थायी" (जो आपको याद है r16 है) रजिस्टर में सभी 8 बिट्स को 1 पर सेट करता है। तो अस्थायी में अब 0b11111111 है।

डीडीआरबी, अस्थायी; डेटा दिशा I/O रजिस्टर पर 1 के रूप में थोड़ा सा सेट करना

; पोर्टबी के लिए, जो डीडीआरबी है, उस पिन को आउटपुट के रूप में सेट करता है; a 0 उस पिन को इनपुट के रूप में सेट करेगा; तो यहां, सभी पोर्टबी पिन आउटपुट हैं (1 पर सेट करें)

रजिस्टर डीडीआरबी (पोर्टबी के लिए डेटा डायरेक्शन रजिस्टर) बताता है कि पोर्टबी (यानी पीबी0 से पीबी7) पर कौन से पिन इनपुट के रूप में नामित हैं और कौन से आउटपुट के रूप में नामित हैं। चूँकि हमारे पास पिन PB0 हमारे LED से जुड़ा है और बाकी किसी भी चीज़ से नहीं जुड़ा है, इसलिए हम सभी बिट्स को 1 पर सेट कर देंगे, जिसका अर्थ है कि वे सभी आउटपुट हैं।

एलडीआई अस्थायी, 0b11111110; अस्थायी रजिस्टर में 'तत्काल' संख्या लोड करें

; अगर यह सिर्फ एलडी होता तो दूसरा तर्क होता; एक स्मृति स्थान होना चाहिए

यह लाइन बाइनरी नंबर 0b11111110 को अस्थायी रजिस्टर में लोड करती है।

डीडीआरडी, अस्थायी; डीडीआरडी के लिए एमवी अस्थायी, परिणाम यह है कि पीडी0 इनपुट है और

; बाकी आउटपुट हैं

अब हम अस्थायी से पोर्टडी के लिए डेटा डायरेक्शन रजिस्टर सेट करते हैं, क्योंकि अस्थायी में अभी भी 0b11111110 है, हम देखते हैं कि PD0 को एक इनपुट पिन के रूप में नामित किया जाएगा (चूंकि सबसे सही जगह पर 0 है) और बाकी को आउटपुट के रूप में नामित किया गया है क्योंकि वहाँ हैं 1 उन स्थानों में है।

क्लियर अस्थायी; अस्थायी में सभी बिट 0's. पर सेट हैं

पोर्टबी, अस्थायी; पोर्टबी में सभी बिट्स (यानी पिन) को 0V. पर सेट करें

पहले हम रजिस्टर अस्थायी को "साफ़" करते हैं जिसका अर्थ है कि सभी बिट्स को शून्य पर सेट करना। फिर हम उसे पोर्टबी रजिस्टर में कॉपी करते हैं जो उन सभी पिनों पर 0V सेट करता है। पोर्टबी बिट पर शून्य का मतलब है कि प्रोसेसर उस पिन को 0V पर रखेगा, एक बिट पर उस पिन को 5V पर सेट करने का कारण होगा।

अभ्यास 2: एक मल्टीमीटर का उपयोग यह जांचने के लिए करें कि पोर्टबी पर सभी पिन वास्तव में शून्य हैं या नहीं। क्या PB1 के साथ कुछ अजीब हो रहा है? कोई विचार ऐसा क्यों हो सकता है? (नीचे दिए गए व्यायाम ४ के समान, फिर कोड का पालन करें…)व्यायाम ३: अपने कोड से उपरोक्त दो पंक्तियों को हटा दें। क्या कार्यक्रम अभी भी सही ढंग से चलता है? क्यों?

एलडीआई अस्थायी, 0b00000001; अस्थायी पर तत्काल संख्या लोड करें

पोर्टडी, अस्थायी; अस्थायी को पोर्टडी में ले जाएं। PD0 5V पर है (एक पुलअप रोकनेवाला है); चूँकि इसमें उस बिट में 1 है, शेष 0V हैं। अभ्यास 4: अपने कोड से उपरोक्त दो पंक्तियों को हटा दें। क्या कार्यक्रम अभी भी सही ढंग से चलता है? क्यों? (यह ऊपर दिए गए अभ्यास 3 से भिन्न है। पिन आउट आरेख देखें। PD0 के लिए डिफ़ॉल्ट DDRD सेटिंग क्या है? (डेटा शीट का पृष्ठ 90 देखें)

पहले हम संख्या 0b00000001 को "तत्काल लोड" करते हैं। "तत्काल" भाग वहां है क्योंकि हम लोड करने के लिए संख्या वाले स्मृति स्थान पर पॉइंटर की बजाय सीधे ऊपर की संख्या को अस्थायी रूप से लोड कर रहे हैं। उस स्थिति में हम केवल "ld" के बजाय "ld" का उपयोग करेंगे। फिर हम इस नंबर को पोर्टडी को भेजते हैं जो पीडी0 को 5वी और बाकी को 0वी पर सेट करता है।

अब हमने पिन को इनपुट या आउटपुट के रूप में सेट कर दिया है और हमने उनकी प्रारंभिक अवस्थाओं को 0V या 5V (LOW या HIGH) के रूप में सेट कर दिया है और इसलिए अब हम अपने प्रोग्राम "लूप" में प्रवेश करते हैं।

मुख्य: अस्थायी में, पिनडी; पिनडी पोर्टडी की स्थिति रखता है, इसे अस्थायी पर कॉपी करें

; यदि बटन PD0 से जुड़ा है तो यह होगा; a 0 जब बटन को धक्का दिया जाता है, 1 अन्यथा तब से; PD0 में एक पुल अप रेसिस्टर होता है जो सामान्य रूप से 5V. पर होता है

रजिस्टर पिनडी में पोर्टडी पिन की वर्तमान स्थिति होती है। उदाहरण के लिए, यदि आपने 5V तार को PD3 से जोड़ा है, तो अगले घड़ी चक्र में (जो प्रति सेकंड 16 मिलियन बार होता है क्योंकि हमारे पास माइक्रोकंट्रोलर 16MHz क्लॉक सिग्नल से जुड़ा हुआ है) PinD3 बिट (PD3 की वर्तमान स्थिति से) 0 के बजाय 1 बन जाएगा। इसलिए इस लाइन में हम पिन की वर्तमान स्थिति को अस्थायी रूप से कॉपी करते हैं।

पोर्टबी, अस्थायी; 0 और 1 के ऊपर पढ़े गए पोर्टबी को भेजता है

; इसका मतलब है कि हम चाहते हैं कि एलईडी PB0 से जुड़ा हो, इसलिए; जब PD0 कम होता है, तो यह PB0 को LOW पर सेट कर देगा और मुड़ जाएगा; एलईडी पर (एलईडी का दूसरा पक्ष जुड़ा हुआ है; 5V से और यह PB0 से 0V को सेट करेगा ताकि करंट प्रवाहित हो)

अब हम पिन की स्थिति को पिनडी में पोर्टबी आउटपुट में भेजते हैं। प्रभावी रूप से, इसका मतलब है कि PD0 पोर्टडी0 को 1 भेजेगा जब तक कि बटन दबाया न जाए। उस स्थिति में चूंकि बटन जमीन से जुड़ा है इसलिए पिन 0V पर होगा और यह 0 को PortB0 पर भेजेगा। अब, यदि आप सर्किट आरेख को देखते हैं, तो PB0 पर 0V का अर्थ है कि LED चमकेगी क्योंकि इसका दूसरा भाग 5V पर है। यदि हम बटन नहीं दबा रहे हैं, जिससे कि 1 को PB0 पर भेजा जाता है, तो इसका मतलब है कि हमारे पास PB0 पर 5V है और LED के दूसरी तरफ भी 5V है और इसलिए कोई संभावित अंतर नहीं है और कोई करंट प्रवाहित नहीं होगा और इसलिए एलईडी नहीं चमकेगी (इस मामले में यह एक एलईडी है जो एक डायोड है और इसलिए करंट केवल एक दिशा की परवाह किए बिना प्रवाहित होता है लेकिन जो भी हो)।

आरजेएमपी मुख्य; प्रारंभ करने के लिए वापस लूप

यह सापेक्ष छलांग हमें हमारे मुख्य: लेबल पर वापस ले जाती है और हम पिनडी को फिर से जांचते हैं और इसी तरह। एक सेकंड के हर 16 मिलियनवें हिस्से की जाँच करना कि क्या बटन को धक्का दिया जा रहा है और उसके अनुसार PB0 सेट कर रहा है।

व्यायाम 5: अपने कोड को संशोधित करें ताकि आपका एलईडी PB0 के बजाय PB3 से जुड़ा हो और देखें कि यह काम करता है। व्यायाम 6: अपने एलईडी को 5V के बजाय GND में प्लग करें और तदनुसार अपना कोड संशोधित करें।

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

इस ट्यूटोरियल में हमने ATmega328p के लिए असेंबली भाषा की और जांच की है और सीखा है कि पुशबटन के साथ एलईडी को कैसे नियंत्रित किया जाए। विशेष रूप से हमने निम्नलिखित कमांड सीखे:

सेर रजिस्टर रजिस्टर के सभी बिट्स को 1's. पर सेट करता है

clr रजिस्टर रजिस्टर के सभी बिट्स को 0's. पर सेट करता है

रजिस्टर में, i/o रजिस्टर एक i/o रजिस्टर से एक कार्यशील रजिस्टर में नंबर कॉपी करता है

अगले ट्यूटोरियल में हम ATmega328p की संरचना और उसमें निहित विभिन्न रजिस्टरों, संचालनों और संसाधनों की जांच करेंगे।

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

सिफारिश की: