Daftar Isi:
- Langkah 1: Membangun Sirkuit
- Langkah 2: Mengapa Kita Membutuhkan Komentar dan File M328Pdef.inc?
- Langkah 3: Blink.asm
- Langkah 4:.org Assembler Directive
- Langkah 5: Timer/Penghitung 0
- Langkah 6: Overflow Handler
- Langkah 7: Tunda
- Langkah 8: Berkedip
- Langkah 9: Kesimpulan
Video: Tutorial Perakitan AVR 3: 9 Langkah
2024 Pengarang: John Day | [email protected]. Terakhir diubah: 2024-01-30 09:53
Selamat datang di tutorial nomor 3!
Sebelum kita mulai, saya ingin membuat poin filosofis. Jangan takut untuk bereksperimen dengan sirkuit dan kode yang kita buat dalam tutorial ini. Ganti kabel, tambahkan komponen baru, keluarkan komponen, ubah baris kode, tambahkan baris baru, hapus baris, dan lihat apa yang terjadi! Sangat sulit untuk memecahkan apa pun dan jika Anda melakukannya, siapa yang peduli? Tidak ada yang kami gunakan, termasuk mikrokontroler, yang sangat mahal dan selalu mendidik untuk melihat bagaimana sesuatu bisa gagal. Anda tidak hanya akan mengetahui apa yang tidak boleh dilakukan lain kali, tetapi yang lebih penting, Anda akan tahu mengapa tidak melakukannya. Jika Anda seperti saya, ketika Anda masih kecil dan Anda mendapatkan mainan baru, tidak lama kemudian Anda memilikinya untuk melihat apa yang membuatnya berdetak, kan? Terkadang mainan itu berakhir dengan kerusakan yang tidak dapat diperbaiki tetapi bukan masalah besar. Membiarkan seorang anak mengeksplorasi keingintahuannya bahkan sampai mainan rusak adalah apa yang mengubahnya menjadi ilmuwan atau insinyur alih-alih pencuci piring.
Hari ini kita akan memasang rangkaian yang sangat sederhana dan kemudian sedikit membahas teorinya. Maaf tentang ini, tetapi kami membutuhkan alatnya! Saya berjanji kita akan menebusnya dalam tutorial 4 di mana kita akan melakukan beberapa pembangunan sirkuit yang lebih serius dan hasilnya akan sangat keren. Namun, cara yang Anda perlukan untuk melakukan semua tutorial ini adalah dengan cara yang sangat lambat dan kontemplatif. Jika Anda hanya membajak, membangun sirkuit, menyalin dan menempelkan kode, dan menjalankannya, tentu saja, itu akan berhasil, tetapi Anda tidak akan belajar apa pun. Anda perlu memikirkan setiap baris. Berhenti sebentar. Percobaan. Menciptakan. Jika Anda melakukannya dengan cara itu, maka pada akhir tutorial ke-5 Anda akan dapat membuat hal-hal keren dan tidak perlu lagi les. Jika tidak, Anda hanya menonton daripada belajar dan mencipta.
Bagaimanapun, filosofi yang cukup, mari kita mulai!
Dalam tutorial ini Anda akan membutuhkan:
- papan prototipe Anda
- sebuah LED
- menghubungkan kabel
- resistor sekitar 220 hingga 330 ohm
- Manual Set Instruksi: www.atmel.com/images/atmel-0856-avr-instruction-se…
- Lembar Data: www.atmel.com/images/Atmel-8271-8-bit-AVR-Microco…
- osilator kristal yang berbeda (opsional)
Berikut ini tautan ke kumpulan tutorial lengkap:
Langkah 1: Membangun Sirkuit
Rangkaian dalam tutorial ini sangat sederhana. Kami pada dasarnya akan menulis program "berkedip" sehingga yang kami butuhkan hanyalah sebagai berikut.
Hubungkan LED ke PD4, lalu ke resistor 330 ohm, lalu ke Ground. yaitu
PD4 - LED - R(330) - GND
dan itu dia!
Teorinya akan sangat sulit…
Langkah 2: Mengapa Kita Membutuhkan Komentar dan File M328Pdef.inc?
Saya pikir kita harus mulai dengan menunjukkan mengapa file sertakan dan komentar sangat membantu. Tak satu pun dari mereka yang benar-benar diperlukan dan Anda dapat menulis, merakit, dan mengunggah kode dengan cara yang sama tanpa mereka dan itu akan berjalan dengan sangat baik (walaupun tanpa file yang disertakan Anda mungkin mendapatkan beberapa keluhan dari assembler -- tetapi tidak ada kesalahan)
Berikut adalah kode yang akan kita tulis hari ini, kecuali bahwa saya telah menghapus komentar dan file include:
.perangkat ATmega328P
.org 0x0000 jmp a.org 0x0020 jmp ea: ldi r16, 0x05 keluar 0x25, r16 ldi r16, 0x01 sts 0x6e, r16 sei clr r16 keluar 0x26, r16 sbi 0x0a, 0x04 sbi 004x b0b, 0x 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 reti
cukup sederhana bukan? Ha ha. Jika Anda merakit dan mengunggah file ini, Anda akan menyebabkan LED berkedip dengan kecepatan 1 kedipan per detik dengan kedipan berlangsung 1/2 detik dan jeda antar kedipan berlangsung selama 1/2 detik.
Namun, melihat kode ini hampir tidak mencerahkan. Jika Anda menulis kode seperti ini, Anda dan ingin mengubahnya atau menggunakannya kembali di masa mendatang, Anda akan mengalami kesulitan.
Jadi mari masukkan komentar dan sertakan file kembali sehingga kita bisa memahaminya.
Langkah 3: Blink.asm
Berikut adalah kode yang akan kita bahas hari ini:
;************************************
; ditulis oleh: 1o_o7; tanggal:; versi: 1.0; file disimpan sebagai: blink.asm; untuk AVR: atmega328p; frekuensi jam: 16MHz (opsional);************************************; Fungsi program:---------------------; menghitung detik dengan mengedipkan LED;; PD4 - LED - R (330 ohm) - GND;;--------------------------------------.nolist.include "./m328Pdef.inc".daftar;==============; Deklarasi:.def temp = r16.def overflows = r17.org 0x0000; memori (PC) lokasi reset handler rjmp Reset; jmp biaya 2 siklus cpu dan biaya rjmp hanya 1; jadi kecuali Anda perlu melompat lebih dari 8k byte; Anda hanya perlu rjmp. Beberapa mikrokontroler karena itu hanya; memiliki rjmp dan bukan jmp.org 0x0020; lokasi memori pengatur overflow Timer0 rjmp overflow_handler; buka di sini jika terjadi interupsi overflow timer0;============ Reset: ldi temp, 0b00000101 out TCCR0B, temp; atur Clock Selector Bits CS00, CS01, CS02 ke 101; ini menempatkan Penghitung Penghitung Waktu0, TCNT0 ke mode FCPU/1024; jadi berdetak di CPU freq/1024 ldi temp, 0b00000001 sts TIMSK0, temp; atur bit Timer Overflow Interrupt Enable (TOIE0); dari Timer Interrupt Mask Register (TIMSK0) sei; aktifkan interupsi global -- setara dengan "sbi SREG, I" clr temp out TCNT0, temp; inisialisasi Timer/Counter ke 0 sbi DDRD, 4; setel PD4 ke output;======================; Bagian utama program: blink: sbi PORTD, 4; nyalakan LED pada penundaan panggilan PD4; penundaan akan menjadi 1/2 detik cbi PORTD, 4; matikan LED pada penundaan panggilan PD4; penundaan akan menjadi 1/2 detik rjmp berkedip; loop kembali ke penundaan awal: clr overflows; setel overflows ke 0 sec_count: cpi overflows, 30; bandingkan jumlah overflow dan 30 brne sec_count; cabang untuk kembali ke sec_count jika tidak sama dengan ret; jika 30 overflows telah terjadi kembali ke blink overflow_handler: inc overflows; tambahkan 1 ke variabel overflows cpi overflows, 61; bandingkan dengan 61 brne PC+2; Program Counter + 2 (lewati baris berikutnya) jika tidak sama dengan clr overflows; jika terjadi 61 overflows reset counter ke nol reti; kembali dari interupsi
Seperti yang Anda lihat, komentar saya sedikit lebih singkat sekarang. Setelah kita tahu apa perintah dalam set instruksi, kita tidak perlu menjelaskannya di komentar. Kita hanya perlu menjelaskan apa yang terjadi dari sudut pandang program.
Kita akan membahas apa yang dilakukan semua ini sepotong demi sepotong, tetapi pertama-tama mari kita coba untuk mendapatkan perspektif global. Bagian utama dari program ini bekerja sebagai berikut.
Pertama kita set bit 4 PORTD dengan "sbi PORTD, 4" ini mengirimkan 1 ke PD4 yang menempatkan tegangan ke 5V pada pin itu. Ini akan menyalakan LED. Kami kemudian melompat ke subrutin "penundaan" yang menghitung 1/2 detik (kami akan menjelaskan bagaimana melakukannya nanti). Kami kemudian kembali untuk berkedip dan menghapus bit 4 pada PORTD yang menetapkan PD4 ke 0V dan karenanya mematikan LED. Kami kemudian menunda selama 1/2 detik, dan kemudian melompat kembali ke awal kedipan lagi dengan "rjmp blink".
Anda harus menjalankan kode ini dan melihat bahwa ia melakukan apa yang seharusnya.
Dan di sana Anda memilikinya! Hanya itu yang dilakukan kode ini secara fisik. Mekanisme internal dari apa yang mikrokontroler lakukan sedikit lebih terlibat dan itulah sebabnya kami melakukan tutorial ini. Jadi mari kita bahas setiap bagian secara bergantian.
Langkah 4:.org Assembler Directive
Kita sudah tahu apa yang dilakukan direktif.nolist,.list,.include, dan.def assembler dari tutorial kita sebelumnya, jadi mari kita lihat 4 baris kode yang muncul setelah itu:
.org 0x0000
jmp Reset.org 0x0020 jmp overflow_handler
Pernyataan.org memberi tahu assembler di mana dalam "Memori Program" untuk meletakkan pernyataan berikutnya. Saat program Anda dijalankan, "Penghitung Program" (disingkat PC) berisi alamat baris saat ini yang sedang dieksekusi. Jadi dalam hal ini ketika PC berada di 0x0000 maka akan melihat perintah "jmp Reset" yang berada di lokasi memori tersebut. Alasan kami ingin meletakkan jmp Reset di lokasi itu adalah karena ketika program dimulai, atau chip direset, PC mulai mengeksekusi kode di tempat ini. Jadi, seperti yang kita lihat, kita baru saja menyuruhnya untuk segera "melompat" ke bagian yang berlabel "Reset". mengapa kita melakukan itu? Itu berarti dua baris terakhir di atas baru saja dilewati! Mengapa?
Nah di situlah hal-hal menjadi menarik. Anda sekarang harus membuka penampil pdf dengan lembar data ATmega328p lengkap yang saya tunjukkan di halaman pertama tutorial ini (itulah sebabnya item 4 di bagian "Anda akan membutuhkan"). Jika layar Anda terlalu kecil, atau Anda memiliki terlalu banyak jendela yang terbuka (seperti halnya dengan saya), Anda dapat melakukan apa yang saya lakukan dan meletakkannya di Ereader, atau ponsel Android Anda. Anda akan menggunakannya sepanjang waktu jika Anda berencana untuk menulis kode perakitan. Hal yang keren adalah bahwa semua mikrokontroler diatur dengan cara yang sangat mirip dan begitu Anda terbiasa membaca lembar data dan mengkodekannya, Anda akan merasa hampir sepele untuk melakukan hal yang sama untuk mikrokontroler yang berbeda. Jadi kami sebenarnya belajar bagaimana menggunakan semua mikrokontroler dalam arti tertentu dan bukan hanya atmega328p.
Oke, buka halaman 18 di lembar data dan lihat Gambar 8-2.
Ini adalah bagaimana Memori Program di mikrokontroler diatur. Anda dapat melihat bahwa itu dimulai dengan alamat 0x0000 dan dipisahkan menjadi dua bagian; bagian flash aplikasi dan bagian flash boot. Jika Anda merujuk secara singkat ke halaman 277 tabel 27-14, Anda akan melihat bahwa bagian flash aplikasi mengambil lokasi dari 0x0000 hingga 0x37FF dan bagian flash boot mengambil lokasi yang tersisa dari 0x3800 hingga 0x3FFF.
Latihan 1: Berapa banyak lokasi yang ada di memori Program? Yaitu. konversi 3FFF ke desimal dan tambahkan 1 karena kita mulai menghitung pada 0. Karena setiap lokasi memori lebarnya 16 bit (atau 2 byte), berapa jumlah total byte memori? Sekarang konversikan ini ke kilobyte, dengan mengingat bahwa ada 2^10 = 1024 byte dalam satu kilobyte. Bagian flash boot berubah dari 0x3800 ke 0x37FF, berapa kilobyte ini? Berapa kilobyte memori yang tersisa untuk kita gunakan untuk menyimpan program kita? Dengan kata lain, seberapa besar program kita? Akhirnya, berapa banyak baris kode yang bisa kita miliki?
Baiklah, sekarang setelah kita mengetahui semua tentang organisasi memori program flash, mari kita lanjutkan pembahasan kita tentang pernyataan.org. Kami melihat bahwa lokasi memori pertama 0x0000 berisi instruksi kami untuk melompat ke bagian yang kami beri label Reset. Sekarang kita melihat apa yang dilakukan oleh pernyataan ".org 0x0020". Dikatakan bahwa kita ingin instruksi pada baris berikutnya ditempatkan di lokasi memori 0x0020. Instruksi yang kami tempatkan di sana adalah lompatan ke bagian dalam kode kami yang telah kami beri label "overflow_handler"… sekarang mengapa kami menuntut lompatan ini ditempatkan di lokasi memori 0x0020? Untuk mengetahuinya, kita buka halaman 65 di datasheet dan lihat Tabel 12-6.
Tabel 12-6 adalah tabel "Reset dan Interrupt Vectors" dan menunjukkan dengan tepat ke mana PC akan pergi ketika menerima "interrupt". Misalnya, jika Anda melihat Vektor nomor 1. "Sumber" interupsi adalah "RESET" yang didefinisikan sebagai "Pin Eksternal, Reset Power-on, Reset Brown-out, dan reset sistem Watchdog", jika ada hal itu terjadi pada mikrokontroler kita, PC akan mulai mengeksekusi program kita di lokasi memori program 0x0000. Lalu bagaimana dengan arahan.org kami? Yah, kami menempatkan perintah di lokasi memori 0x0020 dan jika Anda melihat ke bawah tabel, Anda akan melihat bahwa jika terjadi overflow Timer/Counter0 (berasal dari TIMER0 OVF) ia akan mengeksekusi apa pun yang ada di lokasi 0x0020. Jadi setiap kali itu terjadi, PC akan melompat ke tempat yang kami beri label "overflow_handler". Keren kan? Anda akan melihat sebentar lagi mengapa kami melakukan ini, tetapi pertama-tama mari selesaikan langkah tutorial ini dengan tambahan.
Jika kita ingin membuat kode kita lebih rapi dan rapi kita harus benar-benar mengganti 4 baris yang sedang kita bahas dengan berikut ini (lihat halaman 66):
.org 0x0000
rjmp Setel Ulang; PC = 0x0000 reti; PC = 0x0002 reti; PC = 0x0004 reti; PC = 0x0006 reti; PC = 0x0008 reti; PC = 0x000A … reti; PC = 0x001E jmp overflow_handler: PC = 0x0020 reti: PC = 0x0022 … reti; PC = 0x0030 reti; PC = 0x0032
Sehingga jika terjadi interupsi yang diberikan hanya akan “reti” yang artinya “kembali dari interupsi” dan tidak ada lagi yang terjadi. Tetapi jika kita tidak pernah "Aktifkan" berbagai interupsi ini, maka interupsi tersebut tidak akan digunakan dan kita dapat meletakkan kode program di tempat tersebut. Dalam program "blink.asm" kami saat ini, kami hanya akan mengaktifkan interupsi overflow timer0 (dan tentu saja interupsi reset yang selalu diaktifkan) sehingga kami tidak akan repot dengan yang lain.
Bagaimana kita "mengaktifkan" interupsi overflow timer0? … itu adalah subjek dari langkah kita selanjutnya dalam tutorial ini.
Langkah 5: Timer/Penghitung 0
Perhatikan gambar di atas. Ini adalah proses pengambilan keputusan dari "PC" ketika beberapa pengaruh luar "mengganggu" aliran program kami. Hal pertama yang dilakukan ketika mendapat sinyal dari luar bahwa interupsi telah terjadi adalah memeriksa untuk melihat apakah kita telah menyetel bit "interrupt enable" untuk jenis interupsi tersebut. Jika belum, maka itu hanya terus mengeksekusi baris kode berikutnya. Jika kita telah menyetel bit pengaktif interupsi tertentu (sehingga ada 1 di lokasi bit itu alih-alih 0) maka akan memeriksa apakah kita telah mengaktifkan "interupsi global" atau tidak, jika tidak maka akan kembali ke baris berikutnya kode dan melanjutkan. Jika kita juga telah mengaktifkan interupsi global, maka ia akan menuju ke lokasi Memori Program dari jenis interupsi tersebut (seperti yang ditunjukkan pada Tabel 12-6) dan menjalankan perintah apa pun yang telah kita tempatkan di sana. Jadi mari kita lihat bagaimana kita mengimplementasikan semua ini dalam kode kita.
Bagian Reset berlabel kode kami dimulai dengan dua baris berikut:
Mengatur ulang:
suhu ldi, 0b00000101 keluar TCCR0B, suhu
Seperti yang sudah kita ketahui, ini memuat ke temp (yaitu R16) nomor yang segera mengikuti, yaitu 0b00000101. Kemudian ia menulis nomor ini ke register yang disebut TCCR0B menggunakan perintah "keluar". Apa ini register? Baiklah, mari kita menuju ke halaman 614 dari datasheet. Ini berada di tengah tabel yang merangkum semua register. Di alamat 0x25 Anda akan menemukan TCCR0B. (Sekarang Anda tahu dari mana baris "out 0x25, r16" berasal dari versi kode saya yang tidak dikomentari). Kami melihat dari segmen kode di atas bahwa kami telah mengatur bit ke-0 dan bit ke-2 dan menghapus sisanya. Dengan melihat tabel Anda dapat melihat bahwa ini berarti kami telah menetapkan CS00 dan CS02. Sekarang mari kita menuju ke bab dalam lembar data yang disebut "8-bit Timer/Counter0 with PWM". Secara khusus, buka halaman 107 dari bab itu. Anda akan melihat deskripsi yang sama dari register "Timer/Counter Control Register B" (TCCR0B) yang baru saja kita lihat di tabel ringkasan register (jadi kita bisa langsung ke sini, tapi saya ingin Anda melihat bagaimana menggunakan tabel ringkasan untuk referensi di masa mendatang). Lembar data terus memberikan deskripsi setiap bit dalam register itu dan apa yang mereka lakukan. Kami akan melewatkan semua itu untuk saat ini dan membalik halaman ke Tabel 15-9. Tabel ini menunjukkan "Clock Select Bit Description". Sekarang lihat tabel itu sampai Anda menemukan baris yang sesuai dengan bit yang baru saja kita atur di register itu. Baris mengatakan "clk/1024 (dari prescaler)". Artinya, kita ingin Timer/Counter0 (TCNT0) berdetak pada kecepatan yang merupakan frekuensi CPU dibagi 1024. Karena mikrokontroler kita diberi makan oleh osilator kristal 16MHz, itu berarti kecepatan CPU kita mengeksekusi instruksi adalah 16 juta instruksi per detik. Jadi tingkat yang akan dicentang oleh penghitung TCNT0 kami adalah 16 juta/1024 = 15625 kali per detik (coba dengan bit pilih jam yang berbeda dan lihat apa yang terjadi - ingat filosofi kami?). Mari kita simpan angka 15625 di benak kita untuk nanti dan beralih ke dua baris kode berikutnya:
suhu ldi, 0b00000001
st TIMSK0, suhu
Ini menetapkan bit ke-0 dari register yang disebut TIMSK0 dan menghapus sisanya. Jika Anda melihat halaman 109 di datasheet Anda akan melihat bahwa TIMSK0 adalah singkatan dari "Timer/Counter Interrupt Mask Register 0" dan kode kami telah menetapkan bit ke-0 yang diberi nama TOIE0 yang merupakan singkatan dari "Timer/Counter0 Overflow Interrupt Enable" … Di sana! Sekarang Anda melihat apa ini semua tentang. Kami sekarang memiliki "interrupt enable bit set" seperti yang kami inginkan dari keputusan pertama dalam gambar kami di atas. Jadi sekarang yang harus kita lakukan adalah mengaktifkan "interupsi global" dan program kita akan dapat merespons jenis interupsi ini. Kami akan segera mengaktifkan interupsi global, tetapi sebelum kami melakukannya, Anda mungkin bingung dengan sesuatu.. mengapa saya menggunakan perintah "sts" untuk menyalin ke register TIMSK0 alih-alih "out" yang biasa?
Setiap kali Anda melihat saya menggunakan instruksi yang belum pernah Anda lihat sebelumnya, hal pertama yang harus Anda lakukan adalah membuka halaman 616 di lembar data. Ini adalah "Ringkasan Set Instruksi". Sekarang temukan instruksi "STS" yang saya gunakan. Dikatakan dibutuhkan nomor dari register R (kami menggunakan R16) dan lokasi "Simpan langsung ke SRAM" k (dalam kasus kami diberikan oleh TIMSK0). Jadi mengapa kami harus menggunakan "sts" yang membutuhkan 2 siklus clock (lihat kolom terakhir dalam tabel) untuk disimpan di TIMSK0 dan kami hanya membutuhkan "out", yang hanya membutuhkan satu siklus clock, untuk disimpan di TCCR0B sebelumnya? Untuk menjawab pertanyaan ini kita perlu kembali ke tabel ringkasan register kita di halaman 614. Anda lihat register TCCR0B ada di alamat 0x25 tapi juga di (0x45) kan? Ini berarti bahwa ini adalah register di SRAM, tetapi juga merupakan jenis register tertentu yang disebut "port" (atau register i/o). Jika Anda melihat tabel ringkasan instruksi di samping perintah "out" Anda akan melihat bahwa perintah itu mengambil nilai dari "register kerja" seperti R16 dan mengirimkannya ke PORT. Jadi kita bisa menggunakan "out" saat menulis ke TCCR0B dan menghemat siklus clock. Tapi sekarang cari TIMSK0 di tabel register. Anda melihat bahwa ia memiliki alamat 0x6e. Ini berada di luar jangkauan port (yang hanya merupakan lokasi 0x3F pertama dari SRAM) sehingga Anda harus kembali menggunakan perintah sts dan mengambil dua siklus clock CPU untuk melakukannya. Silakan baca Catatan 4 di akhir tabel ringkasan instruksi di halaman 615 sekarang. Perhatikan juga bahwa semua port input dan output kita, seperti PORTD terletak di bagian bawah tabel. Misalnya, PD4 adalah bit 4 di alamat 0x0b (sekarang Anda melihat dari mana semua barang 0x0b berasal dalam kode saya yang tidak dikomentari!).. oke, pertanyaan singkat: apakah Anda mengubah "sts" menjadi "out" dan lihat apa terjadi? Ingat filosofi kami! hancurkan! jangan hanya mengambil kata-kata saya untuk hal-hal.
Oke, sebelum kita melanjutkan, buka halaman 19 di lembar data sebentar. Anda melihat gambar memori data (SRAM). 32 register pertama di SRAM (dari 0x0000 hingga 0x001F) adalah "register kerja tujuan umum" R0 hingga R31 yang kami gunakan sepanjang waktu sebagai variabel dalam kode kami.64 register berikutnya adalah port I/O hingga 0x005f (yaitu yang kita bicarakan yang memiliki alamat yang tidak dikurung di sampingnya di tabel register yang dapat kita gunakan perintah "out" alih-alih "sts") Akhirnya bagian berikutnya dari SRAM berisi semua register lain dalam tabel ringkasan hingga alamat 0x00FF, dan terakhir adalah SRAM internal. Sekarang cepat, mari kita beralih ke halaman 12 sebentar. Di sana Anda melihat tabel "register kerja tujuan umum" yang selalu kami gunakan sebagai variabel kami. Anda melihat garis tebal antara angka R0 ke R15 dan kemudian R16 ke R31? Baris itulah mengapa kita selalu menggunakan R16 sebagai yang terkecil dan saya akan membahasnya lebih dalam di tutorial berikutnya di mana kita juga akan membutuhkan tiga register alamat tidak langsung 16-bit, X, Y, dan Z. Saya tidak akan masuk ke itu dulu meskipun karena kita tidak membutuhkannya sekarang dan kita terjebak cukup di sini.
Balikkan satu halaman ke halaman 11 dari lembar data. Anda akan melihat diagram register SREG di kanan atas? Anda melihat bahwa bit 7 dari register itu disebut "I". Sekarang turun halaman dan baca deskripsi Bit 7…. ya! Ini adalah bit Global Interrupt Enable. Itulah yang perlu kita atur untuk melewati keputusan kedua dalam diagram kita di atas dan memungkinkan interupsi timer/counter overflow dalam program kita. Jadi baris berikutnya dari program kami harus membaca:
sbi SREG, saya
yang menetapkan bit yang disebut "I" dalam register SREG. Namun, daripada ini kami telah menggunakan instruksi
sei
sebagai gantinya. Bit ini sering diatur dalam program sehingga mereka hanya membuat cara yang lebih sederhana untuk melakukannya.
Oke! Sekarang kita telah menyiapkan interupsi overflow sehingga "jmp overflow_handler" kita akan dieksekusi setiap kali terjadi.
Sebelum kita lanjut, lihat dulu register SREG (Status Register) karena ini sangat penting. Baca apa yang diwakili oleh masing-masing bendera. Secara khusus, banyak instruksi yang kami gunakan akan mengatur dan memeriksa tanda-tanda ini setiap saat. Misalnya nanti kita akan menggunakan perintah “CPI” yang artinya “bandingkan langsung”. Lihatlah tabel ringkasan instruksi untuk instruksi ini dan perhatikan berapa banyak flag yang dipasang di kolom "flags". Ini semua adalah flag di SREG dan kode kami akan mengaturnya dan memeriksanya terus-menerus. Anda akan melihat contoh segera. Akhirnya bit terakhir dari bagian kode ini adalah:
suhu clr
keluar TCNT0, temp sbi DDRD, 4
Baris terakhir di sini cukup jelas. Itu hanya mengatur bit ke-4 dari Daftar Arah Data untuk PortD yang menyebabkan PD4 menjadi OUTPUT.
Yang pertama menetapkan variabel temp ke nol dan kemudian menyalinnya ke register TCNT0. TCNT0 adalah Timer/Counter0 kami. Ini menetapkannya ke nol. Segera setelah PC mengeksekusi baris ini, timer0 akan mulai dari nol dan menghitung dengan kecepatan 15625 kali setiap detik. Masalahnya adalah ini: TCNT0 adalah register "8-bit" bukan? Jadi, berapakah bilangan terbesar yang dapat ditampung oleh register 8-bit? Nah 0b11111111 itu. Ini adalah nomor 0xFF. Yang mana 255. Jadi Anda lihat apa yang terjadi? Pengatur waktu bergerak cepat meningkat 15625 kali per detik dan setiap kali mencapai 255 itu "meluap" dan kembali ke 0 lagi. Pada saat yang sama ketika kembali ke nol, ia mengirimkan sinyal Interupsi Timer Overflow. PC mendapatkan ini dan Anda tahu apa yang dilakukannya sekarang kan? Ya. Ia pergi ke lokasi Memori Program 0x0020 dan mengeksekusi instruksi yang ditemukannya di sana.
Besar! Jika Anda masih bersama saya maka Anda adalah pahlawan super yang tak kenal lelah! Ayo lanjutkan…
Langkah 6: Overflow Handler
Jadi mari kita asumsikan bahwa register timer/counter0 baru saja meluap. Kita sekarang tahu bahwa program menerima sinyal interupsi dan mengeksekusi 0x0020 yang memberitahu Program Counter, PC untuk melompat ke label "overflow_handler" berikut adalah kode yang kita tulis setelah label itu:
overflow_handler:
inc overflows cpi overflows, 61 brne PC+2 clr overflows reti
Hal pertama yang dilakukan adalah menaikkan variabel "overflows" (yang merupakan nama kami untuk register kerja tujuan umum R17) kemudian "membandingkan" isi overflows dengan angka 61. Cara kerja instruksi cpi adalah dengan hanya mengurangi dua angka dan jika hasilnya nol itu menetapkan bendera Z di register SREG (saya katakan bahwa kami akan melihat register ini sepanjang waktu). Jika kedua angka sama maka bendera Z akan menjadi 1, jika kedua angka tidak sama maka akan menjadi 0.
Baris berikutnya bertuliskan "brne PC+2" yang artinya "cabang jika tidak sama". Pada dasarnya, ia memeriksa bendera Z di SREG dan jika BUKAN satu (yaitu dua angka tidak sama, jika mereka sama, bendera nol akan ditetapkan) PC bercabang ke PC+2, yang berarti ia melewatkan yang berikutnya baris dan langsung menuju "reti" yang kembali dari interupsi ke tempat mana pun dalam kode saat interupsi tiba. Jika instruksi brne menemukan 1 di bit bendera nol, itu tidak akan bercabang dan sebaliknya itu hanya akan melanjutkan ke baris berikutnya yang akan clr overflow mengatur ulang ke 0.
Apa hasil bersih dari semua ini?
Nah kita melihat bahwa setiap kali ada timer overflow handler ini meningkatkan nilai "overflows" satu per satu. Jadi variabel "luapan" menghitung jumlah luapan yang terjadi. Setiap kali jumlahnya mencapai 61 kita reset ke nol.
Sekarang mengapa di dunia kita akan melakukan itu?
Ayo lihat. Ingat bahwa kecepatan clock untuk CPU kami adalah 16MHz dan kami "mempercepat"nya menggunakan TCCR0B sehingga penghitung waktu hanya menghitung pada kecepatan 15625 hitungan per detik, bukan? Dan setiap kali timer mencapai hitungan 255, timer akan meluap. Jadi itu berarti meluap 15625/256 = 61,04 kali per detik. Kami melacak jumlah luapan dengan variabel "melimpah" dan kami membandingkan angka itu dengan 61. Jadi kami melihat bahwa "melimpah" akan sama dengan 61 setiap detik! Jadi pawang kami akan mengatur ulang "meluap" ke nol sekali setiap detik. Jadi jika kita hanya memantau variabel "meluap" dan mencatat setiap kali disetel ulang ke nol, kita akan menghitung detik demi detik secara real time (Perhatikan bahwa dalam tutorial berikutnya kita akan menunjukkan cara mendapatkan yang lebih tepat penundaan dalam milidetik dengan cara yang sama seperti rutinitas "penundaan" Arduino bekerja).
Sekarang kita telah "menangani" interupsi timer overflow. Pastikan Anda memahami cara kerjanya dan lanjutkan ke langkah berikutnya di mana kami menggunakan fakta ini.
Langkah 7: Tunda
Sekarang kita telah melihat bahwa timer overflow interrupt handler rutin "overflow_handler" akan mengatur variabel "overflows" ke nol sekali setiap detik, kita dapat menggunakan fakta ini untuk merancang subrutin "delay".
Lihatlah kode berikut dari bawah penundaan kami: label
menunda:
clr overflows sec_count: cpi overflows, 30 brne sec_count ret
Kami akan memanggil subrutin ini setiap kali kami membutuhkan penundaan dalam program kami. Cara kerjanya adalah pertama-tama set variabel "meluap" ke nol. Kemudian memasuki area berlabel "sec_count" dan membandingkan overflow dengan 30, jika tidak sama, ia bercabang kembali ke label sec_count dan membandingkan lagi, dan lagi, dll. sampai akhirnya sama (ingat bahwa sepanjang waktu ini akan berjalan pada pengatur waktu interupsi kami terus menambah variabel overflow dan berubah setiap kali kita berkeliling di sini. Ketika overflow akhirnya sama dengan 30, ia keluar dari loop dan kembali ke mana pun yang kita sebut delay: from. Hasil bersihnya adalah a penundaan 1/2 detik
Latihan 2: Ubah rutin overflow_handler menjadi berikut:
overflow_handler:
inc meluap reti
dan jalankan programnya. Apakah ada yang berbeda? Mengapa atau mengapa tidak?
Langkah 8: Berkedip
Akhirnya mari kita lihat rutinitas berkedip:
berkedip:
sbi PORTD, 4 rcall delay cbi PORTD, 4 rcall delay rjmp blink
Pertama kita nyalakan PD4, lalu kita panggil subrutin delay kita. Kami menggunakan rcall sehingga ketika PC mendapatkan pernyataan "ret", ia akan kembali ke baris berikut rcall. Kemudian penundaan rutin penundaan selama 30 hitungan dalam variabel overflow seperti yang telah kita lihat dan ini hampir tepat 1/2 detik, lalu kita matikan PD4, penundaan lagi 1/2 detik, dan kemudian kembali ke awal lagi.
Hasil bersihnya adalah LED yang berkedip!
Saya pikir Anda sekarang akan setuju bahwa "blink" mungkin bukan program "hello world" terbaik dalam bahasa assembly.
Latihan 3: Ubah berbagai parameter dalam program sehingga LED berkedip dengan kecepatan yang berbeda seperti satu detik atau 4 kali per detik, dll. Latihan 4: Ubah sehingga LED menyala dan mati untuk waktu yang berbeda. Misalnya hidup selama 1/4 detik lalu mati selama 2 detik atau semacamnya. Latihan 5: Ubah bit pilih jam TCCR0B menjadi 100 lalu lanjutkan naik tabel. Pada titik apa itu menjadi tidak dapat dibedakan dari program "hello.asm" kami dari tutorial 1? Latihan 6 (opsional): Jika Anda memiliki osilator kristal yang berbeda, seperti 4 MHz atau 13,5 MHz atau apa pun, ganti osilator 16 MHz Anda di papan tempat memotong roti Anda untuk yang baru dan lihat bagaimana hal itu memengaruhi tingkat kedipan LED. Anda sekarang harus dapat melalui perhitungan yang tepat dan memprediksi dengan tepat bagaimana hal itu akan mempengaruhi tingkat.
Langkah 9: Kesimpulan
Bagi Anda yang telah berhasil sejauh ini, Selamat!
Saya menyadari itu cukup sulit ketika Anda melakukan lebih banyak membaca dan melihat ke atas daripada Anda memasang kabel dan bereksperimen, tetapi saya harap Anda telah mempelajari hal-hal penting berikut:
- Bagaimana Memori Program bekerja
- Cara kerja SRAM
- Cara mencari register
- Cara mencari instruksi dan mengetahui apa yang mereka lakukan
- Bagaimana menerapkan interupsi
- Bagaimana CP mengeksekusi kode, bagaimana SREG bekerja, dan apa yang terjadi selama interupsi
- Bagaimana melakukan loop dan melompat dan terpental dalam kode
- Betapa pentingnya membaca datasheet!
- Bagaimana setelah Anda tahu bagaimana melakukan semua ini untuk mikrokontroler Atmega328p, itu akan menjadi perjalanan yang relatif mudah untuk mempelajari pengontrol baru yang Anda minati.
- Bagaimana mengubah waktu CPU menjadi waktu nyata dan menggunakannya dalam rutinitas penundaan.
Sekarang setelah kita memiliki banyak teori, kita dapat menulis kode yang lebih baik dan mengontrol hal-hal yang lebih rumit. Jadi tutorial berikutnya kita akan melakukan hal itu. Kami akan membangun sirkuit yang lebih rumit, lebih menarik, dan mengendalikannya dengan cara yang menyenangkan.
Latihan 7: "Pecahkan" kode dengan berbagai cara dan lihat apa yang terjadi! Keingintahuan ilmiah sayang! Orang lain dapat mencuci piring dengan benar? Latihan 8: Susun kode menggunakan opsi "-l" untuk menghasilkan file daftar. Yaitu. "avra -l blink.lst blink.asm" dan lihat file daftarnya. Extra Credit: Kode un-commented yang saya berikan di awal dan kode commented yang kita bahas nanti berbeda! Ada satu baris kode yang berbeda. Dapatkah Anda menemukannya? Mengapa perbedaan itu tidak penting?
Semoga Anda bersenang-senang! Sampai jumpa di lain waktu…
Direkomendasikan:
Tutorial Perakitan AVR 2: 4 Langkah
Tutorial AVR Assembler 2: Tutorial ini merupakan lanjutan dari "Tutorial AVR Assembler 1" Jika Anda belum melalui Tutorial 1 Anda harus berhenti sekarang dan melakukannya terlebih dahulu. Dalam tutorial ini kita akan melanjutkan studi kita tentang pemrograman bahasa assembly dari atmega328p u
Tutorial Perakitan AVR 1: 5 Langkah
Tutorial Assembler AVR 1: Saya telah memutuskan untuk menulis serangkaian tutorial tentang cara menulis program bahasa assembly untuk Atmega328p yang merupakan mikrokontroler yang digunakan di Arduino. Jika orang tetap tertarik, saya akan terus mengeluarkannya seminggu atau lebih sampai saya kehabisan
Tutorial Perakitan AVR 6: 3 Langkah
Tutorial AVR Assembler 6: Selamat Datang di Tutorial 6! Tutorial hari ini akan singkat dimana kita akan mengembangkan metode sederhana untuk mengkomunikasikan data antara satu atmega328p dan lainnya menggunakan dua port yang menghubungkannya. Kami kemudian akan mengambil roller dadu dari Tutorial 4 dan Daftar
Tutorial Perakitan AVR 8: 4 Langkah
AVR Assembler Tutorial 8: Selamat Datang di Tutorial 8! Dalam tutorial singkat ini kita akan mengambil sedikit pengalihan dari memperkenalkan aspek-aspek baru dari pemrograman bahasa assembly untuk menunjukkan bagaimana memindahkan komponen prototyping kita ke "cetak" yang terpisah. papan sirkuit. NS
Tutorial Perakitan AVR 7: 12 Langkah
AVR Assembler Tutorial 7: Selamat Datang di Tutorial 7! Hari ini kita akan menunjukkan cara mengais keypad, dan kemudian menunjukkan cara menggunakan port input Analog untuk berkomunikasi dengan keypad. Kita akan melakukan ini menggunakan interupsi dan kabel tunggal sebagai memasukkan. Kami akan menyambungkan keypad agar