Skip to content Skip to sidebar Skip to footer

Widget HTML #1

Interrupt untuk USART mikrokontroller AVR

Apa itu Interrupt pada mikrokontroller?  - Tutorial ini akan mengajarkan dasar-dasar untuk membuat komunikasi USART yang digerakkan oleh interupsi. Ini mengasumsikan bahwa pembaca telah membaca dan sepenuhnya memahami tutorial saya sebelumnya tentang komunikasi serial dasar.

Interrupt untuk USART mikrokontroller AVR
Interrupt USART AVR


1 Apa itu Interupsi?

AVR - dan hampir semua mikrokontroler - berisi fitur yang disebut interupsi. Interupsi, seperti yang tersirat dari namanya, memungkinkan kejadian eksternal (seperti input dari pengguna atau periferal AVR) untuk sementara menjeda program mikrokontroler utama dan menjalankan "Rutin Layanan Interupsi" (sering disingkat menjadi "ISR") sebelum melanjutkan program utama yang ditinggalkannya. 

Interupsi sangat berguna untuk menangani input eksternal yang tidak teratur (seperti perubahan pin atau kedatangan byte serial), serta untuk memproses "tugas latar belakang" seperti menyalakan LED setiap kali timer meluap.

Dalam tutorial ini, kita akan menggunakan interupsi periferal AVR USART.

2. Program gema sederhana

Kami telah membuat program sederhana dari awal yang akan menggemakan byte yang diterima di antarmuka USART AVR. 

Daftar program lengkapnya adalah sebagai berikut:

# include < avr / io .h >
# define USART_BAUDRATE 9600
# define BAUD_PRESCALE ((( F_CPU / ( USART_BAUDRATE * 16 UL ))) - 1)
int main ( void )
{
char ReceivedByte ;
UCSRB |= (1 << RXEN ) | (1 << TXEN ); // Turn on the transmission and reception circuitry
UCSRC |= (1 << URSEL ) | (1 << UCSZ0 ) | (1 << UCSZ1 ); // Use 8- bit character sizes
UBRRH = ( BAUD_PRESCALE >> 8) ; // Load upper 8- bits of the baud rate value into the high byte
of the UBRR register
UBRRL = BAUD_PRESCALE ; // Load lower 8 - bits of the baud rate value into the low byte of the
UBRR register
for (;;) // Loop forever
{
while (( UCSRA & (1 << RXC )) == 0) {}; // Do nothing until data have been received and is
ready to be read from UDR
ReceivedByte = UDR ; // Fetch the received byte value into the variable " ByteReceived "
while (( UCSRA & (1 << UDRE )) == 0) {}; // Do nothing until UDR is ready for more data to
be written to it
UDR = ReceivedByte ; // Echo back the received byte back to the computer
}
}

Pembaca harus dapat memahami kode ini sepenuhnya. Jjika tidak, anda dapat membaca kembali tutorial  tentang komunikasi serial dasar.

Sekarang, kami ingin memperluas kode ini sehingga data serial digema kembali saat diterima dalam interupsi, bukan loop program utama kami. 

Untuk melakukan ini, pertama-tama kita perlu menyertakan header library standar avr-libc, <avr / interrupt.h>. 

File ini berisi fungsi pustaka dan makro yang berhubungan dengan fungsionalitas interupsi AVR. 

Kami akan menambahkan ini ke bagian atas kode kami, di bawah header perangkat standar, <avr / io.h> termasuk:

# include < avr / io .h >
# include < avr / interrupt .h >

Setelah disertakan, sekarang kami memiliki cara untuk membuat ISR untuk menangani penerimaan serial. 

Untuk membuat ISR, kami menggunakan sintaks:

ISR ({ Vector Name }, { Options })
{
// Code to be executed when ISR fires
}

Dan letakkan di program kita seolah-olah itu adalah fungsi normal. Untuk menambahkan satu untuk menangani penerimaan byte melalui USART, kita perlu mencari nama yang sesuai di lembar data AVR kita. 

Dalam lembar data untuk contoh AVR kita, ATMEGA16, kita melihat bahwa nama interupsi ketika byte diterima adalah “USART RXC”. 

File header perangkat avr-libc standar <avr / io.h> - yang disertakan dalam program kami serta program AVR-GCC lainnya yang melibatkan fungsionalitas I / O AVR mendefinisikan nama vektor untuk kami. 

Nama simbolis avr-libc untuk masing-masing vektor interupsi identik dengan lembar data, dengan tambahan sufiks "vect" untuk menunjukkan bahwa itu adalah nama vektor. 

Jadi, karena lembar data kami mencantumkan "USART RXC" sebagai nama vektor, sintaks untuk program kami adalah:

ISR ( USART_RXC_vect , ISR_BLOCK )
{
// Code to be executed when the USART receives a byte here
}

Yang akan kita tempatkan di akhir program kita, setelah fungsi utama kita. Perhatikan bahwa di sini saya telah menggunakan opsi ISR dari ISR BLOCK, yang harus digunakan oleh sebagian besar rutinitas layanan interupsi kecuali dalam situasi khusus. 

Itu di luar cakupan tutorial ini, tapi harap baca manual avr-libc jika Anda ingin tahu lebih banyak tentang ini. Kode program baru terlihat seperti ini:

# include < avr / io .h >
# include < avr / interrupt .h >
# define USART_BAUDRATE 9600
# define BAUD_PRESCALE ((( F_CPU / ( USART_BAUDRATE * 16 UL ))) - 1)
int main ( void )
{
char ReceivedByte ;
UCSRB |= (1 << RXEN ) | (1 << TXEN ); // Turn on the transmission and reception circuitry
UCSRC |= (1 << URSEL ) | (1 << UCSZ0 ) | (1 << UCSZ1 ); // Use 8- bit character sizes
UBRRH = ( BAUD_PRESCALE >> 8) ; // Load upper 8- bits of the baud rate value into the high byte
of the UBRR register
UBRRL = BAUD_PRESCALE ; // Load lower 8 - bits of the baud rate value into the low byte of the
UBRR register
for (;;) // Loop forever
{
while (( UCSRA & (1 << RXC )) == 0) {}; // Do nothing until data have been received and is
ready to be read from UDR
ReceivedByte = UDR ; // Fetch the received byte value into the variable " ByteReceived "
while (( UCSRA & (1 << UDRE )) == 0) {}; // Do nothing until UDR is ready for more data to
be written to it
UDR = ReceivedByte ; // Echo back the received byte back to the computer
}
}
ISR ( USART_RXC_vect )
{
// Code to be executed when the USART receives a byte here
}

3. Mengisi ISR

Saat ini penerimaan USART baru kami ISR tidak benar-benar melakukan apa-apa - kami baru saja mendefinisikannya. 

Kami ingin itu menggemakan kembali byte yang dikirim, jadi kami akan memindahkan kode loop utama kami:

while (( UCSRA & (1 << RXC )) == 0) {}; // Do nothing until data have been received and is ready
to be read from UDR
ReceivedByte = UDR ; // Fetch the received byte value into the variable " ByteReceived "
while (( UCSRA & (1 << UDRE )) == 0) {}; // Do nothing until UDR is ready for more data to be
written to it
UDR = ReceivedByte ; // Echo back the received byte back to the computer

Ke sana. Namun, kami sekarang dapat menghapus dua while loop - karena ISR hanya aktif ketika byte diterima, dan hanya satu byte yang dikirim setelah setiap penerimaan, kami dapat menjamin bahwa kedua pemeriksaan sekarang redundan. 

Ketika ISR diaktifkan, kita tahu bahwa ada byte yang diterima di buffer input USART, dan juga tidak ada di buffer output. Dengan menggunakan pengetahuan ini, kita dapat menyederhanakan kode ISR kita menjadi berikut:

ISR ( USART_RXC_vect )
{
char ReceivedByte ;
ReceivedByte = UDR ; // Fetch the received byte value into the variable " ByteReceived "
UDR = ReceivedByte ; // Echo back the received byte back to the computer
}

Perhatikan bahwa saya juga telah memindahkan deklarasi variabel dari variabel ReceivedByte ke ISR, karena di situlah sebenarnya ia digunakan. Perlu disebutkan pada titik ini bagian kecil di lembar data tentang interupsi RXC:

Ketika penerimaan data yang digerakkan oleh interupsi digunakan, rutinitas penerimaan lengkap harus membaca data yang diterima dari UDR untuk menghapus Bendera RXC, jika tidak, interupsi baru akan terjadi setelah rutinitas interupsi berakhir.

Itu penting bagi kami untuk diingat: jika Anda menggunakan interupsi USART RXC, Anda harus membaca satu byte dari register UDR untuk menghapus flag interupsi. Kami melakukannya dalam kode di atas, tetapi ingatlah itu untuk proyek Anda di masa mendatang!

4. Mengaktifkan USART Receive Interrupt

Mari kita lihat inkarnasi terbaru dari kode pengujian kami:

# include < avr / io .h >
# include < avr / interrupt .h >
# define USART_BAUDRATE 9600
# define BAUD_PRESCALE ((( F_CPU / ( USART_BAUDRATE * 16 UL ))) - 1)
int main ( void )
{
UCSRB |= (1 << RXEN ) | (1 << TXEN ); // Turn on the transmission and reception circuitry
UCSRC |= (1 << URSEL ) | (1 << UCSZ0 ) | (1 << UCSZ1 ); // Use 8- bit character sizes
UBRRH = ( BAUD_PRESCALE >> 8) ; // Load upper 8- bits of the baud rate value into the high byte
of the UBRR register
UBRRL = BAUD_PRESCALE ; // Load lower 8 - bits of the baud rate value into the low byte of the
UBRR register
for (;;) // Loop forever
{
// Do nothing - echoing is handled by the ISR instead of in the main loop
}
}
ISR ( USART_RXC_vect )
{
char ReceivedByte ;
ReceivedByte = UDR ; // Fetch the received byte value into the variable " ByteReceived "
UDR = ReceivedByte ; // Echo back the received byte back to the computer
}

Jika Anda mengompilasi dan menjalankan ini, Anda akan melihat bahwa tidak ada yang terjadi - tidak ada karakter yang digaungkan kembali ke komputer yang terhubung. 

Ini karena meskipun kami telah menentukan dan mengisi ISR, kami belum mengaktifkannya. Untuk melakukannya, kita perlu melakukan dua hal:
  1. Aktifkan interupsi global
  2. Aktifkan USART Byte Received interrupt
Item pertama sederhana, jadi kami akan melakukannya terlebih dahulu. Mikrokontroler AVR berisi bendera global yang dapat disetel atau dihapus untuk mengaktifkan atau menonaktifkan penanganan interupsi. 

Perhatikan bahwa menyetel tanda ini tidak mengaktifkan semua interupsi, ini hanya memungkinkan kemungkinan menjalankannya. Jika tanda Global Interrupt Enable dinonaktifkan, semua interupsi akan diabaikan, bahkan jika diaktifkan (lebih lanjut tentang itu nanti).

Untuk mengaktifkan flag Global Interrupt Enable, kita dapat menggunakan makro sei () yang didefinisikan oleh file header avr-libc <avr / interrupt.h> secara membantu. 

Ini dinamai demikian karena menghasilkan instruksi perakitan "SEI" dalam daftar kode akhir, yang diinterpretasikan oleh AVR sebagai perintah untuk menyetel bendera Aktifkan Interupsi Global. 

Pujian dari sei () adalah cli () (untuk mematikan penanganan interupsi) namun kita tidak akan menggunakan makro itu dalam tutorial ini.

Kami akan menambahkan instruksi sei () kami ke rutinitas utama kami, setelah mengonfigurasi register USART:
// ...
UBRRH = ( BAUD_PRESCALE >> 8) ; // Load upper 8- bits of the baud rate value into the high byte
of the UBRR register
UBRRL = BAUD_PRESCALE ; // Load lower 8 - bits of the baud rate value into the low byte of the
UBRR register
sei () ; // Enable the Global Interrupt Enable flag so that interrupts can be processed
for (;;) // Loop forever
// ...

Sekarang untuk item kedua di daftar kami, yang perlu dilakukan sebelum interupsi diaktifkan. Kita perlu secara khusus mengaktifkan USART Receive Complete interrupt, yang dapat kita lakukan dengan menyetel flag yang sesuai di register kontrol USART.

Di ATMEGA16, bit ini disebut RXCIE (kependekan dari "Recieve Complete Interrupt Enable") dan merupakan bagian dari register UCSRB. Menyetel bit ini memungkinkan penanganan vektor peristiwa USART RXC:
UCSRB |= (1 << RXCIE );

Kami akan menambahkan ini ke rutinitas utama kami, sebelum "sei ();" baru kami perintah.

5. Menyatukan semuanya

Sekarang kita memiliki contoh serial yang digerakkan interupsi:
#include <avr/io.h>
#include <avr/interrupt.h>
#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL ))) - 1)
int main ( void )
{
UCSRB |= (1 << RXEN ) | (1 << TXEN ); // Turn on the transmission and reception circuitry
UCSRC |= (1 << URSEL ) | (1 << UCSZ0 ) | (1 << UCSZ1 ); // Use 8- bit character sizes
UBRRH = ( BAUD_PRESCALE >> 8) ; // Load upper 8- bits of the baud rate value into the high byte of the UBRR register
UBRRL = BAUD_PRESCALE ; // Load lower 8 - bits of the baud rate value into the low byte of the
UBRR register
UCSRB |= (1 << RXCIE ); // Enable the USART Recieve Complete interrupt ( USART_RXC )
sei () ; // Enable the Global Interrupt Enable flag so that interrupts can be processed
for (;;) // Loop forever
{
// Do nothing - echoing is handled by the ISR instead of in the main loop
}
}
ISR ( USART_RXC_vect )
{
char ReceivedByte ;
ReceivedByte = UDR ; // Fetch the received byte value into the variable " ByteReceived "
UDR = ReceivedByte ; // Echo back the received byte back to the computer
}

Yang, seperti program asli, akan menggemakan karakter yang diterima melalui USART. Namun, karena program kita sekarang digerakkan oleh interupsi, kita dapat menambahkan kode ke dalam loop utama yang akan dijalankan ketika data tidak diterima - seperti mem-flash LED.

Interupsi memungkinkan tugas-tugas "latar belakang" yang jarang dijalankan ketika terjadi, tanpa menimbulkan hukuman waktu proses karena harus memeriksa perangkat keras sampai terjadi genap. 

Ini membebaskan loop utama kita untuk menangani kode kritis, dengan kode interupsi menjeda kode utama untuk dieksekusi ketika peristiwa yang menarik terjadi.

Interupsi harus dibuat sesingkat mungkin dalam waktu eksekusi. Ini karena ketika satu ISR sedang dijalankan, yang lain diblokir dan dengan demikian jika kondisi ISR ​​lain terjadi ketika satu ISR sedang dijalankan, peristiwa ISR itu akan terlewat atau tertunda.

Karena itu, ISR komunikasi umumnya dibuat pendek dengan menerima karakter melalui ISR, dan menempatkannya ke dalam buffer yang dapat dibaca kode utama kapan saja. 

Ini memastikan bahwa data yang diterima tidak akan terlewatkan, sambil memberikan waktu program utama untuk menyelesaikan apa yang sedang dilakukannya sebelum harus memproses input. 

Demikian pula, transmisi panjang dapat dilakukan dengan menempatkan data yang akan dikirim ke buffer, dan meminta interupsi mengirim data saat perangkat keras siap sementara program utama melakukan tugas lain.

Judul asli : Interrupt Driven USART in AVR-GCC
Penulis: Dean Camera
Tanggal Publish : September 2, 2012

Post a Comment for "Interrupt untuk USART mikrokontroller AVR"