이 블로그는 임베디드 컴퓨터를 이용한 장치(시스템) 개발과 원격제어에 필요한 지식을 공유 하기 위한 블로그 입니다.
실제 개발과 프로그램 예를 위하여 Microchip 사의 ATmega128를 사용한 보드와 Arduino Mega 보드(ATmega2560), Raspberry Pi, Raspberry Pi Pico, WiFi 모듈을 사용 합니다.

avr_interrupt

ATmega128 interrupt
  ATMega128 External Interrupt


  • 인터럽트의 개요
    • Interrupt : 외부 장치의 요구에 의해서 현재 실행 중인 프로그램을 잠시 멈추고, Interrupt에 의하여 요구된 작업을 먼저 수행한 후에 다시 원래의 프로그램으로 복귀하여 실행 한다.
    • 주변장치의 서비스 요청에 맞추어(동기 하여) 서비스를 실행 한다.
    • Embedded System의 Program은 대부분 Interrupt Drive 방식으로 작성 한다.
    • Interrupt Processing 예
    • Main Routine 실행 중 Interrupt 요구가 발생 하면 현재 실행 중인 Routine을 잠시 멈추고 Interrupt Service Routine으로 Jump 하여 Interrupt Service을 실행 하고, Interrupt Service 종료 후 다시 Main Routine 실행 한다.


  • 인터럽트 처리 과정
    • Program 실행 중에 Interrupt가 발생(서로 다른 Interrupt는 Interrupt 번호로 구분) 하면(Interrupt 실행이 허용 된 경우(Interrupt Enable 상태인 경우)),
    • 현재 실행 중인 Program을 잠시 중단 하고(Interrupt Service Routine이 종료 된 다음 현재 실행이 종료된 다음 명령어 부터 실행 할 수 있도록 하기 위하여 다음에 실행 할 명령의 위치를 Stack에 저장 하고),
    • Interrupt Vector Table에서 Interrupt Service Routine의 시작 번지(Interrupt 번호를 이용 하여 Interrupt Vector Table에서 Service Routine의 시작 번지 알 수 있다.)를 획득 하여
    • Interrupt Service Routine으로 Jump 한다.
    • Interrupt Service Routine의 실행이 종료 되면 Stack에 저장된 다음에 실행 할 명령의 Address를 이용 하여 Interrupt 발생 이전에 실행 하던 Program을 계속 하여 실행 한다.

  • ATMega128 Interrupt Vectors
  • 아래 표는 ATMega128에서 사용 하는 Interrupt의 종류와 Interrupt 번호, 각 Interrupt(Interrupt 번호에 따른) Service Routine의 시작 번지를 저장 하는 Memory 번지, 그리고 각 Interrupt에 대한 요약된 설명 이다.

    ATMega128는 External Interrupt와 Timer/Counter, USART 등 다양한 Interrupt Source를 사용 하지만 이 페이지에서는 External Interrupt만 설명 하고, 기타 Interrupt는 각 장치를 설명 하는 부분에서 설명 한다.

    아래 표를 참고 하여 Interrupt Vector Table을 작성 할 수 있다.


  • External interrupt
    • External interrupt 0 - 3( Port D)
    • 아래 표는 External Interrupt 0번 - 3번이 사용 하는 Pin에 대한 설명이다.

      External Interrupt 0번 - 3번은 Port D의 PD0 - PD3번(이 Pin을 Input Port(Pin)으로 사용 하는 경우에만 External Interrupt 신호를 입력 받는 Pin으로 사용 할 수 있다.) Pin을 사용 한다. 이 Pin은 표와 같이 해당 Port가 Input Port로 사용 되지 않는 경우 다른 장치들이 사용 할 수 있다.


    • External interrupt 4 - 7( Port E)
    • 아래 표는 External Interrupt 4번 - 7번이 사용 하는 Pin에 대한 설명이다.

      External Interrupt 4번 - 7번은 Port E의 PE4 - PE7번(이 Pin을 Input Port(Pin)으로 사용 하는 경우에만 External Interrupt 신호를 입력 받는 Pin으로 사용 할 수 있다.) Pin을 사용 한다. 이 Pin은 표와 같이 해당 Port가 Input Port로 사용 되지 않는 경우 다른 장치들이 사용 할 수 있다.


  • External Interrupts를 사용 하기 위한 설정
    • INTn(n은 0 - 7)
      • Port D를 사용 하는 Interrupt: PD0(INT0), PD1(INT1), PD2(INT2), PD3(INT3)
      • Port E를 사용 하는 Interrupt: PE4(INT4), PE5(INT5), PE6(INT6), PE7(INT7)
    • External Interrupt을 사용하기 위한 설정
      • 사용하고자 하는 Port를 입력으로 설정. Push Button Switch 등을 사용하는 경우 Input Port PullUp을 Enable 한다.
      • External Interrupt의 mode 설정
      • External Interrupt를 Enable 한다.
        • External Interrupt Mask Register 에서 사용하고자 하는 INT를 Set(Enable) 한다.
      • Global Interrupt Enable
        • Status Register (SREG)의 I-bit(Global Interrupt Flag)를 Set(Enable) 함
    • Interrupt 0를 사용(Push Button Switch(PD0)의 입력) 하기 위한 초기화 설정 예
      • Interrupt 0(PD0)를 사용 하기 위한 초기화 함수

        void port_init(void)

        {

           // PD0(External Interrupt)와 GND 사이에 SW를 연결 한다.

           PORTD |= (1 << PD0);   // External SW PullUp

           DDRD &= ~(1 << PD0);   // External Interrupt Sensing Port(PD0)

           EICRA = 0x02;   // External Interrupt 0, Falling Edge Asynchronously Interrupt

           EIMSK |= 0x01;   // External Interrupt 0 enable

        }


  • Interrupt Control Register
    • EICRA - External Interrupt Control Register A
    • External Interrupt 0번 - 3번의 Interrupt Sensing Mode를 설정 한다.


    • EICRB - External Interrupt Control Register B
    • External Interrupt 4번 - 7번의 Interrupt Sensing Mode를 설정 한다.

      펄스 신호의 4가지 상태


    • EIMSK - External Interrupt Mask Register
      • INT7~0 Interrupt를 개별적으로 허용하는데 사용
        • 허용 : 1 , 금지 : 0

    • EIFR - External Interrupt Flag Register
      • INT7 ~ 0 Pin에 Interrupt 신호가 입력되면 해당 Flag가 Set되어 Interrupt가 Trigger 되었음 표시
      • 해당 Interrupt routine이 실행되면 0으로 Cleared 됨
      • 또는 해당 Flag에 1을 Write 하면 0으로 Cleared 됨

  • External Interrupt를 이용하는 Program 예:
    • Push Button Switch로 부터 입력되는 신호(SW를 누른 회수)를 LED Bar에 2진수로 출력 하는 실험 구성도

    • External Interrupt(PD0)과 Switch Bouncing 현상 Program(AvrStudio 4 개발 환경) 예: cho_sw_count_bouncing_interrupt.zip
    • Microchip Studio 개발 환경을 이용한 프로그램 예: ms7_sw_count_bouncing_interrupt.zip

      
      // S/W Environment : AVR Studio + WINAVR Compiler
      // Target : M128
      // Crystal: 16Mhz
      //
      // Author : chowk
      
      // 이 프로그램은 Switch bouncing 현상과 External interrupt을 이해 하기 위한 예 이다.
      // 실험 방법
      //   프로그램을 실행 시키고 PD0 Switch를 누르면 LED에 누른 회수가 2진수로 표시 된다.
      //   이 프로그램은 Switch의 bouncing 현상 때문에 Switch를 한번 누르면 경우에 따라 
      //   LED 값이 1 또는 2, 3 씩 증가 한다.
      
      #include <avr/io.h>
      #include <stdio.h>
      #include <avr/interrupt.h>
      
      // count: Switch를 누른 횟수를 저장 하기 위한 변수
      unsigned char count=0;
      
      void port_init(void)
      {
      	PORTD |= 0x01;   	// Switch PullUp 저항을 활성화
      	DDRD &= (~0x01);	// PORTD의 PD0를 Input Port로 설정
      
      	PORTF = 0x00;		// PORTF의 초기값 설정(PORTF의 LED가 꺼진 상태)
      	DDRF  = 0xff;		// PORTF를 Output Port로 설정
      	// External Interrupt 0 ,Falling edge between two samples of INTn
      	EICRA = 0x02;  
      	// External Interrupt 0 enable
      	EIMSK |= (1 << INT0);  
      }
      
      // 사용하는 장치를 초기화 한다.
      void init_devices(void)
      {
      	cli();         // disable all interrupts
      	port_init();
      	sei();         // re-enable interrupts
      }
      
      int main(void)
      {
      	init_devices();
      
      	while(1){
      		// Switch를 누르면 External Interrupt 0 service routine 이
      		// 실행 되고 이 Routine에서 Count와 LED 표시 동작이 실행 된다.
      	}
      }
      
      // External Interrupt이 발생 하였을 때 실행되는 함수
      SIGNAL (INT0_vect)
      { 
      	EIMSK &= ~(1 << INT0);  // External Interrupt 0 Disable
      
      	count++;        // count 값을 1 만큼 증가 시킨다.
      	PORTF = count;  // count 값을 LED에 표시
      
      	EIFR |= (1 << INTF0);			// Clear External Interrupt Flag
      	EIMSK |= (1 << INT0);			// External Interrupt 0 enable
      }
          

      • 실험을 위한 준비
      • 실험 방법
        • cho_sw_count_bouncing_interrupt.zip or ms7_sw_count_bouncing_interrupt.zip 파일을 Download하여 압축을 해제하고 Project를 Build 한다.
        • cho_sw_count_bouncing_interrupt.hex or ms7_sw_count_bouncing_interrupt.hex 파일을 개발 보드에 Upload 한다.
        • 실험: Push button switch(PD0)를 누르면 LED Array(8Bits)의 값(2진수)이 1씩 증가한다.
        • 주: Switch의 상태가 이상적이지 않기 때문에 Switch를 누르면 Switch bouncing 현상에 의하여 LED Array(8Bits)의 값이 1 또는 2, 3씩 불규직하게 증가한다.


    • External Interrupt(PD0와 PD1)를 이용하여 LED의 회전 방향을 제어 하는 Program 예: cho_led_basic_shift_interrupt.c
      • 실험을 위한 준비
        • PD0와 PD1에 Push button switch를 연결한다.
        • PORTF에 저항(330Ω)과 LED Array(8Bits)를 연결한다.
      • 실험 방법
        • cho_led_basic_shift_interrupt.c 파일을 Download하여 Microchip에서 제공하는 IDE를 사용하여 컴파일 한다.
        • cho_led_basic_shift_interrupt.hex를 개발 보드에 Upload 한다.
        • 실험: Push button switch(PD0)를 누르면 LED가 Left로 회전 하고,Push button switch(PD1)를 누르면 LED가 Right로 회전 한다.

    • External Interrupt(PD0)과 Switch debouncing Program 예: cho_sw_count_debouncing_interrupt.c
      • 실험을 위한 준비
        • PD0에 Push button switch를 연결한다.
        • PORTF에 저항(330Ω)과 LED Array(8Bits)를 연결한다.
      • 실험 방법
        • cho_sw_count_debouncing_interrupt.c 파일을 Download하여 Microchip에서 제공하는 IDE를 사용하여 컴파일 한다.
        • cho_sw_count_debouncing_interrupt.hex를 개발 보드에 Upload 한다.
        • 실험: Push button switch(PD0)를 누르면 LED Array(8Bits)의 값(2진수)이 1씩 증가한다.
        • 주: 이 프로그램에는 Debouncing 기능이 포함되어 있기 때문에 Switch bouncing 현상에 발생하지 않는다. 그러므로 LED Array(8Bits)의 값이 1씩 증가한다.