전기전자/Atmega128

[0x04] 외부 인터럽트

jemin0619 2024. 3. 28. 14:40

ISR이란

Interrupt Service Routine의 줄임말

main 함수 내의 프로그램 실행 중 인터럽트가 발생하면 ISR이 동작하며 main 함수 내의 동작을 잠시 미루고 ISR을 실행한다.

 

외부 인터럽트 레지스터

SREG : 인터럽트의 사용 여부를 저장.

- 최상위 비트가 1이면 enable, 0이면 disable

- sei() = (SREG=0b10000000;)

 

EIMSK (External Interrupt Mask)

-  인터럽트를 사용할 핀을 1로 해준다. - DDRX로 입력 포트 설정할 때 썼던 값의 bitwise not (~)을 해주면 편하다.

 

EICRA, EICRB :  인터럽트를 언제 시킬건지 결정

- A는 D0 ~ D3 를 설정

- EICRA = 0b D3 D2 D1 D0 (각 포트마다 2bit씩 사용)

- B는 E4 ~ E7 를 설정

- EICRB = 0b E7 E6 E5 E4 (각 포트마다 2bit씩 사용)

- 10은 상승에지, 11은 하강에지

 

예제

더보기

1. LED 켜고 끄기

#define F_CPU 16000000
#include <avr/io.h>
#include <avr/interrupt.h>

unsigned char led_on = 0x00;

ISR(INT0_vect){
	led_on = ~led_on;
}

int main(void){
	DDRA = 0x0F;
	DDRD = ~0x01;
	EIMSK = 0x01;
	EICRA = 0b00000010;
	sei();
    	while(1){
		PORTA = led_on;
	}
}

 

2. Array FND 구동시키기

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

int number=0; //숫자 초기값
unsigned char arr[3]={0,};

void parseNum(int num){
	arr[0]=arr[1]=0;
	int idx=0;
	while(num){
		arr[idx++]=num%10;
		num/=10;
	}
}

ISR(INT4_vect){ //가산
	number++;
	if(number>99) number=0;
}

ISR(INT5_vect){ //감산
	number--;
	if(number<0) number=99;
}

int main(void){
	DDRA = 0x0F; //FND
	DDRC = 0x03; //TR
	DDRE = ~0b00110000; //SW
	EIMSK = 0b00110000;
	EICRB = 0b00001111;
	sei();
    while(1){
		parseNum(number);
		for(int i=0;i<2;i++){
			PORTC = ~(0x01<<i);
			PORTA = arr[i];
			_delay_ms(5);
		}
	}
}