İçindekiler:

AVR Assembler Eğitimi 2: 4 Adım
AVR Assembler Eğitimi 2: 4 Adım

Video: AVR Assembler Eğitimi 2: 4 Adım

Video: AVR Assembler Eğitimi 2: 4 Adım
Video: CHIANG 2 4 2 5 BAŞLANGICI İLK KAYIT 2024, Temmuz
Anonim
AVR Assembler Eğitimi 2
AVR Assembler Eğitimi 2

Bu eğitim, "AVR Assembler Eğitimi 1"in devamı niteliğindedir.

Eğitim 1'den geçmediyseniz, şimdi durmalı ve önce bunu yapmalısınız.

Bu derste, Arduino'larda kullanılan atmega328p'nin montaj dili programlaması çalışmamıza devam edeceğiz.

İhtiyacın olacak:

  1. bir breadboard Arduino veya Eğitim 1'deki gibi sadece normal bir Arduino
  2. bir LED
  3. 220 ohm'luk bir direnç
  4. bir basma düğmesi
  5. devre tahtanızda devre yapmak için bağlantı telleri
  6. Talimat Seti Kılavuzu: www.atmel.com/images/atmel-0856-avr-instruction-s…
  7. Veri sayfası: www.atmel.com/images/Atmel-8271-8-bit-AVR-Microco…

Eğitimlerimin tam koleksiyonu burada bulunabilir:

Adım 1: Devreyi Kurmak

Devreyi Kurmak
Devreyi Kurmak

Öncelikle bu derste inceleyeceğimiz devreyi kurmanız gerekiyor.

İşte bağlanma şekli:

PB0 (dijital pin 8) - LED - R (220 ohm) - 5V

PD0 (dijital pin 0) - buton - GND

LED'inizin doğru yönlendirildiğini PB0 yerine GND'ye bağlayarak kontrol edebilirsiniz. Hiçbir şey olmazsa, yönü tersine çevirin ve ışık yanmalıdır. Ardından PB0'a yeniden bağlayın ve devam edin. Resim, breadboard arduino'mun nasıl bağlandığını gösteriyor.

Adım 2: Montaj Kodunun Yazılması

Montaj Kodunun Yazılması
Montaj Kodunun Yazılması

Aşağıdaki kodu pushbutton.asm adlı bir metin dosyasına yazın ve Öğretici 1'de yaptığınız gibi avra ile derleyin.

Bu kodda çok sayıda yorumumuz olduğuna dikkat edin. Montajcı her noktalı virgül gördüğünde satırın geri kalanını atlayacak ve bir sonraki satıra geçecektir. Gelecekte geri döndüğünüzde ne yaptığınızı bilmeniz için kodunuzu yoğun bir şekilde yorumlamak (özellikle montaj dilinde!) iyi bir programlama uygulamasıdır. İlk birkaç derste oldukça fazla yorum yapacağım, böylece tam olarak ne olduğunu ve nedenini bileceğiz. Daha sonra, montaj kodlamasında biraz daha iyi olduğumuzda, işleri biraz daha az ayrıntılı olarak yorumlayacağım.

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

; yazan: 1o_o7; tarih: 23 Ekim 2014;****************************************

.nolist

.include "m328Pdef.inc".list.def temp = r16; çalışma kaydı r16'yı temp rjmp Init olarak atayın; ilk satır yürütüldü

İçinde:

ser sıcaklığı; tüm bitleri temp olarak 1'lere ayarlayın. DDRB çıkışı, sıcaklık; Veri Yönü G/Ç'de bir bitin 1 olarak ayarlanması; DDRB olan PortB'ye kaydolun; çıkış olarak pin, bir 0 bu pini giriş olarak ayarlar; yani burada, tüm PortB pinleri çıkışlardır (1'e ayarlıdır) ldi temp, 0b11111110; 'acil' numarayı geçici kayıt defterine yükleyin; sadece ld ise ikinci argüman; DDRD, temp yerine bir bellek konumu olması gerekir; mv temp'den DDRD'ye, sonuç şudur ki PD0 girdidir; ve geri kalanı çıktılardır clr temp; temp içindeki tüm bitler 0'a ayarlanır PortB, temp; PortB'deki tüm bitleri (yani pinleri) 0V ldi temp, 0b00000001 olarak ayarlayın; PortD, temp 'yi geçici olarak çıkarmak için hemen numarayı yükleyin; sıcaklığı PortD'ye taşıyın. PD0 bir yukarı çekme direncine sahiptir; (yani 5V'a ayarlı) çünkü o bitte 1 var; geri kalanı 0'lardan beri 0V'dir.

Ana:

sıcaklıkta, PinD; PinD, PortD durumunu tutar, bunu temp'e kopyalayın; düğme PD0'a bağlıysa bu; 0 butona basıldığında, 1 aksi halde; PD0'da bir çekme direnci vardır, normalde 5V çıkış PortB'dedir, sıcaklık; yukarıda okunan 0'ları ve 1'leri PortB'ye gönderir; bu, LED'in PB0'a bağlanmasını istediğimiz anlamına gelir; PD0 DÜŞÜK olduğunda, PB0'ı DÜŞÜK olarak ayarlar ve döner; LED üzerinde (LED'in diğer tarafı 5V'a bağlı olduğundan ve bu PB0'ı 0V'a ayarlayacaktır, böylece akım akacaktır) rjmp Main; Main'in başlangıcına geri döner

Bu sefer kodumuzda sadece daha fazla yoruma sahip olmadığımıza dikkat edin, aynı zamanda kimin yazdığı ve ne zaman yazıldığı hakkında bazı bilgiler veren bir başlık bölümümüz de var. Kodun geri kalanı da bölümlere ayrılmıştır.

Yukarıdaki kodu derledikten sonra mikrodenetleyiciye yükleyip çalıştığını görmelisiniz. Düğmeye basarken LED yanmalı ve bıraktığınızda tekrar sönmelidir. Resimde nasıl göründüğünü gösterdim.

Adım 3: Kodun Satır Satır Analizi

Amaçları aşikar olduğu için sadece yorum olan satırları atlayacağım.

.nolist

.include "m328Pdef.inc".list

Bu üç satır, programlamakta olduğumuz ATmega328P için Register ve Bit tanımlarını içeren dosyayı içerir..nolist komutu, montajcıya bu dosyayı, bir araya getirdiğinizde ürettiği pushbutton.lst dosyasına dahil etmemesini söyler. Listeleme seçeneğini kapatır. Dosyayı ekledikten sonra.list komutu ile listeleme seçeneğini tekrar açıyoruz. Bunu yapmamızın nedeni, m328Pdef.inc dosyasının oldukça uzun olması ve onu gerçekten liste dosyasında görmemize gerek olmamasıdır. Derleyicimiz avra otomatik olarak bir liste dosyası oluşturmaz ve eğer istersek aşağıdaki komutu kullanarak birleştiririz:

avra -l pushbutton.lst pushbutton.asm

Bunu yaparsanız, pushbutton.lst adında bir dosya oluşturacaktır ve bu dosyayı incelerseniz, program kodunuzu ek bilgilerle birlikte gösterdiğini göreceksiniz. Ek bilgilere bakarsanız, satırların bir C: ile başladığını ve ardından kodun belleğe yerleştirildiği yerin onaltılık göreli adresinin geldiğini göreceksiniz. Esasen ilk komutla 000000'de başlar ve sonraki her komutla oradan artar. Bellekteki göreceli yerden sonraki ikinci sütun, komutun onaltılık kodu ve ardından komutun bağımsız değişkeni için onaltılık koddur. Liste dosyalarını gelecekteki eğitimlerde daha ayrıntılı tartışacağız.

.def sıcaklık = r16; çalışma kaydı r16'yı temp olarak atayın

Bu satırda, "temp" değişkenini r16 "çalışma kaydına" eşit olarak tanımlamak için ".def" montajcı yönergesini kullanıyoruz. Kopyalamak istediğimiz numaraları çeşitli portlara ve kayıtlara (doğrudan yazılamaz) saklayan register r16'yı kullanacağız.

Alıştırma 1: Bir ikili sayıyı doğrudan bir bağlantı noktasına veya DDRB gibi özel bir kayda kopyalamaya çalışın ve kodu birleştirmeye çalıştığınızda ne olduğunu görün.

Bir kayıt, bir bayt (8 bit) bilgi içerir. Esasen, genellikle her biri bir "bit" olan ve 1 veya 0 içeren bir SR-Latches koleksiyonudur. Bunu bu seride daha sonra tartışabiliriz (hatta bir tane oluşturabiliriz!). "Çalışan kayıt" nedir ve neden r16'yı seçtiğimizi merak ediyor olabilirsiniz. Çipin içindekilerin bataklığına daldığımızda, gelecekteki bir öğreticide bunu tartışacağız. Şimdilik, kod yazma ve fiziksel donanımı programlama gibi şeylerin nasıl yapıldığını anlamanızı istiyorum. Ardından, bu deneyimden mikrodenetleyicinin hafızasını ve özelliklerini daha kolay anlaşılmasını sağlayacak bir referans çerçevesine sahip olacaksınız. Giriş niteliğindeki ders kitaplarının ve tartışmaların çoğunun bunu tam tersi şekilde yaptığını biliyorum, ancak kullanım kılavuzunu okumadan önce küresel bir bakış açısı elde etmek için bir süre video oyunu oynamanın, önce kılavuzu okumaktan çok daha kolay olduğunu gördüm.

rjmp Başlat; ilk satır yürütüldü

Bu satır, "Init" etiketine "göreceli bir atlamadır" ve bir sonraki komut zaten Init'te olduğundan burada gerçekten gerekli değildir, ancak onu ileride kullanmak üzere ekledik.

İçinde:

ser sıcaklığı; tüm bitleri temp olarak 1'lere ayarlayın.

Init etiketinden sonra bir "set register" komutu çalıştırıyoruz. Bu, "temp" kaydındaki (hatırladığınız r16'dır) tüm 8 biti 1'lere ayarlar. Yani temp şimdi 0b11111111 içeriyor.

DDRB çıkışı, sıcaklık; Veri Yönü G/Ç kaydında bir bitin 1 olarak ayarlanması

; DDRB olan PortB için bu pini çıkış olarak ayarlar; 0, bu pini girdi olarak ayarlar; yani burada, tüm PortB pinleri çıkıştır (1'e ayarlıdır)

DDRB kaydı (PortB için Veri Yönü Kaydı), PortB'deki (yani PB0 ila PB7) hangi pinlerin giriş olarak ve hangilerinin çıkış olarak belirlendiğini söyler. LED'imize bağlı PB0 pinine sahip olduğumuzdan ve geri kalanı hiçbir şeye bağlı olmadığından, tüm bitleri 1'e ayarlayacağız, yani hepsi çıktı.

ldi temp, 0b11111110; 'acil' numarayı geçici kayıt defterine yükleyin

; sadece ld olsaydı o zaman ikinci argüman; bir hafıza yeri olmalı

Bu satır, 0b11111110 ikili numarasını geçici kayıt defterine yükler.

dışarı DDRD, sıcaklık; DDRD'ye mv temp, sonuç, PD0'ın girilmesi ve

; geri kalanı çıktılar

Şimdi PortD için Veri Yönü Kaydı'nı temp'den ayarladık, temp hala 0b11111110 içerdiğinden, PD0'ın bir giriş pini olarak (en sağda bir 0 olduğu için) ve geri kalanı çıkış olarak atandığını görüyoruz. 1'ler bu noktalarda.

clr sıcaklığı; temp'deki tüm bitler 0'lara ayarlanmıştır

çıkış PortB, sıcaklık; PortB'deki tüm bitleri (yani pinleri) 0V olarak ayarlayın

İlk önce, tüm bitleri sıfıra ayarlamak anlamına gelen kayıt sıcaklığını "temizliyoruz". Sonra bunu, tüm bu pinlere 0V ayarlayan PortB kaydına kopyalarız. PortB bitindeki sıfır, işlemcinin bu pimi 0V'da tutacağı, bit üzerinde bir ise bu pimin 5V'a ayarlanmasına neden olacağı anlamına gelir.

Alıştırma 2: PortB'deki tüm pinlerin gerçekten sıfır olup olmadığını kontrol etmek için bir multimetre kullanın. PB1'de garip bir şeyler mi oluyor? Bunun neden olabileceğine dair bir fikriniz var mı? (aşağıdaki Alıştırma 4'e benzer, ardından kodu takip edin…) Alıştırma 3: Yukarıdaki iki satırı kodunuzdan kaldırın. Program hala düzgün çalışıyor mu? Niye ya?

ldi sıcaklığı, 0b00000001; anında numarayı geçici olarak yükle

çıkış PortD, sıcaklık; sıcaklığı PortD'ye taşıyın. PD0 5V'dadır (çekme direncine sahiptir); o bitte 1 olduğu için geri kalanı 0V'dir. Alıştırma 4: Yukarıdaki iki satırı kodunuzdan kaldırın. Program hala düzgün çalışıyor mu? Niye ya? (Bu, yukarıdaki Alıştırma 3'ten farklıdır. Pin çıkış şemasına bakın. PD0 için varsayılan DDRD ayarı nedir? (Veri sayfasının 90. sayfasına bakın)

İlk önce 0b00000001 sayısını temp'e "anında yükleriz". "Acil" kısım orada çünkü yüklenecek sayıyı içeren bir bellek konumuna bir işaretçi yerine doğrudan bir sayıyı temp'e yüklüyoruz. Bu durumda "ldi" yerine "ld" kullanırız. Daha sonra bu numarayı PD0'ı 5V'a ve kalanını 0V'a ayarlayan PortD'ye gönderiyoruz.

Şimdi pinleri giriş veya çıkış olarak belirledik ve başlangıç durumlarını 0V veya 5V (DÜŞÜK veya YÜKSEK) olarak ayarladık ve şimdi programımıza "loop" giriyoruz.

Ana: sıcaklıkta, PinD; PinD, PortD durumunu tutar, bunu geçici olarak kopyalayın

; düğme PD0'a bağlıysa bu; a 0 butona basıldığında, 1 aksi halde; PD0, normalde 5V olan bir çekme direncine sahiptir.

PinD kaydı, PortD pinlerinin mevcut durumunu içerir. Örneğin, PD3'e bir 5V kablo bağladıysanız, bir sonraki saat döngüsünde (mikrodenetleyiciyi 16MHz saat sinyaline bağladığımız için saniyede 16 milyon kez gerçekleşir) PinD3 biti (mevcut PD3 durumundan) 0 yerine 1 olur. Bu satırda pinlerin mevcut durumunu temp'e kopyalarız.

çıkış PortB, sıcaklık; yukarıda okunan 0'ları ve 1'leri PortB'ye gönderir

; bu, LED'in PB0'a bağlanmasını istediğimiz anlamına gelir, yani; PD0 DÜŞÜK olduğunda, PB0'ı DÜŞÜK olarak ayarlayacak ve dönecektir; LED'de (LED'in diğer tarafı bağlı; 5V'a ve bu, akım akması için PB0'ı 0V'a ayarlayacaktır)

Şimdi PinD'deki pinlerin durumunu PortB çıkışına gönderiyoruz. Etkili olarak bu, düğmeye basılmadığı sürece PD0'ın PortD0'a 1 göndereceği anlamına gelir. Bu durumda buton toprağa bağlı olduğu için o pin 0V olacak ve PortB0'a 0 gönderecektir. Şimdi, devre şemasına bakarsanız, PB0'daki 0V, diğer tarafı 5V'de olduğu için LED'in yanacağı anlamına gelir. PB0'a 1 gönderilecek şekilde düğmeye basmıyorsak, bu, PB0'da 5V ve ayrıca LED'in diğer tarafında 5V'a sahip olduğumuz anlamına gelir ve bu nedenle potansiyel bir fark yoktur ve hiçbir akım akmaz ve böylece LED yanmayacaktır (bu durumda bu bir diyot olan bir LED'dir ve bu nedenle akım ne olursa olsun sadece bir yönde akar).

rjmp Ana; Başlat'a geri döner

Bu göreli atlama bizi Ana: etiketimize geri döndürür ve PinD'yi tekrar kontrol ederiz ve bu böyle devam eder. Her 16 milyonda bir, düğmeye basılıp basılmadığını kontrol etmek ve PB0'ı buna göre ayarlamak.

Alıştırma 5: Kodunuzu, LED'iniz PB0 yerine PB3'e bağlı olacak şekilde değiştirin ve çalıştığını görün. Alıştırma 6: LED'inizi 5V yerine GND'ye takın ve kodunuzu buna göre değiştirin.

4. Adım: Sonuç

Bu eğitimde ATmega328p için montaj dilini daha fazla araştırdık ve bir LED'in bir butonla nasıl kontrol edileceğini öğrendik. Özellikle aşağıdaki komutları öğrendik:

ser register, bir kaydın tüm bitlerini 1'lere ayarlar

clr yazmacı, bir kaydın tüm bitlerini 0'lara ayarlar

kayıtta, i/o kaydı, numarayı bir giriş/çıkış kaydından çalışan bir kayıt defterine kopyalar

Sonraki derste ATmega328p'nin yapısını ve içerdiği çeşitli kayıtlar, işlemler ve kaynakları inceleyeceğiz.

Bu eğitimlere devam etmeden önce bekleyeceğim ve ilgi seviyesini göreceğim. Bu mikroişlemci için programların montaj dilinde nasıl kodlanacağını öğrenmekten gerçekten zevk alan birkaç kişi varsa, o zaman devam edeceğim ve daha karmaşık devreler kuracağım ve daha sağlam kodlar kullanacağım.

Önerilen: