19.04.2026

Apparatli uzilishlar (interrupts) [18+]

Uzilishlar – o’zi nima degani?

uzilish (interrupts, internal ruptures – “Ichki uzilishlar”) – mikrokontrollerning yana bir muhim xususiyatlaridan biri bo’lib, u mikrokontroller asosiy dasturi tomonidan bajarilayotgan jarayonlarning ma’lum bir maxsus vazifani bajarish uchun vaqtincha to’xtatib turilishi hodisasi hisoblanadi. Tegishli “maxsus topshiriq” bajarilib bo’lgan zahoti mikrokontroller asosiy dasturni qolgan joyidan davom ettirib ketaveradi (ko’pincha bunday uzilishlar mikrokontroller piniga yuborilgan tashqi ta’sir oqibatida sodir bo’lganligi sababli, ularni umumiy nom bilan “tashqi uzilish” – “внешнее прерывание” deb ataladi, vaholanki, aslida uzilish mikrokontrollerning o’zida (ichida) amalga oshiriladi).

Mazkur vazifani dastur davomida bajarish ham mumkin, lekin bunda mikrokontroller vazifani bajarish paytida dastur algoritmi asosida ishlaydi va uning navbati yetib kelishini kutadi. Uzilish hosil qilinganda esa, o’sha paytda mikrokontroller qanday vazifa bajarayotganidan qat’iy nazar, ularnig hammasini “yig’ishtirib qo’yib”, kerakli “maxsus topshiriq”ni bajarishga kirishadi. Ya’ni, uzilishni sodir qiluvchi signal qabul qilingan zahoti (atigi bir necha mikrosekundlar ichida) mikrokontroller belgilangan vazifani bajarishga o’tadi.

Uzilishlar ularni keltirib chiqaruvchi ta’sirlarga ko’ra, 2 xil turga bo’linadi: apparatli (tashqi) va dasturiy uzilishlar.

Uzilishlarning amalda keng qo’llaniladigan turi – apparatli uzilishlar hisoblanadi. Bunday deyilishiga sabab, uzilish mikrokontroller pinlaridan birida yuqori (HIGH, +5V) yoki quyi (LOW, 0V) elektr signali paydo bo’lishi natijasida yuzaga keladi. Dasturiy uzilishlar – foydalanuvchi tomonidan dasturiy yo’l bilan, mikrokontroller ichki taymerlari yordamida sodir etiladigan uzilish turi.

Arduinoda uzilishlar bilan ishlashda quyidagi buyruqlardan foydalaniladi:

attachInterrupt(<pin tartibi>,<funksiya>,<rejim>) yoki attachInterrupt(<digitalPinToInterrupt(pin)>, <ISR>, <mode>); – uzilishni yo’lga qo’yish (boshlash);
detachInterrupt(<pin tartibi>); – uzilishni to’xtatish;
noInterrupts(); – uzilish davrida bajarilayotgan funksiyaning bajarilishini to’xtatish;
interrupts(); – to’xtatib qo’yilgan funksiya bajarilishini (uzilishni) davom ettirish;

Bu yerda:
<pin tartibi> – uzilish hosil qilinadigan tartib raqami. Uzilish hosil qilish mumkin bo’lgan pinlar soni turli mikrokontrollerlarda turlicha bo’lishi mumkin. Tartib raqami – AVR mikrokontrollerlarida alohida tartiblanadi va aksariyat hollarda pin raqami bilan bir xil bo’lmaydi. ESP8266 mikrokontrollerlarida esa, pin (GPIO yoki D-pin) raqami bilan bir xil bo’ladi;
<funksiya> – uzilish sodir bo’lgan paytda bajarilishi zarur bo’lgan “maxsus vazifa” nomi. Uzilish sodir bo’lgan zahoti ushbu funksiya bajariladi; ESP8266/32 da funksiya IRAM_ATTR yoki ICACHE_RAM_ATTR atributlari bilan yaratiladi. Agar uzilish paytida bajarladigan funksiya kodida biron o’zgaruvchi qiymati foydalanuvchi kodi tomonidan o’zgartirilishi mumkin bo’lsa, global o’zgaruvchilar (asosiy dastur boshida) volatile spetsifikatori bilan e’lon qilingan bo’lishi kerak. Uzilish paytida bajariladigan funksiyaning kodi imkon qadar qisqa bo’lishi zarur, aksincha uzoq yoki tez-tez uzilishlar mikrokontrollerning to’xtalishlar bilan ishlashiga sabab bo’lishi mumkin.

<rejim> – pinning uzilishni keltirib chiqaradigan holati. U quyidagi holatlardan biri bo’lishi mumkin: <LOW>, <RISING>, <FALLING>, <CHANGE>.

LOW rejimida uzilish tegishli pinda quyi signal (0V) paydo bo’lganda yuzaga keladi.
RISING rejimida uzilish pindagi signal LOW (oV) dan HIGH (+5V) ga o’zgarganda yuzaga keladi.
FALLING rejimida uzilish signal HIGH (+5V) dan LOW (0V) ga o’zgarganda yuzaga keladi.
CHANGE rejimida signal qarama-qarshi holatga (HIGH dan LOW ga yoki LOW dan HIGH ga) o’zgarganda yuzaga keladi.

Xo’sh, uzilishlardan qanday maqsadlarda foydalanish mumkin?

  • tugma bosilishiga yoki datchik ko’rsatkichi o’zgarishiga qarab, asosiy dastur o’sha paytda qaysi vazifani bajarayotganidan qat’iy nazar, uni to’xtatib, tugma holati yoki datchik ko’rsatkichini aniqlash, undan foydalanish uchun;
  • tez o’zgaruvchi jarayonlarni hisoblash (sanash) uchun. Masalan, dvigatelning aylanish tezligini hisoblovchi datchik ko’rsatkichini yuqori aniqlikda hisoblash uchun;
  • “chuqur uyqu” holatidagi mikrokontrollerni “uyg’otish” uchun. Mikrokontrollerning ushbu xususiyatidan ayniqsa, energiyani tejash maqsadlarida keng qo’llaniladi, chunki “uyqu” rejimida mikrokontroller deyarli elektr tokini sarf qilmaydi (faqat bir necha o’nlab mikroamperdan bir necha milliampergacha sarflaydi). Bunday holda mikrokontroller qisqa vaqtga uyg’otiladi va tegishli vazifani bajarib bo’lgach yana uyquga jo’natiladi. Masalan, mikrokontrollerni xonadagi haroratni har 30 sekundda o’lchash yoki kamera yordamida xonani suratga olish uchun uyg’otish, ularni kerakli qurilmaga jo’natish, shundan keyin yana uni uyquga jo’natish mumkin.

Demak, qaysi vaziyatda uzilish hosil qilishni foydalanuvchi o’zi oldindan belgilab olishi mumkin. Asosiysi, dastlab qaysi mikrokontroller nechta uzilish hosil qiladigan pinlarga ega, ular aynan qaysilar, ularning pin tartibi qanday ekanligini aniqlab olish juda muhim.

Eslatma. Uzilishlar hosil qilinganda mikrokontrollerning ichki taymerlari bilan bog’liq kodlarning bajarilishida uzilishlar yuz beradi. Masalan, uzilish funksiyasi kodida Arduinoning delay(), millis() va micros() kabi funksiyalari noto’g’ri ishlaydi. Chunki ushbu funksiyalar mikrokontroller taymeri bilan bog’liq. Bundan tashqari, Serial.print() funksiyasi ishlatilishida ham kamchiliklar kuzatiladi.

Uzilishdan foydalanishga misollar:

1-misol. Ushbu misolda 0-tartib raqamli pinda har safar 0 quyi signali hosil bo’lganda, hisobchi-o’zgaruvchi qiymati  1 taga oshib boradi va portga chiqariladi.

1-misol
volatile int counter = 0; // hisoblovchi o’zgaruvchi
void setup() {
Serial.begin(9600);
// Tugmani D2 va GND pinlari orasiga o’rnatiladi
pinMode(2, INPUT_PULLUP); // 2-raqamli pin musbatga tortish rejimiga o’tkazilmoqda (bu tugma bosilmagan paytda uning bir kontaktida doimiy yuqori signal bo’lishini ta’minlaydi)
// FALLING – tugma bosilgandagi signal 0 bo’lishini hisobga olib shu uzilish rejimni tanlaymiz
attachInterrupt(0, btnIsr, FALLING); // Uzilish pini tartib raqami, uzilish hosil qilinganda bajarilishi kerak bo’lgan funksiya, uzilish rejimini e’lon qilib qo’yamiz.
}
void btnIsr() {  // Uzilish paytida bajariladigan funksiya
counter++; // tugma bosilganda, hisoblovchi qiymati oshadi
}
void loop() {
Serial.println(counter); // Hisoblovchi qiymatini portga chiqaramiz
delay(1000);
}

2-misol. Bu misolda, uzilish sodir bo’lganini uzilish funksiyasida o’zgaruvchi qiymati o’zgarishiga moslashtirib qo’yamiz. Asosiy dastur o’z ishini shu o’zgaruvchi qiymatiga mos holda davom ettirishimiz mumkin. Demak, bunda uzilish sodir bo’lganda ortiqcha kodlar bajarilmaydi, faqat o’zgaruvchi qiymati o’zgaradi xolos.

2-misol
volatile bool intFlag = false; // “bayroq” o’zgaruvchisini e’lon qilamiz
void setup(){
Serial.begin(9600);
pinMode(2, INPUT_PULLUP);
attachInterrupt(0, buttonTick, FALLING);
}
void buttonTick(){  // Uzilish hosil qilinganda bajariladigan funksiya.
intFlag = true; // uzilish sodir bo’lganda “bayroqni ko’taramiz”
}
void loop(){
if(intFlag){ // Agar “bayroq ko’tarilgan” bo’lsa…
intFlag = false; // uni “tushiramiz”
// bu yerga kerakli vazifa kodini kiritish mumkin
Serial.println(“Uzilish sodir bo’ldi!”);
}
}

3-misol. Ushbu misolda, uzilish datchik ulangan pindagi signalning qiymatida o’zgarish bo’lganda sodir bo’ladi. Bu yerdagi millis() funksiyasi qiymati, yuqorida aytilganidek, funksiya ichida o’zgarmaydi, lekin uzilishdan chiqilgan oraliqda o’zgarib qoladi.

3-misol
void setup(){
attachInterrupt(0, isr, CHANGE); Uzilish pini tartib raqami, uzilish hosil qilinganda bajarilishi kerak bo’lgan funksiya, pindagi signal o’zgarganida uzilish rejimi e’lon qilinmoqda.
}
volatile uint32_t debounce;
void isr(){ // Uzilish funksiyasi
// digitalRead funksiyasi yordamida datchik pini holatini aniqlaymiz, tugma bosilgandagi stabillikni ta’minlash uchun 100 millisekundlik pauza o’rnatilmoqda.
if(millis() – debounce >= 100 && digitalRead(2)){
debounce = millis();
// datchik qiymati HIGH ga o’zgarganda bajarilishi kerak bo’lgan ixtiyoriy qisqa kod joyi
}
}
void loop(){
}

Добавить комментарий