β Bagian 3. Pengalamatan tidak langsung dan kontrol aliran
Bagian 5. Merancang aplikasi multi-utas. β
Perpustakaan Generator Kode Assembler untuk Mikrokontroler AVR
Bagian 4. Memprogram perangkat dan menangani gangguan
Di bagian posting ini, kami, seperti yang dijanjikan, akan menangani salah satu aspek paling populer dari pemrograman mikrokontroler - yaitu, bekerja dengan perangkat periferal. Ada dua pendekatan yang paling umum untuk pemrograman periferal. Pertama, sistem pemrograman tidak tahu apa-apa tentang perangkat periferal dan hanya menyediakan sarana akses ke port kontrol perangkat. Pendekatan ini praktis tidak berbeda dengan bekerja dengan perangkat pada tingkat assembler dan memerlukan studi menyeluruh tentang tujuan semua port yang terkait dengan pengoperasian perangkat periferal tertentu. Untuk memudahkan pekerjaan pemrogram, ada program khusus, tetapi bantuan mereka, sebagai suatu peraturan, berakhir dengan pembuatan urutan inisialisasi perangkat awal. Keuntungan dari pendekatan ini adalah akses penuh ke semua kemampuan periferal, dan kerugiannya adalah kompleksitas pemrograman dan banyaknya kode program.
Pekerjaan kedua dengan perangkat periferal dilakukan pada tingkat perangkat virtual. Keuntungan utama dari pendekatan ini adalah kesederhanaan manajemen perangkat dan kemampuan untuk bekerja dengan mereka tanpa mempelajari implementasi perangkat keras tertentu. Kelemahan dari pendekatan ini adalah keterbatasan kemampuan perangkat periferal dengan tujuan dan fungsi dari perangkat virtual yang ditiru.
Perpustakaan NanoRTOS mengimplementasikan pendekatan ketiga. Setiap perangkat periferal dijelaskan oleh kelas khusus, yang tujuannya adalah untuk menyederhanakan pengaturan dan pengoperasian perangkat sambil mempertahankan fungsionalitas penuhnya. Lebih baik menunjukkan fitur pendekatan ini menggunakan contoh, jadi mari kita mulai.
Mari kita mulai dengan perangkat periferal paling sederhana dan paling umum - port input / output digital. Port ini menggabungkan hingga 8 saluran, yang masing-masing dapat dikonfigurasi secara independen untuk input atau output. Klarifikasi ke 8 berarti bahwa arsitektur pengontrol menyiratkan kemungkinan menetapkan fungsi alternatif untuk bit port individual, yang mengecualikan penggunaannya sebagai port air / output, sehingga mengurangi jumlah bit yang tersedia. Pengaturan dan pekerjaan lebih lanjut dapat dilakukan pada level bit yang terpisah, dan pada level port secara keseluruhan (menulis dan membaca semua 8 bit dengan satu perintah). Pengontrol Mega328 yang digunakan dalam contoh memiliki 3 port: B, C, dan D. Pada kondisi awal, dari sudut pandang perpustakaan, debit semua port netral. Ini berarti bahwa untuk aktivasi mereka perlu menunjukkan mode penggunaannya. Jika ada upaya untuk mengakses port yang tidak diaktifkan, program akan menghasilkan kesalahan kompilasi. Ini dilakukan untuk menghilangkan kemungkinan konflik saat menetapkan fungsi alternatif. Untuk mengalihkan port ke mode input / output, gunakan perintah Mode untuk mengatur mode single-bit, dan Direction untuk mengatur mode semua bit port dengan satu perintah. Dari sudut pandang pemrograman, semua port adalah sama dan perilakunya dijelaskan oleh satu kelas.
var m = new Mega328(); m.PortB[0].Mode = ePinMode.OUT;
Contoh di atas menunjukkan bagaimana output data melalui port dapat diatur. Bekerja dengan port B di sini dilakukan pada level satu kategori, dan dengan port C di level port, secara keseluruhan. Perhatikan perintah Aktivasi () . Tujuannya adalah untuk menghasilkan dalam kode output urutan perintah inisialisasi perangkat sesuai dengan properti yang ditetapkan sebelumnya. Dengan demikian, perintah Activate () selalu menggunakan set parameter yang ditetapkan saat ini pada saat eksekusi. Pertimbangkan contoh membaca data dari port.
m.PortB.Activate();
Dalam contoh ini, tipe data Bit baru telah muncul. Analog terdekat dari tipe ini dalam bahasa tingkat tinggi adalah tipe bool . Tipe data Bit digunakan untuk menyimpan hanya satu bit informasi dan memungkinkan nilainya untuk digunakan sebagai kondisi dalam operasi percabangan. Untuk menghemat memori, variabel bit selama penyimpanan digabungkan ke dalam blok sedemikian rupa sehingga satu register RON digunakan untuk menyimpan 8 variabel tipe Bit . Selain tipe yang dijelaskan, pustaka berisi dua tipe data bit: Pin , yang memiliki fungsi yang sama dengan Bit, tetapi menggunakan register IO dan Mbit untuk menyimpan variabel bit dalam memori RAM. Mari kita lihat bagaimana Anda bisa menggunakan variabel bit untuk mengatur cabang
m.IF(m.PortB[0], () => AVRASM.Comment(", = 1")); var b = m.BIT(); b.Set(); m.IF(b, () => AVRASM.Comment(", b "));
Baris pertama memeriksa status port input, dan jika pada input 1, kode blok bersyarat dijalankan. Baris terakhir berisi contoh di mana variabel tipe Bit digunakan sebagai kondisi percabangan.
Perangkat periferal umum dan yang sering digunakan berikutnya dapat dianggap sebagai penghitung / penghitung perangkat keras. Dalam mikrokontroler AVR, perangkat ini memiliki serangkaian fungsi besar dan, tergantung pada pengaturannya, dapat digunakan untuk menghasilkan penundaan, menghasilkan berliku-liku dengan frekuensi yang dapat diprogram, mengukur frekuensi sinyal eksternal, dan juga sebagai modulator PWM multimode. Tidak seperti port I / O, masing-masing timer Mega328 memiliki serangkaian fitur unik. Oleh karena itu, setiap timer dijelaskan oleh kelas yang terpisah.
Mari kita pertimbangkan secara lebih detail. Sebagai sumber sinyal setiap timer, sinyal eksternal dan jam internal prosesor dapat digunakan. Pengaturan perangkat keras mikrokontroler memungkinkan Anda untuk mengonfigurasikan penggunaan frekuensi penuh untuk perangkat periferal, atau mengaktifkan splitter tunggal untuk semua perangkat periferal hingga 8. Karena mikrokontroler memungkinkan operasi dalam rentang frekuensi yang luas, perhitungan nilai pembagi pengatur waktu yang tepat untuk penundaan yang diperlukan selama pencatatan waktu internal memerlukan menentukan frekuensi prosesor. dan mode prescaler. Dengan demikian, bagian pengaturan waktu mengambil bentuk berikut
var m = new Mega328(); m.FCLK = 16000000;
Jelas, pengaturan timer memerlukan mempelajari dokumentasi pabrikan untuk memilih mode yang benar dan memahami tujuan dari berbagai pengaturan, tetapi menggunakan perpustakaan membuat bekerja dengan perangkat lebih mudah dan lebih dimengerti, sambil tetap mempertahankan kemampuan untuk menggunakan semua mode perangkat.
Sekarang saya sarankan sedikit gangguan dari deskripsi penggunaan perangkat tertentu dan sebelum melanjutkan, diskusikan masalah operasi asinkron. Keuntungan utama dari perangkat periferal adalah mereka dapat melakukan fungsi-fungsi tertentu tanpa menggunakan sumber daya CPU. Kompleksitas dapat muncul dalam organisasi interaksi antara program dan perangkat, karena peristiwa yang terjadi selama pengoperasian perangkat periferal tidak sinkron sehubungan dengan aliran eksekusi kode dalam CPU. Metode interaksi sinkron, di mana program mengandung siklus untuk menunggu status perangkat yang diinginkan, meniadakan hampir semua keuntungan pinggiran sebagai perangkat independen. Lebih efisien dan disukai adalah mode interrupt. Dalam mode ini, prosesor terus mengeksekusi kode utas utama, dan ketika peristiwa terjadi, mengalihkan utas eksekusi ke penangannya. Pada akhir pemrosesan, kontrol kembali ke utas utama. Kelebihan dari pendekatan ini jelas, tetapi penggunaannya mungkin rumit oleh kompleksitas pengaturan. Di assembler, untuk menggunakan interupsi, Anda harus:
- atur alamat yang benar di tabel interupsi,
- konfigurasikan perangkat itu sendiri untuk bekerja dengan gangguan,
- Jelaskan fungsi penanganan interupsi
- menyediakan untuk pelestarian semua register dan bendera yang digunakan di dalamnya sehingga interupsi tidak mempengaruhi kemajuan utas utama
- aktifkan interupsi global.
Untuk menyederhanakan pemrograman kerja melalui interupsi, kelas-kelas deskripsi perangkat periferal perpustakaan berisi properti-event dari pengendali event. Pada saat yang sama, untuk mengatur pekerjaan dengan perangkat periferal melalui interupsi, Anda hanya perlu menjelaskan kode untuk memproses acara yang diperlukan, dan perpustakaan akan melakukan semua pengaturan lain secara independen. Mari kita kembali ke pengaturan timer dan menambahkannya dengan definisi kode yang harus dieksekusi ketika ambang batas untuk membandingkan saluran perbandingan timer tercapai. Misalkan kita ingin bahwa ketika ambang batas saluran perbandingan dipicu, bit tertentu dari port I / O diatur ulang ketika meluap. Dengan kata lain, kami ingin mengimplementasikan, menggunakan timer, fungsi menghasilkan sinyal PWM pada port yang dipilih sembarang dengan siklus tugas yang ditentukan oleh nilai-nilai OCRA untuk yang pertama dan OCRB untuk saluran kedua. Mari kita lihat bagaimana kode akan terlihat dalam kasus ini.
var m = new Mega328(); m.FCLK = 16000000; m.CKDIV8 = false; var bit1 = m.PortB[0]; bit1.Mode = ePinMode.OUT; var bit2 = m.PortB[1]; bit2.Mode = ePinMode.OUT; m.PortB.Activate();
Bagian tentang pengaturan mode timer telah dipertimbangkan sebelumnya, jadi mari kita beralih ke penangan interupsi segera. Dalam contoh tersebut, tiga penangan digunakan untuk mengimplementasikan dua saluran PWM menggunakan satu pengatur waktu. Kode penangan cukup jelas, tetapi pertanyaan mungkin timbul bagaimana penghematan negara yang disebutkan sebelumnya diimplementasikan sehingga panggilan interupsi tidak mempengaruhi logika utas utama. Solusinya, di mana semua register dan bendera disimpan, terlihat jelas berlebihan, oleh karena itu perpustakaan menganalisis penggunaan sumber daya dalam interupsi dan menyimpan hanya minimum yang diperlukan. Loop utama kosong mengonfirmasi gagasan bahwa tugas untuk terus menghasilkan beberapa sinyal PWM bekerja tanpa partisipasi dari program utama.
Perlu dicatat bahwa perpustakaan mengimplementasikan pendekatan terpadu untuk bekerja dengan interupsi untuk semua kelas deskripsi perangkat periferal. Ini menyederhanakan pemrograman dan mengurangi kesalahan.
Kami akan terus mempelajari pekerjaan dengan interupsi dan mempertimbangkan situasi di mana mengklik tombol yang terpasang pada port input akan menyebabkan tindakan tertentu pada bagian program. Dalam prosesor yang kami pertimbangkan, ada dua cara untuk menghasilkan interupsi ketika kondisi port input berubah. Yang paling canggih adalah penggunaan mode interupsi eksternal. Dalam hal ini, kami dapat menghasilkan interupsi terpisah untuk masing-masing kesimpulan dan mengkonfigurasi reaksi hanya untuk peristiwa tertentu (depan, resesi, level). Sayangnya, hanya ada dua di kristal kami. Metode lain memungkinkan Anda untuk mengontrol dengan cara menginterupsi salah satu bit dari port input, tetapi pemrosesan lebih rumit karena fakta bahwa peristiwa terjadi pada level port ketika sinyal input dari salah satu bit yang dikonfigurasi berubah, dan klarifikasi lebih lanjut dari penyebab interupsi harus dilakukan pada level algoritma oleh perangkat lunak .
Sebagai ilustrasi, kami akan mencoba memecahkan masalah mengendalikan keadaan output port menggunakan dua tombol. Salah satunya harus mengatur nilai port yang ditunjukkan oleh kami ke 1, dan yang lainnya reset. Karena hanya ada dua tombol, kami akan menggunakan kesempatan untuk menggunakan interupsi eksternal.
var m = new Mega328(); m.PortD[0].Mode = ePinMode.OUT; m.PortD.Write(0x0C);
Menggunakan interupsi eksternal memungkinkan kami untuk memecahkan masalah kami sesederhana dan sejelas mungkin.
Mengelola port eksternal secara terprogram bukan satu-satunya cara yang mungkin. Terutama, timer memiliki pengaturan yang memungkinkan mereka untuk mengontrol output mikrokontroler secara langsung. Untuk melakukan ini, dalam pengaturan timer, Anda harus menentukan mode kontrol output
m.Timer0.CompareModeA = eCompareMatchMode.Set;
Setelah mengaktifkan timer, bit 6 port D akan menerima fungsi alternatif dan akan dikontrol oleh timer. Dengan demikian, kami dapat menghasilkan sinyal PWM pada output prosesor murni pada tingkat perangkat keras, menggunakan perangkat lunak hanya untuk mengatur parameter sinyal. Pada saat yang sama, jika kita mencoba menggunakan alat pustaka untuk beralih ke port sibuk sebagai port input / output, kita akan mendapatkan kesalahan di tingkat kompilasi.
Perangkat terakhir yang akan kita lihat di bagian artikel ini adalah port serial USART. Fungsionalitas perangkat ini sangat luas, tetapi sejauh ini kami hanya akan menyentuh salah satu kasus penggunaan yang paling umum untuk perangkat ini.
Kasing penggunaan paling populer untuk port ini adalah menghubungkan terminal serial ke input / output informasi teks. Bagian dari kode mengenai pengaturan port dalam kasus ini mungkin terlihat sebagai berikut
m.FCLK = 16000000;
Pengaturan yang ditentukan bertepatan dengan pengaturan default USART di perpustakaan, oleh karena itu, mereka dapat dilewati sebagian atau seluruhnya dalam teks program.
Pertimbangkan contoh kecil di mana kita menampilkan teks statis ke terminal. Agar tidak mengembang kode, kami membatasi diri pada output ke terminal klasik "Halo dunia!" di awal program.
var m = new Mega328(); var ptr = m.ROMPTR();
Dalam program ini, dari yang baru, deklarasi str string konstan. Perpustakaan menempatkan semua variabel konstan dalam memori program, oleh karena itu, untuk bekerja dengannya, Anda harus menggunakan penunjuk ROMPtr . Output data ke terminal dimulai dengan output dari karakter pertama dari urutan string, setelah itu kontrol langsung menuju loop utama, tanpa menunggu akhir output. Penyelesaian proses transfer byte menyebabkan interupsi, di mana pawang yang membaca karakter berikutnya dari baris. Jika karakter tidak sama dengan 0 (perpustakaan menggunakan format nol-dihentikan untuk menyimpan string), karakter ini dikirim ke port antarmuka serial. Jika kita mencapai akhir baris, karakter tidak dikirim ke port dan siklus pengiriman berakhir.
Kerugian dari pendekatan ini adalah algoritma pemrosesan interupsi tetap. Ini tidak akan membiarkan port serial digunakan dengan cara lain selain menghasilkan string statis. Kelemahan lain dari implementasi ini adalah kurangnya mekanisme untuk memantau hunian pelabuhan. Jika Anda mencoba mengirim beberapa saluran secara berurutan, mungkin ada situasi di mana transmisi saluran sebelumnya akan terputus atau saluran akan tercampur.
Metode yang lebih efektif untuk memecahkan masalah ini dan masalah lainnya, serta bekerja dengan perangkat periferal lainnya, kita akan lihat di bagian posting selanjutnya. Di dalamnya, kita akan melihat lebih dekat pada pemrograman menggunakan kelas manajemen tugas paralel khusus.