Vektor interupsi studio Atmega8 avr. Interupsi pada pengontrol AVR di Atmel AVR Studio. Simpan proyek dan ruang kerja


Mari kita bicara tentang interupsi. Kata interupsi berbicara sendiri; suatu proses dihentikan selama beberapa waktu untuk melakukan tindakan tambahan. Interupsi bisa bersifat eksternal atau internal. Izinkan saya memberi Anda contoh sederhana yang saya dengar dari teman saya...

Dia bersiap-siap untuk mencuci piring di dapur, memulai dengan semangat, menyingsingkan lengan bajunya... tapi ternyata piringnya berminyak dan dia terpaksa berhenti untuk mencari deterjen untuk mencuci piring berminyak di salah satu rak dapur. , setelah itu dia melanjutkan tugasnya lagi. Tetapi pada suatu saat telepon berdering, dan dia kembali berhenti dari pekerjaannya, mengangkat telepon, ibu mertuanya menelepon dan mengatakan bahwa dia akan datang berkunjung, jadi dia harus pergi ke toko untuk membeli bahan makanan ketika dia tiba. Saya pergi ke toko dan baru kemudian mencuci piring.

Contoh ini menunjukkan dua jenis gangguan, yang pertama terkait dengan pelaksanaan pekerjaan utama - mencari deterjen untuk hidangan berminyak - gangguan internal, yang kedua - panggilan telepon - gangguan eksternal.
Pada mikrokontroler, interupsi eksternal timbul karena adanya sinyal yang datang dari sumber lain, interupsi internal timbul karena perangkat yang terpasang pada mikrokontroler itu sendiri.
Mengapa interupsi begitu menarik?
Yang pertama adalah kita dapat menghentikan proses utama untuk menjalankan beberapa fungsi lainnya, dan kemudian melanjutkan proses ini.
Yang kedua, dan mungkin dalam banyak kasus yang utama, adalah percepatan proses pelaksanaan semua fungsi, karena adanya perangkat tambahan internal. Mari kita kembali ke contoh kita. Katakanlah teman saya mulai mencuci piring ketika istrinya sudah sampai di rumah. Melihat piring berminyak, dia memintanya untuk mencari cairan pencuci piring, dan saat dia mencuci, dia sudah membawakan cairan ini untuknya. Tapi kemudian telepon berdering, istri saya mengangkat telepon, berbicara dengan ibunya dan pergi ke toko. Bersama-sama, semuanya dilakukan dengan sangat cepat!
Teman saya duduk di sofa dan tidak melakukan apa pun, pengurus rumah tangga melihat piring kotor, memberitahunya tentang hal itu, dan setelah mendapat izin, mulai mencuci sendiri. Ketika telepon berdering, dia menyuruh istrinya untuk mengangkat telepon, istrinya sedang berbicara di telepon, dan percakapan berlanjut ke toko kelontong... Cantik! Dalam hal ini, beberapa perangkat I/O beroperasi secara bersamaan di mikrokontroler (dalam mikrokontroler modern jumlahnya bisa cukup banyak) dan kinerja prosesor secara keseluruhan meningkat berkali-kali lipat, tetapi interupsi dari perangkat diproses secara berurutan satu demi satu (tidak secara bersamaan). ), tergantung prioritasnya (dalam contoh kita, istri mempunyai prioritas lebih tinggi daripada pengurus rumah tangga).

Beberapa register bertanggung jawab untuk mengelola interupsi
SREG – daftar status(negara bagian). Kami melihat tabel perangkat input/output. Bit ketujuh dari register SREG adalah bendera I (interupsi), yang disebut bendera pengaktifan interupsi global. Jika flag dihilangkan (bit ketujuh adalah nol), maka semua interupsi dinonaktifkan. Jika bendera dikibarkan (setel I ke 1), kami mengaktifkan interupsi.

Bendera I disetel dan disetel ulang dengan perintah:
SEI - aktifkan interupsi
CLI - nonaktifkan interupsi
Interupsi mana yang akan berfungsi diatur menggunakan register yang disebut - interupsi masker.
Masker interupsi ditetapkan sebagai berikut:
TIMSK,..,..,.. – pengelolaan interupsi dari pengatur waktu dan perangkat internal lainnya.
GIMSK (GIKR dalam keluarga Mega) - pengelolaan semua interupsi eksternal.
Masker interupsi pada gilirannya bergantung pada tanda interupsi:
TIFR dan GIFR masing-masing(jangan bingung dengan tanda pengaktifan interupsi global).

Urutan eksekusi interupsi:
Ketika mikrokontroler dihidupkan, semua flag interupsi direset ke 0. Untuk mengaktifkan interupsi, program harus menyetel flag I dari register SREG ke 1. Setelah itu, daftarkan register mask dengan set interupsi lokal (interupsi yang kita butuhkan) .
Ketika permintaan interupsi (sinyal) tiba, ia akan memunculkan bendera interupsi (bahkan jika interupsi dinonaktifkan, untuk mengatur interupsi bersarang dan prioritas di antara interupsi yang berbeda). Jika interupsi tidak dinonaktifkan, pengontrol akan menghubungi yang sesuai (Vektor Interupsi) - vektor interupsi, menjeda program saat ini.
Vektor interupsi adalah jalur tetap di area program tempat program berjalan ketika terjadi interupsi.
Seluruh daftar vektor interupsi disebut tabel vektor interupsi, yang terletak di awal kode program.
Jadi, pada saat vektor interupsi diakses, flag I pada register SREG dan flag yang menyebabkan interupsi disetel ulang ke 0, menonaktifkan interupsi lainnya. Jika permintaan interupsi lainnya terjadi saat interupsi sedang dijalankan, tanda untuk interupsi tersebut tetap dikibarkan. Setelah interupsi saat ini selesai, flag I pada register SREG dikibarkan, sehingga interupsi berikutnya dapat dieksekusi. Jika beberapa permintaan tiba dan flagnya dikibarkan, interupsi yang vektornya lebih kecil pada alamat dalam tabel, lebih dekat ke awal memori, akan dieksekusi terlebih dahulu. Yang kedua menyusul, dan seterusnya. Selain itu, pemrogram dapat mengatur apa yang disebut interupsi bersarang, ketika interupsi lain terjadi selama pelaksanaan program interupsi. Kemudian eksekusi interupsi saat ini dihentikan dan interupsi baru dijalankan, setelah itu eksekusi interupsi yang dihentikan dilanjutkan kembali.

Sebagai contoh, diberikan tabel vektor interupsi untuk ATtiny2313

Tabel vektor interupsi untuk Atmega16 adalah sebagai berikut:

Jika dibandingkan, tabelnya tidak cocok sama sekali.
Dalam keluarga ATtiny, garis vektor interupsi menempati 16 bit, dan dalam keluarga Mega dibutuhkan 32 bit (perhatikan alamat vektor interupsi; izinkan saya mengingatkan Anda bahwa baris alamat di area program diwakili oleh 16 -sedikit kata).

Kode program untuk ATtiny2313 mungkin terlihat seperti ini:
.cseg .org 0 rjmp Reset rjmp INT_0 rjmp INT_1 rjmp Timer1_capt1 rjmp Timer1_comp1 rjmp Timer1_OVF1 rjmp Timer0_OVF0 rjmp UART_RX rjmp UART_UDRE rjmp UART_TX rjmp ANA_COMP rjmp PCINT rjmp Timer1_compB rjmp Timer0_compA r jmp Timer0_compB rjmp USI_START rjmp USI_OVERFLOW rjmp EE_READY rjmp WDT_ OVERFLOW

Seperti yang Anda lihat, vektor interupsi menciptakan lompatan relatif ke label program interupsi. Tabel di bawah ini menunjukkan pilihannya; 1. Bila tidak ada gangguan; 2, 3. dengan interupsi eksternal pada input INT_1.
Jika labelnya "kosong" (tidak ada program di bawah label), maka tidak ada yang terjadi, dan program secara berurutan "menjalankan" label yang tersisa dan mencapai perintah dengan aman RETI- Pengembalian interupsi - keluar dari pengendali interupsi seperti yang ditunjukkan pada kolom pertama tabel.

Untuk menjalankan program interupsi, misalnya, pada input INT_1, Anda perlu menghapus label INT_1: dari daftar. Hal ini ditunjukkan secara skematis di kolom kedua tabel.
Namun, tidak nyaman bagi pemrogram untuk menulis semua interupsi dan label terpisah setiap kali, terutama pada model terbaru, di mana tabelnya cukup besar untuk segera menulis perintah RETI di baris vektor interupsi jika interupsi tidak digunakan. Kemudian program akan terlihat seperti pada kolom ketiga tabel.

Pengontrol AVR, tergantung pada modelnya, dapat memiliki 1 hingga 8 input interupsi eksternal.
Mari kita pertimbangkan sistem manajemen interupsi eksternal. Untuk tujuan ini, kombinasi register I/O berikut disediakan tergantung pada modelnya (lihat DataSheet terkait):
- GIMSK, EIFR, PCMSK, MCUCR;
- GIKR, GIFR, MCUCR;
- EIMSK, EICR, EIFR;
GIMSK, GIKR, EIMSK - masker interupsi,
EIFR, PCMSK, GIFR, EIFR – tanda interupsi
Untuk izin atau larangan interupsi eksternal register kontrol dimaksudkan: GIMSK- (General Interrupt Mask Register)(Tiny), GICR- (General Interrupt Control Register)(Mega), MCUCR – (MCU Control Register)




EIFR- Daftar Bendera Interupsi Eksternal: 1 - diaktifkan, 0 - dinonaktifkan. Setiap bit (bendera) memungkinkan pin yang sesuai bertindak sebagai sumber interupsi.

Bit kontrol register GIMSK:
Bagian 7 – INT1: Permintaan Interupsi Eksternal 1 Aktif – Bit pengaktifan interupsi INT1: 1 – diaktifkan, 0 – dinonaktifkan. Interupsi akan dihasilkan bahkan jika pin INT1 dikonfigurasi sebagai output. Bit INT1 diatur ke interupsi dalam register flag EIFR. Pin INT1 disinkronkan dengan generator jam.

Bagian 6 – INT0: Permintaan Interupsi Eksternal 0 Aktifkan - bit pengaktifan interupsi INT0: 1 – diaktifkan, 0 – dinonaktifkan. Interupsi akan dihasilkan bahkan jika pin INT0 dikonfigurasi sebagai output. Bit INT0 diatur ke interupsi dalam register flag EIFR. Pin INT10 disinkronkan dengan generator jam.

Bagian 5 – PCIE: Pin Change Interrupt Enable – bit pengaktifan interupsi pada PCINT0…7 pin: 1 – diaktifkan, 0 – dinonaktifkan. Setiap perubahan pada pin PCINT0...7 mana pun akan menghasilkan interupsi. Pin PCINT0...7 dikonfigurasi untuk interupsi secara individual, per bit dalam register flag PCMSK.

PCMSK- Pin Ganti Masker Regiser - daftar bendera PCMSK: 1 - diperbolehkan, 0 - dinonaktifkan. Setiap bit (bendera) memungkinkan pin yang sesuai bertindak sebagai sumber interupsi. Pin PCINT0...7 tidak disinkronkan dengan generator jam, mis. interupsi terjadi ketika terjadi perubahan pada salah satu pin.

Mega8

dan register bendera yang sesuai


Bagian 7

Bagian 6 – INT0: Permintaan Interupsi Eksternal 0 Aktifkan - bit pengaktifan interupsi INT0: 1 – diaktifkan, 0 – dinonaktifkan. Interupsi akan dihasilkan bahkan jika pin INT0 dikonfigurasi sebagai output. Bit INT0 diatur untuk menginterupsi register flag GIFR



GIFR – Daftar Bendera Interupsi Umum: 1 – diaktifkan, 0 – dinonaktifkan. Setiap bit (bendera) memungkinkan pin yang sesuai bertindak sebagai sumber interupsi.

Bit kontrol register GICR:
Bagian 7– : Permintaan Interupsi Eksternal 1 Aktifkan – interupsi aktifkan bit INT1: 1 – diperbolehkan, 0 – dilarang. Interupsi akan dihasilkan bahkan jika pin INT1 dikonfigurasi sebagai output. Bit INT1 diatur untuk menginterupsi register flag GIFR

Bagian 6 – INT0: Permintaan Interupsi Eksternal 0 Aktifkan - interupsi aktifkan bit INT0: 1 – diperbolehkan, 0 – dilarang. Interupsi akan dihasilkan bahkan jika pin INT0 dikonfigurasi sebagai output. Bit INT0 diatur untuk menginterupsi register flag GIFR

Bagian 5 – INT2: Permintaan Interupsi Eksternal 2 Aktifkan - interupsi aktifkan bit INT2: 1 – diperbolehkan, 0 – dilarang. Interupsi akan dihasilkan meskipun pin INT2 dikonfigurasi sebagai output. Bit INT2 diatur untuk menginterupsi register flag GIFR

Fungsi input INT0 dan INT1 di semua pengontrol dikendalikan oleh bit orde rendah dari register MCUCR

MCUCR– Daftar Kontrol MCU
Bit kontrol:
Bit 1, 0 – ISC01, ISC00 (Interrupt Sense Control 0 Bit 1 dan Bit 0) – keadaan bit ini menentukan kejadian pada pin INT0, yang menghasilkan interupsi INT0:
ISC01=0, ISC00=0 – tingkat nol logis;
ISC01=0, ISC00=1 – setiap perubahan keadaan logis;
ISC01=1, ISC00=0 – pada sisi yang menurun;
ISC01=1, ISC00=1 – sedang naik daun.

Bit 3, 2 – ISC11, ISC10 (Interrupt Sense Control 1 Bit 1 dan Bit 0) – keadaan bit ini menentukan level sinyal pada pin INT1, yang menghasilkan interupsi INT1:
ISC11=0, ISC10=0 – tingkat nol logis;
ISC11=0, ISC10=1 – setiap perubahan keadaan logis;
ISC11=1, ISC10=0 – pada sisi yang menurun;
ISC11=1, ISC10=1 – sedang naik daun.

Sepertinya kita sudah berbicara seminimal mungkin tentang interupsi eksternal.
Jelas bahwa agar interupsi dapat berfungsi, interupsi tersebut harus didaftarkan dengan benar.
Mari kita tambahkan inisialisasi interupsi pada INT1 yang dimulai secara kecil di tepi sinyal yang meningkat:

Ldi r16.0x80 ; tulis di r16 nomor 0b10000000 ldi r17.0x0C ; tulis di r17 nomor 0b00001100 keluar MCUCR,r17 ; interupsi akan dihasilkan pada tepi naik ISC11=1, ISC10=1 out GIMSK,r16 ; atur topeng INT0 sei
Omong-omong, Anda dapat membuat interupsi di tiny2313 pada PCINT0…7 pin mana pun, di Mega hingga seri 48 fitur ini tidak tersedia...
Ada beberapa operasi yang mungkin terjadi interupsi yang dapat menyebabkan program terhenti. Dalam kasus seperti itu, sebelum memulai operasi kami menulis CLI, dan setelah SEI. Operasi seperti ini disebut - atom.
Program interupsi diharapkan kompak dan dieksekusi pada kecepatan maksimum, karena tujuan dari setiap interupsi adalah untuk menangkap suatu peristiwa. Jika karena berbagai alasan program berjalan lambat, maka cukup mengabadikan peristiwa tersebut dan memprosesnya nanti.

Agar materi yang disajikan tidak berantakan dengan informasi yang tidak perlu, saya menganjurkan agar pembaca menggunakan lembar data, dan jika semuanya belum jelas, lebih sering ajukan pertanyaan di forum.
Selanjutnya, kami akan mempertimbangkan secara rinci interupsi internal berdasarkan pengatur waktu bawaan. pembaca. Untuk berpartisipasi dalam pemungutan suara, daftar dan masuk ke situs dengan nama pengguna dan kata sandi Anda.

Sering terjadi bahwa sirkuit mikro harus bekerja, bekerja dengan tenang, dan untuk beberapa peristiwa, tinggalkan semuanya dan lakukan hal lain. Dan kemudian - kembali ke tugas awal lagi... Ini seperti jam tangan, misalnya - ini menunjukkan waktu hingga waktu jam alarm tiba. Dan sepertinya tidak ada pengaruh eksternal - menekan tombol, mengatur ulang - dan sirkuit mikro beralih sendiri.

Hal ini dapat diimplementasikan dengan menggunakan interupsi - sinyal yang menginformasikan prosesor tentang terjadinya suatu peristiwa.

Berikut ini contoh dari kehidupan sehari-hari - Anda sedang duduk di dapur, minum teh dengan selai raspberry dan camilan lezat, dan menunggu tamu. Bagaimana Anda tahu bahwa seseorang telah tiba? Ada dua pilihan: kita akan teralihkan dari kemacetan, maksud saya, teh, setiap lima menit dan berlari untuk memeriksa apakah ada orang yang berdiri di depan pintu, atau membeli bel pintu dan dengan tenang menunggu di tempat yang panas sampai seseorang membunyikannya.

Jadi, ketika ada tamu yang menelepon, ini adalah sebuah acara. Oleh karena itu, kami berhenti dan bergegas ke pintu.

Jadi, sirkuit mikro mengalami gangguan. Dan lebih dari satu. Interupsi dibagi menjadi eksternal - ini dipicu pada tegangan tertentu pada beberapa pin sirkuit mikro (INT0, INT1 dan terkadang seluruh port PCINT) - dan internal - ketika penghitung meluap, pengatur waktu pengawas dipicu, saat menggunakan USART, ketika komparator analog, ADC dan periferal lainnya terganggu.

Oleh karena itu, timbul masalah prioritas. Ini seperti kita masih duduk dan minum teh, tetapi mereka tidak hanya membunyikan bel pintu kita, tetapi juga telepon kita... Dan Anda tidak dapat terkoyak, ada yang perlu dilakukan terlebih dahulu. Oleh karena itu, lembar data berisi tabel vektor interupsi. Semakin rendah angka interupsi, semakin tinggi prioritasnya.

Ada beberapa kehalusan di sini...

Suatu peristiwa terjadi - permintaan interupsi dikirim, yaitu, apa yang disebut "bendera permintaan interupsi" disetel. Jika semuanya baik-baik saja, gangguan teratasi, maka hidup ini indah dan berproses.

Namun jika interupsi dinonaktifkan - misalnya, interupsi dengan prioritas lebih tinggi sedang diproses - maka tanda permintaan ini akan tetap hang hingga interupsi diaktifkan. Setelah ini, chip memeriksa register permintaan dalam urutan prioritas, dan jika ada tanda, memprosesnya.

TETAPI! Ternyata meskipun interupsi sudah diproses, bukan fakta bahwa peristiwa yang menyebabkannya masih hidup... Ibarat bel pintu dan telepon berbunyi bersamaan, Anda menjawab telepon, dan para tamu sudah memutuskan bahwa tidak ada seorang pun di rumah dan pergi. Dan sepertinya ada acara – bel pintu berbunyi, tapi tidak ada orang di balik pintu.

Masalah lainnya adalah ketika interupsi lain sedang diproses dan flag permintaan sudah dikibarkan, kejadian tersebut dapat terjadi beberapa kali lagi. Kami menjawab panggilan telepon, membuka pintu - dan sudah ada banyak tamu di sana! Menakutkan? Menakutkan...

Fitur lain dari penggunaan interupsi - dan bukan hanya interupsi: masuk kembali (atau masuk kembali).

Program reentrant adalah program yang dapat dipanggil oleh banyak pengguna (atau proses) tanpa, minimal, menyebabkan kesalahan dan, maksimal, tidak menyia-nyiakan komputasi—misalnya, pengguna lain tidak perlu menjalankan kode lagi.

Dengan kata lain, jika di dapur saat Anda menyambut tamu, tidak ada yang mencuri barang, maka semuanya masuk kembali)

Secara umum, ini adalah hal yang serius - jika Anda tidak memperhitungkannya, Anda dapat menderita untuk waktu yang lama dengan pertanyaan "mengapa tidak berhasil?!" Hal ini perlu diperhitungkan, misalnya jika beberapa interupsi diproses, dan masing-masing interupsi mengubah beberapa variabel global...

Interupsi biasanya TIDAK masuk kembali. Artinya, pada saat interupsi sedang berjalan, Anda tidak dapat memanggil interupsi yang sama lagi. Hal ini untuk melindungi dari masuknya kembali ke dalam handler maka interupsi secara otomatis dilarang pada saat pemrosesannya (jika Anda ingin mengaktifkan interupsi dalam interupsi. prosedur penanganannya, Anda perlu berpikir sepuluh, dua puluh kali sebelum mengambil langkah gegabah).

Mari kita pertimbangkan untuk bekerja dengan interupsi eksternal: pertama, kita perlu mengonfigurasi peristiwa mana yang akan memicu interupsi, dan, kedua, mengizinkan sirkuit mikro untuk memproses interupsi ini.

Register MCUCR bertanggung jawab atas bit pertama dalam chip ATmega8 - ISC11-ISC10, bertanggung jawab atas INT1, dan ISC01-ISC00, bertanggung jawab atas INT0.

Tabel 1. Definisi event untuk menghasilkan interupsi melalui INT1

Oleh karena itu, sama halnya dengan INT0.

Sekarang yang tersisa hanyalah mengaktifkan interupsi pada pin yang kita perlukan - register GIGR memiliki bit INT0 dan INT1; atur ke "1" yang diinginkan - dan interupsi eksternal diaktifkan! Namun masih terlalu dini untuk bersukacita - selain interupsi eksternal, interupsi secara umum harus diaktifkan - setel bit paling kiri I dari register SREG ke "1". Hal yang sama dapat dilakukan dengan perintah assembler: asm sei;

Mari kita lihat contoh sederhana: sebuah tombol dipasang ke pin INT0 (D.2) dari chip ATmega8 (ke pin dan ke nol); tekan - terjadi interupsi dan LED pada pin B.0 menyala. Oleh karena itu, LED terhubung ke kaki dan ke unit:

//program untuk ATmega8 ketika Anda menekan tombol pada pin INT0 (D.2) - terhubung ke 0 - //menyalakan LED pada pin B.0 melalui interupsi eksternal - terhubung ke 1 //mendefinisikan ulang tipe typedef unsigned char byte; sbit DDRButton di ddD2_bit; //tombol pembangkitan sbit pinButton di pinD2_bit; sbit portButton di portD2_bit; sbit ddrLight di ddB0_bit; //output untuk LED, untuk output pull-up, putar 0 pada tombol sbit portLight di portB0_bit; byte tombol bendera = 0; //tanda klik tombol; ditekan - 1 void INT0_interrupt() org IVT_ADDR_INT0 //Anda perlu menulis setidaknya fungsi kosong - //karena kompiler tidak membuatnya sendiri. Kalau tidak, itu tidak akan berfungsi ( flagButton = 1; ) //memproses penekanan tombol - dengan mempertimbangkan bouncing void buttonLight() ( if(flagButton) //jika tombol ditekan ( portLight = 0; //nyalakan LED delay_ms(500); portLight = 1; //matikan LED flagButton = 0; ) ) void main() ( //menginisialisasi semua port yang digunakan ddrB = 0; portB = 0; ddrD = 0; portD = 0; // menginisialisasi tombol - ke input dengan pull-up portButton = 1; //menginisialisasi LED, yang menyala dengan 0 dan dengan menekan tombol - ke output dan ke 1 portLight = 1; interupsi eksternal MCUCR.ISC00 = 0; //interupsi dihasilkan oleh logika 0 pada INT0 MCUCR.ISC01 = 0; //aktifkan interupsi eksternal INT0 asm sei;//SREG.B7 = 1; interupsi pada prinsipnya (bit I); perintahnya sama dengan while(1) ( buttonLight() ; ) )

Sedikit tentang sintaksis. Fungsi interupsi ditulis seperti ini: void function_name() org IVT_ADDR_INT0.

Kata kunci org menunjukkan bahwa alamat interupsi dari lembar data akan muncul berikutnya. Kami mendapatkan nama interupsi dari perpustakaan: kami mengetik IVT lalu tekan Ctrl + Spasi (Saya suka hal-hal seperti itu ˆˆ). Anda juga dapat menggunakan iv sebagai pengganti kata org, dilihat dari bantuan kompiler.

Catatan kecil lainnya: pertama, interupsi tidak boleh rumit - beberapa baris dan hanya itu. Hal ini disebabkan oleh fakta bahwa ketika memproses sebuah interupsi, sirkuit mikro tidak dapat diganggu oleh hal lain, yang berarti bahwa jika kita memiliki beberapa interupsi, maka kita dapat melewatkan terjadinya suatu peristiwa.

Mungkin juga kita tidak memerlukan pemrosesan interupsi sama sekali - misalnya, sirkuit cukup bangun dari mode tidur. Namun dalam kasus ini, Anda masih perlu menulis fungsi interupsi, bahkan fungsi kosong - yang disebut "stub". Pada prinsipnya, beberapa kompiler secara otomatis menulis fungsi kosong untuk setiap interupsi, tetapi ini bukan kasus kami - kami harus melakukannya secara manual.

Apa yang dimaksud dengan interupsi pada mikrokontroler? Ini adalah saat mikrokontroler dipaksa untuk bereaksi terhadap suatu peristiwa. Misalnya, ini seperti jam alarm biasa: berdetak pelan di sudut, tidak mengganggu siapa pun, dan secara umum semua orang sudah melupakannya... Namun tiba-tiba pada waktu tertentu jam itu mulai berdering.

Berikut ini contoh dari kehidupan sehari-hari - Anda sedang duduk di dapur, minum teh dengan selai raspberry dan menunggu tamu. Bagaimana Anda tahu bahwa seseorang telah tiba? Ada dua pilihan: kita akan teralihkan dari kemacetan (dalam arti teh) setiap lima menit dan berlari untuk memeriksa apakah ada orang yang berdiri di depan pintu, atau membeli bel pintu dan dengan tenang menunggu di tempat yang panas sampai seseorang membunyikannya. .

Jadi, ketika ada tamu yang menelepon, ini adalah sebuah acara. Oleh karena itu, kami berhenti dan bergegas ke pintu.

Jadi, sirkuit mikro punya menyela. Dan lebih dari satu. Interupsi dibagi menjadi eksternal - ini dipicu pada tegangan tertentu pada beberapa pin sirkuit mikro (INT0, INT1 dan terkadang seluruh port PCINT) - dan internal - ketika penghitung meluap, pengatur waktu pengawas dipicu, saat menggunakan USART, ketika komparator analog, ADC dan periferal lainnya terganggu.

Oleh karena itu, timbul masalah prioritas. Ini seperti kita masih duduk dan minum teh, tetapi mereka tidak hanya membunyikan bel pintu kita, tetapi juga telepon kita... Dan Anda tidak dapat terkoyak, ada yang perlu dilakukan terlebih dahulu. Oleh karena itu, lembar data berisi tabel vektor interupsi. Semakin rendah angka interupsi, semakin tinggi prioritasnya.

Ada beberapa kehalusan di sini...

Suatu peristiwa terjadi - permintaan interupsi dikirim, yaitu, apa yang disebut "bendera permintaan interupsi" disetel. Jika semuanya baik-baik saja, gangguan teratasi, maka hidup ini indah dan berproses.

Namun jika interupsi dinonaktifkan - misalnya, interupsi dengan prioritas lebih tinggi sedang diproses - maka tanda permintaan ini akan tetap hang hingga interupsi diaktifkan. Setelah ini, chip memeriksa register permintaan dalam urutan prioritas, dan jika ada tanda, memprosesnya.

TETAPI! Ternyata meskipun interupsi sudah diproses, bukan fakta bahwa peristiwa yang menyebabkannya masih hidup... Ibarat bel pintu dan telepon berbunyi bersamaan, Anda menjawab telepon, dan para tamu sudah memutuskan bahwa tidak ada seorang pun di rumah dan pergi. Dan sepertinya ada acara – bel pintu berbunyi, tapi tidak ada orang di balik pintu.

Masalah lainnya adalah ketika interupsi lain sedang diproses dan flag permintaan sudah dikibarkan, kejadian tersebut dapat terjadi beberapa kali lagi. Kami menjawab panggilan telepon, membuka pintu - dan sudah ada banyak tamu di sana! Menakutkan? Menakutkan...

Fitur lain dari penggunaan interupsi - dan bukan hanya interupsi: masuk kembali (atau masuk kembali).

Program reentrant adalah program yang dapat dipanggil oleh banyak pengguna (atau proses) tanpa, minimal, menyebabkan kesalahan dan, maksimal, tidak menyia-nyiakan komputasi—misalnya, pengguna lain tidak perlu menjalankan kode lagi.

Dengan kata lain, jika di dapur saat Anda menyambut tamu, tidak ada yang mencuri barang, maka semuanya masuk kembali)

Secara umum, ini adalah hal yang serius - jika Anda tidak memperhitungkannya, Anda dapat menderita untuk waktu yang lama dengan pertanyaan "mengapa tidak berhasil?!" Hal ini perlu diperhitungkan, misalnya jika beberapa interupsi diproses, dan masing-masing interupsi mengubah beberapa variabel global...

Interupsi biasanya TIDAK masuk kembali. Artinya, pada saat operasi interupsi, interupsi yang sama tidak dapat dipanggil lagi. Hal ini untuk melindungi dari masuknya kembali ke dalam handler maka interupsi secara otomatis dinonaktifkan pada saat pemrosesannya. (jika Anda ingin mengaktifkan interupsi dalam rutinitas penanganan interupsi, Anda perlu berpikir sepuluh, dua puluh kali sebelum mengambil langkah gegabah.)

Mari kita pertimbangkan untuk bekerja dengan interupsi eksternal: pertama, kita perlu mengonfigurasi peristiwa mana yang akan memicu interupsi, dan, kedua, mengizinkan sirkuit mikro untuk memproses interupsi ini.

Register MCUCR bertanggung jawab atas bit pertama dalam chip ATmega8 - ISC11-ISC10, bertanggung jawab atas INT1, dan ISC01-ISC00, bertanggung jawab atas INT0.

Oleh karena itu, sama halnya dengan INT0.

Sekarang yang tersisa hanyalah mengaktifkan interupsi pada pin yang kita perlukan - register GIGR memiliki bit INT0 dan INT1; atur ke "1" yang diinginkan - dan interupsi eksternal diaktifkan! Namun masih terlalu dini untuk bersukacita - selain interupsi eksternal, interupsi secara umum harus diaktifkan - setel bit paling kiri I dari register SREG ke "1". Hal yang sama dapat dilakukan dengan perintah assembler: asm sei;

Mari kita lihat contoh sederhana: sebuah tombol dipasang ke pin INT0 (D.2) dari chip ATmega8 (ke pin dan ke nol); tekan - terjadi interupsi dan LED pada pin B.0 menyala. Oleh karena itu, LED terhubung ke kaki dan ke unit:

Sedikit tentang sintaksis. Fungsi interupsi ditulis seperti ini: void function_name() org IVT_ADDR_INT0.

Kata kunci org menunjukkan bahwa alamat interupsi dari lembar data akan muncul berikutnya. Kami mendapatkan nama interupsi dari perpustakaan: kami mengetik IVT lalu tekan Ctrl + Spasi (Saya suka hal-hal seperti itu ˆˆ). Anda juga dapat menggunakan iv sebagai pengganti kata org, dilihat dari bantuan kompiler.

Catatan kecil lainnya: pertama, interupsi tidak boleh rumit - beberapa baris dan hanya itu. Hal ini disebabkan oleh fakta bahwa ketika memproses sebuah interupsi, sirkuit mikro tidak dapat diganggu oleh hal lain, yang berarti bahwa jika kita memiliki beberapa interupsi, maka kita dapat melewatkan terjadinya suatu peristiwa.

Mungkin juga kita tidak memerlukan pemrosesan interupsi sama sekali - misalnya, sirkuit cukup bangun dari mode tidur. Namun dalam kasus ini, Anda masih perlu menulis fungsi interupsi, bahkan fungsi kosong - yang disebut "stub". Pada prinsipnya, beberapa kompiler secara otomatis menulis fungsi kosong untuk setiap interupsi, tetapi ini bukan kasus kami - kami harus melakukannya secara manual.

Pertama-tama, apa itu interupsi?
Interupsi adalah sejenis fungsi yang akan dieksekusi ketika sinyal tiba di beberapa input pengontrol.
Saat bekerja di AVR Studio, interupsi dibuat menggunakan makro ISR() , SINYAL() Dan MENGGANGGU(). Mereka menandai beberapa fungsi sebagai pengendali interupsi. Perbedaan mereka adalah itu MENGGANGGU() Dan ISR() tentukan fungsi penangan untuk kasus ketika interupsi umum diaktifkan (penangan dapat diinterupsi), dan SINYAL() untuk kasus ketika gangguan umum dinonaktifkan.

Dengan ini, mari kita selesaikan teorinya dan beralih ke praktik (walaupun akan ada lebih banyak teori di bawah).
Mari kita buat diagram berikut di ISIS:

Seperti yang mungkin sudah Anda duga, kami akan menulis interupsi (yang dihasilkan oleh sebuah tombol) yang akan menyala dan mematikan dioda.
Jadi, buka studio dan buat proyek standar.
Untuk menggunakan interupsi, sertakan file header:

#termasuk

Mari kita sepakat bahwa interupsi (secara fisik) tidak akan menghidupkan atau mematikan daya pada kaki pengontrol (seperti yang telah saya anggap sudah dilakukan), tetapi hanya akan mengubah bendera. Pada nilai tertentu dioda akan hidup dan mati.
Mari kita atur tanda ini secara global:

Int angka = 1;

Sekarang mari kita nyatakan interupsi:

ISR(SIG_INTERRUPT1)( jika (angka == 1) angka = 0; jika tidak angka = 1; )

Seperti yang Anda lihat, apa yang disebut vektor interupsi ditunjukkan dalam tanda kurung makro. Vektor ini memberi tahu kompiler input mana yang akan menghasilkan interupsi. Untuk INT1 adalah SIG_INTERRUPT1. Untuk ADC, misalnya, ini adalah SIG_ADC. (seluruh daftar dijelaskan dengan sempurna dalam buku “Pemrograman Shpak Yu.A. dalam C untuk mikrokontroler AVR dan PIC.”)
Sekarang mari kita beralih ke fungsi utama “program” kita.
Kita perlu mengaktifkan interupsi secara umum dan untuk INT1 khususnya:

sei(); // secara umum GIMSK |= (1<

Setelah ini selesai, Anda perlu mengkonfigurasi perilaku interupsi. Itu dapat dihasilkan dengan berbagai cara.
Unduh datasheet (ada tautan saat membuat proyek) dan temukan tabel berikut di bagian interupsi:

Saya pikir Anda akan mengerti bagaimana menerjemahkannya.
Mari kita atur status pembangkitan interupsi untuk setiap "perubahan logis ke INT1".

MCUCR = (0<

Sekarang mari kita atur seluruh port C sebagai output:

DDRC = 0xff; // port C - keluaran

Nah, ini seharusnya sudah jelas:

While (1)( if (num == 1) PORTC |= 1; // nyalakan keluaran pertama C else PORTC &= ~1; // matikan keluaran pertama C _delay_ms(100); // tunggu 100ms )

Tidak perlu menunggu. Selain itu, hal ini mengurangi kinerja. Tapi aku ingin seperti itu.
Keseluruhan program:

#define F_CPU 8000000UL // 8MHz #termasuk #termasuk #termasuk int angka = 1; ISR(SIG_INTERRUPT1)( if (num == 1) num = 0; else num = 1; ) int main (void)( sei(); GIMSK |= (1<

Kami mengkompilasi hex dan merakit sirkuit di Proteus. Kami menikmati fungsi interupsi saat mengubah posisi tombol.

Hari ini kita akan melihat konsep interupsi dan cara menggunakannya. Tentu saja, kami tidak dapat melakukannya tanpa program pelatihan, tetapi kali ini kami tidak akan mengedipkan LED. Sudah bagus. Mari kita membuat sesuatu seperti bel pintu.

Tugas: membuat mikrokontroler mengeluarkan bunyi bip saat menekan tombol.
Diagram untuk contoh kita. File proyek.

Kami membuat proyek cincin di ruang kerja lama.
Tetapkan pengaturan proyek untuk konfigurasi Rilis:

Pilih jenis mikrokontroler.
Opsi Umum > Target > Konfigurasi prosesor
Saya punya ATmega8535 ini.

Izinkan penggunaan nama bit yang ditentukan dalam file header
Di Opsi Umum > Sistem, centang kotak Aktifkan definisi bit di I/O-Sertakan file
Kami belum menggunakan nama bit sejauh ini, tapi hari ini kami membutuhkannya.

Ubah jenis file keluaran.
Tautan > Keluaran.
Di kolom Output file, centang kotak Override default dan ganti ekstensi d90 dengan hex
Di bidang Format, pilih Lainnya dan di menu tarik-turun Format keluaran, pilih jenis file intel-standart

Simpan proyek dan ruang kerja.

________________ Interupsi ___________________________

Bayangkan situasinya. Anda sedang duduk di tempat kerja dan mempelajari program mikrokontroler lainnya. Bos mendatangi Anda dan berkata: “Dengar, Pash, kami membeli osiloskop untuk departemen kami - Tektronix, empat saluran. Bantu Vasya menyeret mereka.” Anda berpikir: “Ya ampun, hanya pikiran itu saja yang menghalangi... dan menimpa Anda.” Dan bosnya memandang Anda seperti itu, dan matanya sangat baik, sangat baik. Bagaimana kamu bisa menolaknya? Nah, Anda meninggalkan semuanya dan pergi bersama seorang teman untuk membeli osiloskop. Mereka membawanya masuk. Kami telah melaporkan. Dan mereka duduk untuk program mereka lagi. Kira-kira seperti inilah mekanisme interupsinya.

Cukup sederhana, tetapi ada beberapa poin mendasar.
Pertama:
- kamu melakukan pekerjaanmu
- pada saat yang sama, seseorang sedang membeli osiloskop
- setelah terjadinya peristiwa "osiloskop dibeli" - Anda menghentikan pekerjaan Anda
- untuk beberapa waktu Anda melakukan pekerjaan lain - membawa osiloskop
- kemudian Anda kembali ke tempat kerja Anda dan melanjutkan pekerjaan Anda dari bagian terakhir yang Anda tinggalkan

Kedua:
- Anda dapat dengan mudah mengirim atasan Anda dan tidak pergi kemana-mana
- setelah berangkat ke osiloskop, Anda bisa tinggal di sana untuk waktu yang lama, atau bahkan tidak kembali sama sekali
- ketika Anda kembali ke tempat kerja, Anda mungkin sudah melupakan ide cemerlang Anda

Ini semua sangat mirip dengan apa yang terjadi di mikrokontroler. Mikrokontroler AVR mencakup sejumlah perangkat periferal (pengatur waktu/penghitung, konverter analog-ke-digital, komparator analog, transceiver asinkron... dll.). Kekuatan mikrokontroler adalah semua perangkat ini dapat bekerja secara paralel dan independen satu sama lain, serta paralel dengan program yang dijalankan. Setiap perangkat periferal dapat memicu interupsi ketika peristiwa tertentu terjadi. Interupsi hanya akan terjadi jika diaktifkan. Pengaktifan interupsi diatur untuk setiap perangkat secara terpisah. Selain itu, ada flag aktif/nonaktif global untuk semua interupsi - ini adalah flag I di register SREG. Ketika terjadi interupsi, mikrokontroler menyimpan isi penghitung program PC di stack, yaitu mengingat tempat di mana interupsi tersebut terjadi. Memuat alamat vektor interupsi yang sesuai ke dalam penghitung program dan melompat ke alamat tersebut. Itu mengenai perintah lompat tanpa syarat, yang menuju ke subrutin pemrosesan interupsi. Menonaktifkan interupsi dengan menyetel ulang bendera I, menjalankan subrutin. Setelah menjalankan rutinitas penanganan interupsi, mikrokontroler mengaktifkan interupsi dengan menyetel flag I dan mengembalikan konten penghitung program, yaitu kembali ke tempat yang sama dalam program di mana ia diinterupsi.

Secara teori, pengendali interupsi tidak boleh merusak isi register mikrokontroler, karena mungkin berisi data dari program yang sedang dijalankan. Untuk melakukan ini, pada awal subrutin penanganan interupsi, isi register mikrokontroler disimpan di tumpukan, dan pada akhir subrutin dikembalikan. Dengan demikian, setelah keluar dari interupsi, mikrokontroler akan dapat terus menjalankan program seolah-olah tidak terjadi apa-apa. Saat memprogram dalam assembler, programmer sendiri yang mengatur penyimpanan register; di C, ini dilakukan oleh kompiler.

_______________________________________________________________

Sekarang mari kita bicara tentang pengatur waktu. ATmega8535 memiliki tiga pengatur waktu/penghitung - dua delapan bit (T0, T2) dan satu enam belas bit (T1). Kami akan menggunakan pengatur waktu/penghitung delapan bit T0. Timer ini terdiri dari tiga register - register kontrol TCCR0, register penghitungan TCNT0, dan register perbandingan OCR0. Ketika pengatur waktu dimulai, register penghitung TCNT0 meningkatkan nilainya sebesar satu untuk setiap tepi jam. Frekuensi jam dipilih dari beberapa kemungkinan nilai dalam register kontrol TCCR0. Juga, dengan menggunakan register ini, mode pengoperasian pengatur waktu diatur. Timer T0 dapat memicu interupsi ketika peristiwa "melimpah" terjadi - ini adalah saat register penghitung TCNT0 meluap dan ketika peristiwa "kebetulan" terjadi - ini adalah saat nilai register penghitung TCNT0 menjadi sama dengan nilainya dari register perbandingan OCR0. Flag yang mengaktifkan interupsi ini terletak di register TIMSK.
Kami akan mengonfigurasi pengatur waktu/penghitung T0 untuk memicu interupsi peristiwa "kecocokan" pada 5 kHz. Pada fungsi handler kita akan membalikkan keadaan output mikrokontroler yang terhubung dengan speaker piezo. Dengan demikian, frekuensi bunyi piezo akan menjadi 2,5 kHz. (Yang terhubung piezospeaker! Jangan bingung. Resistansi piezospeaker tergantung pada frekuensi dan pada 2,5 KHz biasanya satuan Com, sehingga dapat dihubungkan ke output mikrokontroler secara langsung, tanpa resistor pembatas) .

Sekarang tentang programnya. Tidak mungkin lagi menulis program baris demi baris, jadi saya akan segera memberikan teksnya. Di bawah ini kami akan menganalisis semua lininya satu per satu, dan semuanya akan menjadi jelas. Saya sengaja tidak menggunakan makro; programnya kecil dan saya tidak ingin mengacaukannya.

ke dalam utama( ruang kosong )
{
//mengatur port I/O
DDRD = (0<PELABUHAN = (1<

//atur pengatur waktu T0
TCCR0 = (1<TCNT0 = 0;
OCR0 = 0xc8;

//aktifkan interupsi
__aktifkan_interupsi();

//loop program utama – melakukan polling pada tombol
ketika(1){
jika((PIND & (1<TIMSK = (1<kalau tidak
TIMSK = 0;
}
kembali 0;
}

//penanganan interupsi untuk pengatur waktu T0

__mengganggu ruang kosong Timer0CompVect( ruang kosong)
{
PORTD ^= (1<}

Pengaturan pelabuhan

Di sirkuit kami, sebuah tombol dan speaker piezo terhubung ke port D. Pin yang menghubungkan tombol harus dikonfigurasi sebagai input dan resistor pull-up harus dihidupkan. Pin yang terhubung dengan speaker piezo harus disetel ke output.

DDRD = (0<PELABUHAN = (1<

Mengatur pengatur waktu

Mode pengoperasian pengatur waktu T0 adalah CTC (reset secara kebetulan), sinyal jam adalah clk/8. Kami mencerminkan hal ini dalam register TCCR0

TCCR0 = (1<

Untuk jaga-jaga, kami mereset register penghitungan TCNT0

Tulis 0xc8 ke register perbandingan OCR0. Mengapa? Karena saya menghitungnya kalkulator. Nah, di atas kertas perhitungannya seperti ini.
Frekuensi jam mikrokontroler 8 MHz
Sinyal jam pengatur waktu adalah 8000000 Hz/8 = 1000000 Hz.
Waktu satu jam pengatur waktu 1/1000000 = 1 µs
Waktu satu siklus frekuensi yang kita perlukan adalah 1/5000 Hz = 200 μs
Berapa banyak detak pengatur waktu yang cocok dalam 200 µs? 200/1 = 200 kutu
200 dalam heksadesimal = 0xc8

Untuk penjelasan rinci tentang pengatur waktu T0, lihat dokumentasi untuk ATMega8535.

Kami telah mengonfigurasi pengatur waktu dan mengaktifkan interupsi umum menggunakan fungsi bawaan.

__aktifkan_interupsi();

Tombol jajak pendapat

Ketika tombol tidak ditekan, keluaran mikrokontroler dihubungkan ke daya melalui resistor pull-up internal, yaitu ada satu pada keluaran; ketika tombol ditekan, keluarannya dihubung pendek ke ground, yaitu ada adalah nol pada keluarannya. Untuk menentukan apakah suatu tombol ditekan, Anda perlu membaca isi register PIND dan memeriksa nilai bit nol (tombol terhubung ke PD0). Kami akan melakukan polling tombol dalam putaran tanpa akhir.

ketika (1)
{
jika((PIND & (1<//jika tombol ditekan, mikrokontroler akan berbunyi
}
kalau tidak {
//jika tidak, diamlah seperti ikan
}
}

Jangan lupa == bukan operator penugasan =.

Tombol penanganan tekan/lepas

Dengan menekan tombol tersebut kita akan mengaktifkan interupsi pengatur waktu T0, dan dengan melepaskannya kita akan menonaktifkannya. Untuk melakukan ini, kita akan memanipulasi bit OCIE0 dari register TIMSK

TIMSK = (1<// izinkan gangguan pada pengatur waktu T0 karena kejadian yang kebetulan

TIMSK = 0; //menonaktifkan interupsi

Karena kita hanya menggunakan satu pengatur waktu, tidak perlu menyetel atau menyetel ulang bit satu per satu.

Fungsi interupsi

_____________________ Sintaks fungsi interupsi _____________________

Fungsi interupsi ditentukan menggunakan direktif #pragma vector= dan kata fungsi __mengganggu. Fungsi tersebut harus bertipe void dan tidak boleh menggunakan parameter apa pun.

#pragma vektor = Alamat
__mengganggu ruang kosong Nama( ruang kosong)
{
//kode kita terletak di sini
}

Nama– nama fungsi, pilih sesuai kebijaksanaan kami
Alamat– alamat vektor interupsi, dapat ditentukan berdasarkan nomor, atau dengan nama yang ditentukan dalam file header mikrokontroler (iom8535.h – bagian Definisi Vektor Interupsi)

______________________________________________________________

Untuk tugas kita, fungsi pengendali interupsi terlihat seperti ini

#pragma vektor = TIMER0_COMP_vect
__mengganggu ruang kosong Timer0CompVect( ruang kosong)
{
PORTD ^= (1<//membalikkan sinyal pada pin PD1
}

Ya, itu saja. Saya harap semuanya jelas.
Pada artikel selanjutnya kita akan membuat mikrokontroler memainkan melodi.

  • Sergei Savenkov

    semacam ulasan "pendek"... seolah-olah mereka sedang terburu-buru di suatu tempat