Operácie

Prerušenia

Zo stránky SensorWiki

Verzia z 20:32, 17. marec 2021, ktorú vytvoril Balogh (diskusia | príspevky)



Prerušenia v AVR-GCC

Kompilátor AVR-GCC má obsluhu prerušení vyriešenú tak, že tabuľka s vektormi jednotlivých prerušení ukazuje na obslužné rutiny s preddefinovanými názvami. Pri výskyte niektorého z povolených prerušení sa vykoná rutina so zodpovedajúcim názvom.

Vo vašom kóde použijete obslužné funkcie pre prerušenie napr. takto (obsluha prerušenia z AD prevodníka):

#include <avr/interrupt.h>
ISR(ADC_vect)
{
// user code here
}

Takáto obsluha prerušenia sa potom spustí so globálnym zákazom prerušení (jednoúrovňové), ktoré sa po skončení prípadne zasa obnovia. Obsluha sa skončí špeciálnou inštrukciiou RETI, preto sa nedá zavolať z programu ako bežná funkcia.

Niektoré názvy vektorov:

ADC Conversion Complete 	ADC_vect
External Interrupt Request 0 	INT0_vect
External Interrupt Request 1 	INT1_vect
External Interrupt Request 2 	INT2_vect
Pin Change Group 0 Interrupt   PCINT0_vect
Pin Change Group 1 Interrupt   PCINT1_vect
Pin Change Group 2 Interrupt   PCINT2_vect
Timer/Counter1 Overflow 	TIMER1_OVF_vect
USART, Rx Complete 	        USART_RXC_vect
USART, Tx Complete 	        USART_TXC_vect

Ak potrebujete prerušenia povoliť, resp. zakázať, máte k dispozícii funkcie

void sei(void);  // Enables interrupts by setting the global interrupt mask. 
void cli(void);  // Disables all interrupts by clearing the global interrupt mask.

Obe funkcie sa preložia do jedinej asm inštrukcie, bez zbytočného pridaného kódu.

Pozn.: Ak chcete používať v obsluhe premenné, ktorých obsah chcete uchovať napr. až do ďalšieho prerušenia, musia byť deklarované ako static. Ak chcete mať v obsluhe prerušenia prístup aj k nejakej premennej v hlavnom programe, musí byť deklarovaná ako globálna. Navyše, ak kompilátor pri preklade nenájde miesto, kde sa premenná mení, vyhodí ju z programu úplne. Nie je taký múdry, aby zistil, že s ňou manipulujete v ISR nezistí, preto použite pri deklarácii volatile.


Prerušenie pri zmene stavu niektorého pinu procesora

Prerušenie INT0/1 vyvolané priamo na vstupoch PD2/PD3 žiaľ nemôžeme použiť, pretože sme ich obsadili LCD displejom.

Namiesto toho použijeme prerušenie vyvolané zmenou (log.0 -> 1 aj log. 1 -> 0) na vstupe PD5. Tomuto vstupu je priradené prerušenie PCINT21, ktoré patrí do skupiny 2. Na povolenie tohto prerušenia musíme okrem globálneho bitu SREG: I nastaviť aj bity PCICR: PCIE2 a PCMSK2: PCINT21.

Nižšie máte uvedený ako príklad program pre ovládanie LED diódy na výstupe PD7 tlačidlom na PD5. Podobný program sme už robili na druhom cvičení. Upravený program nastaví stav LED diódy poľa tlačidla v obsluhe prerušenia, takže v hlavnej programovej slučke už nič neostalo.

#include <avr/io.h>

/* Pripojenie periferii k vyvojovej doske Arduino: */

#define LED2 PD7   // externa LED dioda 
#define SW2  PD5   // externe tlacitko

#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
#define toggle_bit(ADDRESS,BIT)

#define	SW2_ON bit_is_clear(PIND, SW2) 
#define LED2_ON  set_bit(PORTD,LED2)
#define LED2_OFF clear_bit(PORTD,LED2)


int main(void)
{

  /*  SETUP   */ 
	 
   /* Konfiguracia I/O: portD.7 je vystupny (LED2) a portD.5 je vstup (SW2) *
    * naviac je PortD.5 so zapnutym pull-up rezistorom cez reg. PORTD       */   
   
    DDRD = 0b11011111;       // PORTD: LED2 na PD7  je output, SW2 (PD5) input
   PORTD = 0b00100000;       // LED Active low, LED off, pull-up ON
	

  /*   LOOP   */ 

    while(1)
    {             
       if ( SW2_ON  ) 
         LED2_ON;
       else 
	 LED2_OFF;	
    }

   return(0);
}
#include <avr/io.h>
#include <avr/interrupt.h>

/* Pripojenie periferii k vyvojovej doske Arduino: */

#define LED2 PD7   // externa LED dioda 
#define SW2  PD5   // externe tlacitko

#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
#define toggle_bit(ADDRESS,BIT)

#define	SW2_ON bit_is_clear(PIND, SW2) 
#define LED2_ON  set_bit(PORTD,LED2)
#define LED2_OFF clear_bit(PORTD,LED2)

ISR (PCINT2_vect)
{
  if ( SW2_ON  ) 
   LED2_ON;
  else 
   LED2_OFF;	
}



int main(void)
{

  /*  SETUP   */ 
	 
   /* Konfiguracia I/O: portD.7 je vystupny (LED2) a portD.5 je vstup (SW2) *
    * naviac je PortD.5 so zapnutym pull-up rezistorom cez reg. PORTD       */   
   
    DDRD = 0b11011111;       // PORTD: LED2 na PD7  je output, SW2 (PD5) input
   PORTD = 0b00100000;       // LED Active low, LED off, pull-up ON
	
   /* *******  Konfiguracia prerusovacieho systemu ****************         */
   		
	PCMSK2 |= (1<<PCINT21);
	 PCICR |= (1<<PCIE2);
   
	sei();   //  t.j. SREG |= (1<<I);

  /*   LOOP   */ 
 
    while(1)
    {             
      asm("nop");
    }

   return(0);
}

Úloha

  1. Doplňte program o vyhodnocovanie pretečenia časovača v prerušení.
    Pozri AVR ExampleT1int.c

Časovač T1

Pozri AVR ExampleT1pooled.c


Úlohy

  1. Program doplňte podľa pokynov asistenta a odsimulujte.
    Pozn.: Treba vypnúť optimalizáciu! (Project/Project options Pozri obr.)
  2. Doplňte chýbajúce časti programu tak, aby LED blikala s frekvenciou 1 s.
  3. Vyskúšajte na svojej doske.

Literatúra:



Návrat na zoznam cvičení...