Urutan pemrograman mikrokontroler avr. pemrograman mikrokontroler avr

Selamat siang para amatir radio yang terkasih!
Saya menyambut Anda di situs ""

Apa itu mikrokontroler dan mengapa dibutuhkan. Mari kita lihat definisinya:

- sirkuit mikro yang dirancang untuk mengontrol perangkat elektronik, atau dengan cara lain - komputer sederhana (komputer mikro) yang mampu melakukan tugas-tugas sederhana.

Artinya, pada kenyataannya, mikrokontroler adalah perangkat yang memungkinkan kita untuk mewujudkan ide-ide kita (bahkan yang gila), tetapi, tentu saja, dalam kemampuannya. Dan yang paling penting, realisasi sebuah ide dicapai bukan dengan penciptaan struktur elektronik yang canggih, tetapi hanya, pada dasarnya, dengan kekuatan pemikiran kita (apakah Anda ingin menjadi penyihir?).
Yang paling populer di kalangan amatir radio adalah dua jenis mikrokontroler:
gambar- Teknologi Mikrochip
AVR- oleh Atmel

Saya ingin membuat penyimpangan singkat dan mengklarifikasi salah satu posisi saya. Saya tidak akan membahas manfaat mikrokontroler jenis ini atau itu, perangkat lunak ini atau itu, dan secara umum segala sesuatu yang berhubungan dengan mikrokontroler, untuk menyarankan sesuatu, dan terlebih lagi, untuk dikenakan pada pembaca. Ini semua masalah selera, preferensi pribadi, dan tujuan akhir Anda dalam mempelajari mikrokontroler. Nah, karena "keluasan tidak dapat dipeluk", saya akan melakukan semua narasi lebih lanjut saya sehubungan dengan mikrokontroler AVR dan, tidak terlalu umum, tetapi favorit saya, program "Pembangun Algoritma". Berbagai jenis mikrokontroler, program, tentu saja, memiliki perbedaan, tetapi mereka juga memiliki banyak kesamaan. Dan kita akan mempelajari dunia mikrokontroler sedemikian rupa sehingga nantinya, pengetahuan yang diperoleh dapat diterapkan ke PIC dan perangkat lunak apa pun tanpa masalah. Dan izinkan saya mengingatkan Anda sekali lagi bahwa rangkaian artikel ini adalah upaya saya untuk membantu mereka yang pertama kali mendengar tentang keberadaan mikrokontroler dan ingin memahami cara bekerja dengannya.

Apa yang Anda butuhkan untuk mempelajari cara bekerja dengan mikrokontroler? Saya akan memilih beberapa, menurut pendapat saya, kondisi utama:
1. Keinginan dan ketekunan .
Semuanya sangat sederhana di sini: ada keinginan - semuanya akan berhasil. Dan keinginan dengan ketekunan, secara umum, adalah hal yang luar biasa.
2. Pengetahuan tentang perangkat mikrokontroler.
Pengetahuan mendalam tidak penting di sini (dan mungkin tidak diperlukan sama sekali), tetapi penting untuk mengetahui apa yang "terpasang" pada mikrokontroler. Hanya mengetahui terdiri dari mikrokontroler, perangkat apa yang dimilikinya, kemampuannya, cara kerjanya - hanya dengan demikian kita dapat menggunakan kemampuan mikrokontroler secara maksimal.
3. Pengetahuan tentang bahasa pemrograman dan perintah kontrol mikrokontroler.
Bagaimana mikrokontroler akan bekerja, tugas apa yang Anda tetapkan untuknya dan bagaimana ia akan melakukannya, ditentukan oleh program yang tertanam di dalamnya - program yang Anda buat sendiri untuk mikrokontroler. Dan kami akan membahas poin ini secara lebih rinci untuk mempertimbangkan masalah yang mungkin muncul di masa depan.

Program(dalam terjemahan, kata ini berarti "resep") - deskripsi awal tentang peristiwa atau tindakan yang akan datang.

Misalnya, kita ingin mikrokontroler mengedipkan LED. Tugas sederhana, namun demikian, agar mikrokontroler menyelesaikan tugas ini, pertama-tama kita harus, selangkah demi selangkah, menjelaskan semua tindakan mikrokontroler, menulis program yang harus dijalankan untuk mendapatkan hasil yang kita butuhkan - LED yang berkedip . Sesuatu seperti ini:
Nyalakan LED:
- konfigurasikan output yang terhubung dengan LED untuk bekerja pada output informasi
- terapkan level logika ke pin ini, yang memungkinkan Anda menyalakan LED
Tunggu beberapa saat:
- buka subrutin yang membentuk jeda (yang juga perlu "dikunyah")
- setelah menyelesaikan subrutin jeda, kembali ke program utama
Matikan LED:
- terapkan level logika ke output, padamkan LED
dan seterusnya.
dengan istilah Program istilah lain terkait erat - algoritma(seperti Serigala dan Kelinci, Tom dan Jerry).

algoritma- satu set instruksi yang menjelaskan prosedur untuk mencapai hasil yang diinginkan.

Jika dalam program kami dalam cara yang paling detail meresepkan tindakan mikrokontroler, maka dalam algoritma kita menentukan tindakan mikrokontroler, atas dasar itu kita akan membuat program. Mirip dengan contoh di atas:
Nyalakan LED
Tunggu sebentar
Matikan LED
dan seterusnya.
Lewat sini, algoritma adalah cikal bakal program. Dan semakin hati-hati dan cermat suatu algoritma dibuat, semakin mudah untuk membuat program.

Secara total, program untuk mikrokontroler adalah urutan tindakan mikrokontroler dalam bentuk serangkaian perintah dan instruksi yang harus dijalankan untuk mencapai tujuan kita.

Perintah untuk mikrokontroler terlihat seperti satu set dan nol:
00110101 011000100
disebut - kode perintah, dan kode perintah adalah bahasa yang dimengerti mikrokontroler. Dan untuk menerjemahkan algoritme kami dari bahasa Rusia ke bahasa mikrokontroler - ke dalam set nol dan satu ini, ada program khusus.
Program-program ini memungkinkan kita untuk menggambarkan urutan kerja mikrokontroler dalam bahasa yang kurang lebih dapat kita pahami, dan kemudian menerjemahkan urutan ini ke dalam bahasa yang dapat dimengerti oleh mikrokontroler, menghasilkan apa yang disebut kode mesin- urutan perintah dan instruksi (nol dan satu) yang hanya dimengerti oleh mikrokontroler. Teks program yang ditulis oleh programmer disebut Kode sumber. Program diterjemahkan dari bahasa pemrograman (kode sumber) ke dalam bahasa mikrokontroler (kode mesin) penerjemah. Penerjemah mengubah teks program menjadi kode mesin, yang kemudian ditulis ke memori mikrokontroler.
Dalam program seperti itu, urutan operasi mikrokontroler dijelaskan oleh bahasa khusus - bahasa pemrograman. Bahasa pemrograman berbeda dengan bahasa manusia kita. Jika bahasa komunikasi kita terutama untuk bertukar informasi, maka:

Bahasa pemrograman - ini adalah cara mengirimkan perintah, instruksi, panduan yang jelas untuk bertindak untuk mikrokontroler.

Ada banyak bahasa pemrograman dan dapat dibagi menjadi dua jenis:
bahasa pemrograman tingkat rendah
bahasa pemrograman tingkat tinggi
Apa bedanya. Dan mereka berbeda dalam kedekatannya dengan mikrokontroler.
Pada awal kemunculan teknologi mikroprosesor, program ditulis dalam kode mesin, yaitu, seluruh algoritma kerja ditulis secara berurutan dalam bentuk nol dan satu. Seperti inilah tampilan programnya:

01000110
10010011
01010010

Tidak mungkin ada orang yang dapat menemukan serangkaian kombinasi dua angka seperti itu, dan pekerjaan programmer pertama sangat melelahkan. Untuk membuat hidup mereka lebih mudah, programmer mulai membuat bahasa pemrograman pertama. Jadi, semakin dekat bahasa pemrograman dengan kumpulan nol dan satu seperti itu, semakin "tingkat rendah", dan semakin jauh dari mereka, semakin "tingkat tinggi".
Bahasa pemrograman yang paling umum untuk mikrokontroler:
- bahasa tingkat rendah - perakit
– bahasa tingkat tinggi – C (Ci)
Mari kita lihat contoh perbedaannya (contoh ini abstrak).
Katakanlah kita perlu menambahkan dua angka: 25 dan 35.
Dalam kode asli, perintah ini mungkin terlihat seperti ini:
00000101 1101001
Dalam bahasa tingkat rendah:
TAMBAHKAN Rd, Rr
Dalam bahasa tingkat tinggi:
25+35
Perbedaan antara bahasa tingkat rendah dan tingkat tinggi terlihat dengan mata telanjang, komentar, seperti yang mereka katakan, berlebihan.
Tapi mari kita menggali lebih dalam contoh-contoh ini. Kami tidak akan menganalisis contoh kode mesin, karena identik dengan contoh di assembler. Pada intinya, instruksi Majelis adalah kode mesin (perintah) yang sama yang hanya diberi singkatan huruf agar tidak tersesat dalam nol dan satu. Dengan instruksi assembler ADD Rd, Rr, kami mengatur mikrokontroler untuk menambahkan dua angka yang ditemukan (dan untuk ini pertama-tama kita harus menulisnya di sana) - yang pertama di Rd, yang kedua di Rr, dan tempatkan hasil penjumlahan di Rd. Seperti yang Anda lihat, kami menetapkan tugas yang sangat spesifik untuk mikrokontroler: di mana mendapatkannya, apa yang harus dilakukan dengannya, dan di mana harus meletakkan hasilnya. Dalam hal ini, kami bekerja langsung dengan mikrokontroler.
Perintah dalam bahasa tingkat tinggi: 25+35 , notasi matematika yang akrab bagi kita, menyenangkan mata kita. Namun dalam hal ini, kita tidak bekerja langsung dengan mikrokontroler, kita cukup mengatur tugas menjumlahkan dua angka saja. Hasil dan urutan tindakan dalam hal ini akan sama seperti saat menjalankan perintah assembler: pertama, kedua angka ini akan ditulis di suatu tempat, kemudian dijumlahkan dan hasilnya ditempatkan di suatu tempat.
Dan disinilah letak perbedaan utama antara bahasa tingkat tinggi dan bahasa tingkat rendah. Jika di Assembler kita mengontrol seluruh proses (suka atau tidak suka): kita tahu di mana dua angka ini ditulis, dan kita tahu di mana hasilnya, maka dalam bahasa tingkat tinggi kita tidak mengontrol prosesnya. Program itu sendiri memutuskan di mana harus menulis angka sebelumnya dan di mana menempatkan hasilnya. Dalam kebanyakan kasus, kita tidak perlu mengetahui hal ini, karena bagi kita hasil utama adalah angka 60 pada output. Akibatnya, program dalam bahasa tingkat tinggi lebih mudah dibaca, enak dipandang, dan ukurannya lebih kecil - lagi pula, kita tidak perlu "mendaki semua lubang" dan mengecat setiap langkah mikrokontroler, program melakukan ini nanti untuk kita ketika mengkompilasinya - menerjemahkannya ke dalam kode mesin . Tapi ada juga sisi negatifnya. Dua algoritma identik yang ditulis dalam Assembler dan dalam C, setelah mengubahnya menjadi kode mesin, akan memiliki ukuran yang berbeda: program yang ditulis dalam Assembler akan 20-40% lebih pendek daripada program yang ditulis dalam C - iblis tahu ke mana arah C mencapai hasil yang kita butuhkan. Dan ada kasus ketika tidak ada kepercayaan dalam bahasa tingkat tinggi dan dalam program C mereka memasukkan kode yang ditulis dalam Assembler.
Pemrogram profesional, sebagai suatu peraturan, mengetahui beberapa bahasa pemrograman (atau bekerja dalam tim yang mencakup spesialis dalam berbagai bahasa), secara kreatif menggabungkan fitur dan manfaat mereka dalam satu program. Yah, kita, amatir, perlu tahu setidaknya satu bahasa (sebagai permulaan), dan kita harus mulai (dan saya sangat yakin akan hal ini, dan tidak ada yang akan meyakinkan saya) dari bahasa tingkat rendah - Majelis.

Yah, saya pikir, dan di sini semuanya jelas bagi kami - Anda perlu mempelajari bahasa pemrograman, dengan cara yang berbeda - tidak mungkin.

Perintah dan instruksi untuk mengendalikan mikrokontroler.
Mikrokontroler AVR memiliki lebih dari 130 perintah berbeda yang memungkinkannya mewujudkan semua kemungkinan yang ada di dalamnya. Tetapi saya akan segera mengatakan bahwa hanya sedikit amatir yang mengetahui semuanya, apalagi menggunakan semuanya. Biasanya, dalam latihan amatir, ada pengetahuan yang cukup dan setengah dari tim, atau bahkan kurang. Tetapi Anda perlu mempelajari perintah. Semakin banyak perintah yang Anda ketahui, semakin canggih (dalam arti kata yang baik) dan semakin elegan programnya.

Unit logika aritmatika dan organisasi memori - memori program, memori data, memori non-volatile



Dalam tutorial tentang avr ini, saya mencoba menjelaskan semua hal paling dasar bagi pemula untuk memprogram mikrokontroler. avr. Semua contoh dibangun di atas mikrokontroler atmega8. Ini berarti bahwa untuk mengulang semua pelajaran Anda hanya membutuhkan satu MK. Sebagai emulator sirkuit elektronik, Proteus digunakan - menurut saya, pilihan terbaik untuk pemula. Program dalam semua contoh ditulis pada kompiler C untuk avr CodeVision AVR. Mengapa tidak di beberapa assembler? Karena pemula sudah dimuat dengan informasi, dan program yang mengalikan dua angka membutuhkan sekitar seratus baris dalam assembler, dan mereka menggunakan C dalam proyek-proyek tebal yang kompleks.Komilator CodeVision AVR diasah untuk mikrokontroler atmel, memiliki generator kode yang nyaman, antarmuka yang baik dan langsung dari itu dapat di-flash oleh mikrokontroler.

Tutorial ini akan menunjukkan dan menjelaskan dengan contoh sederhana bagaimana:

  • Mulai pemrograman mikrokontroler, mulai dari mana, apa yang Anda butuhkan untuk ini.
  • Program apa yang digunakan untuk menulis firmware untuk avr, untuk mensimulasikan dan men-debug kode pada PC,
  • Perangkat periferal apa yang ada di dalam MK, bagaimana mengontrolnya menggunakan program Anda
  • Cara menulis firmware yang sudah jadi ke mikrokontroler dan cara men-debugnya
  • Cara membuat PCB untuk perangkat Anda
Untuk mengambil langkah pertama menuju pemrograman MK, Anda hanya perlu dua program:
  • Proteus adalah program emulator (Anda dapat mengembangkan sirkuit di dalamnya tanpa menggunakan solder nyata dan kemudian menguji program kami di sirkuit ini). Kami pertama-tama akan meluncurkan semua proyek di Proteus, dan kemudian kami sudah dapat menyolder perangkat nyata.
  • CodeVisionAVR adalah compiler bahasa pemrograman C untuk AVR. Di dalamnya, kami akan mengembangkan program untuk mikrokontroler, dan dimungkinkan untuk mem-flash MK asli langsung darinya.
Setelah menginstal Proteus, jalankan
Dia menawarkan kami untuk melihat proyek yang menyertainya, kami menolak dengan sopan. Sekarang mari kita buat rangkaian paling sederhana di dalamnya. Untuk melakukan ini, klik ikon secara visual tidak ada yang terjadi. Sekarang Anda perlu mengklik huruf kecil R (pilih dari perpustakaan) di panel daftar komponen, jendela pemilihan komponen akan terbuka
di bidang topeng, masukkan nama komponen yang ingin kita temukan di perpustakaan. Misalnya, kita perlu menambahkan mikrokontroler mega8
dalam daftar hasil, colok mega8 dan tekan tombol Oke. Kami memiliki mikrokontroler mega8 dalam daftar komponen
Jadi, kami menambahkan resistor lain ke daftar komponen dengan memasukkan kata di bidang topeng res dan LED dipimpin

Untuk menempatkan bagian pada diagram, klik bagian tersebut, lalu klik bidang diagram, pilih lokasi komponen dan klik lagi. Untuk menambahkan ground atau minus umum ke sirkuit di sebelah kiri, klik "Terminal" dan pilih Ground. Jadi, menambahkan semua komponen dan menghubungkannya, kami mendapatkan rangkaian sederhana
Semuanya, sekarang skema pertama kami sudah siap! Tapi Anda mungkin bertanya, apa yang bisa dia lakukan? Tapi tidak ada. Tidak ada, karena agar mikrokontroler berfungsi, Anda perlu menulis program untuknya. Program adalah daftar instruksi yang akan dijalankan oleh mikrokontroler. Kami membutuhkan mikrokontroler untuk dipasang di kaki PC0 logika 0 (0 volt) dan logika 1 (5 volt).

Menulis Program untuk Mikrokontroler

Kami akan menulis program dalam bahasa C menggunakan kompiler CodeVisionAVR. Setelah meluncurkan CV, ia menanyakan apa yang ingin kami buat: Sumber atau Proyek Kami memilih yang terakhir dan menekan tombol OK. Selanjutnya, kita akan diminta untuk menjalankan CVAVR CodeWizard (ini adalah alat yang sangat berharga untuk pemula, karena dapat menghasilkan kerangka utama program) memilih Ya
Wizard dimulai dengan tab Chip aktif, di sini kita dapat memilih model MK kita - ini adalah mega8, dan frekuensi di mana MK akan beroperasi (mega8 diatur ke 1 megahertz secara default), jadi kami mengatur semuanya seperti yang ditunjukkan pada tangkapan layar di atas. Buka tab Port
Mikrokontroler atmega8 memiliki 3 port yaitu Port C, Port D, Port B. Setiap port memiliki 8 pin. Pin port dapat berada dalam dua status:
  • KELUAR
Dengan bantuan register DDRx.y, kita dapat mengatur pin sebagai input atau output. Jika di
  • DDRx.y = 0 - keluaran berfungsi seperti MEMASUKKAN
  • DDRx.y = 1 pin berfungsi KELUAR
Ketika pin dikonfigurasi sebagai output, kita dapat mengaturnya ke logika 1 (+5 volt) dan logika 0 (0 volt). Ini dilakukan dengan menulis ke register PORTx.y. Selanjutnya akan dibahas secara detail tentang port input-output. Dan sekarang kami mengatur semuanya seperti yang ditunjukkan pada tangkapan layar, dan klik File-> Generate, Save and Exit. Selanjutnya, CodeWizard akan menawarkan kami untuk menyimpan proyek, kami menyimpannya dan melihat kode:

#termasuk //library untuk membuat waktu tunda void main(void) ( PORTB=0x00; DDRB=0x00; PORTC=0x00; DDRC=0x01; // membuat output kaki PC0 PORTD=0x00; DDRD=0x00; // inisialisasi Timer/Counter 0 TCCR0=0x00; TCNT0=0x00; // Inisialisasi Pengatur Waktu/Penghitung 1 TCCR1A=0x00; TCCR1B=0x00; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x0x00; OCR1 ; OCR1BL=0x00; // Inisialisasi Timer/Penghitung 2 ASSR=0x00; TCCR2=0x00; TCNT2=0x00; OCR2=0x00; // Inisialisasi Interupsi Eksternal MCUCR=0x00; // Timer/Penghitung ) Inisialisasi interupsi TIMSK=0x00; // Inisialisasi pembanding Analog ACSR=0x80; SFIOR=0x00; while (1) ( ); )


Segala sesuatu di sini mungkin tampak menakutkan dan asing bagi Anda, tetapi pada kenyataannya semuanya tidak demikian. Kode dapat disederhanakan dengan membuang inisialisasi periferal MK yang tidak kita gunakan. Setelah disederhanakan akan terlihat seperti ini:

#termasuk //library untuk bekerja dengan mikrokontroler mega8 #include //library untuk membuat waktu tunda void main(void) ( DDRC=0x01; /* membuat kaki PC0 entri output 0x01 mungkin tampak asing bagi Anda, dan ini hanya nomor 1 dalam heksadesimal, baris ini akan setara dengan 0b00000001 dalam biner, maka saya akan menulis persis seperti ini. */ while (1) ( ); )


Semuanya baik-baik saja. Tetapi agar LED berkedip, kita perlu mengubah level logika pada kaki PC0. Untuk melakukan ini, tambahkan beberapa baris ke loop utama:

#termasuk //library untuk bekerja dengan mikrokontroler mega8 #include //library untuk membuat waktu tunda void main(void) ( DDRC=0x01; /* membuat kaki PC0 entri output 0x01 mungkin tampak asing bagi Anda, dan ini hanya nomor 1 dalam heksadesimal, baris ini akan setara dengan 0b00000001 dalam biner, maka saya akan menulis persis seperti ini.*/ while (1)//loop program utama (// braket operator dari loop program utama membuka PORTC.0=1; //set port C 1 ke pin 0 delay_ms(500); //membuat penundaan dalam 500 milidetik PORTC.0=0; // mengatur port C 0 ke pin 0 delay_ms(500); // membuat penundaan 500 milidetik );// tutup kurung operator dari loop program utama)


Semuanya, sekarang kodenya sudah siap. Kami mengklik ikon Build all Project files untuk mengkompilasi (menerjemahkan ke dalam instruksi prosesor MK) program kami. Di folder Exe, yang terletak di proyek kami, file dengan ekstensi hex akan muncul, ini adalah file firmware kami untuk MK. Untuk memasukkan firmware kami ke mikrokontroler virtual di Proteus, Anda perlu mengklik dua kali pada gambar mikrokontroler di Proteus. Jendela seperti ini akan muncul
klik ikon folder di bidang File Program, pilih hex - file firmware kami dan tekan tombol OK. Sekarang kita dapat menjalankan simulasi rangkaian kita. Untuk melakukan ini, klik tombol "Mainkan" di sudut kiri bawah jendela Proteus.

Sudah lebih dari satu atau dua kali saya katakan bahwa belajar MK harus dimulai dari assembler. Seluruh kursus di situs dikhususkan untuk ini (meskipun tidak terlalu konsisten, tetapi secara bertahap saya menyisirnya ke tampilan yang memadai). Ya, sulit, hasilnya tidak akan pada hari pertama, tetapi Anda akan belajar memahami apa yang terjadi di pengontrol Anda. Anda akan tahu cara kerjanya, dan tidak menyalin sumber orang lain seperti monyet dan mencoba memahami mengapa tiba-tiba berhenti bekerja. Selain itu, jauh lebih mudah bagi C untuk mengacaukan kode redneck yang akan keluar dengan garpu rumput pada saat yang paling tidak tepat.

Sayangnya, semua orang menginginkan hasil segera. Oleh karena itu, saya memutuskan untuk pergi ke arah lain - untuk membuat tutorial tentang C, tetapi dengan demonstrasi pakaian dalamnya. Seorang programmer embedder yang baik selalu memegang besinya dengan erat pada greave, mencegahnya mengambil satu langkah tanpa izin. Jadi apa yang akan menjadi kode C terlebih dahulu, lalu apa yang dilahirkan oleh kompiler dan bagaimana semuanya bekerja dalam kenyataan :)

Di sisi lain, keunggulan C adalah portabilitas kode. Jika, tentu saja, untuk menulis semuanya dengan benar. Memisahkan algoritma kerja dan implementasi besinya ke dalam bagian proyek yang berbeda. Kemudian, untuk mentransfer algoritme ke MK lain, cukup menulis ulang hanya lapisan antarmuka, tempat semua akses ke perangkat keras ditulis, dan biarkan semua kode yang berfungsi apa adanya. Dan, tentu saja, keterbacaan. Kode sumber Sish lebih mudah dipahami secara sekilas (walaupun .. misalnya, saya tidak peduli apa yang harus dijentikkan - setidaknya si, setidaknya asm :)), tetapi, sekali lagi, jika semuanya ditulis dengan benar. Saya juga akan memperhatikan poin-poin ini.

Sebagai sepotong besi eksperimental di mana bagian terbesar dari semua contoh akan ditempatkan, papan debug saya akan menjadi.

Program C pertama untuk AVR

Memilih Kompilator dan Memasang Lingkungan
Ada banyak kompiler C yang berbeda untuk AVR:
Pertama-tama, ini IAR AVR C- hampir secara tegas diakui sebagai kompiler terbaik untuk AVR, tk. pengontrol itu sendiri dibuat dalam kolaborasi erat antara Atmel dan spesialis dari IAR. Tetapi Anda harus membayar semuanya. Dan kompiler ini tidak hanya perangkat lunak komersial yang mahal, tetapi juga memiliki banyak sekali pengaturan sehingga Anda hanya perlu bekerja keras untuk mengompilasinya di dalamnya. Saya benar-benar tidak berteman dengannya, proyek itu membusuk karena kesalahan aneh pada tahap penautan (kemudian saya mengetahui bahwa itu adalah celah yang bengkok).

Kedua pergi WinAVR GCC adalah kompiler pengoptimal yang kuat. Sumber terbuka penuh, lintas platform, secara umum, semua kesenangan hidup. Ini juga terintegrasi dengan sempurna ke dalam AVR Studio, memungkinkan Anda untuk melakukan debug di sana, yang sangat nyaman. Secara umum, saya memilihnya.

Juga punya CodeVision AVR C adalah kompiler yang sangat populer. Ini menjadi populer karena kesederhanaannya. Anda bisa mendapatkan program yang berfungsi di dalamnya dalam beberapa menit - wizard kode awal sangat berkontribusi untuk ini, mencap standar untuk menginisialisasi uarts apa pun. Sejujurnya, saya entah bagaimana memperlakukannya dengan kecurigaan - begitu saya harus membongkar program yang ditulis oleh kompiler ini, semacam bubur dan bukan kode ternyata. Sejumlah besar gerakan dan operasi yang tidak perlu, yang menghasilkan jumlah kode yang agak besar dan kinerja yang lambat. Namun, mungkin ada kesalahan dalam DNA penulis firmware asli. Apalagi dia menginginkan uang. Tidak sebanyak IAR, tapi terlihat. Dan dalam mode demo memungkinkan Anda untuk menulis tidak lebih dari 2kb kode.
Tentu ada cracknya, tapi kalau curi ya sejuta, dalam artian IAR :)

Ada juga Gambar Kerajinan AVR C dan MikroC dari mikroelektronika. Tidak harus menggunakan keduanya, tapi... SWG sangat memuji mikropaskal, kata mereka, lingkungan pemrograman dan perpustakaan yang sangat nyaman. Saya pikir MicroC tidak akan lebih buruk, tetapi juga dibayar.

Seperti yang saya katakan, saya memilih WinAVR karena tiga alasan: gratis, terintegrasi ke dalam AVR Studio dan hanya sekumpulan kode siap pakai yang ditulis untuknya untuk semua kesempatan.

Jadi unduh WinAVR dengan dan AVR Studio. Selanjutnya, studio pertama kali diinstal, kemudian, dari atas, WinAVR menggulung dan menempel ke studio dalam bentuk plug-in. Saya sangat menyarankan untuk menempatkan WinAVR di jalur pendek, seperti C:\WinAVR, sehingga Anda akan menghindari banyak masalah dengan jalur.

Pembuatan proyek
Jadi, studio sudah diatur, C kacau, saatnya mencoba memprogram sesuatu. Mari kita mulai dengan yang sederhana, yang paling sederhana. Jalankan studio, pilih proyek baru di sana sebagai kompiler AVR GCC dan masukkan nama proyek.

Ruang kerja terbuka dengan file *.c kosong.

Sekarang tidak ada salahnya untuk mengonfigurasi tampilan jalur di bookmark studio. Untuk melakukannya, buka:
Menu Tools - Options - General - FileTabs dan pilih "Filename Only" dari daftar drop-down. Jika tidak, tidak mungkin untuk bekerja - tab akan berisi jalur lengkap file dan tidak akan ada lebih dari dua atau tiga tab di layar.

Pengaturan proyek
Secara umum, dianggap klasik untuk membuat file make di mana semua dependensi akan dijelaskan. Dan ini mungkin benar. Tapi bagi saya, yang tumbuh dengan IDE terintegrasi seperti uVision atau Studio AVR pendekatan ini sangat asing. Oleh karena itu, saya akan melakukannya dengan cara saya sendiri, dengan segala cara di studio.

Klik pada tombol roda gigi.


Ini adalah pengaturan untuk proyek Anda, atau lebih tepatnya, pengaturan untuk pembuatan file make secara otomatis. Di halaman pertama, Anda hanya perlu memasukkan frekuensi di mana MK Anda akan bekerja. Itu tergantung pada bit sekering, jadi kami berasumsi bahwa frekuensinya adalah 8000000Hz.
Perhatikan juga garis optimasi. Sekarang ada -Os adalah optimasi ukuran. Biarkan apa adanya untuk saat ini, lalu Anda dapat mencoba bermain-main dengan parameter ini. -O0 tidak ada optimasi sama sekali.

Langkah selanjutnya adalah mengatur jalur. Pertama-tama, tambahkan direktori proyek Anda di sana - Anda akan meletakkan perpustakaan pihak ketiga di sana. Jalur ".\" akan muncul dalam daftar

File make dihasilkan, Anda dapat melihatnya di folder default di proyek Anda, lihat saja, lihat apa yang ada di sana.


Itu saja untuk saat ini. Klik OK di mana-mana dan pergi ke sumbernya.

Rumusan masalah
Sebuah batu tulis kosong tergoda untuk mewujudkan semacam ide licik, karena kedipan dangkal dioda tidak lagi menyisipkan. Mari kita segera mengambil banteng dengan tanduk dan menerapkan koneksi dengan komputer - ini adalah hal pertama yang saya lakukan.

Ini akan bekerja seperti ini:
Ketika unit tiba di port COM (kode 0x31), kami akan menyalakan dioda, dan ketika nol tiba (kode 0x30), kami akan memadamkannya. Selain itu, semuanya akan dilakukan pada interupsi, dan tugas latar belakang adalah mengedipkan dioda lain. Sederhana dan bermakna.

Merakit skema
Kita perlu menghubungkan modul konverter USB-USART ke pin USART mikrokontroler. Untuk melakukan ini, kami mengambil jumper dua kabel dan meletakkannya di pin secara melintang. Artinya, kami menghubungkan Rx pengontrol dengan Tx konverter, dan Tx konverter dengan Rx pengontrol.

Ternyata, pada akhirnya, inilah skemanya:


Saya tidak mempertimbangkan untuk menghubungkan output yang tersisa, catu daya, reset, itu standar

Kami menulis kode

Saya akan segera membuat reservasi bahwa saya tidak akan menyelidiki secara khusus deskripsi bahasa C itu sendiri. Untuk melakukan ini, hanya ada sejumlah besar materi, mulai dari "Bahasa Pemrograman C" klasik dari K&R hingga berbagai manual.

Salah satu metode tersebut ditemukan di simpanan saya, saya pernah mempelajari bahasa ini menggunakannya. Semuanya singkat, jelas dan to the point. Saya secara bertahap mengetiknya dan menyeretnya ke situs saya.

Memang belum semua chapter dipindahkan ke sana, tapi saya rasa itu tidak lama.

Sepertinya saya tidak akan menjelaskannya dengan lebih baik, oleh karena itu, dari kursus pelatihan, alih-alih penjelasan terperinci tentang seluk-beluk Cish, saya hanya akan memberikan tautan langsung ke halaman individual dari manual ini.

Menambahkan perpustakaan.
Pertama-tama, kami menambahkan perpustakaan dan header yang diperlukan dengan definisi. Bagaimanapun, C adalah bahasa universal dan perlu dijelaskan bahwa kami bekerja dengan AVR, jadi masukkan baris ke dalam kode sumber:

1 #termasuk

#termasuk

File ini terletak di folder WinAVR dan berisi deskripsi semua register dan port pengontrol. Dan semuanya rumit di sana, dengan mengacu pada pengontrol tertentu, yang ditransmisikan oleh kompiler melalui membuat file dalam parameter MCU dan berdasarkan variabel ini, file header dengan deskripsi alamat semua port dan register untuk pengontrol khusus ini terhubung ke proyek Anda. Bagaimana! Tanpa itu, Anda juga bisa, tetapi kemudian Anda tidak akan dapat menggunakan nama register simbolis seperti SREG atau UDR, dan Anda harus mengingat alamat masing-masing seperti "0xC1", dan itu membuat Anda pusing.

Tim yang sama #termasuk<имя файла> memungkinkan Anda untuk menambahkan konten file teks apa pun ke proyek Anda, misalnya, file dengan deskripsi fungsi atau potongan kode lainnya. Dan agar arahan dapat menemukan file ini, kami menunjukkan jalur ke proyek kami (direktori WinAVR sudah terdaftar di sana secara default).

fungsi utama.
Program C adalah semua tentang fungsi. Mereka dapat bersarang dan dipanggil satu sama lain dalam urutan apa pun dan dengan berbagai cara. Setiap fungsi memiliki tiga parameter yang diperlukan:

  • Nilai kembalian, misalnya, dosa(x) mengembalikan nilai sinus x. Seperti dalam matematika, singkatnya.
  • Parameter yang ditransfer, x yang sama.
  • Fungsi tubuh.

Semua nilai yang diteruskan dan dikembalikan harus dari beberapa jenis, tergantung pada datanya.

Setiap program C harus mengandung fungsi utama sebagai titik masuk ke program utama, selain itu bukan C sama sekali :). Dengan kehadiran utama di sumber orang lain dari sejuta file, Anda dapat memahami bahwa ini adalah bagian utama dari program dari mana semuanya dimulai. Di sini kita akan mengatur:

1 2 3 4 5 int main(void ) ( kembali 0 ; )

int main(void) ( kembali 0; )

Itu saja, program paling sederhana pertama telah ditulis, tidak masalah bahwa itu tidak melakukan apa-apa, kami baru saja mulai.

Mari kita lihat apa yang kita lakukan.
ke dalam adalah tipe data yang dikembalikan oleh fungsi utama.

Tentu saja, di mikrokontroler utama pada prinsipnya, tidak ada yang bisa dikembalikan, dan secara teori itu harus batal utama (batal), tetapi GCC awalnya diasah di PC dan di sana program dapat mengembalikan nilai ke sistem operasi setelah selesai. Oleh karena itu GCC aktif batal utama (batal) bersumpah demi Peringatan.

Ini bukan kesalahan, ini akan berhasil, tetapi saya tidak suka peringatan.

ruang kosong ini adalah tipe data yang kita lewati ke fungsi, dalam hal ini utama juga tidak bisa menerima apapun dari luar, penyair ruang kosong- kosong. Sebuah rintisan digunakan ketika tidak ada yang perlu dilewatkan atau dikembalikan.

Ini dia { } kurung kurawal adalah blok program, dalam hal ini badan fungsi utama, kode akan ditempatkan di sana.

kembali- ini adalah nilai pengembalian yang akan diberikan fungsi utama setelah selesai, karena kita memiliki int, yaitu angka, maka kita harus mengembalikan angka. Meskipun masih tidak masuk akal, karena. pada mikrokontroler dari utama, kita hanya bisa pergi ke mana-mana. Saya mengembalikan nol. Untuk nefig. Dan kompiler biasanya cerdas dan tidak menghasilkan kode untuk kasus ini.
Meskipun, jika sesat, maka dari utama Anda dapat pergi ke MK - misalnya, jatuhkan ke bagian bootloader dan jalankan, tetapi di sini Anda sudah perlu memilih firmware tingkat rendah untuk memperbaiki alamat transisi. Di bawah ini Anda akan melihat dan memahami cara melakukannya. Untuk apa? Sekarang ini adalah pertanyaan lain, dalam 99,999% kasus ini tidak perlu :)

Selesai, lanjutkan. Mari kita tambahkan variabel, kita tidak benar-benar membutuhkannya dan kita tidak boleh memperkenalkan variabel tanpanya, tapi kita sedang belajar. Jika variabel ditambahkan di dalam badan fungsi, maka variabel tersebut bersifat lokal dan hanya ada dalam fungsi ini. Saat Anda keluar dari fungsi, variabel-variabel ini akan dihapus, dan memori RAM diberikan untuk kebutuhan yang lebih penting. .

1 2 3 4 5 6 int main(void ) ( unsigned char i; return 0 ; )

int main(void) ( unsigned char i; return 0; )

tidak ditandatangani berarti tidak bertanda tangan. Faktanya adalah bahwa dalam representasi biner, bit paling signifikan diberikan ke tanda, yang berarti bahwa angka +127/-128 cocok dengan satu byte (char), tetapi jika tanda dibuang, itu akan cocok dari 0 hingga 255. Biasanya tanda tidak diperlukan. Sehingga tidak ditandatangani.
saya hanyalah nama variabel. Tidak lagi.

Sekarang kita perlu menginisialisasi port dan UART. Tentu saja, Anda dapat mengambil dan menghubungkan perpustakaan dan memanggil semacam UartInit (9600); tapi kemudian Anda tidak akan tahu apa yang sebenarnya terjadi.

Kami melakukan ini:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int main(void ) ( unsigned char i; #define XTAL 8000000L #define baudrate 9600L #define bauddivider (XTAL/(16*baudrate)-1)#define HI(x) ((x)>>8) #define LO(x) ((x)& 0xFF) UBRRL = LO(bauddivider) ; UBRRH = HI(pembagi bau) ; UCSRA = 0 ; UCSRB = 1<< RXEN| 1 << TXEN| 1 << RXCIE| 0 << TXCIE; UCSRC = 1 << URSEL| 1 << UCSZ0| 1 << UCSZ1; }

int main(void) ( unsigned char i; #define XTAL 8000000L #define baudrate 9600L #define bauddivider (XTAL/(16*baudrate)-1) #define HI(x) ((x)>>8) #define LO( x) ((x)& 0xFF) UBRRL = LO(pembagi bau); UBRRH = HI(pembagi bau); UCSRA = 0; UCSRB = 1<

Menakutkan? Faktanya, hanya ada lima baris terakhir dari kode asli. Semuanya, itu #mendefinisikan itu adalah bahasa makro preprocessor. Hampir sama seperti di Assembler, tetapi sintaksnya agak berbeda.

Mereka akan memfasilitasi operasi rutin Anda untuk menghitung koefisien yang diperlukan. Di baris pertama kami mengatakan itu alih-alih XTAL Anda dapat dengan aman mengganti 8000000, dan L- indikasi jenis, mereka mengatakan panjang adalah frekuensi clock prosesor. Sama baudrate- frekuensi transfer data melalui UART.

pembagi bau sudah lebih rumit, alih-alih ekspresi yang dihitung dengan rumus dari dua sebelumnya akan diganti.
Baik dan LO dan HAI dari hasil ini akan diambil byte rendah dan tinggi, karena itu jelas tidak bisa masuk ke dalam satu byte. PADA HAI x digeser (parameter input makro) delapan kali ke kanan, akibatnya, hanya byte tinggi yang tersisa darinya. Dan masuk LO kami melakukan bitwise AND dengan angka 00FF, hanya menyisakan byte rendah sebagai hasilnya.

Jadi semua yang dilakukan adalah seperti #mendefinisikan anda dapat membuangnya dengan aman, dan menghitung angka yang diperlukan pada kalkulator dan segera memasukkannya ke dalam baris UBBRL = .... dan UBBRH=…..

Bisa. Tetapi! Melakukan hal ini SANGAT TIDAK MUNGKIN!

Ini akan bekerja dengan cara ini dan itu, tetapi Anda akan memiliki apa yang disebut angka ajaib- nilai diambil entah dari mana dan tidak jelas mengapa, dan jika Anda membuka proyek seperti itu dalam beberapa tahun, maka akan sangat sulit untuk memahami apa nilai-nilai ini. Dan sekarang, jika Anda ingin mengubah kecepatan, atau mengubah frekuensi kuarsa dan Anda harus menghitung ulang semuanya, jadi Anda mengubah beberapa angka dalam kode dan hanya itu. Secara umum, jika Anda tidak ingin dianggap sebagai pembuat kode yang buruk, maka buatlah kode tersebut agar mudah dibaca, dimengerti, dan mudah dimodifikasi.

Maka semuanya sederhana:
Semua "UBRLL and Co" ini adalah register konfigurasi pemancar UART yang dengannya kita akan berkomunikasi dengan dunia. Dan sekarang kami telah memberi mereka nilai yang diperlukan, mengaturnya ke kecepatan yang diinginkan dan mode yang diinginkan.

Ketik entri 1< Artinya sebagai berikut: ambil 1 dan taruh di tempatnya RXEN dalam satu byte. RXEN ini adalah bit ke-4 dari register UCSRB, jadi 1< membentuk bilangan biner 00010000, TXEN adalah bit ke-3, dan 1< akan memberikan 00001000. Satu "|" itu sedikit demi sedikit ATAU, jadi 00000000 | 00001000 = 00011000. Dengan cara yang sama, sisa bit konfigurasi yang diperlukan diatur dan ditambahkan ke tumpukan umum. Akibatnya, nomor yang dikumpulkan ditulis ke UCSRB. Lebih rinci dijelaskan dalam lembar data MK di bagian USART. Jadi jangan terganggu oleh detail teknis.

Selesai, saatnya melihat apa yang terjadi. Klik kompilasi dan mulai emulasi (Ctrl+F7).

Debug
Segala macam progress bar melewati, studio berubah dan panah kuning muncul di dekat pintu masuk ke fungsi utama. Di sinilah prosesor saat ini dan simulasi dihentikan sementara.

Faktanya adalah bahwa awalnya, sebenarnya, itu di jalur UBRRL = LO(bauddivider); Lagi pula, yang kami definisikan bukanlah kode, tetapi hanya perhitungan awal, jadi simulatornya sedikit membosankan. Tetapi sekarang dia menyadari bahwa instruksi pertama telah terpenuhi dan jika Anda memanjat pohon Tampilan I/O, ke bagian USART dan lihat byte UBBRL di sana, Anda akan melihat bahwa sudah ada nilai di sana! 0x33.

Ambil satu langkah lagi. Lihat bagaimana isi register lain akan berubah. Jadi lihat semuanya, perhatikan fakta bahwa semua bit yang ditentukan diatur seperti yang saya katakan, dan mereka disetel secara bersamaan untuk seluruh byte. Hal-hal tidak akan lebih jauh dari Return - program sudah berakhir.

Pembukaan
Sekarang reset simulasi ke nol. Klik di sana Atur Ulang (Shift+F5). Buka daftar yang dibongkar, sekarang Anda akan melihat apa yang sebenarnya terjadi di pengontrol. Lihat -> Pembongkaran. Dan tidak YYAAAA!!! Perakit!!! MENGERIKAN!!! TAPI ANDA HARUS. Sehingga nanti, ketika ada yang tidak beres, Anda tidak bodoh dalam kode dan tidak mengajukan pertanyaan lamer di forum, tetapi segera masuk ke jeroan ayam itik dan lihat di mana Anda memiliki colokan. Tidak ada yang mengerikan di sana.

Pertama akan ada puncak dari seri:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 +00000000: 940C002A JMP 0x0000002A Lompat +00000002: 940C0034 JMP 0x00000034 Lompat +00000004: 940C0034 JMP 0x00000034 Lompat +00000006: 940C0034 JMP 0x00000034 Lompat +00000008: 940C0034 JMP 0x00000034 + Lompat +00000034A: 940000C00000034A: 0000000E: 940C0034 JMP 0x00000034 Lompat +00000010: 940C0034 JMP 0x00000034 Lompat +00000012: 940C0034 JMP 0x00000034 Lompat +00000014: 940C0034 JMP 0x00000034 Lompat +00000016: 940C0034 JMP 0x00000034 Lompat +00000034: 940000C00000034: 9400000 : 940C0034 JMP 0x00000034 Lompat +0000001E: 940C0034 JMP 0x00000034 Lompat +00000020: 940C0034 JMP 0x00000034 Lompat +00000022: 940C0034 JMP 0x00000034 Lompat +00000024: 940C0034 JMP 0x00000034 Lompat +00000026: 940C300034

00000000: 940C002A JMP 0x0000002A Lompat +00000002: 940C0034 JMP 0x00000034 Lompat +00000004: 940C0034 JMP 0x00000034 Lompat +00000006: 940C0034 JMP 0x00000034 Lompat +00000008: 940C0034 JMP 0x00000034 + Lompat +00000034A: 90000000C0034A: 00000000E : 940C0034 JMP 0x00000034 Lompat +00000010: 940C0034 JMP 0x00000034 Lompat +00000012: 940C0034 JMP 0x00000034 Lompat +00000014: 940C0034 JMP 0x00000034 Lompat +00000016: 940C0034 JMP 0x00000034 Lompat +00000018: 940C340034 940C0034 JMP 0x00000034 Lompat +0000001E: 940C0034 JMP 0x00000034 Lompat +00000020: 940C0034 JMP 0x00000034 Lompat +00000022: 940C0034 JMP 0x00000034 Lompat +00000024: 940C0034 JMP 0x00000034 Lompat +00000026: 940C300034 JMP + 940C00000 Lompat

Ini adalah tabel vektor interupsi. Kami akan kembali ke sana nanti, untuk saat ini, lihat saja dan ingat bahwa itu ada di sana. Kolom pertama adalah alamat sel flash tempat perintah berada, yang kedua adalah kode perintah, mnemonic perintah ketiga, instruksi assembler yang sama, operan ketiga dari perintah. Oh, dan komentar otomatis.
Jadi, jika Anda perhatikan, maka ada transisi berkelanjutan. Dan kode perintah JMP adalah empat byte, berisi alamat lompat yang ditulis mundur - byte rendah di alamat rendah dan kode perintah lompat 940C

0000002B: BE1F KELUAR 0x3F, R1 Keluar ke lokasi I/O

Tulis nol ini ke alamat 0x3F. Jika Anda melihat di kolom tampilan I / O, Anda akan melihat bahwa alamat 0x3F adalah alamat register SREG - register flag pengontrol. Itu. kami mereset SREG untuk menjalankan program pada kondisi nol.

1 2 3 4 +0000002C: E5CF LDI R28,0x5F Muat langsung +0000002D: E0D4 LDI R29,0x04 Muat langsung +0000002E: BFDE OUT 0x3E,R29 Keluar ke lokasi I/O +0000002F: BFCD OUT 0x3D,R28 Keluar ke lokasi I/O

0000002C: E5CF LDI R28,0x5F Muat langsung +0000002D: E0D4 LDI R29,0x04 Muat langsung +0000002E: BFDE OUT 0x3E,R29 Keluar ke lokasi I/O +0000002F: BFCD OUT 0x3D,R28 Keluar ke lokasi I/O

Ini sedang memuat penunjuk tumpukan. Anda tidak dapat langsung memuat register ke I/O, hanya melalui register perantara. Oleh karena itu, pertama LDI ke intermediate, dan kemudian dari sana OUT ke I/O. Saya juga akan memberi tahu Anda lebih banyak tentang tumpukan. Sementara itu, ketahuilah bahwa ini adalah area memori yang dinamis, ia menggantung di ujung RAM dan menyimpan alamat dan variabel perantara dalam dirinya sendiri. Sekarang kami telah menunjukkan dari mana tumpukan akan dimulai.

00000032: 940C0041 JMP 0x00000041 Lompat

Lompatan ke akhir saaaaamy program, dan di sana kami memiliki interupsi yang dinonaktifkan dan berulang dengan sendirinya:

1 2 +00000041: 94F8 CLI Global Interrupt Disable +00000042: CFFF RJMP PC-0x0000 Lompatan relatif

00000041: 94F8 CLI Global Interrupt Disable +00000042: CFFF RJMP PC-0x0000 Lompatan relatif

Ini jika terjadi keadaan yang tidak terduga, seperti keluar dari fungsi utama. Pengontrol dapat dikeluarkan dari loop seperti itu baik dengan reset perangkat keras, atau, lebih mungkin, dengan reset dari pengawas. Nah, atau, seperti yang saya katakan di atas, perbaiki tempat-tempat ini di editor hex dan naik ke mana pun kita mau. Perhatikan juga bahwa ada dua jenis lompatan JMP dan RJMP yang pertama adalah lompatan langsung ke suatu alamat. Ini menempati empat byte dan dapat melakukan lompatan langsung ke seluruh area memori. Jenis transisi kedua - RJMP - bersifat relatif. Perintahnya membutuhkan dua byte, tetapi dia melompat dari posisi saat ini (alamat) 1024 langkah maju atau mundur. Dan parameternya menunjukkan offset dari titik saat ini. Lebih sering digunakan, tk. menghabiskan setengah ruang dalam flash, dan transisi panjang jarang diperlukan.

1 +00000034: 940C0000 JMP 0x00000000 Lompat

00000034: 940C0000 JMP 0x00000000 Lompat

Dan ini adalah lompatan ke awal kode. Reboot semacam. Anda dapat memeriksa apakah semua vektor melompat di sini. Dari kesimpulan ini - jika Anda sekarang mengaktifkan interupsi (mereka dinonaktifkan secara default) dan Anda memiliki interupsi, tetapi tidak ada penangan, maka akan ada reset perangkat lunak - program akan dilemparkan ke awal.

fungsi utama. Semuanya sama, Anda bahkan tidak bisa menggambarkannya. Lihat saja di register nomor yang sudah dihitung dimasukkan. Batu preprosesor kompiler!!! Jadi tidak ada angka "ajaib"!

1 2 3 4 5 6 7 8 9 10 11 12 <

00000036: E383 LDI R24,0x33 Muat langsung +00000037: B989 KELUAR 0x09,R24 Keluar ke lokasi I/O 15: UBRRH = HI(bauddivider); +00000038: BC10 KELUAR 0x20,R1 Keluar ke lokasi I/O 16: UCSRA = 0; +00000039: B81B KELUAR 0x0B,R1 Keluar ke lokasi I/O 17: UCSRB = 1<

Dan inilah kusennya:

1 2 3 +0000003E: E080 LDI R24,0x00 Muat segera +0000003F: E090 LDI R25,0x00 Muat segera +00000040: 9508 RET Pengembalian subrutin

0000003E: E080 LDI R24,0x00 Muat segera +0000003F: E090 LDI R25,0x00 Muat segera +00000040: 9508 RET Pengembalian subrutin

Pertanyaannya adalah, mengapa kompiler menambahkan atasan seperti itu? Dan ini tidak lebih dari Return 0, lalu kami mendefinisikan fungsinya sebagai int main (void) jadi kami mengacaukan empat byte lagi, tidak mengerti apa :) Dan jika Anda membuat void main (void) maka hanya RET yang tersisa, tetapi peringatan akan muncul, bahwa mereka mengatakan fungsi utama kami tidak mengembalikan apa pun. Secara umum, lakukan apa yang Anda inginkan :)

Sulit? Tampaknya tidak. Klik eksekusi langkah demi langkah dalam mode disassembler dan lihat bagaimana prosesor mengeksekusi instruksi individual, yang terjadi dengan register. Bagaimana gerakan melalui perintah dan perulangan terakhir.

Bersambung beberapa hari lagi...

Dari atas:
Alexei78 Saya membuat plugin untuk firefox yang memudahkan navigasi situs dan forum saya.
Diskusi dan unduh,

Ada berbagai bahasa pemrograman untuk mikrokontroler AVR, tetapi assembler dan C mungkin yang paling cocok, karena bahasa ini memberikan implementasi terbaik dari semua kemampuan yang diperlukan untuk mengontrol perangkat keras mikrokontroler.

Assembler adalah bahasa pemrograman tingkat rendah yang menggunakan set instruksi langsung mikrokontroler. Membuat program dalam bahasa ini membutuhkan pengetahuan yang baik tentang sistem perintah dari chip yang dapat diprogram dan waktu yang cukup untuk mengembangkan program. Assembler kalah dari C dalam hal kecepatan dan kenyamanan pengembangan program, tetapi memiliki keunggulan nyata dalam ukuran kode akhir yang dapat dieksekusi, dan, karenanya, dalam kecepatan eksekusinya.

C memungkinkan Anda membuat program dengan lebih nyaman, memberikan pengembang semua manfaat bahasa tingkat tinggi.
Perlu dicatat sekali lagi bahwa arsitektur AVR dan sistem perintah dibuat dengan partisipasi langsung dari pengembang kompiler C dan memperhitungkan fitur bahasa ini. Kompilasi kode sumber yang ditulis dalam C cepat dan menghasilkan kode yang ringkas dan efisien.

Keuntungan utama C dibandingkan assembler adalah: kecepatan pengembangan program yang tinggi; keserbagunaan yang tidak memerlukan studi menyeluruh tentang arsitektur mikrokontroler; keterdokumentasian dan keterbacaan algoritma yang lebih baik; ketersediaan fungsi perpustakaan; dukungan untuk perhitungan floating point.

Bahasa C secara harmonis menggabungkan kemampuan pemrograman tingkat rendah dengan fitur bahasa tingkat tinggi. Kemampuan pemrograman tingkat rendah memudahkan pengoperasian langsung pada perangkat keras, dan properti bahasa tingkat tinggi memungkinkan pembuatan kode program yang mudah dibaca dan dimodifikasi. Selain itu, hampir semua kompiler C memiliki kemampuan untuk menggunakan sisipan assembler untuk menulis bagian penting dari program dalam hal waktu dan sumber daya eksekusi.

Singkatnya, C adalah bahasa yang paling nyaman bagi pemula untuk berkenalan dengan mikrokontroler AVR dan pengembang yang serius.

Compiler digunakan untuk mengubah kode sumber program menjadi file firmware mikrokontroler.

Atmel menyediakan compiler assembler yang kuat yang disertakan dengan lingkungan pengembangan Atmel Studio berbasis Windows. Bersama dengan kompiler, lingkungan pengembangan berisi debugger dan emulator.
Atmel Studio sepenuhnya gratis dan tersedia dari situs web Atmel.

Ada beberapa kompiler C untuk AVR saat ini. Yang paling kuat dari mereka adalah kompiler Sistem IAR dari Stockholm. Karyawannyalah yang pada pertengahan 90-an berpartisipasi dalam pengembangan sistem komando AVR. IAR C Compiler memiliki kemampuan pengoptimalan kode yang luas dan hadir sebagai bagian dari lingkungan pengembangan terintegrasi IAR Embedded Workbench (EWB), yang juga mencakup compiler assembler, linker, manajer proyek dan perpustakaan, dan debugger. Harga paket versi lengkap adalah 2820 EUR. Di situs web perusahaan, Anda dapat mengunduh versi evaluasi gratis selama 30 hari atau versi tidak terbatas dengan batas ukuran kode 4 KB.

Perusahaan Amerika Image Craft dari Palo Alto, California, memproduksi kompiler untuk bahasa C, yang telah mendapatkan popularitas yang cukup luas. JumpStart C untuk AVR memiliki pengoptimalan kode yang dapat diterima dan tidak terlalu mahal (dari $50 hingga $499 tergantung pada versinya). Versi demo JumpStart C untuk AVR berfungsi penuh selama 45 hari.

Rumania Code Vision AVR C Compiler memenangkan popularitas yang tidak kalah, harga versi lengkap dari kompiler ini relatif rendah dan berjumlah 150 EUR. Kompilator dilengkapi dengan lingkungan pengembangan terintegrasi, yang, selain fitur standar, menyertakan fitur yang agak menarik - Generator Program Otomatis CodeWizardAVR. Kehadiran terminal serial di lingkungan pengembangan memungkinkan program debugging menggunakan port serial mikrokontroler. Pengembang dapat mengunduh versi evaluasi gratis dengan batas ukuran kode 4 KB dan menonaktifkan penyimpanan kode sumber C yang dihasilkan.

MikroElektronika, yang terletak di kota Belgrade, Serbia, menghasilkan seluruh keluarga kompiler untuk mikrokontroler AVR. Kompiler C yang disebut mikroC PRO untuk AVR berharga $249. Ada juga mikroBasic dan mikroPascal dengan harga yang sama. Ada demo di situs pengembang dengan batas ukuran kode 4096 byte. Keuntungan dari keluarga compiler ini adalah platform tunggal dan ideologi tunggal, yang dapat memberikan transisi yang mudah tidak hanya antar bahasa, tetapi juga antar mikrokontroler (ada versi compiler untuk PIC, STM32, 8051 ...).

Lingkungan pengembangan terintegrasi telah menjadi benar-benar ikonik. Ini termasuk compiler C dan assembler yang kuat, programmer AVRDUDE, debugger, simulator, dan banyak program dan utilitas pendukung lainnya. WinAVR terintegrasi sempurna dengan lingkungan pengembangan AVR Studio Atmel. Assembler identik dalam kode input dengan assembler AVR Studio. Kompiler C dan assembler memiliki kemampuan untuk membuat file debug dalam format COFF, yang memungkinkan Anda untuk tidak hanya menggunakan alat bawaan, tetapi juga menggunakan simulator AVR Studio yang canggih. Kelebihan penting lainnya adalah bahwa WinAVR didistribusikan secara gratis tanpa batasan (produsen mendukung Lisensi Publik Umum GNU).

Singkatnya, WinAVR adalah pilihan ideal bagi mereka yang mulai menguasai mikrokontroler AVR. Lingkungan pengembangan inilah yang dianggap sebagai yang utama dalam kursus ini.

Operasi bitwise didasarkan pada operasi logis, yang telah kita bahas sebelumnya. Mereka memainkan peran kunci dalam pemrograman mikrokontroler AVR dan jenis lainnya. Hampir tidak ada program yang dapat melakukannya tanpa menggunakan operasi bitwise. Selama ini kita sengaja menghindarinya agar lebih mudah mempelajari pemrograman MK.

Di semua artikel sebelumnya, kami hanya memprogram port I / O dan tidak menggunakan node bawaan tambahan, seperti timer, konverter analog-ke-digital, interupsi, dan perangkat internal lainnya yang tanpanya MK kehilangan semua kekuatannya.

Sebelum beralih ke penguasaan perangkat MK bawaan, Anda perlu mempelajari cara mengontrol atau memeriksa bit individu dari register AVR MK. Sebelumnya, kami melakukan pemeriksaan atau mengatur bit dari seluruh register sekaligus. Mari kita lihat apa perbedaannya, dan kemudian lanjutkan lebih jauh.

Operasi Bitwise

Paling sering, ketika memprogram mikrokontroler AVR, kami menggunakannya, karena memiliki kejelasan yang lebih besar dibandingkan dan dipahami dengan baik oleh pemrogram MK pemula. Misalnya, kita hanya perlu mengatur bit ke-3 dari port D. Untuk ini, seperti yang sudah kita ketahui, kita dapat menggunakan kode biner berikut:

PORTD = 0b00001000;

Namun, dengan perintah ini, kami mengatur bit ke-3 menjadi satu, dan kami mengatur ulang semua yang lain (0, 1, 2, 4, 5, 6 dan 7) ke nol. Dan sekarang mari kita bayangkan situasi bahwa digit ke-6 dan ke-7 digunakan sebagai input ADC dan saat ini sinyal dari beberapa perangkat tiba di output MK yang sesuai, dan kami mengatur ulang sinyal ini menggunakan perintah di atas. Akibatnya, mikrokontroler tidak melihat mereka dan percaya bahwa sinyal tidak datang. Oleh karena itu, alih-alih perintah seperti itu, kita harus menggunakan perintah lain yang hanya akan mengatur bit ke-3 menjadi satu, sementara tidak mempengaruhi bit lainnya. Untuk ini, operasi bitwise berikut biasanya digunakan:

PELABUHAN |= (1<<3);

Kami akan menganalisis sintaksnya secara rinci di bawah ini. Dan sekarang contoh lain. Katakanlah kita perlu memeriksa status bit ke-3 dari register PIND, dengan demikian memeriksa status tombol. Jika bit ini direset ke nol, maka kita tahu bahwa tombol ditekan dan kemudian kode perintah dijalankan, yang sesuai dengan status tombol yang ditekan. Sebelumnya, kita akan menggunakan notasi berikut:

jika (pind == 0b00000000)

(kode apa saja)

Namun, dengan bantuannya, kami memeriksa tidak satu pun, - yang ke-3, tetapi semua bit register PIND sekaligus. Oleh karena itu, bahkan jika tombol ditekan dan bit yang diinginkan direset, tetapi pada saat itu sinyal diterima pada pin port D lainnya, bit yang sesuai akan diset ke satu, dan kondisi dalam tanda kurung akan salah. Akibatnya, kode dalam kurung kurawal tidak akan dieksekusi meskipun tombol ditekan. Oleh karena itu, untuk memeriksa status bit ke-3 dari register PIND, operasi bitwise harus digunakan:

jika (~PIND & (1<<3))

(kode apa saja)

Untuk bekerja dengan bit mikrokontroler individu, bahasa pemrograman C memiliki gudang senjatanya, yang dengannya Anda dapat mengubah atau memeriksa status satu atau lebih bit individu sekaligus.

Mengatur satu bit

Untuk mengatur satu bit, seperti port D, operasi OR bitwise digunakan. Itulah yang kami gunakan di awal artikel.

PORTD = 0b00011100; // nilai awal

PORTD = PORTD | (satu<<0); применяем побитовую ИЛИ

PELABUHAN |= (1<<0); // сокращенная форма записи

PORTD == 0b00011101; // hasil

Perintah ini mengatur bit ke nol dan membiarkan sisanya tidak berubah.

Sebagai contoh, mari kita atur bit ke-6 dari port D.

PORTD = 0b00011100; // status port awal

PELABUHAN |= (1<<6); //

PORTD == 0b01011100; // hasil

Untuk menulis satu hingga beberapa bit terpisah sekaligus, misalnya port nol, keenam, dan ketujuh B notasi berikut berlaku.

PORTB = 0b00011100; // nilai awal

PORTB |= (1<<0) | (1<<6) | (1<<7); //

PORTB == 0b1011101; // hasil

Menyetel ulang (meniadakan) bit individu

Untuk mereset satu bit, tiga perintah yang dibahas sebelumnya digunakan sekaligus: .

Mari kita reset bit ke-3 dari register PORTC dan biarkan sisanya tidak berubah.

PORTC = 0b00011100;

PORTC &= ~(1<<3);

PORTC == 0b00010100;

Mari kita lakukan tindakan serupa untuk digit ke-2 dan ke-4:

PORTC = 0b00111110;

PORTC &= ~((1<<2) | (1<<4));

PORTC == 0b00101010;

Mengganti ketukan

Selain pengaturan dan pengaturan ulang, perintah yang berguna juga digunakan yang mengalihkan satu bit ke keadaan yang berlawanan: satu ke nol dan sebaliknya. Operasi logis ini banyak digunakan dalam konstruksi berbagai efek pencahayaan, misalnya, seperti karangan bunga Tahun Baru. Perhatikan contoh PORTA

PORTA = 0b00011111;

PORTA ^= (1<<2);

PORTA == 0b00011011;

Ubah status bit nol, kedua dan keenam:

PORTA = 0b00011111;

PORTA ^= (1<<0) | (1<<2) | (1<<6);

PORTA == 0b01011010;

Memeriksa status bit individu. Biarkan saya mengingatkan Anda bahwa memeriksa (sebagai lawan menulis) port I / O dilakukan dengan membaca data dari register PIN.

Tes yang paling umum dilakukan oleh salah satu dari dua pernyataan loop: if dan while. Kita sudah akrab dengan operator ini sebelumnya.

Memeriksa debit untuk keberadaan nol logis (reset) dengan jika

jika (0==(PIND & (1<<3)))

Jika bit ketiga dari port D dikosongkan, Code1 dijalankan. Jika tidak, Code2 dijalankan.

Tindakan serupa dilakukan dengan dan dalam bentuk rekaman ini:

jika (~PIND & (1<<3))

Memeriksa debit untuk keberadaan unit logis (pengaturan) dengan jika

jika (0 != (PIND & (1<<3)))

jika (PIND & (1<<3))

Dua loop di atas bekerja dengan cara yang sama, tetapi karena fleksibilitas bahasa pemrograman C, mereka dapat ditulis secara berbeda. Operasi != berarti tidak sama. Jika bit ketiga dari port I/O PD diset (satu), maka Code1 dijalankan, jika tidak, Code2.

Menunggu sedikit reset dengan ketika

sementara (PIND & (1<<5))

Code1 akan dieksekusi selama bit ke-5 dari register PIND diatur. Menyetel ulang akan mulai mengeksekusi Code2.

Menunggu bit disetel ketika

Di sini, sintaks bahasa C memungkinkan Anda untuk menulis kode dalam dua cara yang paling umum. Dalam praktiknya, kedua jenis rekaman digunakan.