외부 인터럽트는 INT7:0핀에 입력되는 트리거 신호에 의해서 발생한다.
트리거 신호는 폴링 에지, 라이징 에지, 로우 레벨 3가지가 될 수 있다. 어떤 신호 입력을 기다릴지 미리 설정해놓고 기다리다가 해당 신호가 입력되는 순간 인터럽트가 발생하는 것이다.
Atmega 128에서 외부 인터럽트용 핀은 아래 그림처럼 8개가 있다.
INT7:0 핀을 출력으로 설정해 놓고 인터럽트 핀을 소프트웨어적으로 조작하더라도 인터럽트가 발생한다. 예를들어 falling edge때 인터럽트가 발생하게 해놓고 해당 핀의 출력이 1에서 0으로 떨어지는 것처럼 값을 1과 0 값을 순서대로 출력해도 인터럽트가 발생한다.
어떤 트리거 신호가 입력될 때 인터럽트를 발생시킬지는 외부 인터럽트 제어 레지스터 EICRA (INT3:0)와 EICRB (INT7:4)에서 설정한다.
로우 레벨 트리거 신호 때 외부 인터럽트가 발생하도록 설정했다면, 핀이 LOW상태를 유지하는 동안 인터럽트가 연속해서 계속 발생한다.
INT7:4 핀들에서 폴링 에지 또는 라이징 에지 트리거 신호를 검출하기 위해서는 입출력 클록이 있어야한다. 반면 INT3:0 핀들에선 로우 레벨 또는 폴링/라이징 에지 트리거 신호가 비동기적으로 검출된다.
External Interrupt Control Register A – EICRA
SREG 레지스터의 I플래그가 1로 세팅되어 있고, EIMSK 레지스터에서 해당하는 인터럽트 마스크가 1로 세팅되어 있다면, 외부 인터럽트 3-0은 외부 핀 INT3:0에서 입력되는 트리거 신호에 의해서 동작한다.
검출 가능한 트리거 신호를 설정하는 방법은 표48에 나와있다.
INT3..INT0 핀 상에 폴링 에지와 라이징 에지 트리거는 비동기적으로 인식되며 INT3:0 핀에 입력되는 펄스는 최소 너비(50ns)보다 넓어야 인터럽트가 발생한다. 최소 너비보다 짧은 펄스들은 인터럽트가 발생한다고 보장하지 못한다.
Low level 트리거가 선택되었을 땐, 인터럽트가 발생하기 위해 현재 실행중인 명령어가 완료될 때까지 Low lovel을 유지하고 있어야한다.
Low level 인터럽트가 발생하도록 설정해놓았다면 핀이 로우 레벨을 계속 유지하는 동안 연속적으로 인터럽트가 발생한다
ISCn 비트를 변경하는 중에 인터럽트가 발생할 수 있다. 그러므로, 변경하기 전에 EIMSK 레지스터에서 해당 인터럽트 인에이블 비트를 클리어해서 INTn을 먼저 비활성화하는 것을 권장한다. 그리고 나서 ISCn 비트를 변경하고 인터럽트를 다시 활성화하기 전에 EIFR 레지스터의 Interrupt Flag bit (INTFn)에 1을 기록함으로써 INTn 인터럽트 플래그를 클리어해야 한다.
External Interrupt Control Register B – EICRB
SREG레지스터의 I플래그가 1로 세팅되고 EIMSK 레지스터의 해당되는 인터럽트 마스크가 1로 세팅되면 외부 인터럽트 7-4는 외부 핀 INT7:4에 의해 동작하다.
검출 가능한 트리거 신호를 설정하는 방법은 표50에 나와 있다.
에지 또는 토글 트리거가 선택되었다면, 펄스는 1 클록보다 넓어야 한다. 짧으면 인터럽트가 발생한다는 보장을 하지 못한다.
Low 레벨 트리거가 선택되었다면, low 레벨은 반드시 현재 실행중인 명령어가 완료될 때까지 유지되어야한다.
Low level 인터럽트가 발생하도록 설정해놓았다면 핀이 로우 레벨을 계속 유지하는 동안 연속적으로 인터럽트가 발생한다
External Interrupt Mask Register – EIMSK
EIMSK레지스터의 INT7-INT0 비트가 1로 세팅되고 Status Register의 I비트가 1로 세팅되면, 해당되는 외부 인터럽트 핀에서의 트리거 신호 입력으로 인터럽트가 발생할 수 있다.
External Interrupt Control Registers( EICRA, EICRB)에서 인터럽트가 발생하는 트리거 신호를 정의한다. 상승 에지, 하강 에지, 로우레벨을 선택할 수 있다.
핀을 출력으로 해놓고 소프트웨어적으로 조작해도 해당 핀에서 인터럽트가 발생한다.
External Interrupt Flag Register – EIFR
INT7:0 핀에 트리거 신호가 입력되어 인터럽트가 발생하면 EIFR레지스터의 해당되는 비트가 1로 세팅된다.
SREG 레지스터의 I비트가 1로 세팅되어 있고 EIMSK 레지스터에서 해당되는 비트가 1로 세팅되어 있다면, MCU는 현재 실행중인 프로그램 흐름을 중단하고 인터럽트 벡터로 점프한다. 이 흐름은 인터럽트 루틴이 실행되면 EIFR레지스터의 해당되는 비트가 0으로 클리어 된다. 해당 비트에 1을 기록하여 강제로 클리어 시키는 방법도 있다.
Low 레벨 트리거때 인터럽트가 발생하도록 설정되었다면 EIFR 레지스터의 해당 비트는 항상 0으로 클리어 된다. Low 레벨을 유지하는 동안 계속 인터럽트가 발생할 수 있는 것도 이 때문일 것이다.
아래처럼 회로를 구성하고 두가지 프로그램을 테스트 해본다. 5V에 풀업저항을 달아서 평소에 PD0핀이 5V를 유지하도록 했다. 버튼을 누르게 되면 그라운드와 연결이 되어 PD0핀의 전압은 0V로 떨어지게 된다.
1. Low 레벨 인터럽트 태스트.. 버튼을 누르고 있는 동안 계속 인터럽트가 발생하는 것을 볼 수 있다.
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 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | /* * interrupt_example1.c * Low Level을 유지하는 동안 인터럽트가 계속 발생한다. * * Created: 2016-06-16 * Author : webnautes */ #define F_CPU 16000000UL #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> //1. baud rate를 선택 #define USART_BAUDRATE 9600 //2.시스템 클록과 원하는 baud rate를 이용하여 UBRR 값을 계산한다. #define UBRR_VALUE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1) void usartInit() { //3. UBRR0은 16비트 레지스터이기 때문에 8비트씩 나누어서 넣어야 한다. UBRR0H = (uint8_t)(UBRR_VALUE>>8); UBRR0L = (uint8_t) UBRR_VALUE; //4. USART 설정 UCSR0C |= (1<<UCSZ00)|(1<<UCSZ01); //Charecter size : 8비트 UCSR0C &= ~(1<<USBS0); //stop bit : 1비트 UCSR0C &= ~((1<<UPM01)|(1<<UPM00)); // no parity mode //5. 송수신을 가능하게 한다. UCSR0B=(1<<RXEN0)|(1<<TXEN0); } void transmitByte(uint8_t data) { //이전 전송이 끝나기를 기다림 while(!(UCSR0A&(1<<UDRE0))){}; UDR0 = data; /* send data */ } void printString(const char str[]) { uint8_t i = 0; while (str[i]) { transmitByte(str[i]); i++; } } //Interrupt Service Routine for INT0 ISR(INT0_vect) { printString("인터럽트발생\n\r"); PORTB |= 1<<PB3; _delay_ms(500); } int main(void) { usartInit(); DDRB |= 1<<PB3; //PORTB3을 출력으로 설정, LED용 //Low level에서 인터러브 발생 EICRA &= ~(1<<ISC00); EICRA &= ~(1<<ISC01); EIMSK |= 1<<INT0; //External Interrupt Request 0 Enable //PD0에 스위치 연결, 풀업 저항을 추가한 회로여야 한다. sei(); //Grobal Interrupt Enable while(1) { PORTB &= ~(1<<PB3); _delay_ms(500); } } | cs |
2. falling edge 인터럽트 태스트 - 버튼을 누르는 순간 인터럽트가 발생한다.
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 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | /* * interrupt_example2.c * * Created: 2016-06-16 * Author : webnautes */ #define F_CPU 16000000UL #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> //1. baud rate를 선택 #define USART_BAUDRATE 9600 //2.시스템 클록과 원하는 baud rate를 이용하여 UBRR 값을 계산한다. #define UBRR_VALUE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1) void usartInit() { //3. UBRR0은 16비트 레지스터이기 때문에 8비트씩 나누어서 넣어야 한다. UBRR0H = (uint8_t)(UBRR_VALUE>>8); UBRR0L = (uint8_t) UBRR_VALUE; //4. USART 설정 UCSR0C |= (1<<UCSZ00)|(1<<UCSZ01); //Charecter size : 8비트 UCSR0C &= ~(1<<USBS0); //stop bit : 1비트 UCSR0C &= ~((1<<UPM01)|(1<<UPM00)); // no parity mode //5. 송수신을 가능하게 한다. UCSR0B=(1<<RXEN0)|(1<<TXEN0); } void transmitByte(uint8_t data) { //이전 전송이 끝나기를 기다림 while(!(UCSR0A&(1<<UDRE0))){}; UDR0 = data; /* send data */ } void printString(const char str[]) { uint8_t i = 0; while (str[i]) { transmitByte(str[i]); i++; } } //Interrupt Service Routine for INT0 ISR(INT0_vect) { printString("인터럽트발생\n\r"); PORTB |= 1<<PB3; _delay_ms(500); } int main(void) { usartInit(); DDRB |= 1<<PB3; //PORTB3을 출력으로 설정, LED용 //falling edge에서 인터러브 발생 EICRA &= ~(1<<ISC00); EICRA |= 1<<ISC01; EIMSK |= 1<<INT0; //External Interrupt Request 0 Enable //PD0에 스위치 연결, 풀업 저항을 추가한 회로여야 한다. sei(); //Grobal Interrupt Enable while(1) { PORTB &= ~(1<<PB3); _delay_ms(500); } } | cs |
'AVR > Atmega128 강좌' 카테고리의 다른 글
Atmega128 기초 - 8비트 타이머/카운터 CTC 모드 (0) | 2016.06.18 |
---|---|
Atmega128 기초 - 8비트 타이머/카운터 일반모드 (2) | 2016.06.17 |
ATmega128 기초 - 입출력 포트 (2) | 2016.06.15 |
USB To TTL 컨버터 모듈 사용기 ( Atmega328p 자작 보드에 연결 ) (2) | 2015.12.07 |
AVR로 DC모터 제어 (0) | 2015.11.03 |
시간날때마다 틈틈이 이것저것 해보며 블로그에 글을 남깁니다.
블로그의 문서는 종종 최신 버전으로 업데이트됩니다.
여유 시간이 날때 진행하는 거라 언제 진행될지는 알 수 없습니다.
영화,책, 생각등을 올리는 블로그도 운영하고 있습니다.
https://freewriting2024.tistory.com
제가 쓴 책도 한번 검토해보세요 ^^
그렇게 천천히 걸으면서도 그렇게 빨리 앞으로 나갈 수 있다는 건.
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!