아두이노우노 R4

아두이노에서 인터럽트를 사용하는 방법

지구빵집 2023. 11. 24. 12:30
반응형

 

아두이노로 작업하다 보면 하드웨어 또는 타이머 인터럽트를 사용해야 할 필요성을 느끼게 될 것입니다. 인터럽트는 아두이노가 한 번에 두 가지 이상의 작업을 수행하도록 하고 싶을 때 유용합니다. 인터럽트를 사용하면 아두이노가 다른 작업을 수행하기 위해 수행 중인 작업을 중지할 수 있습니다. 작업이 완료되면 아두이노는 중단되기 전에 하던 작업을 다시 시작합니다. 

 

 

이 글에서는 하드웨어 인터럽트와 타이머 인터럽트라는 두 가지 유형의 인터럽트를 사용하는 방법에 대해 알아보세요. 하드웨어 인터럽트는 버튼 누르기나 센서의 신호와 같은 외부 이벤트에 의해 트리거됩니다. 타이머 인터럽트는 아두이노의 내부 타이머 중 하나에 의해 트리거됩니다.

 

하지만 시작하기 전에 먼저 인터럽트가 유용한 이유에 대한 예를 살펴보겠습니다.

 

SunFounder의 3-in-1 스마트 자동차 및 IOT 학습 키트에는 Arduino를 마스터하는 방법을 배우는 데 필요한 모든 것이 포함되어 있습니다. 여기에는 58개의 다양한 로봇 및 사물 인터넷 프로젝트를 위한 모든 부품, 배선 다이어그램, 코드, 단계별 지침이 포함되어 있어 매우 재미있게 만들 수 있습니다!

인터럽트 없이 깜박이는 LED

 

푸시 버튼으로 깜박이는 LED를 제어하는 예제 프로젝트를 만들어 봅시다. 아래 회로에서는 노란색 LED가 반복적으로 켜졌다 꺼집니다. 버튼을 누르면 녹색 LED가 켜집니다.

 

이것이 프로젝트를 빌드하는 데 필요한 부품입니다:

 

아두이노 우노 점퍼

와이어 브레드보드

촉각 푸시 버튼 1K

옴 저항기 2개 LED 2개

 

이 배선도에 따라 회로를 연결합니다:

 

 

다음은 회로의 코드입니다:

 

int buttonPin = 7;
int buttonLED = 11;
int blinkLED = 12;

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(buttonLED, OUTPUT);
  pinMode(blinkLED, OUTPUT);
}

void loop() {
  int buttonState = digitalRead(buttonPin);

  if (buttonState == HIGH) {
    digitalWrite(buttonLED, LOW);
  }

  if (buttonState == LOW) {
    digitalWrite(buttonLED, HIGH);
  }

  digitalWrite(blinkLED, HIGH);
  delay(200);
  digitalWrite(blinkLED, LOW);
  delay(200);
}

 

 

이 프로젝트를 빌드하면 노란색 LED가 정상적으로 켜지고 꺼지는 것을 볼 수 있습니다. 하지만 버튼을 누르면 녹색 LED가 가끔 켜지긴 하지만 누르는 횟수를 많이 놓칩니다. 아두이노가 지연() 함수 중 하나에 도달하면 일시 정지하고 지연이 끝날 때까지 다른 작업을 수행할 수 없으므로 일부 버튼 누름을 놓칩니다. 하드웨어 인터럽트를 사용하여 이 문제를 해결해 보겠습니다.

 

하드웨어 인터럽트 만드는 방법

 

아래 스케치는 위의 깜박이는 LED 스케치에 하드웨어 인터럽트를 추가하여 모든 버튼 누름이 아두이노에서 감지되도록 합니다: 

 

int buttonPin = 2;
int buttonLED = 11;
int blinkLED = 12;
volatile int buttonState;

void buttonInterrupt() {
  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH) {
    digitalWrite(buttonLED, LOW);
  }
  if (buttonState == LOW) {
    digitalWrite(buttonLED, HIGH);
  }
}

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
  pinMode(buttonLED, OUTPUT);
  pinMode(blinkLED, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(buttonPin), buttonInterrupt, CHANGE);
}

void loop() {
  digitalWrite(blinkLED, HIGH);
  delay(200);
  digitalWrite(blinkLED, LOW);
  delay(200);
}

 

인터럽트를 만들려면 먼저 인터럽트 서비스 루틴(ISR)이라는 특수 함수를 작성해야 합니다. 인터럽트 서비스 루틴에는 인터럽트가 트리거될 때 실행하려는 모든 코드가 포함됩니다. 앞의 깜박이는 LED 예제에서는 노란색 LED가 켜지고 꺼지는 동안 버튼을 누르면 녹색 LED가 제어되기를 원했습니다. 따라서 논리적인 선택은 버튼을 누를 때 인터럽트가 트리거되도록 하는 것입니다.

 

위 스케치에는 버튼 누름에 대한 buttonInterrupt()라는 ISR이 있습니다. ISR 내부에는 버튼핀을 읽고 녹색 LED를 켜고 끄는 코드가 있습니다.

 

인터럽트 서비스 루틴

 

인터럽트 서비스 루틴에는 인터럽트가 트리거될 때 실행할 코드가 포함되어 있습니다. 코드는 가능한 한 짧고 빠르게 작성해야 합니다. 여러 인터럽트를 사용하는 경우 한 번에 하나의 인터럽트만 실행할 수 있다는 점에 유의하세요.

 

밀리(), 마이크로(), 지연() 함수는 모두 인터럽트 자체에 의존하므로 인터럽트 서비스 루틴 내부에서는 작동하지 않습니다. 그러나 ISR에 지연이 필요한 경우 delayMicroseconds() 함수를 사용하여 동일한 효과를 얻을 수 있습니다. 또한 데이터가 인터럽트와 함께 직렬 모니터로 전송되기 때문에 Serial.print()가 ISR 내부에서 항상 작동하는 것은 아닙니다. 인터럽트 서비스 루틴은 입력을 받거나 값을 반환할 수 없습니다.

 

버튼스테이트와 같이 ISR에 변수가 있는 경우, 변수 앞에 volatile 키워드를 붙여야 합니다. 변수를 휘발성으로 선언하면 컴파일러가 변수를 최적화할 수 없으며, 다른 변수처럼 스토리지 레지스터에 저장되는 것이 아니라 아두이노의 SRAM에 저장되도록 합니다. 그렇지 않으면 변수 값이 정확하지 않을 수 있습니다. 예를 들어, 프로그램이 현재 ISR 내부에서 실행 중이고 루프() 섹션에서 변수가 변경되는 경우 ISR 내부의 변수가 새 값으로 업데이트되지 않을 수 있습니다. volatile 키워드를 사용하면 스케치의 다른 부분에서 변수가 변경될 경우 변수가 업데이트되도록 할 수 있습니다.

 

인터럽트 서비스 루틴을 트리거하는 방법

 

인터럽트 서비스 루틴을 트리거하려면 setup() 섹션의 attachInterrupt() 함수를 사용합니다. attachInterrupt() 함수에는 세 개의 매개변수가 필요합니다. 첫 번째 매개변수는 인터럽트 번호입니다. 아두이노 우노에는 인터럽트 0과 인터럽트 1의 두 가지 인터럽트가 있습니다. 인터럽트 0은 디지털 핀 2에 연결되고 인터럽트 1은 디지털 핀 3에 연결됩니다. 함수의 첫 번째 파라미터로 인터럽트 0의 경우 0을, 인터럽트 1의 경우 1을 입력하면 사용할 인터럽트를 지정할 수 있습니다.

 

어떤 인터럽트가 어떤 핀에 연결되어 있는지 쉽게 기억할 수 있도록 인터럽트 번호 대신 디지털 핀 투 인터럽트()라는 함수를 사용할 수 있습니다. 디지털핀투인터럽트() 함수는 인터럽트 번호 대신 디지털 핀 번호(핀 2 또는 핀 3의 경우 각각 2 또는 3)를 파라미터로 받습니다.

 

attachInterrupt() 함수에서 사용하는 두 번째 파라미터는 인터럽트 서비스 루틴의 이름입니다. 위 스케치에서 인터럽트 이름은 buttonInterrupt입니다.

 

attachInterrupt() 함수의 세 번째 매개변수는 인터럽트 모드입니다. 인터럽트 모드는 인터럽트를 트리거할 신호의 유형을 정의합니다. 인터럽트 모드는 네 가지가 있습니다:

 

  • LOW - 인터럽트 핀이 LOW일 때마다 인터럽트가 트리거됩니다.
  • RISING - 신호가 LOW에서 HIGH로 전환될 때 인터럽트가 트리거됩니다.
  • FALLING - 신호가 HIGH에서 LOW로 내려갈 때 인터럽트가 트리거됩니다.
  • CHANGE - 신호가 HIGH에서 LOW로 또는 LOW에서 HIGH로 전환될 때 인터럽트가 트리거됩니다.

 

타이머 인터럽트

 

하드웨어 인터럽트는 버튼 누름과 같은 외부 이벤트에 의해 트리거됩니다. 하지만 타이머 인터럽트는 아두이노의 내부 시계에 의해 트리거됩니다. 타이머 인터럽트의 작동 원리를 제대로 이해하려면 먼저 아두이노 타이머에 대한 배경 정보가 필요합니다.

 

타이머는 시간을 계산하는 마이크로 컨트롤러에 내장된 전자 회로입니다. 타이머 인터럽트는 일반적으로 일정한 간격으로 핀을 읽거나 쓰는 데 사용됩니다. 예를 들어 타이머 인터럽트를 사용하여 5초마다 습도 센서에서 판독값을 가져올 수 있습니다.  

 

아두이노에는 타이머0, 타이머1, 타이머2의 세 가지 타이머가 있습니다:

 

  • Timer0 - 지연(), 밀리() 및 마이크로() 함수에 사용되는 8비트 타이머입니다.
  • Timer1 - 16비트 타이머
  • Timer2 - 8비트 타이머

 

인터럽트에 Timer0을 사용하지 마십시오. 지연(), 밀리() 및 마이크로() 함수가 중단될 수 있습니다. 대신 Timer1 또는 Timer2를 사용하십시오.

 

세 타이머는 모두 Arduino의 클럭 주파수인 16Mhz를 기반으로 합니다. 각 클록 사이클은 타이머의 한 틱으로 계산됩니다. 타이머1은 16비트 타이머로, 최대 216회, 즉 65,535회까지 카운트할 수 있습니다. 65,535 카운트에 도달하면 타이머가 0으로 재설정되고 다시 카운트를 시작합니다. 

 

타이머0과 타이머2는 8비트 타이머이므로 최대 28회, 즉 256회까지 카운트가 채워질 때까지 유지할 수 있습니다. 프리스칼라 값을 사용하여 타이머의 속도를 늦출 수 있습니다. 프리스칼라 값을 변경하여 타이머의 길이를 조정할 수 있습니다.

 

타이머 인터럽트를 사용하여 두 개의 LED 깜박이기

 

타이머 인터럽트를 사용하는 방법을 보여드리기 위해 두 개의 LED가 깜박이는 프로젝트를 빌드해 보겠습니다. 노란색 LED는 500밀리초의 주기로 깜박이고 빨간색 LED는 5초의 주기로 깜박입니다.

LED를 깜빡이는 일반적인 방법은 지연() 함수를 사용하지만, 이 경우에는 작동하지 않으므로 타이머 인터럽트를 사용하여 LED 중 하나를 제어해야 합니다.

프로젝트를 빌드하는 데 필요한 부분은 다음과 같습니다:

 

아두이노 우노

점퍼 와이어

브레드보드

1K 옴 저항기 2개

LED 2개

 

아래 그림에 따라 회로를 연결합니다: 

 

 

 

프로그래밍을 더 쉽게 하기 위해 Timer1이라는 라이브러리를 사용하겠습니다. 이 링크로 이동하여 라이브러리의 ZIP 파일을 다운로드하고 컴퓨터에 설치합니다. Timer1 라이브러리가 설치되면 이 코드를 아두이노에 업로드합니다: 

 

#include <TimerOne.h>

void setup() {
  pinMode(10, OUTPUT);
  pinMode(5, OUTPUT);
  
  Timer1.initialize(5000000);    
  Timer1.attachInterrupt(longBlink);  
}

void longBlink() {
  digitalWrite(10, !digitalRead(10));
}

void loop() {
  digitalWrite(5, HIGH);
  delay(500);
  digitalWrite(5, LOW);
  delay(500);
}

 

 

코드 설명

 

스케치 맨 위에는 Timer1 라이브러리가 포함되어 있습니다. 노란색 LED는 500밀리초마다 한 번씩 깜박이고 꺼집니다. 빨간색 LED는 훨씬 더 긴 시간인 5초마다 켜지고 꺼집니다. 따라서 빨간색 LED를 제어하도록 타이머 인터럽트를 설정하겠습니다.

 

설정() 섹션에서 핀 10과 핀 5의 핀 모드를 출력으로 설정합니다. 타이머1 라이브러리는 타이머 인터럽트에 9번과 10번 핀만 사용할 수 있으므로 10번 핀을 사용하겠습니다. 핀 5는 loop() 섹션에서 500밀리초마다 노란색 LED를 깜박이는 데 사용됩니다.

 

setup() 섹션에서는 Timer1.initialize()를 사용하여 타이머를 초기화합니다. 초기화() 함수의 인수는 인터럽트가 트리거되기 전까지의 시간을 마이크로초 단위로 설정합니다. 위 스케치에서 초기화() 함수의 인수는 5000000마이크로초이므로 타이머 인터럽트는 5초에 한 번씩 트리거됩니다. Timer1 라이브러리를 사용하면 최소 인터럽트 주기는 1마이크로초이고 최대 인터럽트 주기는 8,388,480마이크로초입니다.

 

다음으로 Timer1.attachInterrupt()를 사용하여 인터럽트 서비스 루틴을 첨부합니다. attachInterrupt() 함수는 인터럽트 서비스 루틴의 이름이라는 하나의 인수만 받습니다. 위의 스케치에서 ISR은 longBlink()라고 불립니다. 따라서 타이머가 5초에 도달할 때마다 longBlink() ISR이 실행됩니다.

 

longBlink() ISR의 코드에는 빨간색 LED를 켜고 끄는 디지털 쓰기() 함수가 있습니다. 일반적으로는 지연() 함수를 사용하여 LED를 켜고 끕니다. 하지만 인터럽트 서비스 루틴은 한 번에 하나만 실행할 수 있고, delay() 함수 자체가 ISR을 사용하기 때문에 다른 ISR 내부에서 사용할 수 없습니다.

 

따라서 핀 10을 켜고 끄는 다른 방법이 필요합니다. delay() 함수를 사용하는 대신 핀 10의 디지털 읽기를 가져와서 쓰기 값으로 사용할 수 있습니다. 따라서 !.digitalRead(10)을 디지털 쓰기() 함수의 두 번째 파라미터로 사용합니다. 느낌표는 NOT의 부울 연산자입니다. 이렇게 하면 핀 10의 현재 상태를 디지털로 읽은 다음 반대 값으로 핀 10을 디지털로 씁니다. 핀 10이 높으면 낮게 기록되고, 핀 10이 낮으면 높게 기록됩니다. 이것은 LED를 토글하는 매우 유용한 방법이며 한 줄의 코드만 사용합니다.

 

loop() 섹션에는 노란색 LED를 깜빡이는 코드가 있습니다. 일반적으로 디지털 쓰기 사이에 일시 정지하기 위해 지연() 함수를 사용하여 LED를 깜박이는 방식입니다.

 

모든 것이 올바르게 작동한다면 노란색 LED는 500밀리초마다 한 번씩 깜박이고 빨간색 LED는 5초 동안 켜졌다가 5초 동안 꺼져야 합니다. 이것은 매우 간단한 예시이지만 타이머 인터럽트는 다른 많은 방법으로도 유용합니다. ISR을 사용하여 LED를 켜는 대신 시간 간격을 두고 센서를 읽는 데 사용할 수 있습니다. 또는 센서를 계속 읽는 동안 5V 릴레이를 트리거하는 데 사용할 수도 있습니다.

 

아두이노에서 하드웨어 인터럽트 및 타이머 인터럽트를 사용하는 데 도움이 되었기를 바랍니다. 궁금한 점이 있으면 아래에 댓글을 남겨 주세요!  

 

 

삶을 제대로 살기 위한 기술 “위대한 마인드“ 다운로드

https://kimbongzo.gumroad.com/l/greatmindset 

 

위대한 마인드

"일찍 알았더라면 삶이 훨씬 더 나았을 텐데.... 절대 이런 말을 하지 마세요.지금 당장 "위대한 마인드"를 읽지 않으면 당신은 후회합니다."안녕하세요. 위대한 마인드 저자 김봉조입니다.가끔

kimbongzo.gumroad.com

 

아두이노 우노 R4 Minima 빠르게 시작하기

https://kimbongzo.gumroad.com/l/Arduino-R4-Minima 

 

아두이노 우노 R4 Minima 빠르게 시작하기

진정한 메이커로 성장하는 여러분이 되세요.메이커 활동과 코딩 교육하면 빠질 수 없는 아두이노 우노(Arduino Uno)의 신규 버전이 2023년 6월 26일 출시되었습니다. 정식 명칭은 아두이노 우노 R4 미

kimbongzo.gumroad.com

 

아두이노 우노 R4 WiFi 빠르게 시작하기

https://kimbongzo.gumroad.com/l/arduinor4wifi 

 

아두이노 우노 R4 WiFi 빠르게 시작하기

진정한 메이커로 성장하는 여러분이 되세요.메이커 활동과 코딩 교육하면 빠질 수 없는 아두이노 우노(Arduino Uno)의 신규 버전이 2023년 6월 26일 출시되었습니다. 정식 명칭은 아두이노 우노 R4 미

kimbongzo.gumroad.com

 

 

 

참고 문서: 아두이노 인터럽트 사용

 

 

 

반응형