아트메가/이론

아트메가128 외부인터럽트입니다.

원원 2016. 11. 25. 01:14

 

 

인터럽트란?

메인문에서 어떤 작업을 하구있을때, 갑자기 어떤 코드가 실행되는것을 말합니다. 

예) 메인문에서 LED만 계속 키고있을때 버튼을 클릭하면 LED가 켜짐.(외부인터럽트)

 

외부인터럽트란?

 

쉽게말해서 외부에서 HIGH나 LOW가 들어오고 그 신호에 따라서 어떤 함수로 가서 동작하는 것입니다.

외부인터럽트는 8개가 있습니다. INT0~INT7까지있는데 INT0~INT3는 PD0~PD3을 사용하고, INT4~INT7은 PE4~PE7을 사용합니다.

 

 

외부인터럽트를 설정하는 레지스터는?

외부 인터럽트를 사용하려면 일단 허락을 받고 사용할 핀을 허락해 줘야합니다. 이런것들은 레지스터에 정의되어있는데 그 레지스터들을 알아보겠습니다.

SREG레지스터의 7번비트: Global Interrupt Enable - 전역인터럽트 이네이블 변수입니다. 인터럽트를 발생하게하려면 항상 이 비트를 set시켜줘야합니다. sei()함수를 호출하면 SREG레지스터의 7번비트가 set 됩니다.

EIMSK(External Interrupt Mask Register)  - INT0~INT7번까지 핀중에 사용할 핀을 SET 시켜줘야 그 핀을 외부인터럽트로 사용할 수 있게 됩니다.

EIFR(External Interrupt Flag Register) - 인터럽트가 발생하면 해당핀이 1로 Set됩니다. 그 의미가 있는데 만약 외부인터럽트 INT0,INT1에서 인터럽트가 동시에걸렸으면 INT0부터 실행하게 됩니다.

이 표를 보면 순서가 정의되어 있습니다. 인터럽트 0,1이 동시에 발생하게됬다면 인터럽트 백터 테이블 표에의해서 INT0인터럽트를 먼저 처리합니다. 

처음에 말했듯이 외부인터럽트는 HIGH와 LOW를 입력으로 받는다고 했습니다. 그런 신호를 입력 받으면 언제 도대체 언제 인터럽트를 걸리게 할것인지는 레지스터 설정에따라 달라집니다.

A일때를 우리가 HIGH 라고 하고 B일때를 LOW라고 한다면 A상태에서 B상태가될때! 위에서 아래로 내려갈때! 이때를 하강엣지라고 부릅니다. 또한 B에서 C로갈때는 상승엣지입니다. 이 것을 보고 외부인터럽트를 걸리는 때를 정할수 있습니다.
그 레지스터는 EICRA, ECIRB 두개입니다.
EICRA는 INT0~3을 결정하는 것이고 EICRB는 IN4~7를 결정하는 것입니다. 뭘 결정하냐면 바로 인터럽트가 어느시점에 걸리냐를 결정합니다.

 

 

EICRA

EICRA는 인터럽트 0~3번이 발생하는 시점을 결정하는 레지스터이고 조건은 3가지입니다.
첫번째) LOW상태일때
두번째) 하강엣지
세번째) 상승엣지

EICRB

EICRA는 인터럽트 4~7번이 발생하는 시점을 결정하는 레지스터이고 조건은 4가지입니다.
첫번째) LOW상태일때
두번째) 하강엣지 or 상승엣지
세번째) 하강엣지
네번째) 상승엣지

 

-EIMSK

외부인터럽트 이네이블 레지스터입니다


-EIFR

외부인터럽트가 발생하면 해당번호에맞는 비트가 set됩니다. 

 
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <string.h>
volatile int won = 0; // 인터럽트에 사용되는 변수는 volatile로 선언해야함

ISR(INT0_vect) // 외부 인터럽트 0번
{
	won++;
}
ISR(INT1_vect) //외부 인터럽트 1번
{
	won--;
}

int main(void)
{
	sei(); // 전역 인터럽트 이네이블
	EICRA = 0xaa; // INT0,1 하강엣지 사용
	EIMSK = 0x03; // INT0,INT1 인터럽트 이네이블
	DDRD = 0x00; // D포트 입력설정
	PORTD = 0xff; // D포트 외부풀업 설정
	DDRB = 0xff; // B포트 출력설정

	while(1)
	{
		PORTB = won;
	}
}

 

포트B에는 LED를 연결하고, 포트D 0,1번에는 버튼을 연결하면 됩니다.
그러면 버튼을 클릭할때 won의 값이 1증가하거나 1감소해서 그 값이 PORTB에 들어가서 LED가 켜지게 됩니다.

 

외부인터럽트가 발생했고, 그 인터럽트를 수행중일때 우선순위가 높은 인터럽트가 발생했으면 그 인터럽트로 이동하는지 테스트해보겠습니다

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <string.h>
volatile int won = 0;

ISR(INT0_vect) // 외부 인터럽트 0번
{
	while(1)
	{
		won = 1;
	}
}
ISR(INT1_vect) //외부 인터럽트 1번
{
	while(1)
	{
		won = 2;
	}
}
ISR(INT2_vect) //외부 인터럽트 2번
{
	while(1)
	{
		won = 3;
	}
}
int main(void)
{
	sei();
	EICRA = 0xaa;
	EIMSK = 0x07;
	DDRD = 0x00;
	PORTD = 0xff;
	DDRB = 0xff;

	while(1)
	{
		PORTB = won;
	}
}

외부인터럽트 2번을 발생시켜보겠습니다

EIFR의 1번째비트가 set되고 won=2 무한루프에 빠집니다. 이때 우선순위가 높은 인터럽트 0번을 발생시켜보겠습니다

EIFR의 0번째비트도 set됬는데 여전히 won=2 무한루프에 빠져있습니다.

인터럽트 함수는 무한루프에 빠지면 안되고 될수있으면 delay를 먹는요소를 줄여야합니다.