Develop Knowledge/Atmega, AVR

7강. 내부 인터럽트와 외부 인터럽트

정수열 2022. 12. 18. 22:38

본 글은 Atmega의 인터럽트에 대해서 얼아본다.

 

- 인터럽트?

'방해하다', '중단하다'라는 뜻을 가진 인터럽트는, 인터럽트가 실행 될 떄 메인 프로그램을 중지하고 다른 일을 수행하는걸 말합니다.

인터럽트가 발생하게 되면, 인터럽트 서비스 루틴(ISR)이 발생하면서 그 안에 있는 동작이 실행 된 후, 다시 메인 프로그램으로 돌아갑니다.

 

- 인터럽트 종류

Atmega에는 다양한 인터럽트가 있습니다. 대표적인 것만 보면,

> 내부 인터럽트 : 타이머, ADC, UART통신, SPI 통신 등, Atmega 내부의 동작에 의해 발생하는 인터럽트 입니다.

> 외부 인터럽트 : INT0~INT7로, 외부의 전기 신호에 의해 발생하는 인터럽트 입니다.

내부 인터럽트는 다룰게 많아서 나중의 글에서 하나씩 살펴보기로 하고,

이번 시간에는 외부 인터럽트를 알아보겠습니다.

 

- 외부 인터럽트

ATmega128a 기준으로, 외부 인터럽트는 8개가 있습니다.

PD0~PD3 핀에는 INT0~INT3, PE4~PE7 핀에는 INT4~INT7이 있네요.

 

- 외부 인터럽트의 입력 신호

atmega의 외부 인터럽트는 3가지 신호를 인식할 수 있습니다.

Rising Edge, Falling Edge, Low level이 그것입니다. High Level은 인식할 수 없습니다.

 

- 외부 인터럽트의 레지스터

레지스터는 간단히 의미하면 '설정 값'을 의미한다. 외부 인터럽트는 크게 3가지 레지스터가 있다.

1. EIMSK로 어느 핀의 외부 인터럽트를 사용할지 정한다.

2. EICRA, EICRB로 외부 인터럽트를 설정한다.

3. sei(); 함수 호출, 혹은 SREG로 외부 인터럽트 사용을 허가한다.

 

하나씩 알아보도록 하겠습니다.

> 1. EIMSK (External Interrupt Mask Register) : 외부 인터럽트 활성화

INT7~INT0 중, 어느 비트를 활성화 시킬지 정합니다. 비트 값이 1이면 활성화 됩니다.

 

> 2. EICRA, EICRB (External Interrupt Control Register A, B) : 외부 인터럽트 설정

EICRA는 INT0~INT3 외부 인터럽트를 설정할 수 있습니다.

EICRA의 Bit7,6은 INT3, Bit5,4는 INT2, Bit3,2는 INT1, Bit1,0은 INT0을 다룰 수 있고,

비트가 00이면 Low level, 01은 없고, 10이면 falling edge, 11이면 rising edge를 인식합니다.

 

EICRB는 INT4~INT7 외부 인터럽트를 설정할 수 있고, EICRA와 동일합니다.

다만, 비트가 01이면 falling edge/rising edge 둘 다 인식할 수 있는 기능이 추가되었습니다.

 

> 3. SREG (Statue REGister) : 상태 비트 설정

7번 비트가 'I'(Interrupt)를 1로 하면, 모든 인터럽트 종류에 대한 사용을 승인하는 레지스터이다

참고로 6,5,4,... 비트는 인터럽트와는 관련없는 기능이다.

 

레지스터를 활성화 시켜도 되고, 간단하게는 이렇게도 가능하다.

sei(); // SREG 레지스터의 7번 비트 활성화
cli(); // SREG 레지스터의 7번 비트 비활성화

 

> 기타.  EIFR (External Interrupt Flag Register) : 인터럽트 결과 확인

인터럽트가 발생안한 핀을 0, 인터럽트가 발생한 핀을 1로 읽어와서 EIFR 레지스터에 나타내어준다.

참고로 이 레지스터는 Read Only이다. 결과값을 읽어오는 것만 가능하다.

 

 

 

- 예제 : 0번 외부 인터럽트를 Rising Edge로 인식하는 코드

// 0번 외부인터럽트를 rising edge로 사용해보기

#define F_CPU 16000000UL

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

volatile int sw;

// 인터럽트 서비스 루틴.
// 인터럽트 발생시, 이 안의 코드가 수행된다.
ISR(INT0_vect) // 외부 인터럽트 0번 사용.
{
	sw=1;
}

// 인터럽트 설정.
void external_interrupt_setting()
{
	EIMSK=(1<<INT0); //0번 외부 인터럽트를 사용하겠다.
	EICRA=((1<<ISC01)|(1<ISC00)); //0번 외부 인터럽트는 입력 신호가 rising edge일 때 발생한다.
}

int main(void)
{
	DDRD = 0x00;
	DDRA = 0xff;
	
	external_interrupt_setting();
	sei(); //인터럽트 사용을 승인한다..!
	
	while (1) 
	{
		if(sw==1)
		{
        	// PORTA의 LED가 1초동안 켜졌다가 꺼진다.
			PORTA = 0xff;
			_delay_ms(1000);
			PORTA = 0x00;
			sw=0;
		}
	}
}