Cum se configurează smartphone-uri și PC-uri. Portal informativ

Întreruperi și cazuri speciale. Exemple de întreruperi

Mecanismul prioritar (PM) indică ce dispozitive trebuie întreținute mai întâi. MP rezolvă următoarele sarcini:

    Fixează prioritatea oricărui program executat de procesor.

    Identifică RFP de la VU cu cea mai mare prioritate.

    Permite întreruperea programului atunci când apare o solicitare cu prioritate ridicată.

Întreruperea unei rutine de serviciu de întrerupere se numește întrerupere imbricată.

Orez. 6.4 Un exemplu de CPU în modul de întrerupere imbricată.

Figura 6.4 prezintă un exemplu de întrerupere imbricată:

    Inainte de t 1 nici un salariu

    t 1 → RFP de la VU4

    t 2 → RFP de la VU3

    t 3 → RFP de la VU2

    t 4 → întreținerea VU2 este finalizată

    t 5 → RFP de la VU1

    t 6 → întreținerea VU1 este finalizată

    t 7 → întreținerea completă a VU3

    t 8 → întreținerea VU4 este finalizată

Dezavantaj: Cu o frecventa mare de primire a salariului, CPU nu functioneaza eficient, deoarece se cheltuiește mult timp CPU pe ZP, restabilind registrele procesorului, trecând de la un program la altul.

Puteți reduce frecvența ZP pornind memoria tampon.

La atribuirea priorităților VU, se iau în considerare următoarele condiții:

    Cu cât dispozitivul este mai rapid, cu atât i se atribuie prioritate mai mare.

    Cea mai mare prioritate este atribuită dispozitivului de pe care datele nu pot fi recuperate (de obicei, un cronometru).

    În familia calculatoarelor Macintosh prioritatea programului este indicată în al doilea cuvânt al VI.

    În familia calculatoarelor IBMPC prioritatea programului este setată folosind un LSI special (circuit integrat mare) - un controler de întrerupere programabil.

Implementarea tehnică a întreruperilor vectoriale cu prioritate imbricată pe mai multe niveluri într-un computer bazat pe un singur canal de schimb de date de coloană principală.

Implementarea VI-urilor pe mai multe niveluri în calculatoarele familieiIBM .

Pentru implementarea multinivelului VI într-un computer al familiei IBM LSI aplicat Intel 8259A.

Specificații pentru Intel 8259a.

    Numărul de niveluri RFP = 8.

    Numărul de niveluri poate fi extins la 64 prin microcircuite în cascadă

    Modul de serviciu salarial, nivelurile de prioritate, WUA sunt setate programatic.

    Implementarea tehnică a întreruperilor vectoriale prioritare într-un computer cu canale de schimb de date trunchi izolate (familie IBMLA): moduri de funcționare ale controlerului de întrerupere programabil (SCP),

schema de conectare a panoului de control la magistrala de sistem,

Schema de conectare a panoului de control la magistrala de sistem VU.

Orez. 6.7 Schema de conectare a panoului de control la magistrala de sistem și la panoul de control.

Alocarea pinului LSI:

    D7- D0 - ieșirile motorului pas cu pas, sunt folosite pentru a primi informații de control de la CPU și a transmite informații de stare către CPU.

    A0 - intrare adresa, adresarea registrelor interne ale controlerului (2 adrese).

    ~ Cs (cip Selectați) - selectarea unui cristal, activează sau dezactivează comunicarea controlerului cu magistrala de sistem.

    • ~Cs= 0 - există o conexiune, ~ Cs= 1 - fără conexiune.

Primul panou de control folosește adresele - 20 h, 21 h.

Al doilea panou de control folosește adresele - A0 h, A1 h.

    ~ RD, ~ WR- intrarea, iesirea (semnale Shu) sunt conectate la liniile principale ~ IORşi ~IOW.

    INT(ieșire) - semnal ZP către CPU.

    ~ INTA (confirmare întrerupere)- Semnal RP de la CPU.

    CAS2, CAS1, CAS0 - autobuz în cascadă. Pentru controlerul de întrerupere master, aceste linii sunt ieșiri, iar pentru slave, sunt intrări.

    ~ SP/~ RU- indică masterul (1) sau slave (0) al panoului de control.

    IR0... IR7 - intrări de solicitări de întrerupere de la VU.

compoziția funcțională și modelul de program al panoului de control.

Întrerupe- aceasta este o schimbare a ordinii naturale de execuție a programului, care este asociată cu necesitatea ca sistemul să răspundă la funcționarea dispozitivelor externe, precum și la erori și situații speciale care au apărut în timpul execuției programului. Acest lucru numește un program special - handler de întrerupere, specific fiecărei situații apărute, după executarea căreia se reia funcționarea programului întrerupt.

Mecanismul de întrerupere este asigurat de hardware-ul și software-ul corespunzător al computerului.

Clasificarea întreruperilor este prezentată în Fig. 7.1.


Orez. 7.1.

Solicitările de întrerupere hardware apar asincron în raport cu funcționarea microprocesorului și sunt asociate cu funcționarea dispozitivelor externe.

O cerere de la întreruperi nemascabile ajunge la intrare NMI microprocesor și nu poate fi blocat de software. De obicei, această intrare este utilizată pentru a solicita întreruperi de la circuitele de control al puterii sau erori fatale I/O.

Pentru întrebări întreruperi mascate este utilizată intrarea INT a microprocesorului. Tratament cerere de întrerupere pe această intrare poate fi blocată prin ștergerea bitului IF în registrul steagului microprocesor.

Software-ul se întrerupe sunt, strict vorbind, numite excepții sau cazuri speciale. Ele sunt asociate cu situații speciale care apar în timpul execuției programului (lipsa unei pagini în RAM, încălcarea protecției, depășire), adică acele situații pe care programatorul nu le poate prevedea sau cu prezența unei comenzi speciale INT n în program, care este folosit de programator pentru a apela funcții ale sistemului de operare sau ale BIOS-ului care acceptă lucrul cu dispozitive externe. În cele ce urmează, atunci când discutăm despre activitatea sistemului de întrerupere, vom folosi termenul unic „întrerupere” pentru întreruperi hardware și excepții, dacă nu se specifică altfel.

Întreruperile software sunt de următoarele tipuri.

Încălcare (negare)- un caz special pe care microprocesorul îl poate detecta înainte ca eroarea efectivă să apară (de exemplu, absența unei pagini în RAM); după procesarea încălcării, programul este executat cu repornirea comenzii care a cauzat încălcarea.

Capcană- un caz special care este detectat după terminarea execuției comenzii (de exemplu, prezența comenzii INT n în program sau steag TF setat în registrul steagului). După ce această întrerupere a fost procesată, execuția programului continuă cu următoarea instrucțiune.

Prăbușire(ieșirea din proces) este o eroare atât de gravă încât un anumit context al programului se pierde și continuarea acestuia este imposibilă. Este imposibil de stabilit cauza accidentului, așa că programul este scos din procesare. Alarmele includ erori hardware și valori incompatibile sau invalide în tabelele de sistem.

Întreruperea comenzii de manipulare

Întreruperile și excepțiile sunt recunoscute la granițele instrucțiunilor și este posibil ca programatorului să nu-i pese de starea registrelor interne de lucru și a dispozitivelor de conductă.

Răspunzând solicitărilor de întrerupere, microprocesorul trebuie să-și identifice sursa, să păstreze contextul minim al programului curent și să treacă la un program special - handler-ul de întrerupere. După întrerupere, MP revine la programul întrerupt și ar trebui să se reia ca și cum nu ar exista nicio întrerupere.

Procesarea cererii de întrerupere constă în:

  • acțiuni „reflex” ale procesorului, care sunt aceleași pentru toate întreruperile și cazurile speciale și pe care programatorul nu le poate controla;
  • execuția handler-ului creat de programator.

Pentru ca microprocesorul să identifice sursa întreruperii și să găsească handlerul corespunzător cererii primite, fiecărei cereri de întrerupere i se atribuie propriul număr ( tip de întrerupere).

Tip de întrerupere pentru întreruperi software introdus din interiorul microprocesorului; de exemplu, întreruperea paginii din memorie este de tipul 14. Pentru întreruperile apelate de instrucțiunea INT n, tipul este conținut în instrucțiunea însăși. Pentru întreruperi hardware mascate, tipul este introdus de la controler de întrerupere prioritar pe magistrala de date. Întreruperea nemascabilă tip 2 atribuit.

În total, microprocesorul distinge 256 tipuri de întreruperi... Astfel, toate pot fi codificate pe 1 octet.

Acțiuni „reflex” ale microprocesorului asupra procesării cerere de întrerupere sunt realizate de hardware MP și includ:

  • definiție tip de întrerupere ;
  • salvarea contextului programului întrerupt (unele informații care vă vor permite să reveniți la programul întrerupt și să continuați execuția acestuia). Cel puțin registrele sunt întotdeauna salvate automat EIP si CS, definind punctul de revenire la programul intrerupt, si registrul steagurilor EFLAGS. Dacă un handler de întrerupere este apelat folosind o poartă de sarcini, atunci segmentul de stare TSS al sarcinii întrerupte este complet stocat în memorie;
  • definirea adresei handler de întrerupereși transferarea controlului către prima comandă a acestui handler.

După aceea, programul este executat - handler de întrerupere corespunzătoare cererii primite. Acest program este scris și plasat în memorie de către un programator de aplicații sau de sistem. Operatorul de întrerupere trebuie să se încheie cu comanda I RET, de-a lungul căruia trecerea la continuarea programului întrerupt cu restabilirea contextului acestuia are loc automat.

Pentru a apela operatorul de întrerupere, microprocesorul atunci când lucrați în modul real utilizări tabel de vectori de întrerupere si in modul protejat - tabel de descriptori de întrerupere.


Orez. 7.3.

Conținutul registrului IDTr nu este stocat în segmente TSS și nu este modificat atunci când sarcina este comutată. Programele nu pot accesa IDT din moment ce singurul bit de TI indicator de masă v selector segment oferă o alegere numai între tabele Gdtși LDT.

Limita maximă pentru tabelul descriptor de întrerupere este 256 * 8 - 1 = 2047.

Este posibil să setați limita mai mică, dar acest lucru nu este recomandat. Dacă mânerul este accesat în afara limitelor IDT, procesorul intră în modul de oprire până când primește un semnal la intrare NMI sau resetați.

V IDT pot fi stocați doar descriptori de următoarele tipuri:

  • poarta capcana,
  • gateway de întrerupere, gateway de sarcini.

Temporizatoare de supraveghere.

Adesea, zgomotul electric generat de echipamentele din jur face ca microcontrolerul să abordeze o adresă greșită, după care comportamentul său devine imprevizibil (microcontrolerul este „scăpat de sub control”). Pentru a monitoriza astfel de situații, cronometrele de supraveghere sunt adesea incluse în microcontroler.

Acest dispozitiv determină resetarea microcontrolerului dacă conținutul său nu este actualizat într-o anumită perioadă de timp (de obicei de la zeci de milisecunde la câteva secunde). Dacă modificarea conținutului contorului programului nu corespunde programului specificat, comanda de modificare a cronometrului watchdog nu va fi executată. În acest caz, timer-ul watchdog resetează microcontrolerul, punându-l la starea inițială.

Mulți dezvoltatori nu folosesc temporizatoare watchdog în aplicațiile lor, deoarece nu văd nevoia să le folosească pentru a combate efectele zgomotului electric, de exemplu, atunci când plasează un microcontroler într-un afișaj cu raze catodice lângă un transformator care asigură o amortizare a zgomotului electric. calea de întoarcere a fasciculului sau lângă bobinele de aprindere din mașină. În electronica modernă, este puțin probabil să apară perturbări electrice, deși acestea apar uneori în situații precum cele enumerate mai sus.

Nu este recomandat să utilizați timer-ul watchdog pentru a masca problemele software. Deși acest temporizator poate reduce probabilitatea erorilor software, este puțin probabil să elimine toate cauzele posibile ale erorilor. În loc să vă bazați pe hardware pentru a preveni erorile software, este mai bine să testați software-ul mai amănunțit în diferite situații.

Mulți utilizatori cred că întreruperile sunt o piesă hardware care este cel mai bine lăsată în pace, deoarece utilizarea lor necesită cunoștințe excelente despre procesor pentru a dezvolta un handler de întreruperi. În caz contrar, atunci când apare o întrerupere, sistemul „adoarme” sau „pedalează”. Acest sentiment vine de obicei la un dezvoltator după experiența cu întreruperi pentru un computer personal, care are o serie de caracteristici care fac dificilă crearea unui handler de întreruperi. Multe dintre aceste probleme nu apar în hardware-ul bazat pe microcontrolere. Utilizarea întreruperilor în acest echipament poate simplifica foarte mult proiectarea și utilizarea acestuia.

Dacă nu te-ai ocupat niciodată de întreruperi, atunci apare întrebarea - ce este? Într-un sistem informatic, o întrerupere este lansarea unei subrutine speciale (numită „gestionar de întreruperi” sau „rutină de servicii de întrerupere”) care este declanșată de un semnal hardware. În timpul execuției acestei subrutine, implementarea programului curent este oprită. Termenul de cerere de întrerupere este folosit deoarece uneori programul refuză să confirme întreruperea și să execute imediat manerul de întrerupere (Figura 2.19).


Întreruperile dintr-un sistem informatic sunt similare cu întreruperile din viața de zi cu zi. Un exemplu clasic de astfel de întrerupere este un apel telefonic în timp ce vizionați un program TV. Când sună telefonul, aveți trei opțiuni. Primul este să ignori apelul. Al doilea este să răspunzi la apel, dar să spui că vei suna mai târziu. Al treilea este de a răspunde la apel, amânând toate treburile curente. Sistemul informatic are, de asemenea, trei astfel de răspunsuri care pot fi utilizate ca răspuns la o solicitare hardware externă.

Primul răspuns posibil - „nu răspunde la o întrerupere până la finalizarea sarcinii curente” - este implementat prin dezactivarea (mascarea) serviciului cererii de întrerupere. După finalizarea sarcinii, este posibilă una dintre cele două opțiuni: resetarea măștii și activarea serviciului, ceea ce va duce la un apel către operatorul de întrerupere sau analizarea valorii biților ("polling"). indicând sosirea cererilor de întrerupere și execuția directă a programului de serviciu fără invocarea gestionarului de întreruperi. Această metodă de gestionare a întreruperilor este utilizată atunci când este necesar să se asigure un timp de execuție specificat al programului principal, deoarece orice întrerupere poate încălca implementarea interfeței necesare.

Orez. 2.18 - Executarea unei întreruperi.

Mascarea pe termen lung a întreruperilor nu este recomandată, deoarece în acest timp se pot suprapune mai multe evenimente care provoacă întreruperi și doar unul va fi recunoscut. Durata de mascare permisă depinde de aplicația specifică a microcontrolerului și de tipul și frecvența unor astfel de evenimente. Nu este recomandat să dezactivați întreruperile pentru o perioadă mai mare de jumătate din perioada minimă așteptată de succesiune a evenimentelor care solicită întreruperi.

Managerul de întrerupere oferă întotdeauna următoarea secvență de acțiuni:

2. Resetați controlerul de întrerupere și hardware-ul care a cauzat solicitarea.

3. Prelucrați datele.

4. Restaurați conținutul registrelor de context.

5. Reveniți la programul întrerupt.

Registrele de context sunt registre care determină starea curentă de execuție a programului principal. De obicei, acestea includ contorul de programe, registrele de stare și acumulatorii. Alte registre de procesor, cum ar fi registrele index, pot fi utilizate în timpul procesării întreruperilor, astfel încât conținutul lor trebuie și el salvat. Toate celelalte registre sunt specifice unui anumit microcontroler și aplicației sale.

După ce a fost resetat, controlerul de întrerupere este gata să accepte următoarea cerere, iar echipamentul care provoacă întreruperea este gata să trimită cererea atunci când este cazul. Dacă sosește o nouă solicitare de întrerupere, registrul de mascare a întreruperilor al procesorului va preveni procesarea întreruperilor, dar registrul de stare a întreruperii va captura această solicitare, care va aștepta serviciul ei. După finalizarea procesării întreruperii curente, masca de întrerupere va fi ștearsă, iar cererea nou primită este trimisă pentru procesare.

Întreruperile imbricate sunt greu de implementat cu unele tipuri de microcontrolere care nu au o stivă. Aceste întreruperi pot cauza, de asemenea, probleme de depășire a stivei. Problema overflow este relevantă pentru microcontrolere datorită cantității limitate a memoriei și a stivei lor de date: o secvență de întreruperi imbricate poate duce la faptul că mai multe date vor fi împinse în stivă decât este permis.

În cele din urmă, întreruperea este procesată. Al doilea exemplu TV arată că puteți răspunde rapid la o solicitare de întrerupere acceptând datele necesare, care vor fi apoi folosite după rezolvarea problemei curente. În microcontrolere, acest lucru este implementat prin stocarea datelor primite într-o matrice de memorie și apoi procesarea lor când execuția programului original este finalizată. Acest mod de service este un bun compromis între gestionarea imediată completă a întreruperii, care poate dura mult timp, și ignorarea întreruperii, ceea ce poate duce la pierderea informațiilor despre evenimentul care a provocat întreruperea.

Restaurarea registrelor de context și executarea comenzii de returnare a întreruperii readuce procesorul la starea în care se afla înainte de apariția întreruperii.

Luați în considerare ce se întâmplă cu conținutul diferitelor registre atunci când este procesată o întrerupere. Conținutul registrului de stare este de obicei salvat automat împreună cu conținutul contorului software înainte ca întreruperea să fie procesată. Acest lucru elimină nevoia de a-l stoca în mod programatic în memorie folosind instrucțiuni de transfer și apoi de a-l restabili când reveniți la programul original. Cu toate acestea, o astfel de salvare automată nu este implementată în toate tipurile de microcontrolere, prin urmare, trebuie acordată o atenție deosebită organizării gestionării întreruperilor.

Dacă conținutul registrului de stare este salvat înainte de începerea execuției gestionarului de întrerupere, atunci la comanda de returnare este restaurat automat.

Dacă conținutul altor registre de procesor se modifică atunci când serviciul de întrerupere este executat, atunci acesta trebuie, de asemenea, salvat în memorie înainte de modificare și restaurat înainte de a reveni la programul principal. Este o practică obișnuită să păstrați toate registrele procesorului pentru a evita erorile imprevizibile care sunt foarte greu de localizat.

Adresa care este încărcată în contorul de program atunci când sare la handler-ul de întrerupere se numește „vector de întrerupere”. Există mai multe tipuri de vectori. Adresa care este încărcată în contorul de programe atunci când microcontrolerul pornește (resetare) se numește „vector de resetare”. Pot fi specificați diferiți vectori pentru diferite întreruperi, eliminând necesitatea ca rutina de service să determine cauza întreruperii. Utilizarea unui vector prin diferite întreruperi de obicei nu cauzează probleme microcontrolerelor, deoarece cel mai adesea microcontrolerul execută un singur program. Acesta este modul în care microcontrolerul diferă de un computer personal, în timpul funcționării căruia se pot adăuga diverse surse de întreruperi. (Dacă ați conectat vreodată două dispozitive la COM1 și COM3, atunci știți despre ce este vorba). Într-un microcontroler în care hardware-ul este bine cunoscut, nu ar trebui să existe nicio problemă la partajarea vectorilor de întrerupere.

Ultimul lucru care rămâne de luat în considerare sunt întreruperile software. Există instrucțiuni de procesor care pot fi folosite pentru a simula întreruperi hardware. Cea mai evidentă utilizare a acestor comenzi este apelarea rutinelor de sistem care sunt situate într-o locație arbitrară din memorie sau necesită salturi de intersegment pentru a le accesa. Această caracteristică este implementată în familia de microprocesoare Intel i86 și este utilizată în sistemul de intrare/ieșire de bază (BIOS) și sistemul de operare DOS al computerelor personale pentru a apela rutinele sistemului fără a fi nevoie să repari punctul de intrare. În schimb, diferiți vectori de întrerupere sunt utilizați pentru a selecta instrucțiunea care trebuie executată atunci când are loc o astfel de întrerupere software.

Poate după ce ați citit acest capitol, mecanismul de întrerupere va deveni mai ușor de înțeles pentru dvs. sau invers. Vei deveni doar mai confuz. Descrierea fiecărui microcontroler va arăta cum utilizarea întreruperilor poate simplifica aplicarea acestuia.

Există o situație în care trebuie să agățați multe sarcini diferite pe un singur dispozitiv periferic, dar există doar una și trebuie făcut ceva în acest sens.

Un exemplu simplu este un temporizator și întreruperea acestuia de depășire.
Putem seta viteza obturatorului și putem întrerupe pentru a face unele operații. Dar dacă la un moment dat vrem ca temporizatorul de întrerupere să facă o operație, apoi alta, o a treia. Da, atat cat este necesar, in functie de stat. Și există un singur vector.

Sau, de exemplu, USART. Este posibil să avem nevoie cu ușurință de a executa un cod diferit, în funcție de modul de întrerupere la sosirea unui octet. Într-un mod - emiterea unui salut, în celălalt - trimiterea de obscenități la baie. În al treilea, o lovitură în cap. Și există un singur vector.

Desigur, puteți adăuga o construcție de tip comutator la manipulatorul de întreruperi și, alegând modul, mergeți la secțiunea dorită a codului, dar acest lucru este destul de greoi și, cel mai important, timpul de tranziție va fi diferit, în funcție de ordinea în care vor merge structurile de comparație-caz de comutare-sondare.

Adică într-un comutator de forma:

1 2 3 4 5 6 7 comutator (x) (1: Acțiune 1 2: Acțiune 2 3: Acțiune 3 4: Acțiune 4)

comutator (x) (1: Acțiune 1 2: Acțiune 2 3: Acțiune 3 4: Acțiune 4)

Va exista o comparație secvențială a lui x, mai întâi cu 1, apoi cu 2, apoi cu 3 și așa mai departe până când toate opțiunile sunt enumerate. În acest caz, reacția la Acțiunea 1 va fi mai rapidă decât reacția la Acțiunea 4. Acest lucru este deosebit de important atunci când se calculează intervalele exacte de timp pe cronometru.

Dar există o soluție simplă la această problemă - un salt de index. Este suficient înainte de a începe să așteptăm ca întreruperea să se preîncarce în variabile (sau puteți direct în registrul index Z) direcția în care trebuie să redirecționăm vectorul nostru și să introducem saltul de index în handler-ul de întrerupere. Și voila! Tranziția va fi acolo unde trebuie, fără nicio comparație de opțiuni.

În memorie, creați variabile pentru un vector plutitor:

Timer0_Vect_L: .byte 1; Doi octeți ai adresei, înaltă și scăzută Timer0_Vect_H: .byte 1

Pregătirea pentru a aștepta o întrerupere este simplă, luăm și încărcăm în variabila noastră adresa dorită

CLI; Partea critică. Întrerupe OFF LDI R16, low (Timer_01); Luați adresa și salvați STS Timer0_Vect_L, R16; o celulă de memorie. LDI R16, High (Timer_01); În mod similar, dar cu vectorul senior STS Timer0_Vect_H, R16 SEI; Întreruperi ON

Gata, puteți porni cronometrul și așteptați întreruperea noastră. Este la fel și cu alte cazuri.

Și handlerul este așa:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 ; ===============================; Introducerea unei întreruperi de overflow de la Timer0; ============================ TIMER_0: PUSH ZL; salvați registrul index pe stiva PUSH ZH; de cand il folosim PUSH R2; salvați R2, pentru că stricam si noi IN R2, SREG; Preluați și salvați registrul de steag PUSH R2; Dacă nu faceți acest lucru, atunci 100% vor avea erori LDS ZL, Timer0_Vect_L; încărcați adresa noului vector LDS ZH, Timer0_Vect_H; ambii octeți. CLR R2; Curățăm R2 SAU R2, ZL; Verificarea vectorului pentru zero. În caz contrar, să înțelegem analogul lui OR R2, ZH; reset "a. Verificarea trece prin operația OR BREQ Exit_Tm0; cu acumularea rezultatului în R2; deci nu stricăm conținutul lui Z și nu trebuie să; încărcăm din nou IJMP; Plecăm cu un nou vector ; Ieșire din întrerupere. Ieșire_Tm0: POP R2; Scoatem și restabilim registrul flag OUT SREG, R2 POP R2; restabilim R2 POP ZH; Restaurați Z POP ZL RETI; Vector suplimentar 1 Timer_01: NOP; Aceștia sunt noii noștri vectori NOP; aici putem face orice NOP; de preferință nu pentru mult timp - în întrerupere NOP; Dacă folosim orice alte NOP; registre, atunci le salvăm și în stiva RJMP Exit_Tm0; Aceasta este o tranziție pentru a ieși din întrerupere; special făcută prin RJMP astfel încât; Vector suplimentar 2; salva zece octeți pe codul de întoarcere :))) Timer_02: NOP NOP NOP NOP NOP RJMP Exit_Tm0; Vector suplimentar 3 Timer_03: NOP NOP NOP NOP NOP RJMP Exit_Tm0

; ===============================; Introducerea unei întreruperi de overflow de la Timer0; ============================ TIMER_0: PUSH ZL; salvați registrul index pe stiva PUSH ZH; de cand il folosim PUSH R2; salvați R2, pentru că stricam si noi IN R2, SREG; Preluați și salvați registrul de steag PUSH R2; Dacă nu faceți acest lucru, atunci 100% vor avea erori LDS ZL, Timer0_Vect_L; încărcați adresa noului vector LDS ZH, Timer0_Vect_H; ambii octeți. CLR R2; Curățăm R2 SAU R2, ZL; Verificarea vectorului pentru zero. În caz contrar, să înțelegem analogul lui OR R2, ZH; reset "a. Verificarea trece prin operația OR BREQ Exit_Tm0; cu acumularea rezultatului în R2; deci nu stricăm conținutul lui Z și nu trebuie să; încărcăm din nou IJMP; Plecăm cu un nou vector ; Ieșire din întrerupere. Ieșire_Tm0: POP R2; Scoatem și restabilim registrul flag OUT SREG, R2 POP R2; restabilim R2 POP ZH; Restaurați Z POP ZL RETI; Vector suplimentar 1 Timer_01: NOP; Aceștia sunt noii noștri vectori NOP; aici putem face orice NOP; de preferință nu pentru mult timp - în întrerupere NOP; Dacă folosim orice alte NOP; registre, atunci le salvăm și în stiva RJMP Exit_Tm0; Aceasta este o tranziție pentru a ieși din întrerupere; special făcută prin RJMP astfel încât; Vector suplimentar 2; salva zece octeți pe codul de întoarcere :))) Timer_02: NOP NOP NOP NOP NOP RJMP Exit_Tm0; Vector suplimentar 3 Timer_03: NOP NOP NOP NOP NOP RJMP Exit_Tm0

Implementarea pentru RTOS
Dar dacă programul nostru este construit în așa fel încât tot codul să se rotească prin lanțurile de sarcini prin managerul RTOS? Este foarte greu să calculezi în capul tău cum sunt realizate aceste lanțuri unul în raport cu celălalt. Și fiecare dintre ei poate încerca să intre în posesia cronometrului (desigur, nu în mod arbitrar, din depunerea noastră, scriem programul, dar va fi dificil să urmăriți în timp cât de dificil va fi totul).
În axele majore moderne, există un mecanism de excludere reciprocă pentru acest caz - mutex. Acestea. este un fel de steag ocupat. Dacă un proces comunică, de exemplu, cu un UART, atunci un alt proces nu îndrăznește să lipească un octet acolo și așteaptă cu grijă până când primul proces eliberează UART, ceea ce va fi indicat de un steag.

În cazul meu, nu există mecanisme de excludere reciprocă, dar pot fi implementate. Cel puțin faceți o aparență minimă. Nu vreau să fac o implementare completă a tuturor acestor vechituri, pentru că Scopul meu este să mențin dimensiunea nucleului la 500-800 de octeți.
Cel mai simplu mod de a rezerva încă un octet în memorie este variabila ocupat. Iar atunci când un proces confiscă o resursă, atunci în această variabilă scrie ora când o eliberează aproximativ. Timpul trece în ticks ale temporizatorului de sistem, pe care îl am 1 ms.
Dacă orice alt proces încearcă să acceseze aceeași resursă hardware, se va uita mai întâi la starea de angajare, va număra timpul în care va fi ocupat și va lăsa să fumeze pentru această perioadă - se va încărca singur în coada de cronometru. Acolo va verifica din nou și așa mai departe. Aceasta este cea mai simplă opțiune.

Problema aici este că, dacă există o mulțime de oameni interesați de un vector, atunci procesele vor continua să se desfășoare de jur împrejur, ca un tânăr bătând în jurul singurei toalete de pe piață în timpul festivităților de sărbători. Vezica urinară a cuiva nu va suporta - algoritmul se va strica. Și cine are smochine aici poți ghici, tk. va fi greu de simulat.

Soluția problemei este adăugarea unui alt lanț obișnuit, de data aceasta pentru accesul la resursă. Ca să nu stea deloc degeaba. Acestea. unul a sărit afară, apoi un al doilea, un al treilea și așa mai departe până când toate procesele le eliberează nevoia de un fel de USART.
Dezavantajul este evident - o altă coadă este memorie suplimentară, cod suplimentar, timp suplimentar. Puteți, desigur, să fiți pervertit și să setați codul dispecerului principal al lanțului din coadă la vector. Dar aici trebuie să depanați totul cu atenție, deoarece va fi apelat la întrerupere! Da, și greoaie, se cere doar când avem mulți solicitanți.

A doua soluție este să renunți la variabila de timp ocupat, lăsând doar steagul Ocupat! Iar procesul care încearcă să contacteze nu fuge pentru a fuma, ci sare înapoi câțiva pași - până la sfârșitul cozii de sarcini și imediat exploda înapoi. Oamenii din jurul toaletei nu aleargă, ci își împing coatele la intrare pe principiul cine trece primul.
Un alt dezavantaj este o încărcare mare pe conducta principală, o grămadă de solicitări de a sta la coadă pentru o perioadă scurtă de timp pe întreaga memorie RAM și de întâlnire cu stiva, iar acest lucru este plin de o apocalipsă globală.

Desigur, cronometrul aici este dat ca exemplu, majoritatea sarcinilor pot fi rezolvate cu cronometrul sistemului RTOS, dar dacă brusc aveți nevoie de mai puțină discreție sau de o rată mare de reacție la un eveniment (și nu în timp ce conducta principală trage sarcina). până la execuție), apoi mecanismul de întreruperi controlate, IMHO, apoi pe care medicul l-a prescris.

Top articole similare