본문 바로가기
코스웨어/16년 스마트컨트롤러

20160314_김도관_업무일지_펌웨어실습_인터럽트_버튼으로 LED점멸

by 알 수 없는 사용자 2016. 3. 16.
728x90
반응형

인터럽트 란?



'인터럽트(Interrupt)'는 우리말로 흔히 '끼어들기' 또는 '가로채기'라고 표현

인터럽트가 발생하는 순간은 항상 CPU가 어떤 일을 하고 있을 때인데, 어떤 연속된 과정 중간에 급하게 처리해야할 다른 일이 발생하게 되면 우리는 이러한 상황을 '끼어들었다'라고 하며, 일이 급하니 만큼 하던 일을 잠시 멈추고 그 일을 먼저 처리하게 된다

CPU는 항상 어떤 일을 진행중...대기중이거나 특별한 작업 수행중이거나 이런 중에 CPU가 인터럽트 신호를 감지하게 되(이것을 '인터럽트가 걸렸다'라고 한다)  CPU는 하고 있던 일을 잠시 멈추고 인터럽트 신호에 따라 적절한 동작을 취하게 된다.  여기에서 말하는 '적절한동작'이란, CPU가 현재 하고 있던 동작에 대한 여러가지 주변 상황을 저장하고 이미 준비되어 있는  '인터럽트 처리루틴(또는 핸들러)'을 실행하는 것을 말한다.

인터럽트 처리 루틴이 수행되고 나면 CPU는 다시 '인터럽트 처리 종료' 신호를 받게 된다. 그러면 CPU는 주변상황을 인터럽트가 걸리기 전의 상태로 돌려놓고(인터럽트 처리루틴을 수행하기 전에 저장해 두었었다) 종전에 하던 일을 계속 수행하게 된다.
예를 들어 A와 B가 대화중 새로 대화실에 들어 온 사람에게 인사하고 나서 하던 대화를 계속하는것처럼..

참고 및 자세한글 : http://blog.bagesoft.com/652

외부인터럽트


 내부적인 처리 및 연산에 의한 다른 인터럽트( 소프트웨어적 처리 )와는 달리 외부핀 INT0~INT7에 직접 입력되는 신호(High & Low)값을 입력 값으로 받아 인터럽트가 걸려 정해놓은 인터럽트 루틴을 실행하드웨어적 )



         



Rising                                 Falling                            LOW




외부 인터럽트 관련 레지스터

: 외부 인터럽트를 제어하기 위해서는 상태레지스터(SREG)와 외부 인터럽트 관련 레지스터(EIMSK, EICRA, EICRB, EIFR)의 사용법을 알아야 한다.
 
 
SREG(Status Register)


▪ MCU의 현 상태 및 최근 수치 명령 실행에 대한 결과를 포함한다.
▪ 상태레지스터는 모든 ALU 연산을 수행 후 갱신된다.
▪ Bit7. I (Global Interrupt Enable) : 모든 인터럽트 활성화 비트




EIMSK(External Interrupt Mask Register)

▪ Bit 7..0 – INT 7~0 Q 비트를 SET(1) 시키면 해당 외부 인터럽트 핀이 활성화 된다.
▪ 단, SREG의 I비트가 1로 SET된 상태여야 한다.



EICRA(External Interrupt Control Register A)


▪ 외부 인터럽트의 트리거 방식을 LOW / 상승엣지 / 하강엣지 중에 선택하는 레지스터

ISCn1

ISCn0

설명

0

0

INTn Low 신호시에 일반적인 인터럽트 요청을 한다.

0

1

(reserved)

1

0

INTn의 하강엣지 신호시에 일반 비동기적인 인터럽트를 요청한다

1

1

INTn의 상승엣지 신호시에 일반 비동기적인 인터럽트를 요청한다

 



EICRB(External Interrupt Control Register B)

 
▪ 외부 인터럽트의 트리거 방식을 LOW / 상승엣지 / 하강엣지 중에 선택하는 레지스터

ISCn1

ISCn0

설명

0

0

INTn의 Low 신호시에 일반적인 인터럽트 요청을 한다.

0

1

어떠한 신호의 변화에서든 일반적인 인터럽트 요청을 한다.

1

0

INTn의 두 샘플 신호간의 하강엣지 신호시에 일반적인 인터럽트를 요청한다

1

1

INTn의 두 샘플 신호간의 상승엣지 신호시에 일반적인 인터럽트를 요청한다

 



EIFR(External Interrupt Flag Register)


▪ Bit 7..0 – 외/내부로부터 INT7:0 핀에 인터럽트가 요청되면 해당 비트가 Set(1) 된다. 그 후에 인터럽트 루틴이 실행될 때 해당 비트가 Clear(0)된다.



외부 인터럽트 동작

①    인터럽트가 활성화(SREG.7 / EIMSK 해당 비트 활성화) 되어 있는 상태에서
②    외부INT의 동작 엣지나 논리신호에 의해 인터럽트가 요청되면
③    제일 우선 INTFn=1 상태로 플래그가 Set되고
④    실행 중이던 메인 프로그램의 프로그램카운터 값을 스택에 저장하게 된다.
⑤    그 후 해당 인터럽트 벡터로 점프하게 되며
⑥    지정된 인터럽트 루틴을 실행하는 동시에 INTFn=0 상태로 플래그가 Clear된다.
⑦    해당 인터럽트의 루틴이 처리된다.
⑧    해당 인터럽트의 루틴이 끝나게 되면 RETI 명령을 받는다.
⑨    스택으로부터 저장된 프로그램카운터 값을 로드 한다.
⑩    동작 중이던 프로그램 위치로 복귀하여 실행 중이던 부분부터 메인 프로그램이 재작동된다.


main.c 통합코드  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <interrupt.h> 
 
#define DDRA     (*((volatile unsigned char *)0x21))
#define PORTA    (*((volatile unsigned char *)0x22))
#define PINA     (*((volatile unsigned char *)0x20))
#define EICRA    (*((volatile unsigned char *)0x69))
#define EICRB    (*((volatile unsigned char *)0x6A))
#define EIMSK    (*((volatile unsigned char *)0x3D))
#define SREG     (*((volatile unsigned char *)0x5F))
 
#define INT7 7
#define INT6 6
#define INT5 5
#define INT4 4
#define INT3 3
#define INT2 2
#define INT1 1
#define INT0 0
 
#define ISC7 6
#define ISC6 4
#define ISC5 2
#define ISC4 0
#define ISC3 6
#define ISC2 4
#define ISC1 2
#define ISC0 0
 
#define sei()   __asm__ __volatile__ ("sei" ::)
#define sleep()    __asm__ __volatile__ ( "sleep" "\n\t" :: )
 
void __vector_1 (void) __attribute__((signal, used, externally_visible));
//__attribute__ 속성 전달 
//externally_visible 외부에서 호출가능
 
//함수명 임의로 정할수없음 정확해야됨
 
int main(void)
{
    DDRA = 0xFF;
    PORTA = 0x00;
    EICRA = (3 << ISC0); // ISC0 == INT0 
    EIMSK = (1 << INT0); //EIMSK의 비트 1값들어감 임베디드에서 자주쓰는것 EIMSK = 1 동일
    //EIMSK = (1 << INT0)|(1 << INT3);
    SREG = SREG|(1 << INT7); //다른값건드리면 안됨 //sei(); 와 동일 // 인트럽트활성화
    
    
 
    while(1){
        sleep();
    }
    
    return 0;
}
 
void __vector_1(void// 1번 인터럽 // pdf에선 벡터2번을 의미함 +1 
{    
    volatile unsigned int uiCnt;
     for(uiCnt = 030000>uiCnt ; ++uiCnt);
    PORTA = ~PORTA;
    
    return;
}
cs


29번#define sei() __asm__ __volatile__ ("sei" ::)

SREG 인터럽트 활성화 시키는 어셈블리어 sei(set enable interrupt) 

 자동으로 1의 값을 가짐

30번 : #define sleep() __asm__ __volatile__ ( "sleep" "\n\t" :: ) 

 SREG 인터럽트 슬립 시키는 어셈블리어 ....c로 cpu를 제어할수없는것을 어셈블리어로 제어. 통틀어 inline assembly라고 부름.

 컴파일이 바뀌면 사용불가. 

 void __vector_1(void) __attribute__((signal, used, externally_visible));

 gcc컴파일러만 사용됨 이 함수의 속성을 적어줌. 리눅스에서는 시그널....인터럽트. 

외부에서 이 함수를 호출가능. 

 data sheet 와 달리 벡터 넘버를 보면 실제 코딩할 때는 번호가 0부터 시작


42번 : EICRA 상승엣지 ,외부인터럽트 제어

43번 : EIMSK 의 1의 값일때 sei() 가 처리됨


45번 : sei(); 와 동일, 인트럽트 활성화시킴

50번 : 동작이 없을때 쉬게함


상단 코드 main.c 와 main.h 분리

소스코드를 기능별로 나눠서 관리에 유리

헤더파일 : 일종의 메뉴판 , define 이나 함수의 원형등을 선언함


main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include "main.h"
int main(void)
{
    DDRA = 0xFF;
    PORTA = 0x00;
    EICRA = (3 << ISC0); // ISC0 == INT0 
    EIMSK = (1 << INT0); //EIMSK의 비트 1값들어감 임베디드에서 자주쓰는것 EIMSK = 1 동일
    //EIMSK = (1 << INT0)|(1 << INT3);
    SREG = SREG|(1 << INT7); //다른값건드리면 안됨 //sei(); 와 동일 // 인트럽트활성화
    
    while(1){
        sleep();
    }
    
    return 0;
}
 
void __vector_1(void// 1번 인터럽 // pdf에선 벡터2번을 의미함 +1 
{    
    volatile unsigned int uiCnt;
     for(uiCnt = 030000>uiCnt ; ++uiCnt);
    PORTA = ~PORTA;
    
    return;
}
cs


1번 : 분리된 main.h를 불러옮

main.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#ifndef __MAIN_H__
#define __MAIN_H__
 
#define DDRA     (*((volatile unsigned char *)0x21))
#define PORTA     (*((volatile unsigned char *)0x22))
#define PINA     (*((volatile unsigned char *)0x20))
#define EICRA    (*((volatile unsigned char *)0x69))
#define EICRB    (*((volatile unsigned char *)0x6A))
#define EIMSK    (*((volatile unsigned char *)0x3D))
#define SREG    (*((volatile unsigned char *)0x5F))
 
#define INT7 7
#define INT6 6
#define INT5 5
#define INT4 4
#define INT3 3
#define INT2 2
#define INT1 1
#define INT0 0
 
#define ISC7 6
#define ISC6 4
#define ISC5 2
#define ISC4 0
#define ISC3 6
#define ISC2 4  
#define ISC1 2
#define ISC0 0
 
#define sei()   __asm__ __volatile__ ("sei" ::)
#define sleep()    __asm__ __volatile__ ( "sleep" "\n\t" :: )
 
void __vector_1 (void) __attribute__((signal, used, externally_visible));
 
#endif //__MAIN_H_
cs


기존 코드에서 분리된 define이나 함수의 원형등을 여기서 선언함



미니케이블 연결시



LED ON 상태


버튼누른뒤 LED OFF 상태




그외 참고사항

AVR로 개발시 유의 사항  : Sharehobby.tistory.com

728x90