Operácie

Prerušenia: Rozdiel medzi revíziami

Zo stránky SensorWiki

Balogh (diskusia | príspevky)
Balogh (diskusia | príspevky)
 
(16 medziľahlých úprav od rovnakého používateľa nie je zobrazených.)
Riadok 1: Riadok 1:




Riadok 25: Riadok 22:
  External Interrupt Request 1 INT1_vect
  External Interrupt Request 1 INT1_vect
  External Interrupt Request 2 INT2_vect
  External Interrupt Request 2 INT2_vect
  Pin Change Group 0 Interrupt   PCINT0_vect
  Pin Change Group 0 Interrupt   PCINT0_vect
  Pin Change Group 1 Interrupt   PCINT1_vect
  Pin Change Group 1 Interrupt   PCINT1_vect
  Pin Change Group 2 Interrupt   PCINT2_vect
  Pin Change Group 2 Interrupt   PCINT2_vect
  Timer/Counter1 Overflow TIMER1_OVF_vect
  Timer/Counter1 Overflow TIMER1_OVF_vect
  USART, Rx Complete         USART_RXC_vect
  USART, Rx Complete         USART_RXC_vect
Riadok 38: Riadok 35:
</source>
</source>
Obe funkcie sa preložia do jedinej asm inštrukcie, bez zbytočného pridaného kódu.
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 <TT>static</TT>. 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 <TT>volatile</TT>.


== Prerušenie pri zmene stavu niektorého pinu procesora ==
== 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.
<!-- Prerušenie INT0/1 vyvolané priamo na vstupoch PD2/PD3 žiaľ nemôžeme použiť, pretože sme ich obsadili LCD displejom. -->
 
Na cvičení 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 <code>SREG: I</code> nastaviť aj bity <code>PCICR: PCIE2</code> a <code>PCMSK2: PCINT21</code>.  
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 <code>SREG: I</code> nastaviť aj bity <code>PCICR: PCIE2</code> a <code>PCMSK2: PCINT21</code>.  


<div style='text-align: center;'>
<div style='text-align: center;'>
Riadok 66: Riadok 57:
#define LED2 PD7  // externa LED dioda  
#define LED2 PD7  // externa LED dioda  
#define SW2  PD5  // externe tlacitko
#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 SW2_ON bit_is_clear(PIND, SW2)  
#define LED2_ON set_bit(PORTD,LED2)
#define LED2_ON PORTD |= (1 << LED2)  
#define LED2_OFF clear_bit(PORTD,LED2)
#define LED2_OFF PORTD &= ~(1 << LED2)
 


int main(void)
int main(void)
Riadok 103: Riadok 89:
</tab>
</tab>


<tab name="b) s prerušením"><source lang="c++" style="background: LightYellow;" highlight="2,17-23,40-43,49" line>
<tab name="b) s prerušením"><source lang="c++" style="background: LightYellow;" highlight="2,13-19,34-39,45" line>
#include <avr/io.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/interrupt.h>
Riadok 111: Riadok 97:
#define LED2 PD7  // externa LED dioda  
#define LED2 PD7  // externa LED dioda  
#define SW2  PD5  // externe tlacitko
#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 SW2_ON bit_is_clear(PIND, SW2)  
#define LED2_ON set_bit(PORTD,LED2)
#define LED2_ON PORTD |= (1 << LED2)  
#define LED2_OFF clear_bit(PORTD,LED2)
#define LED2_OFF PORTD &= ~(1 << LED2)


ISR (PCINT2_vect)
ISR (PCINT2_vect)
Riadok 162: Riadok 144:




'''Zákmity tlačidiel a Prerušenia (Interrupt Storm):'''
V reálnom živote aj naďalej platí, že mechanické tlačidlá trpia zákmitmi (tzv. ''bouncing''). Každé jedno stlačenie vyvolá desiatky zákmitov v priebehu milisekúnd a tým pádom desiatky zbytočných prerušení, ktoré procesor extrémne zahltia. Mechanické tlačidlá sa na prerušovacie piny preto pripájajú len výnimočne, a to s využitím hardvérového RC filtra pre debouncing, inak sa preferuje pravidelné čítanie pinu (polling) v prerušení od časovača.




Riadok 167: Riadok 153:
=== Časovač T1 ===
=== Časovač T1 ===


S časovačom T1 sme pracovali na minulom cvičení. Príznak pretečenia počítadla TOV1 sme testovali ''"ručne"'', metódou tzv.  ''pooling'' - dopytovania. Je to neefektívny spôsob, pretože procesor využívame len na otrocké testovanie jedného bitu stále dookola. Preto je vašou úlohou doplniť vzorový (avšak nekompletný) program tak, aby sa pri pretečení T1 po jednej sekunde vyvolalo prerušenie a zmena stavu LED diódy bude tiež vykonaná v obsluhe prerušenia.
S časovačom T1 sme pracovali na minulom cvičení. Príznak pretečenia počítadla TOV1 sme testovali ''"ručne"'', metódou tzv.  ''polling'' - dopytovania. Je to neefektívny spôsob, pretože procesor využívame len na otrocké testovanie jedného bitu stále dookola. Preto je vašou úlohou doplniť vzorový (avšak nekompletný) program tak, aby sa pri pretečení T1 po jednej sekunde vyvolalo prerušenie a zmena stavu LED diódy bude tiež vykonaná v obsluhe prerušenia.




Riadok 187: Riadok 173:
{
{
       DDRB = (1<<LED1);        // PORTB: LED1 on PB5 is output
       DDRB = (1<<LED1);        // PORTB: LED1 on PB5 is output
      PORTD = (1<<SW1);        // PORTD:  SW1 on PD5 is input + pull-up ON
 
 
       TCNT1 = 0x????;          // initialize (CLEAR)counter  
       TCNT1 = 0x????;          // initialize (CLEAR)counter  
     TCCR1B = 0x05;            // T1 clk = internal clock source + prescaler 1:1024
     TCCR1B = 0x05;            // T1 clk = internal clock source + prescaler 1:1024
Riadok 198: Riadok 183:
       if ( TIFR1 & (1<<TOV1) )  // if Timer 1 Overflow Flag is set, then
       if ( TIFR1 & (1<<TOV1) )  // if Timer 1 Overflow Flag is set, then
       {
       {
         PORTB = ????;         // toggle LED1
         PORTB ^= (1 << LED1);   // toggle LED1
         TCNT1 = ????;          // re-initialize counter  
         TCNT1 = ????;          // re-initialize counter  
         TIFR1 = (1<<TOV1);      // Clear Timer Overflow Flag
         TIFR1 = (1<<TOV1);      // Clear Timer Overflow Flag
Riadok 217: Riadok 202:
ISR (TIMER1_OVF_vect)           
ISR (TIMER1_OVF_vect)           
  {  
  {  
  PORTB = PORTB ^ 0b????????; // Toggle the LED
          PORTB ^= (1 << LED1);       // toggle the LED1
           TCNT1 = 0x????;            // Restart T/C1 - reload
           TCNT1 = 0x????;            // Restart T/C1 - reload
// Following is not necessary as it is cleared automatically
// Following is not necessary as it is cleared automatically
Riadok 259: Riadok 244:
# Program doplňte podľa pokynov asistenta a odsimulujte.<BR>Pozn.: Treba vypnúť optimalizáciu! (Project/Project options [[Médiá:AVRstudioOptimize0.png|Pozri obr.]])
# Program doplňte podľa pokynov asistenta a odsimulujte.<BR>Pozn.: Treba vypnúť optimalizáciu! (Project/Project options [[Médiá:AVRstudioOptimize0.png|Pozri obr.]])
-->
-->
# Doplňte chýbajúce časti programu s časovačom T1 tak, aby LED bola ovládaná cez prerušenie a blikala s frekvenciou 1 s. Ak to zvládnete, pridajte si do programu nejakú premennú, ktorej hodnotu budete raz za sekundu inkrementovať, najlepšie tiež v obsluhe prerušenia. Na displeji potom zobrazíte nejaký text a čas od zapnutia procesora v sekundách, popritom bude prehrávať nejakú melódiu a blikať LED diódou v 1 sekundovom intervale. Výsledkom bude program, ktorý dokáže realizovať tri veci "paralelne".  
# Doplňte chýbajúce časti programu s časovačom T1 tak, aby LED bola ovládaná cez prerušenie a blikala s frekvenciou 1 s. Ak to zvládnete, pridajte si do programu nejakú premennú, ktorej hodnotu budete raz za sekundu inkrementovať, najlepšie tiež v obsluhe prerušenia. V termináli potom zobrazíte nejaký text a čas od zapnutia procesora v sekundách, popritom bude prehrávať nejakú melódiu a blikať LED diódou v 1 sekundovom intervale. Výsledkom bude program, ktorý dokáže realizovať tri veci "paralelne".  
 
 
 
{| style="padding:0 0.5em;"|
| style="width:70%; vertical-align:top; border:1px solid #fad67d; background:#f3f0c6;"|
<div style="border-bottom:1px solid #fad67d; background:#faecc8; padding:0.2em 0.5em; font-size:110%; font-weight:bold;">'''Poznámka'''</div>
<div style="border-bottom:1px solid #fad67d; padding:0.4em 1em 1em;">
Ak chcete používať v obsluhe premenné, ktorých obsah chcete uchovať napr. až do ďalšieho prerušenia, musia byť deklarované ako <code>static</code>. 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, preto použite pri deklarácii <code>volatile</code>.
 
|}
 
 
{| style="padding:0 0.5em;"|
| style="width:70%; vertical-align:top; border:1px solid #fad67d; background:#f3f0c6;"|
<div style="border-bottom:1px solid #fad67d; background:#faecc8; padding:0.2em 0.5em; font-size:110%; font-weight:bold;">'''Poznámka'''</div>
<div style="border-bottom:1px solid #fad67d; padding:0.4em 1em 1em;">
'''Presnosť Timerov''' (Reload vs. CTC režim): Na dosiahnutie periódy 1 s sme do ISR napísali: <code>TCNT1 = 0x????; // Restart T/C1 - reload</code>.
Softvérový reload v ISR však vnáša do časovania chybu (tzv. ''jitter''), pretože od pretečenia po vykonanie inštrukcie zápisu ubehne istý počet taktov, ktoré sme nezapočítali.
 
Úloha pre pokročilých: Nakonfigurujte Timer 1 do režimu CTC (Clear Timer on Compare Match) s vektorom prerušenia <code>TIMER1_COMPA_vect</code> v ktorom sa počítadlo vynuluje
hardvérovo s presnosťou na jeden jediný takt.
|}
 
 
{| style="padding:0 0.5em;"|
| style="width:70%; vertical-align:top; border:1px solid #fad67d; background:#f3f0c6;"|
<div style="border-bottom:1px solid #fad67d; background:#faecc8; padding:0.2em 0.5em; font-size:110%; font-weight:bold;">'''Poznámka'''</div>
<div style="border-bottom:1px solid #fad67d; padding:0.4em 1em 1em;">
Premenná na počítanie sekúnd: Máte si do ISR pridať premennú, ktorá sa tam inkrementuje každú sekundu, a v hlavnom programe sa vypíše na terminál.
Čo sa stane, ak si deklarujete túto premennú ako 16-bitovú alebo 32-bitovú? Hlavný 8-bitový program ju bude musieť čítať na viackrát. Ak by prerušenie
nastalo presne medzi prečítaním prvého a druhého bajtu z RAM, na termináli sa vypíše nezmyselné číslo.
 
Preto ak čítate viacbajtovú volatile premennú v hlavnom programe, musíte počas čítania dočasne prerušenia zakázať (cez cli() a následne sei()),
prípadne použiť makro <code>ATOMIC_BLOCK</code> z knižnice <code><util/atomic.h></code>.
|}




Riadok 273: Riadok 293:
* [http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=50106 Newbie's Guide to AVR Timers]
* [http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=50106 Newbie's Guide to AVR Timers]
* [http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=55347 The traps when using interrupts]
* [http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=55347 The traps when using interrupts]
* [http://www.senzor.robotika.sk/mmp/pdf/AVR-C-Timers.pdf Ako používať časovače v AVR C]
* [http://senzor.robotika.sk/mmp/AVR-C-Timers.pdf Ako používať časovače v AVR C]
* [http://www.senzor.robotika.sk/predmety/mmp/pdf/PreruseniaAVR.pdf Prednáška o prerušeniach] (Ing. Chamraz)
* [http://senzor.robotika.sk/mmp/PreruseniaAVR.pdf Prednáška o prerušeniach] (Ing. Chamraz)





Aktuálna revízia z 20:17, 18. marec 2026


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.

Prerušenie pri zmene stavu niektorého pinu procesora

Na cvičení 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.


Schéma prerušovacieho systému externých prerušení.


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	SW2_ON bit_is_clear(PIND, SW2) 
#define LED2_ON PORTD |= (1 << LED2) 
#define LED2_OFF PORTD &= ~(1 << 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	SW2_ON bit_is_clear(PIND, SW2) 
#define LED2_ON PORTD |= (1 << LED2) 
#define LED2_OFF PORTD &= ~(1 << 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);
}


Zákmity tlačidiel a Prerušenia (Interrupt Storm):

V reálnom živote aj naďalej platí, že mechanické tlačidlá trpia zákmitmi (tzv. bouncing). Každé jedno stlačenie vyvolá desiatky zákmitov v priebehu milisekúnd a tým pádom desiatky zbytočných prerušení, ktoré procesor extrémne zahltia. Mechanické tlačidlá sa na prerušovacie piny preto pripájajú len výnimočne, a to s využitím hardvérového RC filtra pre debouncing, inak sa preferuje pravidelné čítanie pinu (polling) v prerušení od časovača.


Časovač T1

S časovačom T1 sme pracovali na minulom cvičení. Príznak pretečenia počítadla TOV1 sme testovali "ručne", metódou tzv. polling - dopytovania. Je to neefektívny spôsob, pretože procesor využívame len na otrocké testovanie jedného bitu stále dookola. Preto je vašou úlohou doplniť vzorový (avšak nekompletný) program tak, aby sa pri pretečení T1 po jednej sekunde vyvolalo prerušenie a zmena stavu LED diódy bude tiež vykonaná v obsluhe prerušenia.



Pri povolení prerušenia nezabudnite okrem samotného prerušenia povoliť aj globálny príznak...


#include <avr/io.h>

#define SW1  PD5
#define LED1 PB5


int main(void)
{
       DDRB = (1<<LED1);        // PORTB: LED1 on PB5 is output
  
      TCNT1 = 0x????;           // initialize (CLEAR)counter 
     TCCR1B = 0x05;             // T1 clk = internal clock source + prescaler 1:1024
      TIFR1 = (1<<TOV1);	// clear Timer 1 Overflow Flag (yes, writing 1 will clear it)
   
    
    while(1)                    // do forever this:
    {
      if ( TIFR1 & (1<<TOV1) )  // if Timer 1 Overflow Flag is set, then
      {
        PORTB ^= (1 << LED1);   // toggle LED1
        TCNT1 = ????;           // re-initialize counter 
        TIFR1 = (1<<TOV1);      // Clear Timer Overflow Flag
      }	   	  
    }
	
    return(0);                  // this will never happen
}
#include <avr/io.h>
#include <avr/interrupt.h>


//  if ( (TIFR1 & 0x01) == 0x01)  // If the overflow flag is set
//  ... then following Interrupt routine is called

ISR (TIMER1_OVF_vect)          
 { 
          PORTB ^= (1 << LED1);        // toggle the LED1
           TCNT1 = 0x????;             // Restart T/C1 - reload
	// Following is not necessary as it is cleared automatically
        // TIFR1 = 0x01;               // Clear the overflow flag
  }
      
int main( void )
{
  /* *********************** Init device ************************************ */

  ...

// Enable interrupts:

  TIMSK1 = (1<<TOIE1);            // Timer 1 overflow interrupt enable
   sei();                   // Assembler macro for global int. enable


  /* *********************** Main Loop ************************************** */

  do {

        asm("nop");                 // Do nothing

  } while(1);                       // And do this forever


 return(0);
}



Prehľad registrov pre počítadlo T1.


Úloha

  1. Doplňte chýbajúce časti programu s časovačom T1 tak, aby LED bola ovládaná cez prerušenie a blikala s frekvenciou 1 s. Ak to zvládnete, pridajte si do programu nejakú premennú, ktorej hodnotu budete raz za sekundu inkrementovať, najlepšie tiež v obsluhe prerušenia. V termináli potom zobrazíte nejaký text a čas od zapnutia procesora v sekundách, popritom bude prehrávať nejakú melódiu a blikať LED diódou v 1 sekundovom intervale. Výsledkom bude program, ktorý dokáže realizovať tri veci "paralelne".


Poznámka

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, preto použite pri deklarácii volatile.


Poznámka

Presnosť Timerov (Reload vs. CTC režim): Na dosiahnutie periódy 1 s sme do ISR napísali: TCNT1 = 0x????; // Restart T/C1 - reload. Softvérový reload v ISR však vnáša do časovania chybu (tzv. jitter), pretože od pretečenia po vykonanie inštrukcie zápisu ubehne istý počet taktov, ktoré sme nezapočítali.

Úloha pre pokročilých: Nakonfigurujte Timer 1 do režimu CTC (Clear Timer on Compare Match) s vektorom prerušenia TIMER1_COMPA_vect v ktorom sa počítadlo vynuluje hardvérovo s presnosťou na jeden jediný takt.


Poznámka

Premenná na počítanie sekúnd: Máte si do ISR pridať premennú, ktorá sa tam inkrementuje každú sekundu, a v hlavnom programe sa vypíše na terminál. Čo sa stane, ak si deklarujete túto premennú ako 16-bitovú alebo 32-bitovú? Hlavný 8-bitový program ju bude musieť čítať na viackrát. Ak by prerušenie nastalo presne medzi prečítaním prvého a druhého bajtu z RAM, na termináli sa vypíše nezmyselné číslo.

Preto ak čítate viacbajtovú volatile premennú v hlavnom programe, musíte počas čítania dočasne prerušenia zakázať (cez cli() a následne sei()), prípadne použiť makro ATOMIC_BLOCK z knižnice <util/atomic.h>.


Literatúra:

2021

2016




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