Diberi mikrokontroler yang menjalankan kode berikut:
volatile bool has_flag = false;
void interrupt(void) //called when an interrupt is received
{
clear_interrupt_flag(); //clear interrupt flag
has_flag = true; //signal that we have an interrupt to process
}
int main()
{
while(1)
{
if(has_flag) //if we had an interrupt
{
has_flag = false; //clear the interrupt flag
process(); //process the interrupt
}
else
sleep(); //place the micro to sleep
}
}
Misalkan if(has_flag)
kondisi bernilai false dan kita akan menjalankan instruksi tidur. Tepat sebelum kami menjalankan instruksi tidur, kami menerima interupsi. Setelah kami meninggalkan interupsi, kami menjalankan instruksi tidur.
Urutan eksekusi ini tidak diinginkan karena:
- Mikrokontroler pergi tidur alih-alih bangun dan memanggil
process()
. - Mikrokontroler mungkin tidak pernah bangun jika tidak ada interupsi setelahnya diterima.
- Panggilan ke
process()
ditunda hingga interupsi berikutnya.
Bagaimana kode dapat ditulis untuk mencegah kondisi lomba ini terjadi?
Edit
Beberapa mikrokontroler, seperti di ATMega, memiliki bit aktifkan Tidur yang mencegah kondisi ini terjadi (terima kasih Kvegaoro karena telah menunjukkan ini). JRoberts menawarkan contoh implementasi yang mencontohkan perilaku ini.
Mikro lainnya, seperti pada PIC18s, tidak memiliki bit ini, dan masalahnya masih terjadi. Namun, micros ini dirancang sedemikian rupa sehingga interupsi masih dapat membangun inti terlepas dari apakah bit global interrupt diaktifkan diatur (terima kasih supercat untuk menunjukkan ini). Untuk arsitektur seperti itu, solusinya adalah menonaktifkan interupsi global tepat sebelum tidur. Jika interupsi menyala tepat sebelum menjalankan instruksi tidur, penangan interupsi tidak akan dieksekusi, inti akan bangun, dan begitu interupsi global diaktifkan kembali, penangan interupsi akan dieksekusi. Dalam pseudo-code, implementasinya akan terlihat seperti ini:
int main()
{
while(1)
{
//clear global interrupt enable bit.
//if the flag tested below is not set, then we enter
//sleep with the global interrupt bit cleared, which is
//the intended behavior.
disable_global_interrupts();
if(has_flag) //if we had an interrupt
{
has_flag = false; //clear the interrupt flag
enable_global_interrupts(); //set global interrupt enable bit.
process(); //process the interrupt
}
else
sleep(); //place the micro to sleep
}
}
interrupt_flag
sebagaiint
, dan menambahkannya setiap kali ada interupsi. Kemudian gantiif(has_flag)
kewhile (interrupts_count)
dan kemudian tidur. Meskipun demikian, interupsi dapat terjadi setelah Anda keluar dari loop sementara. Jika ini merupakan masalah, maka apakah pemrosesan dalam interrupt itu sendiri?Jawaban:
Biasanya ada beberapa jenis dukungan perangkat keras untuk kasus ini. Misalnya,
sei
instruksi AVR untuk mengaktifkan interupsi akan mengaktifkan hingga instruksi berikut selesai. Dengan itu orang dapat melakukannya:Interupsi yang terlewatkan dalam contoh akan dalam kasus ini ditunda sampai prosesor menyelesaikan urutan tidurnya.
sumber
Pada banyak mikrokontroler, selain dapat mengaktifkan atau menonaktifkan penyebab interupsi tertentu (biasanya dalam modul pengendali interupsi), ada flag utama dalam inti CPU yang menentukan apakah permintaan interupsi akan diterima. Banyak mikrokontroler akan keluar dari mode tidur jika permintaan interupsi mencapai inti, baik inti mau menerimanya atau tidak.
Pada desain seperti itu, pendekatan sederhana untuk mencapai perilaku tidur yang dapat diandalkan adalah dengan memeriksa lingkaran utama menghapus bendera dan kemudian memeriksa apakah tahu alasan mengapa prosesor harus bangun. Setiap interupsi yang terjadi selama waktu itu yang dapat mempengaruhi salah satu dari alasan-alasan itu harus menetapkan bendera. Jika loop utama tidak menemukan alasan untuk tetap terjaga, dan jika flag tidak disetel, loop utama harus menonaktifkan interupsi dan memeriksa lagi flag [mungkin setelah beberapa instruksi NOP jika mungkin interupsi yang menjadi tertunda selama instruksi penonaktifan-interupsi dapat diproses setelah pengambilan operan yang terkait dengan instruksi berikut telah dilakukan]. Jika bendera masih belum diatur, maka tidurlah.
Dalam skenario ini, interupsi yang terjadi sebelum loop utama menonaktifkan interupsi akan mengatur bendera sebelum tes akhir. Suatu interupsi yang menjadi tertunda terlalu terlambat untuk diservis sebelum instruksi tidur akan mencegah prosesor dari tidur. Kedua situasi baik-baik saja.
Sleep-on-exit terkadang merupakan model yang baik untuk digunakan, tetapi tidak semua aplikasi benar-benar "pas". Misalnya, perangkat dengan LCD hemat energi mungkin paling mudah diprogram dengan kode yang terlihat seperti:
Jika tidak ada tombol yang ditekan, dan tidak ada hal lain yang terjadi, tidak ada alasan sistem tidak tidur selama eksekusi
get_key
metode. Meskipun dimungkinkan untuk memiliki kunci memicu interupsi, dan mengelola semua interaksi antarmuka pengguna melalui mesin negara, kode seperti di atas sering kali merupakan cara paling logis untuk menangani aliran antarmuka pengguna yang sangat-modal khas mikrokontroler kecil.sumber
Programkan mikro untuk bangun saat interupsi.
Rincian spesifik akan bervariasi tergantung pada mikro yang Anda gunakan.
Kemudian, ubah rutinitas utama ():
sumber