라즈베리파이, 아두이노

[간단한 아두이노 코딩] 4. 버튼 입력 제어하기 (인터럽트)

포도알77 2020. 11. 24. 10:06

버튼 입력 제어하기 (인터럽트)

 

1. Busy waiting vs Interrupt

 [간단한 아두이노 코딩] 3. 버튼 입력 제어하기에서 다뤘던 방식은 loop 함수를 이용하여 지속적으로 BUTTON이 연결된 GPIO를 확인하는 방식이었다.

void loop(){
	if(digitalRead(BUTTON)==HIGH)
		doSomething();
}

  

 이와 같이 원하는 결과가 들어올 때까지 확인하면서 대기하는 방식을 Busy waiting이라고 한다. 유사한 개념으로는 Polling이 있으나, 약간의 차이는 있다. (Busy waiting은 끊임 없이 확인하는 방식이고 Polling은 주기적으로 확인하는 방식이다.)

 

 Busy waiting의 문제는 확인하는 동작이 반복되는 동안 다른 작업을 수행할 수 없다는 것이다. 예를 들어 오락기의 버튼을 입력받는 동안 화면이 멈춰있다고 생각해보자. 이러한 문제를 해결하기 위해서 아래의 인터럽트를 이용해야 한다.

 

 인터럽트(interrupt)는 "가로채다"라는 뜻처럼, 프로그램의 동작을 멈추고 미리 정의한 동작을 우선적으로 실행하는 것을 뜻한다. 즉, loop 함수를 실행하다가 인터럽트가 발생하면, 지금 동작을 잠시 멈추고 인터럽트 루틴에 정의된 함수를 실행한 다음 다시 원래의 동작으로 돌아온다.

 

 

 인터럽트를 지원하는 핀은 아래와 같이 확인할 수 있다.


 2. 버튼 인터럽트 회로도

 인터럽트를 이용하기 위해서 버튼의 한쪽을 GND 그리고 한쪽을 GPIO 2번에 연결한다.

 

 


 

3. 소스코드

 인터럽트 루틴으로 등록한 함수에서는 delay나 millis와 같은 함수를 사용할 수 없다. 따라서 블링크를 수행하기 위해서는 microSeconds를 호출해야 한다. 이때 너무 큰 값을 주게되면 무시되어 버리므로, loop를 이용하여 작은 값으로 여러번 수행해야 한다.

 

 인터럽트의 경우 LOW, HIGH, FALLING, RISING 그리고 CHANGE 총 다섯 개로 동작 트리거를 설정할 수 있는데, 이는 전압 그래프에서 아래와 같이 정의된다.

 

 

위 코드는 FALLING EDGE(HIGH->LOW로 변화하는 시점)에서 발생한 인터럽트에 BlinkLED를 호출하는 동작을 수행한다. 이때 LED_BUILTIN는 깜박리는 동안 잠시 멈춘다.

 

#define BUTTON 2
#define LED_RED 7
// LED GPIO 7번, BUTTON 인터럽트 0번

// LED를 0.5초씩 2초간 Blink 하는 함수
void blinkLED(){
  // for 루프를 이용하여 2회 실행
  for(int i = 0; i < 2; i++){
    // LED 블링크 0.5초 켜고, 0.5초 끄고
    digitalWrite(LED_RED, HIGH);
    // 2ms씩 250회 == 500ms
    for(int j = 0; j < 250; j++) delayMicroseconds(2000);
    
    digitalWrite(LED_RED, LOW);
    // 2ms씩 250회 == 500ms
    for(int j = 0; j < 250; j++) delayMicroseconds(2000);
  }
  // 인터럽트 루틴에서는 위와 같이 delay를 주면 안됩니다.
  // 최대한 빠르게 처리되고 돌아갈 수 있도록 하여야 합니다.
}

void setup() {
  // LED 설정
  pinMode(LED_RED, OUTPUT);

  // 인터럽트 버튼 설정
  pinMode(BUTTON, INPUT_PULLUP);
  // 인터럽트 루틴 설정
  // FALLING으로 정의하여 인터럽트 핀의 전압이 GND로 떨어지는 시점에 트리거
  attachInterrupt(digitalPinToInterrupt(BUTTON), blinkLED, FALLING);

  // 내장 LED 설정
  pinMode(LED_BUILTIN, OUTPUT);
  
}

void loop() {
  // 인터럽트가 loop 실행 도중 처리되는 것을 확인하기 위하여 
  // LED_BUILTIN을 1초 마다 Blink
  digitalWrite(LED_BUILTIN, HIGH);
  delay(1000);
  digitalWrite(LED_BUILTIN, LOW);
  delay(1000);
}
페이스북으로 공유카카오톡으로 공유카카오스토리로 공유트위터로 공유URL 복사