본문 바로가기

AVR/AVR 연습, Tutorial

AVR 외부 인터럽트를 이용한 LED 제어 - AVR 연습하기



안녕하세요. 2일 정도 뜸하다 돌아왔네요.^

인터럽트관련 정리글을 올려놓고 실제 실험해본 것을 안올렸는데.. 뒤늦게 올립니다.^

이제 점차 AVR을 다루는 난이도가 올라가는데요. 

AVR은 인터럽트시에는 사용하는 핀이 정해져 있는데 아래 핀아웃을 볼까요.!


AVR 외부인터럽트 핀아웃


ATTINY2313의 핀아웃을 보면 PD1~7 포트가 있고 그 옆에 괄호가 있는데 괄호가 해당핀에서 사용 할 수있는 기능이라고 보면됩니다.

외부인터럽트의 경우에는 앞에 INT가 붙고 뒤에 비트값이 차례대로 붙는데 Tiny2313의 경우에는 외부인터럽트신호를 2선밖에 지원하지않기 때문에 INT0, INT1이 있고, 인터럽트 설정시에도 INT0, INT1 두 인터럽트설정만 하기에 레지스터수가 적습니다.



연습 하드웨어 회로는?




일단 그냥 보기에는 회로는 그냥 스위치입력 연습할때와 다를게 없죠..

하지만 다른점이 3가지 정도있습니다. 먼저 스위치 입력단에 저항이 생겼죠.!

저항이 제 설계에는 GND에 연결되어있는데 이 연결은 조건이 붙습니다.

제가 만약 AVR 외부인터럽트 설정시에 상승에지에 동작한다고 설정을 한다면 위회로로 설계하고

스위치를 누르면 인터럽트가 걸립니다.

하지만 하강에지에서 동작한다고 설정하면 저항과 스위치의 연결을 완전히 바꿔야 합니다.

저항은 GND가 아닌 VCC에 연결되어야하고, 스위치의 1번핀은 GND에 연결되어야 하강에지설정시에 인터럽트가 걸립니다.

그리고 위 핀아웃에서 말한것처럼 INT0, INT1 에만 스위치를 연결했습니다.

갈수록 설명도 어려워지네요.. ㅎ

항상하던 순서로 다음은 소스코드인가요.!!

역시 소스코드는 AVR Studio와 CodeVisionAVR로 나눠서 올립니다.


CodeVisionAVR 용 소스코드


#include <tiny2313.h>    // tiny2313의 입출력 관련 헤더파일을 포함합니다.

#include <delay.h>    // 지연함수관련 헤더파일을 포함합니다.


interrupt [EXT_INT0] void ext_int0_isr(void)    // 핵심 인터럽트가 걸리면 여기로 점프합니다.

{

    PORTB=0b11110000;    // 포트B의 상위 4비트에 1 (5V) 출력합니다.

    delay_ms(500);    // 위 상태를 0.5초 유지합니다.


    EIFR=0x40;    // 인터럽트발생 신호를 초기화해 다시 인터럽트를 받을 수 있는상태로 만듭니다.

}


void main(void)    // main()함수를 호출합니다.

{        

PORTB=0x00;    // 포트B의 초기상태는 모든포트 0 (0V)로 설정합니다.

DDRB=0xFF;    // 포트B의 모든포트를 출력으로 설정합니다.


GIMSK=0x40;    // INT0의 인터럽트를 허용합니다.

MCUCR=0x03;    // MCUCR의 0번,1번 비트를 1로 상승에지에 인터럽트동작으로 설정합니다.


#asm("sei")    // 모든 인터럽트를 허용합니다.


while (1)    // 아래구문을 무한 반복합니다.

      {

      PORTB=0xFF;    // 포트B의 모든포트에 1 (5V)를 출력합니다.

      delay_ms(500);    // 위 상태를 0.5초 유지합니다.

      PORTB=0x00;    // 포트B의 모든포트에 0 (0V)를 출력합니다.

      delay_ms(500);    // 위 상태를 0.5초 유지합니다.

      }

}


이 코드에서 눈여겨 보아야 할것은 interrupt [EXT_INT0] void ext_int0_isr(void) 이 부분과 EIFR 입니다.

interrupt [EXT_INT0] void ext_int0_isr(void) 이 부분은 인터럽트가 걸리면 점프해서 무슨처리를 한뒤에 다시 main()으로 돌아갈지 프로그램 하는곳인데 저 같은 경우에는 인터럽트 처리 구문에 PORTB=0b11110000 로 입력했습니다. 그러면 main()에서 while(1)에서 LED를 무한으로 깜박깜박 반복하다가 제가 스위치입력으로  인터럽트신호를 주게 되면 LED중 앞에 4개만 불이들어온상태로 0.5초 있다가 다시 Main()의 While(1)무한 반복으로 돌아와 깜박깜박 반복하는 것이지요.! 그리고 인터럽트가 걸리면 EIFR레지스터에 인터럽트가 걸렸다고 1이 입력되 다시 인터럽트를 받을수 없는 상태가 됩니다. 따라서  EIFR 해당비트에 다시 1을 써주어 0으로 초기화시켜 다시 인터럽트를 받을 수있는 상태로 만듭니다.



AVR Studio 용 소스코드


#include <avr/io.h>    // AVR 기본 입출력 관련 헤더파일을 포함합니다.

#define F_CPU 8000000UL    // 사용하는 크리스탈속도 8Mhz를 상수로 설정합니다.

#include <util/delay.h>    // 지연함수 관련 헤더파일을 포함합니다.

#include <avr/interrupt.h>    // 인터럽트 관련 헤더파일을 포함합니다.


ISR(INT0_vect)    // 핵심 인터럽트가 걸리면 여기로 점프합니다.

{

    PORTB=0xF0;    // 포트B의 상위 4비트에 1 (5V)를 출력합니다.

    _delay_ms(500);    // 위 상태를 0.5초 유지합니다.


    EIFR=0x40;    // 인터럽트발생 신호를 초기화해 다시 인터럽트를 받을 수 있는상태로 만듭니다.

}


int main(void)    // main() 함수를 호출합니다.

{        

PORTB=0x00;    // 포트B의 모든포트 초기상태를 0 (0V)로 설정합니다.

DDRB=0xFF;    // 포트B의 모든포트를 출력으로 설정합니다.


GIMSK=0x40;    // INT0의 인터럽트를 허용합니다.

MCUCR=0x03;    // MCUCR의 0번,1번 비트를 1로 상승에지에 인터럽트동작으로 설정합니다.


sei();    // 모든 인터럽트를 허용합니다.


while (1)    // 아래구문을 무한 반복합니다.

      {

      PORTB=0xFF;    // 포트B의 모든포트에 1 (5V)를 출력합니다.

      _delay_ms(500);    // 위 상태를 0.5초 유지합니다.

      PORTB=0x00;    // 포트B의 모든포트에 0 (0V)를 출력합니다.

      _delay_ms(500);    // 위 상태를 0.5초 유지합니다.

      }


return 0;    // main함수에 0을 리턴합니다.

}


코드가 비슷하지요. 하지만 나중에 결정적으로 CodeVision과 AVR Studio가 호환이 안되는 부분은 ISR(INT0_vect) 인터럽트 처리부분입니다.

이 부분만 변경하고 Delay함수처리만 변경하면 다른 컴파일러에서도 사용할 수가 있습니다.


프로그래밍 후 동작은?




 버튼까지 누르려니까 손이떨려요.!!!


위 처럼 원래 PINx레지스터로 제어했을 때는 AVR이 다른 작업중일 때 스위치를 눌러도 반응하지 않았지만 인터럽트로 처리하면 중간에 다른작업이 가능해집니다.^