Mündəricat:

AVR Assembler Dərsliyi 2: 4 Addım
AVR Assembler Dərsliyi 2: 4 Addım

Video: AVR Assembler Dərsliyi 2: 4 Addım

Video: AVR Assembler Dərsliyi 2: 4 Addım
Video: Контроллер автоматического пуска-останова с часами реального времени DS3231 2024, Iyul
Anonim
AVR Assembler Dərsliyi 2
AVR Assembler Dərsliyi 2

Bu dərs "AVR Assembler Tutorial 1" in davamıdır

Tutorial 1 -dən keçməmisinizsə, indi dayanmalısınız və əvvəlcə bunu etməlisiniz.

Bu dərslikdə Arduino -da istifadə olunan atmega328p -in montaj dili proqramlaşdırma işimizi davam etdirəcəyik.

Sizə lazım olacaq:

  1. bir çörək taxtası Arduino və ya Tutorial 1 -də olduğu kimi adi bir Arduino
  2. bir LED
  3. 220 ohm müqavimət
  4. basma düyməsi
  5. çörək taxtanızda dövrə düzəltmək üçün birləşdirən tellər
  6. İstifadə dəsti təlimatı: www.atmel.com/images/atmel-0856-avr-instruction-s…
  7. Məlumat cədvəli: www.atmel.com/images/Atmel-8271-8-bit-AVR-Microco…

Dərsliklərimin tam kolleksiyasını burada tapa bilərsiniz:

Addım 1: Dövrün qurulması

Dövrə qurulması
Dövrə qurulması

Əvvəlcə bu dərslikdə öyrənəcəyimiz dövrəni qurmalısınız.

Bağlandığı yol budur:

PB0 (rəqəmsal pin 8) - LED - R (220 ohm) - 5V

PD0 (rəqəmsal pin 0) - düymə - GND

LEDinizin PB0 əvəzinə GND -yə qoşularaq düzgün istiqamətləndirildiyini yoxlaya bilərsiniz. Heç bir şey olmazsa, istiqaməti dəyişdirin və işıq yanmalıdır. Sonra onu PB0 -a yenidən bağlayın və davam edin. Şəkil mənim arduino çörək taxtamın necə bağlı olduğunu göstərir.

Addım 2: Məclis Məcəlləsinin yazılması

Məclis Məcəlləsinin yazılması
Məclis Məcəlləsinin yazılması

Aşağıdakı kodu pushbutton.asm adlı bir mətn faylına yazın və Tutorial 1 -də etdiyiniz kimi avra ilə tərtib edin.

Qeyd edək ki, bu kodda çoxlu şərhlərimiz var. Assembler hər dəfə nöqtəli vergül görəndə sətrin qalan hissəsini atlayaraq növbəti sətrə keçəcəkdir. Gələcəkdə ona qayıtdığınız zaman nə etdiyinizi bilmək üçün kodunuzu ağır şəkildə şərh etmək yaxşı proqramlaşdırma təcrübəsidir (xüsusən montaj dilində!). İlk bir neçə dərsdə çox şey şərh edəcəyəm ki, nəyin və niyə baş verdiyini dəqiq bilək. Daha sonra, montaj kodlaşdırma işində bir az daha yaxşı olduqdan sonra hər şeyi bir az daha ətraflı şərh edəcəyəm.

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

; yazan: 1o_o7; tarix: 23 oktyabr 2014; **********************************

.nolist

.include "m328Pdef.inc".list.def temp = r16; r16 iş reyestrini temp rjmp Init olaraq təyin edin; birinci sətir icra olunur

İçində:

ser temperaturu; bütün bitləri 1 -ə təyin edin. DDRB çıxdı, temp; Məlumat İstiqamətində I/O -da bir az 1 olaraq təyin etmək; DDRB olan PortB üçün qeydiyyatdan keçin; pin kimi çıxış, 0 bu girişi giriş olaraq təyin edər; burada bütün PortB pinləri çıxışlardır (1 olaraq təyin olunur) ldi temp, 0b11111110; temp qeydinə "dərhal" nömrəsini yükləyin; yalnız ld olsaydı, ikinci arqument; bir yaddaş yeri yerinə DDRD, temp; mv tempi DDRD üçün, nəticədə PD0 girişdir; və qalanları çıxış tempi; tempdəki bütün bitlər 0 -ın PortB, tempinə təyin olunur; PortB -dəki bütün bitləri (yəni pinləri) 0V ldi temp, 0b00000001 olaraq təyin edin; PortD, tempi sürətləndirmək üçün dərhal nömrəni yükləyin; tempi PortD -ə köçürün. PD0 bir çəkmə müqavimətinə malikdir; (yəni 5V olaraq təyin olunur) o bitdə 1 olduğu üçün; qalanları 0 -dan bəri 0V -dir.

Əsas:

temperaturda, PinD; PinD, PortD vəziyyətini saxlayır, bunu tempə kopyalayın; düymə PD0 -ya bağlıdırsa, bu belə olacaq; Düyməyə basıldığında 0, əks halda 1; PD0 normal olaraq 5V PortB, tempdə olan bir çəkmə müqavimətçisinə malikdir; yuxarıdakı 0 və 1 rəqəmlərini PortB -ə göndərir; LED -in PB0 -a bağlı olmasını istədiyimiz deməkdir; PD0 LOW olduqda, PB0 -u LOW -a çevirir və çevirir; LED -də (LED -in digər tərəfi olduğu üçün; 5V -ə bağlıdır və bu PB0 -ı 0V -ə qoyacaq; cərəyan axacaq) rjmp Main; Main -in başlanğıcına dönür

Diqqət yetirin ki, bu dəfə kodumuzda nəinki daha çox şərh var, həm də kimin yazdığı və nə vaxt yazıldığı haqqında bəzi məlumatlar verən bir başlıq bölməsinə sahibik. Kodun qalan hissəsi də bölmələrə ayrılır.

Yuxarıdakı kodu tərtib etdikdən sonra onu mikro nəzarətçiyə yükləməli və işlədiyini görməlisiniz. Siz düyməni basarkən LED yanmalı və buraxdığınız zaman yenidən sönməlidir. Şəkildə nəyə bənzədiyini göstərmişəm.

Addım 3: Kodun sətir-sətir təhlili

Məqsədləri aydın olduğu üçün sadəcə şərh olan sətirləri atlayacağam.

.nolist

. "m328Pdef.inc".list daxil edin

Bu üç sətrə proqramlaşdırdığımız ATmega328P üçün Qeyd və Bit tərifləri olan fayl daxildir.. Nolist əmri assambleyaya bu faylı yığdığınız zaman istehsal etdiyi pushbutton.lst faylına daxil etməməyi bildirir. Listinq seçimini deaktiv edir. Fayl daxil edildikdən sonra.list əmri ilə siyahı seçimini yenidən açırıq. Bunu etməyimizin səbəbi, m328Pdef.inc faylının olduqca uzun olması və siyahı faylında görməyimizə ehtiyac olmamasıdır. Assemblerimiz avra avtomatik olaraq bir siyahı faylı yaratmır və istəsək aşağıdakı əmrdən istifadə edərək yığarıq:

avra -l düymə.lst düymə.asm

Bunu etsəniz, pushbutton.lst adlı bir fayl yaradacaq və bu faylı araşdırsanız, proqram kodunuzu əlavə məlumatlarla birlikdə göstərdiyini görəcəksiniz. Əlavə məlumatlara baxsanız, xətlərin C: ilə başladığını, sonra kodun yaddaşa yerləşdirildiyi hexdəki nisbi ünvanın olduğunu görəcəksiniz. Əslində ilk komanda ilə 000000 -də başlayır və hər sonrakı əmrlə oradan artır. Yaddaşdakı nisbi yerdən sonra ikinci sütun, əmrin arqumenti üçün onaltılı kodun ardınca əmrin hex kodudur. Gələcək dərslərdə siyahı sənədlərini daha da müzakirə edəcəyik.

.def temp = r16; r16 iş reyestrini temp olaraq təyin edin

Bu sətirdə "temp" dəyişənini r16 "işçi reyestri" nə bərabər təyin etmək üçün ".def" assembler direktivindən istifadə edirik. R16 qeydini müxtəlif limanlara və qeydlərə kopyalamaq istədiyimiz nömrələri saxlayan kimi istifadə edəcəyik (bunları birbaşa yazmaq mümkün deyil).

Məşq 1: İkili bir nömrəni birbaşa DDRB kimi bir limana və ya xüsusi reyestrə kopyalamağa çalışın və kodu yığmağa çalışanda nə baş verdiyini görün.

Bir reyestrdə bir bayt (8 bit) məlumat var. Əsasən, hər biri bir "bit" olan və 1 və ya 0 olan SR-Latchlar toplusudur. Bunu daha sonra bu seriyada müzakirə edə bilərik (və hətta birini qura bilərik!). "İşçi reyestrinin" nə olduğunu və niyə r16 -nı seçdiyimizi maraqlandıra bilərsiniz. Gələcək bir dərsdə, çipin daxili bataqlığına girəndə müzakirə edəcəyik. Hələlik kod yazmaq və fiziki avadanlıq proqramlaşdırmaq kimi şeyləri necə edəcəyinizi başa düşməyinizi istəyirəm. Sonra mikro nəzarətçinin yaddaşını və qeyd xüsusiyyətlərini başa düşməyi asanlaşdıracaq təcrübədən bir istinad çərçivəsinə sahib olacaqsınız. Giriş dərsliklərinin və müzakirələrin əksəriyyətinin bunun əksini etdiyini başa düşürəm, amma təlimat kitabçasını oxumadan əvvəl qlobal bir perspektiv əldə etmək üçün əvvəlcə bir video oyunu oynamağın əvvəlcə təlimatı oxumaqdan daha asan olduğunu gördüm.

rjmp Giriş; birinci sətir icra olunur

Bu xətt "Init" etiketinə "nisbi bir sıçrayışdır" və burada həqiqətən lazım deyil, çünki növbəti əmr artıq Init -dədir, lakin gələcək istifadə üçün daxil edirik.

İçində:

ser temperaturu; bütün bitləri 1 -ə təyin edin.

Init etiketindən sonra "set register" əmrini yerinə yetiririk. Bu, "temp" qeydindəki 8 bitin hamısını (xatırladığınız r16) 1 -ə təyin edir. Beləliklə temp indi 0b11111111 ehtiva edir.

DDRB çıxdı, temp; Data Direction I/O reyestrində bir az 1 olaraq təyin edin

; DDRB olan PortB üçün bu pimi çıxış olaraq təyin edir; 0 bu girişi giriş olaraq təyin edər; burada bütün PortB pinləri çıxışdır (1 olaraq təyin olunur)

DDRB reyestri (PortB üçün Məlumat İstiqamətləndirmə Reyestri), PortB -də hansı pinlərin (yəni PB0 -dan PB7 -yə qədər) giriş olaraq təyin olunduğunu və çıxış olaraq təyin olunduğunu bildirir. PB0 pinimizi LED -ə, qalanını isə heç bir şeyə bağlamadığımız üçün bütün bitləri 1 olaraq təyin edəcəyik ki, bunların hamısı çıxışdır.

ldi temp, 0b11111110; "dərhal" nömrəsini temp qeydinə yükləyin

; yalnız ld olsaydı, ikinci arqument olardı; yaddaş yeri olmalıdır

Bu xətt 0b11111110 ikili nömrəsini müvəqqəti qeydiyyata yükləyir.

DDRD, temp; mv tempi DDRD üçün, nəticədə PD0 giriş və

; qalanları çıxışdır

İndi PortD üçün Məlumat İstiqamət Reyestrini tempdən qururuq, temp hələ də 0b11111110 ehtiva etdiyindən PD0 -nun giriş pin olaraq təyin ediləcəyini görürük (ən sağ nöqtədə 0 olduğu üçün), qalanları isə çıxışlar olaraq təyin olunduğundan O yerlərdə 1 ədəd var.

clr temp; tempdəki bütün bitlər 0 -a təyin olunur

PortB, temp; PortB -dəki bütün bitləri (yəni pinləri) 0V -ə qoyun

Əvvəlcə qeydlərin tempini "təmizləyirik", yəni bütün bitləri sıfıra endiririk. Sonra bunu bütün pinlərdə 0V təyin edən PortB reyestrinə kopyalayırıq. Bir PortB bitindəki sıfır, prosessorun bu pini 0V -də saxlayacağı, bir -birinin ardınca bu pinin 5V -ə qoyulacağı deməkdir.

Məşq 2: PortB üzərindəki bütün pinlərin həqiqətən sıfır olub olmadığını yoxlamaq üçün bir multimetrdən istifadə edin. PB1 ilə qəribə bir şey gedir? Bunun niyə ola biləcəyi barədə hər hansı bir fikir varmı? (Aşağıdakı Təlim 4 -ə bənzər, sonra kodu izləyin …) 3 -cü Məşq: Kodunuzdan yuxarıdakı iki sətri çıxarın. Proqram hələ də düzgün işləyirmi? Niyə?

ldi tempi, 0b00000001; dərhal nömrəni tempə yükləyin

PortD, temp; tempi PortD -ə köçürün. PD0 5V -dir (çəkmə müqavimətinə malikdir); bu bitdə 1 olduğu üçün qalanları 0V -dir. Məşq 4: Kodunuzdan yuxarıdakı iki sətri çıxarın. Proqram hələ də düzgün işləyirmi? Niyə? (Bu, yuxarıdakı Təlim 3 -dən fərqlidir. Çıxma diaqramına baxın. PD0 üçün standart DDRD ayarı nədir? (Məlumat vərəqinin 90 -cı səhifəsinə baxın)

Əvvəlcə tempə 0b00000001 nömrəsini "dərhal yükləyirik". Yüklənəcək nömrəni ehtiva edən bir yaddaş yerinə göstərici deyil, tempə düz bir ədəd yüklədiyimiz üçün "dərhal" hissə var. Bu halda "ldi" yerinə "ld" istifadə edərdik. Sonra bu nömrəni PD0 -nu 5V -a, qalanını isə 0V -ə təyin edən PortD -ə göndəririk.

İndi pinləri giriş və ya çıxış olaraq təyin etdik və ilkin vəziyyətlərini 0V və ya 5V (LOW və ya HIGH) olaraq təyin etdik və buna görə də indi "loop" proqramımıza daxil oluruq.

Əsas: tempdə, PinD; PinD, PortD vəziyyətini saxlayır, bunu tempə kopyalayın

; düymə PD0 -ya bağlıdırsa, bu belə olacaq; a 0 düyməsinə basıldığında, 1 əks halda; PD0, ümumiyyətlə 5V -də olan bir çəkmə rezistoruna malikdir

PinD reyestri PortD pinlərinin cari vəziyyətini ehtiva edir. Məsələn, PD3 -ə 5V tel bağlamısınızsa, sonrakı saat dövrəsində (mikro nəzarətçimizin 16MHz saat siqnalına bağlandığı üçün saniyədə 16 milyon dəfə olur) PinD3 biti (PD3 -ün indiki vəziyyətindən) 0 əvəzinə 1 olacaq. Bu sətirdə sancaqların mövcud vəziyyətini tempə kopyalayırıq.

PortB, temp; yuxarıdakı 0 və 1 rəqəmlərini PortB -ə göndərir

; LED -in PB0 -a bağlı olmasını istədiyimiz deməkdir; PD0 LOW olduqda, PB0 -u LOW -a çevirir və çevirir; LED -də (LED -in digər tərəfi 5V -ə bağlıdır və bu PB0 -dan 0V -ə qədər cərəyan keçir)

İndi PinD'deki sancaqların vəziyyətini PortB çıxışına göndəririk. Effektiv olaraq, bu, düyməyə basılmadığı təqdirdə PD0 -nin PortD0 -a 1 göndərəcəyi deməkdir. Bu halda düymə yerə qoşulduğundan bu pin 0V -də olacaq və PortB0 -a 0 göndərəcək. İndi, dövrə diaqramına baxsanız, PB0 üzərindəki 0V, LEDin digər tərəfi 5V olduğu üçün parlayacağını bildirir. Düyməni basmasaq, PB0 -a 1 göndərilsə, bu, PB0 -da 5V -un, LED -in digər tərəfində də 5V -un olması deməkdir və buna görə də heç bir potensial fərq yoxdur və heç bir cərəyan axmayacaq və s. LED parlamayacaq (bu vəziyyətdə bir diod olan bir LEDdir və buna görə də cərəyan nə olursa olsun yalnız bir istiqamətə axır).

rjmp Əsas; Başlanğıc döngələri

Bu nisbi atlama bizi Ana: etiketimizə qaytarır və PinD -ni yenidən yoxlayırıq və s. Hər 16 milyonda bir saniyədə bir düymənin basıldığını yoxlayır və buna uyğun olaraq PB0 təyin edir.

Məşq 5: Kodunuzu dəyişdirin ki, LEDiniz PB0 əvəzinə PB3 -ə qoşulsun və işlədiyini görün. 6 -cı məşq: LEDinizi 5V yerinə GND -ə qoşun və kodunuzu buna uyğun olaraq dəyişdirin.

Addım 4: Nəticə

Bu təlimatda ATmega328p üçün montaj dilini daha da araşdırdıq və bir LED -in düymə ilə necə idarə olunacağını öyrəndik. Xüsusilə aşağıdakı əmrləri öyrəndik:

ser register, registrin bütün bitlərini 1 -ə təyin edir

clr register, qeydin bütün bitlərini 0 -a təyin edir

reyestrdə i/o reyestri nömrəni giriş qeydindən işçi reyestrinə köçürür

Növbəti dərsdə ATmega328p -in quruluşunu və orada olan müxtəlif qeydləri, əməliyyatları və mənbələri araşdıracağıq.

Bu dərslərə davam etməzdən əvvəl gözləyəcəyəm və maraq səviyyəsini görəcəyəm. Bu mikroprosessorun proqramlarını montaj dilində necə kodlaşdırmağı öyrənməkdən zövq alan bir çox insan varsa, daha mürəkkəb sxemlər qurmağa və daha möhkəm kod istifadə etməyə davam edəcəyəm.

Tövsiyə: