다중 인터럽트를 활용한 카운트 업/다운
학습목표 - 다중 인터럽트를 활용한 카운트 업/다운 회로를 만들 수 있다.
다중 인터럽트
2개 이상의 인터럽트를 만드는데 그 내용이 서로 상이하여 구분할 수 있게 만들어 보자.
INT0은 count down, INT4는 count up을 만든다.
I. 서술
사용한 코드(7segment digital roulette)에서 인터럽트(interrupt)를 추가적으로 하나 더 달아주고 INT0은 count down, INT4는 count up을 사용하자.
II. 덩어리 나누기
1. 인터럽트 추가
- INT0와 INT4를 쓴다.
- 설정 코딩은 전에 했던 것들을 복사해서 쓴다.
*입력은 PIN을 사용하는 것을 잊지 말자.
2. 추가한 인터럽트에 카운트 업, 카운트다운 코딩
- ++과 --를 사용하여 간단하게 카운트 업/다운을 해준다.
III. 회로를 만들어 주기

코딩한 내용을 프로테우스로 실행시켜 확인해 보자!
AVR 교재 p/139
(2) 인터럽트의 동작에서 SREG 레지스터의 글로벌 인터럽트 허용 비트가 잠정적으로 0으로 되었다가 인터럽트가 종료되면 다시 1로 복구되는데 이중 인터럽트를 허용하기 위해서는 인터럽트가 동작되자 마자 이 레지스터를 1로 설정해 주어야 한다.
인터럽트를 허용시키는 코드!
SREG |= 0x80; //이중 인터럽트 허용 코드 |
코드의 아래와 같다.
/*** main.c ***/
#include <atm128.h> //#include <avr/interrupt.h> #include "SMART.h"
unsigned char ucCnt=50; volatile unsigned int uiCnt;
int main(void) { /*** 숫자 표시를 위한 FND 입력값 ***/
unsigned char FND[10] = {0x40, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x58, 0x00, 0x10}; unsigned char ucCnt=0;
/*** Delay를 위한 변수 입력 ***/
volatile unsigned long uiCnt;
/*** 사용할 PORT 설정 ***/
DDRC = 0xFF; //PORT C 모두 출력 사용 DDRD = 0XFE; //PORTD 1번 핀 입력 사용 DDRE = 0xEF; //PORT E의 5번 핀 입력 사용 /*** 인터럽트 설정 ***/
SREG &= 0x7F; //interrupt disable, 설정 중 오동작을 막기 위해 EICRA = 0X00; //스위치의 트리거 방식 설정 - 하강 에지 방식 EICRB = 0x00; //스위치의 트리거 방식 설정 - 하강 에지 방식 EIMSK = 0x11; //외부 인터럽트 허용 레지스터 - 인터럽트 0 외부 인터럽트 허용 SREG |= 0x80; while(1) { ; } return 0; }
void __vector_1(void) { /*** count down ***/ unsigned char FND[10] = {0x40, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x58, 0x00, 0x10}; while(1) { SREG |= 0x80; PORTC = FND[ucCnt%10]; Delay(2000); --ucCnt; if(ucCnt==0x00|100) ucCnt==50;
if(PIND==0x01) break; }
} void __vector_5(void) { /*** count up ***/ unsigned char FND[10] = {0x40, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x58, 0x00, 0x10}; while(1) { SREG |= 0x80; PORTC = FND[ucCnt%10]; Delay(2000); ++ucCnt;
if(ucCnt==0x00|100) ucCnt==50;
if(PINE==0x10) break;
}
} |
/*** SMART.h ***/
#ifndef __SMART_H__ #define __SMART_H__
/**** General Purpose Register A - L ****/
#define PORTA (*((volatile unsigned char*)0x22)) #define DDRA (*((volatile unsigned char*)0x21)) #define PINA (*((volatile unsigned char*)0x20))
#define PORTB (*((volatile unsigned char*)0x25)) #define DDRB (*((volatile unsigned char*)0x24)) #define PINB (*((volatile unsigned char*)0x23))
#define PORTC (*((volatile unsigned char*)0x28)) #define DDRC (*((volatile unsigned char*)0x27)) #define PINC (*((volatile unsigned char*)0x26))
#define PORTD (*((volatile unsigned char*)0x2B)) #define DDRD (*((volatile unsigned char*)0x2A)) #define PIND (*((volatile unsigned char*)0x29))
#define PORTE (*((volatile unsigned char*)0x2E)) #define DDRE (*((volatile unsigned char*)0x2D)) #define PINE (*((volatile unsigned char*)0x2C))
#define PORTF (*((volatile unsigned char*)0x31)) #define DDRF (*((volatile unsigned char*)0x30)) #define PINF (*((volatile unsigned char*)0x2F))
#define PORTG (*((volatile unsigned char*)0x34)) #define DDRG (*((volatile unsigned char*)0x33)) #define PING (*((volatile unsigned char*)0x32))
#define PORTH (*((volatile unsigned char*)0x102)) #define DDRH (*((volatile unsigned char*)0x101)) #define PINH (*((volatile unsigned char*)0x100))
#define PORTJ (*((volatile unsigned char*)0x105)) #define DDRJ (*((volatile unsigned char*)0x104)) #define PINJ (*((volatile unsigned char*)0x103))
#define PORTK (*((volatile unsigned char*)0x108)) #define DDRK (*((volatile unsigned char*)0x107)) #define PINK (*((volatile unsigned char*)0x106))
#define PORTL (*((volatile unsigned char*)0x10B)) #define DDRL (*((volatile unsigned char*)0x10A)) #define PINL (*((volatile unsigned char*)0x109))
/* 인터럽트 사용을 위한 레지스터 */
#define EICRA (*((volatile unsigned char*)0x69)) #define EICRB (*((volatile unsigned char*)0x6A)) #define EIMSK (*((volatile unsigned char*)0x3D)) #define EIFR (*((volatile unsigned char*)0x3C)) #define SREG (*((volatile unsigned char*)0x5F))
/* PCINT 사용을 위한 레지스터 */
#define PCICR (*((volatile unsigned char*)0x68)) #define PCIFR (*((volatile unsigned char*)0x3B)) #define PCMSK2 (*((volatile unsigned char*)0x6D)) #define PCMSK1 (*((volatile unsigned char*)0x6C)) #define PCMSK0 (*((volatile unsigned char*)0x6B))
/* CPU 동작시간을 맞춰주기 위한 Dealy문과 값 지정 */
#define Delay(x) for(uiCnt=0; uiCnt<(dNum1); ++uiCnt)
#define dNum1 50000 #define dNum2 300000 #define dNum3 10000000
void __vector_1(void)__attribute__((signal,used,externally_visible)); void __vector_5(void)__attribute__((signal,used,externally_visible));
#endif //__SMART_H__ |
PCINT를 사용하여 인터럽트를 걸어보자!
PCINT에서 PC는 Pin Change의 약자이다.
/*** 펌웨어 설계 시 유의해야 할 부분 ***/
1. 출력 PORT의 초기화를 가장 우선으로 했는가?
2. Stack Point의 번지지정에는 이상이 없는가?
3. Stack 영역의 할당은 적절한가?
4. RAM Clear 시 Subroutine을 Call하는가?
5. RAM Clear시 Interrup가 발생하는가?
6. Vector Table의 Address 및 Label 정의는 정확한가?
7. 입/출력 port의 입/출력 모드 registor의 설정은 정확한가?
8. 입/출력 port의 초기화를 했는가?
/*** 외부 인터럽트 학습 ***/
외부 인터럽트(INT0 - 7)의 특징
- 외부 인터럽트는 INT 0 - 7핀의 입력으로 인해 인터럽트가 발생한다.
- 입력 방식의 신호를 선택할 수 있다. ex) low/high/상승&하강 에지
- 외부 인터럽트는 INT0 - 7핀의 입/출력 방향에 관계없이 인터럽트가 발생한다.
- INT 0 - 3 은 비동기적 검출이 가능하다.(슬립모드를 깨울 때 이용되기도 한다.)
- INT 4 - 7 은 I/O클럭이 있어야만 사용가능하다.
외부인터럽트를 사용하려면 관련 레지스터와 그 레지스터의 제어방법을 알아야 한다.
1. SREG(Status Register)
- MCU의 현 상태 및 최근 수치 명령 실행에 대한 결과를 포함한다.
- 상태 레지스터는 모든 ALU 연산을 수행 후 갱신된다.
- Bit7, I (Global Interrupt Enable): 모든 인터럽트 활성화 비트
2. EIMSK(External Interrupt Mask Register)
- Bit7 0 - INT 7~0 Q 비트를 SET(1) 시키면 해당 외부 인터럽트 핀이 활성화 된다.
- 단, SREG의 I비트가 1로 SET된 상태여야 한다.
3. EICRA(External Interrupt Control Register A)
- 외부 인터럽트의 트리거 방식을 선택하는 레지스터

4. EICRB(External Interrupt Control Register B)
- 외부 인터럽트의 트리거 방식을 선택하는 레지스터

5. EIFR(External interrupt Flag Register)
- 인터럽트가 요청되면 해당 비트가 1이 된다. 그 후에 인터럽트 루틴이 실행될 때 해당 비트가 clear(0)된다.