Interruzione sul controller AVR in Atmel AVR Studio. Interrupt - Studiare l'AVR - Catalogo articoli - Microcontrollori: è facile! In quale ambiente programmare gli interrupt del microcontrollore

I sistemi di interruzione sono una parte importante di qualsiasi sistema di controllo.

L'efficienza con cui il sistema a microprocessore svolge le sue funzioni dipende in gran parte dal suo funzionamento. La struttura generale del sistema di interruzione MK-51 è mostrata in Fig. 14.3.

I microcontrollori della famiglia MK-51 forniscono supporto per cinque fonti di interruzione:

* due interrupt esterni in arrivo sugli ingressi INT0 e INT1 (port line P3: P3.2 e P3.3, rispettivamente);

* due interruzioni da timer/contatori T/C0 e T/C1;

* interruzione della porta seriale.

Le richieste di interruzione vengono registrate nei registri delle funzioni speciali del microcontrollore: i flag IE0, IE1, TF0, TF1 le richieste di interruzione da INT0, INT1, T/C0 e T/C1 sono contenute nel registro di controllo TCON (Tabella 14.4), e i flag RI e TI richiede un'interruzione dalla porta seriale - nel registro SCON per il controllo della porta seriale.

Tabella 14.4. Formato registro TCON

0 IT0 Impostazione del tipo di interrupt INT0

1 IE0 Flag di richiesta di interrupt INT0

2 IT1 Impostazione del tipo di interruzione INT1

3 IE1 Flag di richiesta di interrupt INT1

4 TR0 Abilita timer/contatore 0

5 TF0 Flag di overflow (richiesta di interruzione) timer/contatore 0

6 TR1 Abilita timer/contatore 1

7 TF1 Flag di overflow (richiesta di interruzione) del timer/contatore 1

I flag TF0 e TF1 vengono impostati dall'hardware quando il timer/contatore corrispondente va in overflow (più precisamente, quando T/Cx passa dallo stato “tutti uno” allo stato “tutti zeri”).

I flag IE0 e IE1 vengono impostati dall'hardware rispettivamente dagli interrupt esterni IT0 e IT1. Una richiesta esterna può far sì che il flag venga impostato sia quando il livello del segnale all'ingresso corrispondente è basso, sia quando questo segnale passa dal livello alto a quello basso (con una frequenza non superiore alla metà della frequenza del clock esterno del MK).

Il tipo di richiesta viene configurato dal software impostando i bit IT0 e IT1 nel registro di controllo TCON. L'impostazione ITx = 0 configura il sistema di interruzione per richiedere un livello di segnale basso, ITx = 1: imposta l'interruzione per richiedere un livello di segnale basso.

I flag TI e RI vengono impostati dall'hardware dell'interfaccia seriale rispettivamente dopo la fine della trasmissione o dopo la fine della ricezione.

Tutti i flag di richiesta di interruzione specificati sono disponibili a livello di codice per l'impostazione e il ripristino. L'impostazione del flag di richiesta di interruzione nel software produce la stessa risposta da parte del microcontrollore dell'impostazione dello stesso flag nell'hardware.

I flag TF0 e TF1 vengono resettati dall'hardware quando il controllo viene trasferito alla corrispondente routine di interrupt.

Il ripristino dei flag IEx viene eseguito nell'hardware durante la manutenzione dell'interrupt solo se l'interrupt è stato configurato per rilevare la caduta del segnale INTx. Se l'interruzione è stata configurata per rilevare il livello del segnale di richiesta, il ripristino del flag IEx deve essere eseguito dal programma di servizio dell'interruzione, agendo sulla sorgente dell'interruzione per rimuovere la richiesta.

I flag TI e RI possono essere ripristinati solo tramite software.

Ciascun tipo di interruzione viene abilitato o disabilitato individualmente impostando o cancellando i bit corrispondenti del registro di abilitazione dell'interruzione IE. Questo registro contiene anche un bit di disabilitazione generale per tutti gli interrupt. Il formato del registro IE è riportato nella tabella. 14.5.

Tabella 14.5. Assegnazione dei bit di registro IE

Posizione del registro

Piccoli mnemonici

Funzione

Disabilita le interruzioni da tutte le fonti

Non usato

Non usato

Disabilita interruzione da porta seriale

Disabilita l'interruzione del timer/contatore T/C1

Disabilita interruzione da fonte esterna INT1

Disabilita interruzione timer/contatore T/C0

Disabilita l'interruzione dalla fonte esterna INT0

A ciascun tipo di interruzione può essere assegnata a livello di codice una delle due possibili priorità: 0 - la più bassa o 1 - la più alta.

Le priorità vengono configurate impostando o cancellando il bit corrispondente nel registro di priorità dell'interrupt IP. Il formato di questo registro è riportato nella tabella. 14.6.

Quando le richieste di interruzione vengono ricevute simultaneamente da origini con priorità diverse, la richiesta proveniente dall'origine con priorità più alta viene elaborata per prima.

In caso di ricezione simultanea di più richieste di interruzione con la stessa priorità, l'ordine della loro elaborazione è determinato dall'hardware del microcontrollore e non può essere modificato dal software. Questo ordine corrisponde alla sequenza dei flag di richiesta di interruzione del polling, che assomiglia a questa:

IT0 -> TF0 -> IT1 -> TF1 -> (RI, TI)

Tabella 14.6. Assegnazioni dei bit del registro IP

Posizione del registro Bit mnemonico Funzione

7 - Non utilizzato

6 - Non utilizzato

5 - Non utilizzato

4 PS Priorità di interruzione della porta seriale

3 Priorità interruzione timer/contatore PT1 T/C1

2 PX1 Priorità di interrupt da sorgente esterna INT1

1 PT0 Priorità interruzione timer/contatore T/C0

0 PX0 Priorità di interrupt da sorgente esterna INT0

Una chiamata al gestore di interrupt implementata dall'hardware è costituita dalle seguenti azioni:

* salvataggio del valore del contatore del programma nello stack;

I punti di ingresso del gestore di interruzione per ciascuna origine di interruzione sono fissati nell'hardware. I loro valori sono riportati nella tabella. 14.7.

Tabella 14.7. Indirizzi dei punti di ingresso per i gestori delle interruzioni

Sorgente di interruzione

Indirizzi dei punti di ingresso per i gestori delle interruzioni

Interruzione esterna( ITO)

Contatore temporizzato (TFO)

Interruzione esterna (IT1)

Contatore temporizzato (TF1)

Porta seriale (R1 o T1)

Il primo comando del gestore di interrupt dovrebbe trovarsi all'indirizzo specificato. Di norma, tale comando è un comando per passare incondizionatamente al punto del programma in cui si trova effettivamente il gestore.

Quando si passa alla routine di gestione degli interrupt, automaticamente, indipendentemente dallo stato del registro IE, tutti gli interrupt che hanno un livello di priorità uguale al livello di priorità dell'interrupt servito vengono disabilitati, ovvero gli interrupt nidificati con un livello di priorità uguale sono disabilitati . Pertanto, un interrupt a bassa priorità (avente uno "0" nel bit corrispondente del registro IP) può essere interrotto da un interrupt ad alta priorità (avente un "1" nel bit corrispondente del registro IP), ma non da un interrupt ad alta priorità (avente un "1" nel bit corrispondente del registro IP). quello a bassa priorità. Il servizio di un'interruzione ad alta priorità non può essere interrotto da un'altra fonte.

Il ritorno dal gestore degli interrupt viene effettuato utilizzando l'istruzione RETI, che ripristina dallo stack il valore del contatore del programma del PC memorizzato lì nel momento in cui è stato chiamato il gestore degli interrupt, e la logica della priorità degli interrupt.


Parliamo di interruzioni. La parola interruzione parla da sola; un processo viene interrotto per un certo periodo per eseguire ulteriori azioni. Gli interrupt possono essere esterni o interni. Lascia che ti faccia un semplice esempio che ho sentito dal mio amico...

Si preparò a lavare i piatti in cucina, cominciò con entusiasmo, rimboccandosi le maniche... ma i piatti risultarono unti e fu costretto a fermarsi per cercare un detersivo per lavare i piatti unti su uno degli scaffali della cucina. l'unità della cucina, dopodiché ha continuato nuovamente il suo compito. Ma a un certo punto il telefono squillò e lui fece di nuovo una pausa dal lavoro, prese il telefono, sua suocera chiamò e disse che sarebbe venuta a trovarlo, quindi doveva andare al negozio a fare la spesa prima di lei. arrivato. Sono andato al negozio e solo allora ho lavato i piatti.

Questo esempio mostra due tipi di interruzioni, la prima è associata all'esecuzione del lavoro principale - ricerca del detersivo per piatti grassi - un'interruzione interna, la seconda - telefonata– interruzione esterna.
In un microcontrollore, le interruzioni esterne sorgono a causa di segnali provenienti da altre fonti, le interruzioni interne sorgono a causa di dispositivi integrati nel microcontrollore stesso. Perché le interruzioni sono così attraenti?
Il primo è che possiamo fermare il processo principale per eseguire qualche altra funzione, e poi continuare questo processo.
Il secondo, e probabilmente in molti casi il principale, è considerato l'accelerazione del processo di esecuzione di tutte le funzioni, a causa dei processi interni dispositivi aggiuntivi. Torniamo al nostro esempio. Diciamo che il mio amico ha iniziato a lavare i piatti quando sua moglie era già arrivata a casa. Vedendo i piatti unti, le chiede di trovare del detersivo per i piatti e, mentre lui si lava, lei gli porterà già questo liquido. Ma poi è squillato il telefono, mia moglie ha preso il telefono, ha parlato con sua madre ed è andata al negozio. Insieme, tutto è stato fatto molto velocemente!
Ed è ancora più facile rimanere bloccati – ad es. non esiste un programma principale.
La mia amica si siede sul divano e non fa nulla, la governante vede i piatti sporchi, glielo racconta e, ottenuto il permesso, comincia a lavarsi. Quando squilla il telefono, dice alla moglie di alzare la cornetta, la moglie sta parlando al telefono e la conversazione si sposta al supermercato... Bellezza! In questo caso, diversi dispositivi I/O operano contemporaneamente nel microcontrollore (nei microcontrollori moderni ce ne possono essere parecchi) e le prestazioni complessive del processore aumentano molte volte, ma gli interrupt dai dispositivi vengono elaborati in sequenza uno dopo l'altro (non simultaneamente ), a seconda della priorità (nel nostro esempio la moglie ha priorità maggiore rispetto alla governante).

Diversi registri sono responsabili della gestione degli interrupt
SREG – registro di stato(stati). Guardiamo la tabella dei dispositivi di input/output. Il settimo bit del registro SREG è il flag I (interrupt), chiamato flag di abilitazione globale dell'interrupt. Se il flag viene omesso (il settimo bit è zero), tutti gli interrupt vengono disabilitati. Se il flag viene alzato (imposta I a 1), abilitiamo gli interrupt.

Il flag I viene impostato e resettato con i comandi:
SEI: abilita gli interrupt
CLI: disabilita gli interrupt
Quali interrupt funzioneranno vengono impostati utilizzando i registri chiamati - maschere di interruzione.
Le maschere di interruzione sono designate come segue:
TIMSK,..,..,.. – gestione delle interruzioni da timer e altri dispositivi integrati.
GIMSK (GIKR nella famiglia Mega) - gestione di tutti gli interrupt esterni.
Le maschere di interruzione a loro volta dipendono dai flag di interruzione:
Rispettivamente TIFR e GIFR(da non confondere con il flag di abilitazione dell'interrupt globale).

Sequenza di esecuzione dell'interruzione:
Quando il microcontrollore è acceso, tutti i flag di interruzione vengono reimpostati su 0. Per abilitare gli interrupt, il programma deve impostare il flag I del registro SREG su 1. Successivamente, registrare i registri maschera con gli interrupt locali impostati (le interruzioni di cui abbiamo bisogno) .
Quando arriva una richiesta di interruzione (segnale), solleva il flag di interruzione (anche se l'interruzione è disabilitata, per organizzare interruzioni nidificate e priorità tra diverse interruzioni). Se gli interrupt non sono disabilitati, il controller contatterà la persona appropriata (Vettori di interruzione) - vettore di interruzione, mettendo in pausa il programma corrente.
Vettore di interruzioneè una linea fissa nell'area del programma dove va il programma quando si verifica un'interruzione.
Viene richiamato l'intero elenco di vettori di interruzione tabella dei vettori di interruzione, che è posizionato all'inizio del codice del programma.
Quindi, nel momento in cui si accede al vettore di interruzione, il flag I del registro SREG e il flag che ha causato l'interrupt vengono reimpostati a 0, disabilitando gli altri interrupt. Se si verificano altre richieste di interruzione durante l'esecuzione dell'interruzione, i flag per tali interruzioni rimangono alzati. Al completamento dell'interruzione corrente, il flag I del registro SREG viene sollevato, consentendo l'esecuzione di quello successivo. Se arrivano più richieste e i relativi flag vengono attivati, verrà eseguito per primo l'interrupt il cui vettore è più piccolo in corrispondenza dell'indirizzo nella tabella, più vicino all'inizio della memoria. Segue il secondo e così via. Inoltre il programmatore può organizzare un cosiddetto interrupt annidato, quando durante l'esecuzione del programma di interrupt si verifica un altro interrupt. Quindi l'esecuzione dell'interrupt corrente viene interrotta e ne viene eseguita una nuova, dopodiché viene ripresa l'esecuzione dell'interrupt interrotto.

A titolo di esempio viene fornita la tabella dei vettori di interruzione per ATtiny2313

La tabella dei vettori di interruzione per Atmega16 è la seguente:

Se confrontate, le tabelle non corrispondono affatto.
Nella famiglia ATtiny la linea del vettore di interruzione occupa 16 bit, nella famiglia Mega occupa 32 bit (attenzione agli indirizzi dei vettori di interruzione; ricordo che la linea di indirizzo nell'area del programma è rappresentata da un 16 -parola in bit).

Il codice del programma per ATtiny2313 potrebbe assomigliare a questo:
... jmp Timer0_compA rj mp Timer0_compB rjmp USI_START rjmp USI_OVERFLOW rjmp EE_READY rjmp WDT_ OVERFLOW

Come puoi vedere, il vettore di interruzione crea un salto relativo alle etichette del programma di interruzione. La tabella seguente mostra le opzioni; 1. Quando non ci sono interruzioni; 2, 3. con interrupt esterno sull'ingresso INT_1.
Se le etichette sono "vuote" (non c'è nessun programma sotto l'etichetta), non succede nulla e il programma "percorre" in sequenza le etichette rimanenti e raggiunge in sicurezza il comando RETI- Ritorno all'interruzione: uscita dal gestore dell'interruzione come mostrato nella prima colonna della tabella.

Per eseguire un programma di interrupt, ad esempio sull'ingresso INT_1, è necessario rimuovere l'etichetta INT_1: dall'elenco. Ciò è mostrato schematicamente nella seconda colonna della tabella.
Ma è scomodo per il programmatore scrivere ogni volta tutti gli interrupt e separarli con etichette, soprattutto negli ultimi modelli, dove la tabella è piuttosto grande; è più facile scrivere immediatamente il comando RETI nella riga del vettore di interrupt se il l'interruzione non viene utilizzata. Quindi il programma apparirà come mostrato nella terza colonna della tabella.

I controller AVR, a seconda del modello, possono avere da 1 a 8 ingressi interruzioni esterne.
Consideriamo il sistema di gestione delle interruzioni esterne. A questo scopo sono previste le seguenti combinazioni di registri I/O a seconda del modello (vedere il relativo DataSheet):
- GIMSK, EIFR, PCMSK, MCUCR;
- GIKR, GIFR, MCUCR;
- EIMSK, EICR, EIFR;
GIMSK, GIKR, EIMSK - maschere di interruzione,
EIFR, PCMSK, GIFR, EIFR – flag di interruzione
Per permesso o divieto interruzioni esterne si intendono registri di controllo: GIMSK-(General Interrupt Mask Register)(Tiny), GICR- (General Interrupt Control Register)(Mega), MCUCR – (MCU Control Register)




EIFR- Registro flag di interruzione esterno: 1 - abilitato, 0 - disabilitato. Ogni bit (flag) consente al pin corrispondente di agire come fonte di interruzione.

Bit di controllo del registro GIMSK:
Bit 7 – INT1: Abilitazione richiesta interruzione esterna 1 – Bit di abilitazione interruzione INT1: 1 – abilitato, 0 – disabilitato. L'interrupt verrà generato anche se il pin INT1 è configurato come uscita. Il bit INT1 è impostato per interrompere nel registro flag EIFR. Il pin INT1 è sincronizzato con il generatore di clock.

Bit 6 – INT0: Richiesta di interruzione esterna 0 Abilitata - bit di abilitazione dell'interruzione INT0: 1 – abilitato, 0 – disabilitato. L'interrupt verrà generato anche se il pin INT0 è configurato come uscita. Il bit INT0 è impostato per interrompere nel registro flag EIFR. Il pin INT10 è sincronizzato con il generatore di clock.

Puntata 5 – PCIE: Abilitazione interruzione cambio pin – bit di abilitazione interruzione sui pin PCINT0…7: 1 – abilitato, 0 – disabilitato. Qualsiasi modifica su uno qualsiasi dei pin PCINT0...7 genererà un'interruzione. I pin PCINT0...7 sono configurati per l'interruzione individualmente, tramite bit nel registro flag PCMSK.

PCMSK- Registro maschera cambio pin - registro delle bandiere PCMSK: 1 - consentito, 0 - disabilitato. Ogni bit (flag) consente al pin corrispondente di agire come fonte di interruzione. I pin PCINT0...7 non sono sincronizzati con il generatore di clock, cioè si verifica un'interruzione quando si verifica una modifica su uno qualsiasi dei pin.

Mega8

e il corrispondente registro flag


Poso 7

Bit 6 – INT0: Richiesta di interruzione esterna 0 Abilitata - bit di abilitazione dell'interruzione INT0: 1 – abilitato, 0 – disabilitato. L'interrupt verrà generato anche se il pin INT0 è configurato come uscita. Il bit INT0 è impostato su interruzione nel registro dei flag GIFR



GIFR – Registro flag di interruzione generale: 1 – abilitato, 0 – disabilitato. Ogni bit (flag) consente al pin corrispondente di agire come fonte di interruzione.

Bit di controllo del registro GICR:
Poso 7–: Richiesta di interruzione esterna 1 abilitata – bit di abilitazione dell'interrupt INT1: 1 – consentito, 0 – vietato. L'interrupt verrà generato anche se il pin INT1 è configurato come uscita. Il bit INT1 è impostato su interruzione nel registro dei flag GIFR

Bit 6 – INT0: Richiesta di interruzione esterna 0 Abilita - bit di abilitazione dell'interrupt INT0: 1 – consentito, 0 – vietato. L'interrupt verrà generato anche se il pin INT0 è configurato come uscita. Il bit INT0 è impostato su interruzione nel registro dei flag GIFR

Bit 5 – INT2: Richiesta di interruzione esterna 2 Abilita - bit di abilitazione dell'interruzione INT2: 1 – consentito, 0 – vietato. L'interrupt verrà generato anche se il pin INT2 è configurato come uscita. Il bit INT2 è impostato per interrompere nel registro dei flag GIFR

Le funzioni degli ingressi INT0 e INT1 in tutti i controller sono controllate dai bit di ordine basso del registro MCUCR

MCUCR – Registro di controllo MCU
Bit di controllo:
Bit 1, 0 – ISC01, ISC00 (Interrupt Sense Control 0 Bit 1 e Bit 0) – lo stato di questi bit determina l'evento sul pin INT0, che genera un interrupt INT0:
ISC01=0, ISC00=0 – livello zero logico;
ISC01=0, ISC00=1 – qualsiasi cambiamento di stato logico;
ISC01=1, ISC00=0 – su un fronte di discesa;
ISC01=1, ISC00=1 – su un fronte di salita.

Bit 3, 2 – ISC11, ISC10 (Interrupt Sense Control 1 Bit 1 e Bit 0) – lo stato di questi bit determina il livello del segnale sul pin INT1, che genera l'interrupt INT1:
ISC11=0, ISC10=0 – livello zero logico;
ISC11=0, ISC10=1 – qualsiasi cambiamento di stato logico;
ISC11=1, ISC10=0 – su un fronte di discesa;
ISC11=1, ISC10=1 – su un fronte di salita.

Ebbene, sembra che abbiamo parlato al minimo delle interruzioni esterne.
È chiaro che affinché le interruzioni funzionino, devono essere registrate di conseguenza.
Aggiungiamo l'inizializzazione dell'interrupt su INT1 iniziato per minuscolo sul fronte di salita del segnale:

Ldi r16.0x80 ; scrivere in r16 il numero 0b10000000 ldi r17.0x0C ; scrivere in r17 il numero 0b00001100 out MCUCR,r17 ; l'interrupt verrà generato sul fronte di salita ISC11=1, ISC10=1 out GIMSK,r16 ; impostare la maschera INT0 sei
A proposito, puoi generare un'interruzione su tiny2313 su qualsiasi pin PCINT0…7, su Mega fino alla serie 48 queste funzionalità non sono disponibili...
Ci sono operazioni durante le quali possono verificarsi interruzioni che possono causare il blocco del programma. In questi casi, prima di iniziare l'operazione scriviamo CLI e dopo SEI. Tali operazioni sono chiamate: atomico.
È auspicabile che i programmi di interruzione siano compatti ed eseguiti alla massima velocità, poiché lo scopo di qualsiasi interruzione è catturare un evento. Se secondo ragioni varie il programma gira lentamente, è sufficiente registrare l'evento ed elaborarlo poco dopo.

Per non ingombrare il materiale presentato con informazioni non necessarie, consiglio ai lettori di utilizzare le schede tecniche e, se tutto non è chiaro, di porre domande più spesso sui forum.
Successivamente, considereremo in dettaglio gli interrupt interni basati su timer integrati. lettori. Per partecipare alla votazione registrati e accedi al sito con il tuo nome utente e password.

Uno dei vantaggi del microcontrollore ATmega8 è la sua vasta gamma di interruzioni diverse.

Interrompereè un evento al verificarsi del quale viene sospesa l'esecuzione del programma principale e viene chiamata una funzione che gestisce un interrupt di un certo tipo.

Gli interrupt si dividono in interni ed esterni. Le fonti di interruzioni interne includono moduli microcontrollore integrati (timer, ricetrasmettitore USART, ecc.). Gli interrupt esterni si verificano quando segnali esterni arrivano ai pin del microcontrollore (ad esempio, segnali ai pin RESET e INT). La natura dei segnali che portano al verificarsi di un'interruzione è impostata nel registro di controllo MCUCR, in particolare nei bit - ISC00 (bit 0) e ISC01 (bit 1) per l'ingresso INT 0; ISC10 (bit2) e ISC11 (bit3) per ingresso INT1.

Nel microcontrollore ATmega8, ogni interruzione ha il proprio vettore di interruzione(indirizzo all'inizio dell'area di memoria del programma in cui è memorizzato il comando per passare alla routine di interrupt specificata). In mega8 tutti gli interrupt hanno la stessa priorità. Se si verificano più allarmi contemporaneamente, verrà elaborato per primo l'allarme con il numero di vettore più basso.

Vettori di interruzione in Atmega8

Indirizzo Sorgente di interruzione Descrizione
0x0000 RIPRISTINA Resettare il segnale
0x0001 INT0 Richiesta di interrupt esterno all'ingresso INT0
0x0002 INT1 Richiesta di interrupt esterno all'ingresso INT1
0x0003 T/C1 Acquisizione con timer T/C1
0x0004 T/C1 Confronta registro timer T/C1 A
0x0005 T/C1 Corrispondenza con il registro di confronto B del timer T/C1
0x0006 T/C1 Traboccamento contatore T/C1
0x0007 T/CO0 Overflow del contatore T/C0
0x0008 SPI Trasferimento dati SPI completato
0x0009 UART Il ricetrasmettitore UART ha completato la ricezione dei dati.
0x000A UART Il registro dati UART è vuoto
0x000B UART La trasmissione dei dati dal ricetrasmettitore UART è completata
0x000C ANA_COMP Interruzione dal comparatore analogico

Gestione delle interruzioni

4 registri sono responsabili della gestione degli interrupt in ATmega8:

GIMSK(noto anche come GICR) - proibisce/abilita le interruzioni in base ai segnali sugli ingressi INT0, INT1

GIFR- gestione di tutti gli interrupt esterni

TIMSK, TIF- gestione delle interruzioni da timer/contatori

Registrati GIMSK(GICR)

INTFx=1: si è verificato un interrupt sull'ingresso INTx. Quando si accede alla routine di gestione degli interrupt, INTFx viene automaticamente reimpostato allo stato di registro. 0

Registrati TIMSK

7 6 5 4 3 2 1 0
TOIE1
OCIE1A
OCIE1B
-
TICIE
-
TOIE0
-

TOIE1=1: Interruzione overflow T/C1 abilitata

OCIE1A=1: interruzione quando il registro di confronto A corrisponde al contenuto del contatore T/C1 abilitato

OCIE1B=1: interruzione quando il registro di confronto B corrisponde al contenuto del contatore T/C1 abilitato

TICIE=1: interruzione abilitata quando la condizione di cattura è soddisfatta

TOIE0=1: Interruzione overflow T/C0 abilitata

Registrati TIF

7 6 5 4 3 2 1 0
TOV1
OCF1A
OCF1B
-
ICF1
-
TOV0
-

TOV1=1: Si è verificato un trabocco T/C1

OCF1A=1: il registro di confronto A coincideva con il contenuto del contatore T/C1 consentito

OCF1B=1: il registro di confronto B corrisponde al contenuto del contatore T/C1 consentito

ICF=1: condizioni di cattura soddisfatte

TOV0=1: Si è verificato un superamento del T/C0

Quando si accede alla subroutine di gestione delle interruzioni, il flag del registro TIFR corrispondente all'interruzione viene automaticamente reimpostato allo stato di registro. 0

Gli interrupt funzionano solo quando gli interrupt generali sono abilitati nel registro di stato SREG (bit 7 = 1). Quando si verifica un'interruzione, questo bit viene automaticamente reimpostato su 0, disabilitando le interruzioni successive.

In questo esempio, il pin INT0 è abilitato nella modalità di ingresso pull-up. Quando il pin viene cortocircuitato a massa utilizzando un pulsante, su di esso viene impostato 0 logico (il fronte del segnale scende dalla tensione di alimentazione a 0) e viene attivato il gestore di interruzione, accendendo la lampadina collegata al pin zero della porta B

lampada vuotaON()
{
PORTA.0=1;
DDRB.0=1;
}

interruzione void ext_int0_isr(void)
{
lampada ACCESA();
}

DDRD.2=0;
PORTA.2=1;

SREG|= (1 mentre(1) (

L'esempio sopra mostra anche come sono impostati i vettori di interruzione in Code Vision AVR (interrupt void ext_int0_isr(void)). I vettori di interrupt sono impostati in modo simile per gli altri casi:

EST_INT02
EST_INT1 3
TIM2_COMP4
TIM2_OVF 5
TIM1_CAPT6
TIM1_COMPA7
TIM1_COMPB8
TIM1_OVF9
TIM0_OVF10
SPI_STC11
USART_RXC12
USART_DRE13
USART_TXC14
ADC_INT15
EE_RDY 16
ANA_COMP17
TWI 18
SPM_PRONTO 19

Parte Microcontrollori AVR include un gran numero di dispositivi periferici (ADC, timer/contatori, EXTI, comparatore analogico, EEPROM, USART, SPI, I2C, ecc.), ciascuno dei quali può eseguire determinate azioni su dati/segnali e altre informazioni. Questi dispositivi sono integrati nel microcontrollore per migliorare l'efficienza dell'applicazione e ridurre i costi durante lo sviluppo di tutti i tipi di dispositivi basati sui microcontrollori AVR.

Il processore comunica/controlla i dispositivi periferici attraverso i registri I/O, che si trovano nella memoria dati, consentendo loro di essere utilizzati come normali variabili. Ogni dispositivo ha i propri registri I/O.

Tutti i registri I/O possono essere divisi in tre gruppi: registri dati, registri di controllo e registri di stato.

Utilizzando i registri di controllo, il dispositivo è configurato per funzionare in una modalità o nell'altra, con una certa frequenza, precisione, ecc., E utilizzando i registri dati, viene letto il risultato del lavoro di questo dispositivo(conversione da analogico a digitale, dati ricevuti, valore del timer/contatore, ecc.). Sembrerebbe che qui non ci sia nulla di complicato (in effetti, qui non c'è davvero nulla di complicato :)), ha acceso il dispositivo, ha indicato la modalità operativa desiderata, e quindi non resta che ritagliare i coupon, leggere i dati già pronti e usarli nei calcoli. L'intera questione è "quando" leggere proprio questi dati (il dispositivo ha completato il suo lavoro o sta ancora elaborando i dati), perché tutti i dispositivi periferici funzionano in parallelo con il core del microcontrollore e anche a frequenze diverse. e sincronizzazione tra il processore e unità periferica.

Come probabilmente avrete già intuito, per implementare la comunicazione e la sincronizzazione tra il dispositivo e il processore vengono utilizzati i "registri di stato", che memorizzano lo stato operativo corrente di un particolare dispositivo. Ogni stato in cui il dispositivo può trovarsi corrisponde a un "bit in lo stato del registro” (flag), il cui valore attuale “parla” dello stato attuale di questo dispositivo o della sua singola funzione (lavoro completato/non completato, errore durante l'elaborazione dei dati, registro vuoto, ecc.).

Il meccanismo di comunicazione tra il processore e un dispositivo periferico è implementato tramite flag polling, che sono responsabili di una particolare funzione di questo dispositivo. A seconda del valore di un particolare flag (stato del dispositivo), è possibile modificare il flusso di esecuzione del programma (ramificazione). Per esempio:

Verifica se è impostato un determinato flag (si è verificato un evento):

se (RegX & (1<< Flag) ) // se il flag nel registro RegX è impostato
{
// fare qualcosa
}

In attesa del completamento di qualche azione (evento):

while(!(RegX & (1<

Interrogare i flag è un'attività piuttosto dispendiosa in termini di risorse, sia in termini di dimensioni del programma che di velocità del programma. Poiché il numero totale di flag nei microcontrollori AVR è piuttosto elevato (un vantaggio), l'implementazione della comunicazione tra il processore e il dispositivo tramite polling dei flag porta ad una diminuzione dell'efficienza (velocità del codice/dimensione del codice) del programma che si scrive, inoltre, il programma diventa molto confuso, il che contribuisce alla comparsa di errori difficili da rilevare anche con un debug dettagliato del codice.

Al fine di aumentare l'efficienza dei programmi per i microcontrollori AVR, nonché per facilitare il processo di creazione e debug di questi programmi, gli sviluppatori hanno dotato tutti i dispositivi periferici di "fonti di interruzione" ( Sorgenti di interruzione), alcuni dispositivi potrebbero avere più sorgenti di interruzione.

Utilizzando le fonti di interruzione, viene implementato meccanismo di sincronizzazione, tra il processore e il dispositivo periferico, ovvero il processore inizierà a ricevere dati, polling flag e altre azioni sul dispositivo periferico solo quando il dispositivo sarà pronto per questo (segnalerà il completamento dell'elaborazione dei dati, un errore durante elaborazione dati, registro vuoto, ecc.), ecc.), generando una “richiesta di interruzione” ( Richiesta di interruzione), a seconda del valore di alcuni flag (dispositivo/funzione/stato evento).

In letteratura, molto spesso, l'intera catena di eventi, dalla “richiesta di interruzione” (IRQ) alla “procedura di servizio di interruzione” (ISR), viene abbreviata come interruzione ( Interrompere).

Cos'è un'interruzione?


L'interrupt è un segnale che avvisa il processore del verificarsi di un evento. In questo caso l'esecuzione della sequenza di comandi corrente viene sospesa e il controllo viene trasferito alla procedura di gestione dell'interrupt corrispondente a questo evento, dopodiché l'esecuzione del codice riprende esattamente dal punto in cui era stata interrotta (ritorno del controllo). (Wiki)

Interrompere la routine(Interrupt Service Routine) non è altro che una funzione/subroutine che deve essere eseguita al verificarsi di un determinato evento. Utilizzeremo la parola “procedura” per sottolinearne la differenza rispetto a tutte le altre funzioni.

La differenza principale tra la procedura e le funzioni semplici è che invece del solito “ritorno dalla funzione” (comando assembly RET), dovresti usare “ritorno dall'interrupt” (comando assembler RETI) - " RETURN da Interrupt".

Proprietà dell'interruzione AVR:

  • Ogni dispositivo periferico che fa parte dei microcontrollori AVR ha almeno una fonte di interruzione. Tra tutte queste interruzioni va annoverata anche l'interruzione di reset, il cui scopo è diverso da tutti gli altri.
  • Ogni interruzione ha un vettore (collegamento) strettamente assegnato che punta alla routine del servizio Interrupt. Tutti i vettori di interruzione si trovano all'inizio della memoria del programma e insieme formano la "tabella dei vettori di interruzione".
  • Ogni interruzione è associata a uno specifico "bit di abilitazione dell'interrupt". Pertanto, per utilizzare un interrupt specifico, è necessario scrivere nel relativo registro "bit di abilitazione dell'interrupt". unità. Inoltre, indipendentemente dal fatto che siano stati abilitati o meno determinati interrupt, il microcontrollore non inizierà a elaborare questi interrupt finché non ne verrà scritto uno logico nel "bit di abilitazione interrupt globale" nel registro di stato SREG. Inoltre, per disabilitare tutti gli interrupt (per un tempo indefinito), è necessario scrivere uno zero logico nel bit di abilitazione dell'interrupt generale.

L'interruzione Reset, a differenza di tutte le altre, non può essere disabilitata. Tali interruzioni sono anche chiamate interruzioni non mascherabili.

  • Ogni interruzione ha una priorità rigorosamente definita. La priorità di un'interruzione dipende dalla sua posizione nella "tabella dei vettori delle interruzioni”. Più basso è il numero del vettore nella tabella, maggiore è la priorità dell'interruzione. Cioè, la priorità più alta è l'interruzione di ripristino, che si trova per prima in nella tabella, e di conseguenza nei programmi di memoria. L'interrupt esterno INT0, che segue l'interrupt Reset nella “tabella vettoriale degli interrupt”, ha una priorità inferiore a quella del Reset, ma superiore a quella di tutti gli altri interrupt, ecc.

La tabella dei vettori di interruzione, ad eccezione del vettore Reset, può essere spostata all'inizio della sezione Boot della memoria Flash impostando il bit IVSEL nel registro GICR. Il vettore di reset può anche essere spostato all'inizio della sezione Boot della memoria Flash programmando il bit del fusibile - BOOTRST.



Fig.1 Tabella dei vettori di interruzione ATmega16

Prototipo di routine di interruzione


Per dichiarare una funzione come routine di gestione degli interrupt, è necessario seguire alcune regole di prototipazione in modo che il compilatore/linker possa identificare e associare correttamente l'interrupt necessario alla sua routine di gestione.

Innanzitutto, la routine del servizio di interruzione non può accettare nulla come argomento (void) e non può nemmeno restituire nulla (void). Ciò è dovuto al fatto che tutti gli interrupt in AVR sono asincroni, quindi non è noto dove verrà interrotta l'esecuzione del programma, da chi ricevere e a chi restituire il valore, e anche per ridurre al minimo il tempo di ingresso e uscire dall'interruzione.

vuoto isr(vuoto)

In secondo luogo, prima del prototipo della funzione, dovresti indicare che si tratta di una procedura di gestione degli interrupt. Come sapete, nel linguaggio C viene eseguito solo il codice utilizzato nella funzione main. Poiché la procedura di gestione delle interruzioni nella funzione principale non viene utilizzata da nessuna parte, in modo che il compilatore non la “butti via” come non necessaria, prima del prototipo della procedura dovrebbe essere indicato che questa funzione è una procedura di gestione delle interruzioni.

Prototipo di procedura di gestione delle interruzioni in ambiente AVR Studio

#includere

ISR (XXX_vect)
{

}

In AVR Studio (AVR GCC), ciascuna routine di interruzione inizia con una definizione di macro ISR, seguita dal seguente costrutto tra parentesi:

XXX_vet

dove "XXX" è il nome del vettore di interruzione. Tutti i nomi dei vettori per uno specifico microcontrollore AVR possono essere trovati nella "tabella dei vettori di interruzione" della scheda tecnica del microcontrollore o nel suo file di intestazione. Ad esempio, la "tabella dei vettori di interruzione" per il microcontrollore ATmega16 è mostrata in Fig. 1, dove nella colonna Sorgente sono elencati tutti i nomi dei vettori di interruzione. I nomi si possono trovare anche nel file header di questo microcontrollore (C :\Program Files\Atmel\AVR Tools\AVR Toolchain\avr\include\avr\iom16.h), vedere Fig. 2. Tutto quello che dobbiamo fare è trovare il nome del vettore di cui abbiamo bisogno nella tabella e aggiungere il suffisso "_vect" ad esso.


Fig.2 File di intestazione ATmega16 per AVR Studio

Ad esempio, scriviamo una procedura di gestione degli interrupt per la ricezione di un byte tramite USART (USART, Rx Complete):

ISR (USART_RXC_vect)
{
// Corpo del gestore degli interrupt
}

A proposito: prima di utilizzare qualsiasi interruzione in AVR Studio, dovresti includere i file header io.h e interrupt.h nel progetto:

#includere
#includere

Puoi leggere ulteriori informazioni sui gestori di interruzioni in AVR Studio (AVR GCC) nella sezione Introduzione alla gestione delle interruzioni di avr-libc.

Prototipo di procedura di gestione delle interruzioni in ambiente ImageCraft

#pragma gestore_interrupt : iv_XXX
vuoto< handler_name>(vuoto)
{
// Corpo del gestore degli interrupt
}

Nell'ambiente ImageCraft, la routine di interruzione del prototipo assomiglia a questa:

vuoto< handler_name>(vuoto)

Dove , questo è il nome che vuoi dare a questo gestore di interruzioni. Uno dei requisiti per dichiarare le procedure di gestione degli interrupt è che prima del prototipo della funzione venga indicato che si tratta di un gestore di interrupt. Questo viene fatto utilizzando una direttiva pragma gestore_interrupt :

#pragma gestore_interrupt : iv_XXX

Dove questo è il nome della funzione che verrà utilizzata come gestore di interruzioni e la costruzione "iv_XXX" è il nome del vettore di interruzione (XXX) con il prefisso "iv_". Come nel caso di AVR Studio, tutti i nomi dei vettori per uno specifico microcontrollore AVR può essere trovato nella "tabella vettoriale degli interrupt" del foglio dati di un dato microcontrollore o nel suo file di intestazione (vedere Fig. 3).


Fig.3 File di intestazione ATmega16 per ImageCraft IDE

Ad esempio, la procedura per gestire un'interruzione per la ricezione di un byte tramite USART (USART, Rx Complete) nell'ambiente ImageCraft sarà simile alla seguente:

#pragma interrupt_handler usart_rxc_isr: iv_USART_RXC
void usart_rxc_isr(void)
{
// Corpo del gestore degli interrupt
}

Maggiori informazioni sulle procedure di gestione degli interrupt nell'IDE ImageCraft possono essere trovate nel menu Aiuto->Programmazione dell'AVR->Gestori di interrupt dell'ambiente di sviluppo.

A volte, se più gestori di interrupt devono fare la stessa cosa, per risparmiare memoria di programma è possibile indirizzare diversi vettori di interrupt alla stessa routine di interrupt.

In AVR Studio appare così:

ISR (INT0_vect)
{
// Fare qualcosa
}
ISR(INT1_vect, ISR_ALIASOF(INT0_vect) ) ;

Per prima cosa arriva la procedura di elaborazione dell'interruzione per un vettore specifico, in questo caso INT0. Tutte le altre procedure possono fare riferimento a qualsiasi gestore di interrupt utilizzando il costrutto:

ISR (YYY_vect, ISR_ALIASOF(XXX_vect) ) ;

dove YYY è il nome del vettore di interrupt che fa riferimento al gestore di interrupt precedentemente dichiarato per il vettore XXX.

In ImageCraft appare così:

#pragma gestore_interrupt : iv_XXX : iv_AAAA
vuoto< handler_name>(vuoto)
{
// Corpo del gestore degli interrupt
}

#pragma gestore_interrupt : iv_XXX
#pragma gestore_interrupt : iv_AAAA
vuoto< handler_name>(vuoto)
{
// Corpo del gestore degli interrupt
}

dove i vettori XXX e YYY si riferiscono allo stesso gestore di interrupt .

Come funziona l'interruzione nei microcontrollori AVR?

1. Supponiamo che " richiesta di interruzione"(IRQ).

A proposito: se si verificano più richieste di elaborazione dell'interruzione contemporaneamente, verrà elaborato per primo l'interruzione con la massima priorità, tutte le altre richieste verranno elaborate dopo la conclusione dell'interruzione con alta priorità.

2. Visita medica.

Se il bit di abilitazione per questo interrupt è impostato (bit di abilitazione dell'interruzione) e il bit I (bit di abilitazione dell'interruzione generale) del registro di stato del processore (SREG) è impostato, allora il processore inizia a preparare la routine di servizio dell'interruzione, mentre il bit di abilitazione generale il bit di abilitazione dell'interruzione (bit I del registro SREG) viene ripristinato, disabilitando così tutte le altre interruzioni. Ciò avviene in modo che nessun altro evento possa interrompere l'elaborazione dell'interrupt attuale.

A proposito: se nella procedura di gestione degli interrupt imposti il ​​bit I sullo stato di registro. unità, qualsiasi interruzione attivata può a sua volta interrompere l'elaborazione dell'interruzione corrente. Tali interruzioni sono chiamate interruzioni nidificate.

3. Preparazione.

Il processore completa l'esecuzione dell'istruzione assembly corrente, quindi inserisce l'indirizzo dell'istruzione successiva nello stack (PC->STACK). Successivamente, il processore controlla quale fonte di interruzione ha inviato una "richiesta di interruzione" (IRQ), dopodiché, utilizzando il vettore di questa fonte (collegamento) dalla tabella vettoriale (che è saldamente assegnata a ciascuna fonte di interruzione), procede al procedura di elaborazione dell'interruzione (istruzione JMP). Questo è tutto, il processore impiega almeno 4 cicli di clock (a seconda del momento in cui appare la richiesta e della durata dell'esecuzione dell'istruzione corrente). Questo è un tempo di risposta all'IRQ molto buono, rispetto a microcontrollori di altri produttori.

A proposito: se si verifica un IRQ mentre il microcontrollore è in modalità sleep, il tempo di risposta all'IRQ aumenta di altri quattro cicli di clock, più il tempo memorizzato nei bit del fusibile SUT1 e SUT0 (Start-Up Time).

Interrupt: un evento che richiede una risposta immediata da parte del processore. La risposta è che il processore interrompe l'elaborazione del programma corrente ( programma interrotto) e procede con l'esecuzione di qualche altro programma ( programma di interruzione), appositamente progettato per questo evento. Al termine di questo programma, il processore torna ad eseguire il programma interrotto.

Ogni evento che richiede un'interruzione è accompagnato da segnale di interruzione, avvisando il computer di ciò e chiamando richiesta di interruzione.

Stato del programma rappresenta un insieme di stati di tutti gli elementi di archiviazione nel momento corrispondente (ad esempio, dopo l'esecuzione dell'ultimo comando). Quando si verifica un'interruzione, il microcontrollore memorizza il contenuto del contatore del programma nello stack e carica in esso l'indirizzo del vettore di interruzione corrispondente. L'ultimo comando della routine di interruzione deve essere un comando che ritorna al programma principale e ripristina il contatore del programma precedentemente memorizzato. Durante l'esecuzione del gestore delle interruzioni, alcune informazioni potrebbero cambiare. Pertanto, quando si passa al gestore degli interrupt, è necessario salvare gli elementi che vengono modificati. L'insieme di tali elementi è vettore dello stato del programma. In questo caso, altre informazioni sullo stato delle celle di memoria non sono significative o possono essere ripristinate a livello di programmazione.

Vettore stato iniziale contiene tutte le informazioni necessarie per il lancio iniziale del programma. In molti casi, il vettore di stato iniziale contiene un solo elemento: l'indirizzo iniziale del programma avviato.

Vettore di interruzioneè il vettore dello stato iniziale del programma che ha interrotto (gestore) e contiene tutte le informazioni necessarie per passare al gestore, compreso il suo indirizzo iniziale. Ogni tipo di interruzione ha il proprio vettore di interruzione, che avvia l'esecuzione del gestore corrispondente. In genere, i vettori di interruzione vengono archiviati in posizioni di memoria fisse appositamente allocate con indirizzi brevi, che rappresentano tabella dei vettori di interruzione. Per saltare al programma di interruzione appropriato, il processore deve avere un vettore di interruzione e l'indirizzo di questo vettore. A questo indirizzo si trova di norma un comando di salto incondizionato alla subroutine di gestione degli interrupt.

Di norma, il controllo della memorizzazione e della restituzione è assegnato al gestore dell'interruzione. In questo caso, il gestore è composto da tre parti: preparatoria (prologo) e finale (epilogo), che assicurano il cambio di programma, e il programma di interruzione vero e proprio, che esegue le operazioni richieste dalla richiesta. Il tempo di risposta è definito come l'intervallo di tempo dal momento in cui viene ricevuta una richiesta di interruzione fino all'inizio dell'esecuzione del programma che ha interrotto.


t pag– tempo di risposta del sistema all'interruzione;
t z– tempo di memorizzazione dello stato del programma interrotto;
t ppr– ora dell'effettivo programma di interruzione;
lattina– tempo per ripristinare lo stato del programma interrotto

Se esistono più fonti di richieste, è necessario stabilire un determinato ordine di gestione delle richieste in arrivo, denominato relazioni prioritarie O disciplina del servizio. L'insieme di tutti i possibili tipi di interruzione del processore è sistema di interruzione microcontrollore. La disciplina del servizio determina quale delle numerose richieste ricevute contemporaneamente deve essere elaborata per prima e se questa richiesta interrompere l'uno o l'altro gestore di interrupt.
Se viene ricevuta una richiesta di interruzione con priorità più alta mentre un'interruzione viene elaborata, il controllo viene trasferito al gestore di interruzione con priorità più alta e il gestore di interruzione con priorità più bassa viene sospeso. Sorge interrompere l'annidamento. Viene richiamato il numero massimo di programmi che possono sospendersi a vicenda profondità delle interruzioni.

Se la richiesta di interruzione non viene soddisfatta nel momento in cui arriva una nuova richiesta dalla stessa fonte (stessa priorità), allora interrompere la saturazione del sistema. In questo caso parte delle richieste di interruzione andranno perse, per cui operazione normale il microcontrollore non è consentito.

Caratteristiche del sistema di interruzione Sono:

  • numero totale di richieste di interruzione numero di fonti di richieste di interruzione;
  • tipo di rappresentazione dell'interruzione: di norma, una richiesta di interruzione è rappresentata da un livello di segnale logico;
  • priorità di interruzione: determina l'ordine in cui viene elaborata ciascuna richiesta di interruzione; maggiore è la priorità, minore è il ritardo nell'esecuzione del programma di interruzione per essa;
  • tempo di risposta – l'intervallo di tempo tra la comparsa della richiesta di interruzione e l'inizio dell'esecuzione del programma di interruzione;
  • ritardo di interruzione – determinato dal tempo totale di memorizzazione e ripristino del programma;
  • profondità, solitamente coincide con il numero di livelli di priorità nel sistema di interruzione;
  • interrompere la saturazione del sistema;
  • momenti consentiti di interruzione del programma (solitamente la fine dell'esecuzione del comando successivo).

Mascheramento delle interruzioni usato per dire al microcontrollore di rispondere a ogni tipo di interruzione o di ignorarlo. La maschera di interruzione rappresenta un codice binario i cui bit sono assegnati alle sorgenti della richiesta di interruzione. L'unico bit nel codice binario indica al microcontrollore di gestire questo tipo di interruzione. Un bit zero, al contrario, non consente al microcontrollore di procedere all'elaborazione degli interrupt del tipo specificato.
Di norma, oltre al mascheramento degli interrupt, esiste anche un bit di abilitazione globale degli interrupt, il cui valore zero disabilita tutti i gestori di interrupt (ad eccezione del reset hardware e del salto all'inizio del programma in esecuzione).
Oltre al codice binario della maschera di interruzione esiste anche un codice binario flag di interruzione, che consente al gestore dell'interruzione di impostare l'origine dell'interruzione se sono presenti diverse origini con la richiesta specificata nel microcontrollore.




Superiore