AVR툴체인으로 인터럽트를 처리하기 위해서 정해진 형식을 가지는 함수를 작성해야 한다. 어떤 인터럽트가 발생했을 때 이를 받아서 처리하는 함수를 ISR함수라고 하며 이 형식은 <interrupt.h>헤더파일에 정의되어 있다. 따라서 인터럽트를 사용하기 위해서는 이 헤더파일을 반드시 인클루드 시켜줘야 하며 ISR 정의 형식은 다음과 같다.


#include <avr/interrupt.h>
ISR(<vector>) {
   // 함수의 본체
}


여기서 <vector>는 발생한 인터럽트가 어느 것이냐에 따라 미리 정해진 식별자이며 ATmega8A의 경우 다음 표와 같이 정의된다.


[표 1[ ATmega8(A)의 인터럽트 벡터

번호

<vector>

인터럽트 종류

비고

1

INT0_vect

외부 인터럽트 0번

외부

발생

2

INT1_vect

외부 인터럽트 1번

3

TIMER2_COMP_vect

타이머/카운터2 비교매치

내부

발생

4

TIMER2_OVF_vect

타이머/카운터2 오버플로

5

TIMER1_CAPT_vect

타이머/카운터1 캡춰

6

TIMER1_COMPA_vect

타이머/카운터1 비교매치A

7

TIMER1_COMPB_vect

타이머/카운터1 비교매치B

8

TIMER1_OVF_vect

타이머/카운터1 오버플로

9

TIMER0_OVF_vect

타이머/카운터0 오버플로

10

SPI_STC_vect

직렬 전송 완료

11

USART_RXC_vect

USART 읽기(Rx) 완료

12

USART_UDRE_vect

USART 데이터레지스터 비워짐

13

USAER_TXC_vect

USART 쓰기(Tx) 완료

14

ADC_vect

ADC 완료

15

EE_RDY_vect

EEPROM 준비완료

16

ANA_COMP_vect

아날로그 비교

17

TWI_vect

TWI 인터페이스

18

SPM_RDY_vect

프로그램메모리 쓰기 준비완료


AVR-Toolchain에서는 ISR을 작성하지 않은 인터럽트가 발생하면(즉, 인터럽트 발생은 허용시켰는데 해당하는 ISR함수가 없다면) 리셋 벡터로 점프하도록 내부에서 처리하고

있다. 이것을 회피하려면 다음과 같이 ISR함수를 정의하면 ISR함수가 없는 모든 인터럽트를 처리하도록 할 수 있다.


#include <avr/interrupt.h>
ISR(BADISR_vect) {
   // 함수의 본체
}


또한 인터럽트와 관련된 매크로함수로서 sei(), cli() 함수가 있다. sei()함수는 인터럽트 발생을 전역적으로 허용하는 것이고, cli()함수는 반대로 인터럽트의 발생을 전역적으로 허용치 않도록 설정하는 함수이다.


 어떤 경우에는 ISR()함수와 다른 함수 (예를 들어서 main()함수) 들과 변수를 공유할 수도 있다. 이 경우에는 그 변수를 반드시 전역변수로 선언해야 하며, 한 가지 주의할 점은 만약 ISR()내부에서 이 변수가 갱신된다면 반드시 volatile 키워드를 붙여서 선언해야 한다는 점이다. 다음의 예를 보자.


#include <avr/interrupt.h>
int myValue; //<-
ISR(INT0_vect) {
   myValue++;
}
int main(void) {
   ⋮
   while (myValue == 0); // wait for interrupt
       TurnLEDOn;
   ⋮
}


위의 예에서 main()함수의 while()문 안에서는 myValue 변수 값이 변하지 않으므로 무한루프에 빠지게 된다. 이것의 내부적인 동작 방식을 보면 myValue==0 조건을 검사하기 위해서 맨 처음에는 myValue값을 읽어서 레지스터에 저장하고 그 다음 반복부터는 그 레지스터에 저장된 값(맨 처음 읽어들인 값)을 0과 비교하게 되므로 값이 ISR( )함수에서 갱신된 값이 반영이 안 되는 것이다. 따라서 무한루프에 빠지게 되고 여기서 프로그램이 멈추게 된다. 하지만 전역변수 myValue를 다음과 같이 volatile형으로 정의하면 매 반복마다 myValue값을 다시 읽어 들이게 되므로 ISR( )함수 내부에서 갱신된 값이 반영이 된다.


volatile int myValue;


 참고로 AVR은 하드웨어적으로 인터럽트 처리가 시작되면 SREG의 글로벌 인터럽트 프랙 I가 자동적으로 0이 되어 인터럽트처리가 끝날 때까지 추가적인 인터럽트는 발생하지 못하는 상태가 된다.



Posted by 살레시오
,