Სარჩევი:

AVR Assembler Tutorial 2: 4 ნაბიჯი
AVR Assembler Tutorial 2: 4 ნაბიჯი

ვიდეო: AVR Assembler Tutorial 2: 4 ნაბიჯი

ვიდეო: AVR Assembler Tutorial 2: 4 ნაბიჯი
ვიდეო: Example of an AVR Assembly Program 2024, ივლისი
Anonim
AVR Assembler Tutorial 2
AVR Assembler Tutorial 2

ეს გაკვეთილი არის გაგრძელება "AVR Assembler Tutorial 1"

თუ თქვენ არ გაგივლიათ მეცადინეობა 1, უნდა შეწყვიტოთ ახლა და გააკეთოთ ეს ჯერ.

ამ სახელმძღვანელოში ჩვენ გავაგრძელებთ არდუინოში გამოყენებულ atmega328p ასამბლეის ენის პროგრამირების შესწავლას.

თქვენ დაგჭირდებათ:

  1. breadboard Arduino ან უბრალოდ ჩვეულებრივი Arduino, როგორც სამეურვეო 1 -ში
  2. LED
  3. 220 ohm რეზისტორი
  4. დააჭირეთ ღილაკს
  5. დამაკავშირებელი მავთულები სქემის შესაქმნელად თქვენს breadboard- ზე
  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 ohm) - 5V

PD0 (ციფრული პინი 0) - ღილაკი - GND

თქვენ შეგიძლიათ შეამოწმოთ, რომ თქვენი LED არის სწორად ორიენტირებული, მას დაუკავშირებთ GND– ს ნაცვლად PB0. თუ არაფერი მოხდება, შეცვალე ორიენტაცია და შუქი უნდა აანთო. შემდეგ ხელახლა შეაერთეთ ის PB0– თან და განაგრძეთ. სურათი გვიჩვენებს, თუ როგორ არის დაკავშირებული ჩემი პურის დაფა არდუინო.

ნაბიჯი 2: ასამბლეის კოდექსის წერა

ასამბლეის კოდექსის წერა
ასამბლეის კოდექსის წერა

ჩაწერეთ შემდეგი კოდი ტექსტურ ფაილში სახელწოდებით pushbutton.asm და შეადგინეთ იგი avra– ით, როგორც ეს გააკეთეთ მეცადინეობაში 1.

გაითვალისწინეთ, რომ ამ კოდში ჩვენ გვაქვს უამრავი კომენტარი. ყოველ ჯერზე, როდესაც ასამბლერი ხედავს მძიმით, ის გამოტოვებს ხაზის დანარჩენ ნაწილს და გადადის შემდეგ ხაზზე. კარგი პროგრამირების პრაქტიკაა (განსაკუთრებით ასამბლეის ენაზე!) თქვენი კოდის მძიმე კომენტარის გაკეთება, რათა მომავალში მას რომ დაუბრუნდებით, იცოდეთ რას აკეთებდით. მე ვაპირებ ბევრი რამის კომენტარს პირველ რამდენიმე გაკვეთილში, რათა ზუსტად ვიცოდეთ რა ხდება და რატომ. მოგვიანებით, როდესაც ჩვენ ცოტათი უკეთესები გავხდებით ასამბლეის კოდირებაში, მე კომენტარს გავაკეთებ ცოტა უფრო დეტალურად.

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

; დაწერილი: 1o_o7; თარიღი: 23 ოქტომბერი, 2014; **********************************

.ნოლისტი

. ჩართეთ "m328Pdef.inc". სია.def temp = r16; დანიშნოს სამუშაო რეესტრი r16 როგორც temp rjmp Init; პირველი ხაზი შესრულებულია

Მასში:

ser temp; დააყენეთ ყველა ბიტი ტემპერატურაზე 1 -ზე. გარეთ DDRB, ტემპერატურა; მონაცემების მიმართულების I/O- ზე ოდნავ დაყენება 1; რეგისტრაცია PortB– ზე, რომელიც არის DDRB, ადგენს ამას; pin როგორც გამომავალი, 0 იქნება მითითებული, რომ pin როგორც input; ასე რომ, აქ, ყველა PortB ქინძისთავები არის შედეგები (მითითებულია 1 -ზე) ldi temp, 0b11111110; ჩატვირთეთ "უშუალო" ნომერი დროებითი რეგისტრატორში; ეს მხოლოდ მეორე არგუმენტი იქნებოდა; უნდა იყოს მეხსიერების ადგილმდებარეობა DDRD, temp; mv ტემპერატურა DDRD– ზე, შედეგი არის ის, რომ PD0 არის შეყვანილი; და დანარჩენი არის შედეგები clr temp; ტემპერატურის ყველა ბიტი დაყენებულია 0 -ზე PortB, temp; დააყენეთ ყველა ბიტი (ანუ ქინძისთავები) PortB– ში 0V ldi ტემპერატურაზე, 0b00000001; ჩატვირთეთ დაუყოვნებელი ნომერი PortD, temp; ტემპერატურის გადატანა PortD– ზე. PD0– ს აქვს გამწევი რეზისტორი; (ანუ 5V- ზე დაყენებული) ვინაიდან მას აქვს 1 იმ ბიტში; დანარჩენი 0 ვ -დან 0 -დან.

მთავარი:

ტემპში, PinD; PinD ფლობს PortD მდგომარეობას, დააკოპირეთ ეს temp; თუ ღილაკი უკავშირდება PD0- ს ეს იქნება; 0 ღილაკზე დაჭერისას, 1 სხვაგვარად მას შემდეგ; PD0– ს აქვს გამწევი რეზისტორი, ის ჩვეულებრივ 5V– ზეა PortB, ტემპერატურა; აგზავნის ზემოთ წაკითხულ 0 -ს და 1 -ს PortB- ს; ეს იმას ნიშნავს, რომ ჩვენ გვინდა LED დაკავშირებული PB0,; როდესაც PD0 არის LOW, ის ადგენს PB0- ს LOW- ს და მობრუნებას; LED- ზე (რადგან LED- ის მეორე მხარე არის; დაკავშირებულია 5V- თან და ეს დააყენებს PB0- ს 0V- მდე; დენი შემოვა) rjmp Main; მარყუჟები უკან დაწყების მთავარი

გაითვალისწინეთ, რომ ამჯერად ჩვენ არა მხოლოდ გვაქვს ბევრი სხვა კომენტარი ჩვენს კოდში, არამედ გვაქვს სათაურის განყოფილება, რომელიც იძლევა გარკვეულ ინფორმაციას იმის შესახებ, თუ ვინ დაწერა და როდის დაიწერა. დანარჩენი კოდი ასევე იყოფა ნაწილებად.

მას შემდეგ რაც შეადგინეთ ზემოთ მოყვანილი კოდი თქვენ უნდა ჩატვირთოთ იგი მიკროკონტროლერზე და ნახოთ რომ მუშაობს. LED უნდა ჩაირთოს ღილაკზე დაჭერისას და შემდეგ ისევ გამორთოთ როცა გაუშვებთ. მე ვაჩვენე როგორ გამოიყურება სურათზე.

ნაბიჯი 3: კოდის ხაზოვანი ანალიზი

მე გამოვტოვებ ხაზებს, რომლებიც მხოლოდ კომენტარია, რადგან მათი მიზანი თავისთავად ცხადია.

.ნოლისტი

. ჩართეთ "m328Pdef.inc". სია

ეს სამი სტრიქონი შეიცავს ფაილს, რომელიც შეიცავს რეგისტრს და Bit განმარტებებს ATmega328P– სთვის, რომელსაც ჩვენ ვაპროგრამებთ.. Nolist ბრძანება ეუბნება შემკრებელს არ შეიტანოს ეს ფაილი pushbutton.lst ფაილში, რომელსაც ის აწარმოებს მისი აწყობისას. ის გამორთავს ჩამონათვალის ვარიანტს. მას შემდეგ, რაც ფაილი ჩავრთეთ, ჩვენ კვლავ ვრთავთ ჩამონათვალის ვარიანტს.list ბრძანებით. ამის მიზეზი ის არის, რომ m328Pdef.inc ფაილი საკმაოდ გრძელია და ჩვენ ნამდვილად არ გვჭირდება მისი ნახვა სიის ფაილში. ჩვენი ასამბლერი, avra, ავტომატურად არ ქმნის სიის ფაილს და თუ ჩვენ გვსურს ერთი, ჩვენ შევიკრიბებით შემდეგი ბრძანების გამოყენებით:

avra -l pushbutton.lst pushbutton.asm

თუ ამას გააკეთებთ, ის შექმნის ფაილს სახელწოდებით pushbutton.lst და თუ შეისწავლით ამ ფაილს აღმოაჩენთ, რომ ის აჩვენებს თქვენი პროგრამის კოდს დამატებით ინფორმაციასთან ერთად. თუ გადახედავთ დამატებით ინფორმაციას დაინახავთ, რომ ხაზები იწყება C– ით: რასაც მოჰყვება ნათესავი მისამართი იმ ექვსკუთხედში, სადაც კოდი განთავსებულია მეხსიერებაში. არსებითად ის იწყება 000000 პირველი ბრძანებით და იზრდება იქიდან ყოველი მომდევნო ბრძანებით. მეორე სვეტი მეხსიერებაში შედარებითი ადგილის შემდეგ არის ბრძანების ექვსკუთხა კოდი, რასაც მოჰყვება ექვსკუთხა კოდი ბრძანების არგუმენტისთვის. ჩვენ განვიხილავთ ფაილების ჩამონათვალს შემდგომ გაკვეთილებში.

.def temp = r16; დანიშნეთ სამუშაო რეესტრი r16 როგორც ტემპერატურა

ამ ხაზში ჩვენ ვიყენებთ ასამბლეის დირექტივას ".def" ცვლადის "temp" განსაზღვრისათვის, როგორც r16 "სამუშაო რეგისტრის ტოლი". ჩვენ გამოვიყენებთ რეგისტრს r16 როგორც ნომერს, რომელიც ინახავს ნომრებს, რომელთა გადაწერაც გვინდა სხვადასხვა პორტებსა და რეგისტრებში (რომელთა პირდაპირ ჩაწერა შეუძლებელია).

სავარჯიშო 1: შეეცადეთ დააკოპიროთ ორობითი ნომერი პირდაპირ პორტში ან სპეციალურ რეგისტრში, როგორიცაა DDRB და ნახეთ რა მოხდება კოდის შეკრების მცდელობისას.

რეესტრი შეიცავს ინფორმაციის ბაიტს (8 ბიტი). არსებითად ეს ჩვეულებრივ არის SR-Latches- ის კრებული, თითოეული არის "ბიტი" და შეიცავს 1 ან 0. ჩვენ შეგვიძლია განვიხილოთ ეს (და კიდევ ავაშენოთ!) მოგვიანებით ამ სერიაში. ალბათ გაინტერესებთ რა არის "სამუშაო რეგისტრი" და რატომ ავირჩიეთ r16. ჩვენ განვიხილავთ ამას მომავალ გაკვეთილზე, როდესაც ჩიპის შიდა ნაწილში ჩავუღრმავდებით. ახლა მინდა გესმოდეთ, თუ როგორ უნდა გავაკეთოთ ისეთი რამ, როგორიცაა კოდის წერა და ფიზიკური აპარატურის პროგრამა. შემდეგ თქვენ გექნებათ მითითების ჩარჩო იმ გამოცდილებიდან, რაც მიკროკონტროლერის მეხსიერებას და რეგისტრაციას გაუადვილებს. მე ვხვდები, რომ შესავალი სახელმძღვანელოებისა და დისკუსიების უმეტესობა ამას პირიქით აკეთებს, მაგრამ აღმოვაჩინე, რომ ვიდეოთამაშის დაკავება გლობალური თვალსაზრისით, სანამ სახელმძღვანელოს კითხულობდე, ბევრად უფრო ადვილია, ვიდრე სახელმძღვანელოს კითხვა.

rjmp ინიტი; პირველი ხაზი შესრულებულია

ეს ხაზი არის "შეფარდებითი ნახტომი" ეტიკეტზე "Init" და აქ ნამდვილად არ არის საჭირო, რადგან შემდეგი ბრძანება უკვე Init- შია, მაგრამ ჩვენ მას მომავალში გამოვიყენებთ.

Მასში:

ser temp; დააყენეთ ყველა ბიტი ტემპერატურაზე 1 -ზე.

Init label- ის შემდეგ ჩვენ ვასრულებთ ბრძანებას "set register". ეს ადგენს ყველა 8 ბიტს რეესტრში "temp" (რომელიც გახსოვთ არის r16) 1 -ზე. ასე რომ, ტემპერატურა ახლა შეიცავს 0b11111111.

გარეთ DDRB, ტემპერატურა; მონაცემების მიმართულების I/O რეგისტრზე ოდნავ დაყენება 1 -ით

; PortB– ისთვის, რომელიც არის DDRB, ადგენს ამ პინს გამომავალს; 0 ადგენს იმ პინს, როგორც შეყვანას; ასე რომ, აქ, ყველა PortB ქინძისთავები არის შედეგები (დაყენებულია 1 -ზე)

რეგისტრი DDRB (მონაცემთა მიმართულების რეესტრი პორტბისთვის) გვეუბნება, თუ რომელი ქინძისთავები პორტბზე (ანუ PB0– დან PB7– მდე) დანიშნულია შეყვანის სახით და რომელია გამომავალი. მას შემდეგ, რაც ჩვენ გვაქვს pin PB0 დაკავშირებული ჩვენს LED- თან და დანარჩენი არაფერთან არის დაკავშირებული, ჩვენ დავაყენებთ ყველა ბიტს 1 -ზე, რაც ნიშნავს რომ ისინი ყველა გამოსავალია.

ldi temp, 0b11111110; ჩატვირთეთ "დაუყოვნებელი" ნომერი დროებითი რეგისტრატორში

; ეს რომ უბრალოდ ld იყოს მაშინ მეორე არგუმენტი იქნებოდა; უნდა იყოს მეხსიერების ადგილი

ეს ხაზი იტვირთება ორობითი ნომერი 0b11111110 ტემპერატურის რეგისტრატორში.

გარეთ DDRD, ტემპერატურა; mv ტემპერატურა DDRD– ზე, შედეგი არის ის, რომ PD0 არის შეყვანა და

; დანარჩენი არის შედეგები

ახლა ჩვენ დავაყენეთ მონაცემთა მიმართულების რეესტრი PortD– სთვის ტემპერატურიდან, ვინაიდან ტემპერატურა კვლავ შეიცავს 0b11111110 ჩვენ ვხედავთ, რომ PD0 დაინიშნება როგორც შეყვანის პინი (ვინაიდან 0 არის უკიდურეს მარჯვენა ადგილას) და დანარჩენი დანიშნულია როგორც შედეგები 1 ის ადგილებია.

clr ტემპერატურა; ტემპერატურის ყველა ბიტი დაყენებულია 0 -ზე

გარეთ PortB, ტემპერატურა; დააყენეთ ყველა ბიტი (ანუ ქინძისთავები) PortB– ში 0V– ზე

პირველ რიგში ჩვენ "ვასუფთავებთ" რეგისტრაციის ტემპერატურას, რაც ნიშნავს ყველა ბიტის ნულამდე დაყენებას. შემდეგ ჩვენ ამას ვაკოპირებთ PortB რეგისტრში, რომელიც ადგენს 0V ყველა იმ ქინძისთავზე. ნული PortB ბიტზე ნიშნავს, რომ პროცესორი შეინარჩუნებს ამ პინს 0V- ზე, ხოლო ერთზე ბიტი გამოიწვევს, რომ ის დაინიშნოს 5V- ზე.

სავარჯიშო 2: გამოიყენეთ მულტიმეტრი იმის შესამოწმებლად, არის თუ არა PortB– ის ყველა ქინძი რეალურად ნული. რაღაც უცნაური ხდება PB1– ით? რაიმე იდეა რატომ შეიძლება იყოს ეს? (სავარჯიშო 4 -ის მსგავსად ქვემოთ, შემდეგ მიჰყევით კოდს …) სავარჯიშო 3: ამოიღეთ ზემოთ მოყვანილი ორი ხაზი თქვენი კოდიდან. პროგრამა კვლავ მუშაობს სწორად? რატომ?

ldi ტემპერატურა, 0b00000001; ჩატვირთეთ დაუყოვნებელი ნომერი ტემპერატურაზე

გარეთ PortD, ტემპერატურა; ტემპერატურის გადატანა PortD– ზე. PD0 არის 5V- ზე (აქვს გამყვანი რეზისტორი); რადგან მას აქვს 1 იმ ბიტში დანარჩენი 0V. სავარჯიშო 4: ამოიღეთ ზემოთ მოყვანილი ორი ხაზი თქვენი კოდიდან. პროგრამა კვლავ მუშაობს სწორად? რატომ? (ეს განსხვავდება სავარჯიშო 3 -ისგან ზემოთ. იხილეთ pin out დიაგრამა. რა არის ნაგულისხმევი DDRD პარამეტრი PD0– სთვის? (იხილეთ მონაცემთა ფურცლის 90 გვერდი

პირველი ჩვენ "დაუყოვნებლივ ჩავტვირთავთ" რიცხვს 0b00000001 ტემპერატურაზე. "უშუალო" ნაწილი არის იქ, რადგან ჩვენ ვტვირთავთ პირდაპირ ნომერს ტემპზე და არა მაჩვენებელს მეხსიერების ადგილას, რომელიც შეიცავს ჩატვირთვის რაოდენობას. ამ შემთხვევაში ჩვენ უბრალოდ გამოვიყენებთ "ld" - ს ვიდრე "ldi" - ს. შემდეგ ჩვენ ვუგზავნით ამ ნომერს PortD– ს, რომელიც ადგენს PD0– ს 5V– ზე და დანარჩენს 0V– ზე.

ახლა ჩვენ დავაყენეთ ქინძისთავები, როგორც შემავალი ან გამომავალი და ჩვენ დავაყენეთ მათი საწყისი მდგომარეობა 0V ან 5V (დაბალი ან მაღალი) და ასე რომ, ჩვენ ახლა შევიყვანთ ჩვენს პროგრამას "მარყუჟში".

მთავარი: ტემპში, PinD; PinD ფლობს PortD– ის მდგომარეობას, დააკოპირეთ ეს ტემპზე

; თუ ღილაკი უკავშირდება PD0- ს, მაშინ ეს იქნება; a 0 ღილაკის დაჭერისას, 1 სხვაგვარად მას შემდეგ; PD0– ს აქვს გამწევი რეზისტორი, ჩვეულებრივ 5V– ზე

რეგისტრი PinD შეიცავს PortD ქინძისთავების ამჟამინდელ მდგომარეობას. მაგალითად, თუ თქვენ დაერთეთ 5V მავთული PD3- ზე, მაშინ მომდევნო საათის ციკლზე (რაც ხდება 16 მილიონჯერ წამში, ვინაიდან ჩვენ გვაქვს მიკროკონტროლი 16 მჰც სიხშირის სიგნალთან მიერთებული) PinD3 ბიტი (PD3– ის ამჟამინდელი მდგომარეობიდან) გახდება 1 ნაცვლად 0. 0. ამ ხაზში ჩვენ ვაკოპირებთ ქინძისთავების ამჟამინდელ მდგომარეობას ტემპში.

გარეთ PortB, temp; აგზავნის ზემოთ წაკითხულ 0 -ს და 1 -ს PortB- ს

; ეს ნიშნავს, რომ ჩვენ გვინდა, რომ LED იყოს დაკავშირებული PB0- ზე, ასე რომ; როდესაც PD0 არის LOW, ის დააყენებს PB0- ს LOW- ს და აქცევს; LED- ზე (LED- ის მეორე მხარე დაკავშირებულია; 5V- მდე და ეს დააყენებს PB0- ს 0V- მდე, რათა მიმდინარე დინებები იყოს)

ახლა ჩვენ PinD– ში ქინძისთავების მდგომარეობას ვუგზავნით PortB გამომავალს. ეფექტურად, ეს ნიშნავს, რომ PD0 გაუგზავნის 1 -ს PortD0- ს, თუ ღილაკს არ დააჭერთ. ამ შემთხვევაში, რადგან ღილაკი მიწასთან არის დაკავშირებული, პინი იქნება 0V- ზე და ის 0 -ს გაუგზავნის PortB0- ს. ახლა, თუ გადახედავთ სქემის დიაგრამას, 0V PB0– ზე ნიშნავს, რომ LED ანათებს, რადგან მისი მეორე მხარე არის 5 ვ. თუ ჩვენ არ ვაჭერთ ღილაკს, ასე რომ 1 იგზავნება PB0– ზე, ეს ნიშნავს რომ ჩვენ გვაქვს 5V PB0– ზე და ასევე 5V LED– ის მეორე მხარეს და, შესაბამისად, არ არსებობს პოტენციური სხვაობა და დენი არ შემოვა და ასე LED არ ანათებს (ამ შემთხვევაში ეს არის LED რომელიც არის დიოდი და ასე რომ დენი მხოლოდ ერთი მიმართულებით მიედინება მიუხედავად იმისა რაც არ უნდა იყოს).

rjmp მთავარი; მარყუჟები უკან დაწყება

ეს ნათესავი ნახტომი გვაბრუნებს ჩვენს მთავარ: ეტიკეტზე და ჩვენ კვლავ ვამოწმებთ PinD- ს და ასე შემდეგ. წამში ყოველ 16 მილიონ მეათედის შემოწმება ხდება თუ არა ღილაკის დაჭერა და შესაბამისად PB0- ის დაყენება.

სავარჯიშო 5: შეცვალეთ თქვენი კოდი ისე, რომ თქვენი LED იყოს დაკავშირებული PB3– ის ნაცვლად PB0 და ნახეთ რომ მუშაობს. სავარჯიშო 6: შეაერთეთ თქვენი LED GND– ში 5V ნაცვლად და შეცვალეთ თქვენი კოდი შესაბამისად.

ნაბიჯი 4: დასკვნა

ამ სახელმძღვანელოში ჩვენ შემდგომ გამოვიკვლიეთ ATmega328p– ის შეკრების ენა და ვისწავლეთ როგორ გავაკონტროლოთ LED ღილაკი. კერძოდ, ჩვენ ვისწავლეთ შემდეგი ბრძანებები:

ser რეგისტრი ადგენს რეესტრის ყველა ბიტს 1 -ზე

clr რეგისტრი ადგენს რეგისტრის ყველა ბიტს 0 -ზე

რეესტრში, i/o რეგისტრაცია აკოპირებს ნომერს i/o რეგისტრიდან სამუშაო რეესტრში

მომდევნო გაკვეთილში ჩვენ განვიხილავთ ATmega328p- ის სტრუქტურას და მასში შემავალ სხვადასხვა რეგისტრებს, ოპერაციებს და რესურსებს.

სანამ გავაგრძელებ ამ გაკვეთილებს, ვაპირებ დაველოდო და ვნახო ინტერესის დონე. თუკი ბევრი ადამიანი სიამოვნებით სწავლობს ამ მიკროპროცესორის პროგრამების კოდის შეკრების ენაზე, მაშინ მე გავაგრძელებ და ავაშენებ უფრო რთულ სქემებს და გამოვიყენებ უფრო მძლავრ კოდს.

გირჩევთ: