[아두이노] [아두이노 강좌] 22. Interrupt(인터럽트) (2) - 스위치로 LED 켜고 끄기 예제

자, 지난 시간에 인터럽트란 무엇인가에 대해서 알아봤으니, 이번 시간에는 인터럽트는 어디에 사용되는가에 대해 알아보자.


강좌 제목에 나와있다시피 스위치로 LED를 켜고 끄는 예제를 만들어 볼 것이다스위치를 한번 누르면 LED가 켜지고한번 더 누르면LED가 꺼지는 동작을 만들어 보자.

 

우선 브레드 보드에 스위치와 LED를 아래 그럼과 같이 연결한다.


da949dfd061c41205ae94514762df5d8.png


스위치의 검정색 선과 LED의 검정색 선은 아두이노 보드의 GND로 연결하고스위치의 주황색 선은 2번에, LED의 노란색 선은 13번에 꽂는다스위치 핀이야 어디에 꽂아도 상관없지만 LED를 다른 핀에 꽂을 경우 반드시 LED 동작 전압을 확인해서 저항을 사용하도록 한다안 그러면 LED가 터져요!


그리고 다음 소스를 입력한다.

 


 interruptTest01.ino

  

 int ledPin = 13;

 int swPin = 2;

 boolean bLedOn = false;

 

 void setup() {

   pinMode(ledPin, OUTPUT);

   pinMode(swPin, INPUT_PULLUP);

 

   digitalWrite(ledPin, LOW);

 }

 

 void loop() {

   if(digitalRead(swPin) == LOW) {

     if(bLedOn == false) {

       digitalWrite(ledPin, HIGH);

       bLedOn = true;

     } else {

       digitalWrite(ledPin, LOW);

       bLedOn = false;

     }

   }

 }





간단하게 소스 설명.


 

LED를 켜고 끄기 위한 출력 핀과 스위치 상태를 읽기 위한 입력 핀을 선언한 후 모드를 초기화 한다이 때스위치는 따로 풀업 저항을 사용하지 않았으므로 내부 풀업을 사용하도록 INPUT_PULLUP 모드로 설정한다는 것에 유의그리고 LED 핀의 초기 값을 LOW로 줘서 LED가 꺼진 상태로 동작을 시작하도록 한다.

 

“bLedOn” 변수는 LED의 현재 상태를 저장하기 위한 변수이며, bLedOn 값에 따라 LED를 켤 것인가끌 것인가를 결정한다.

 

그리고 loop() 함수에서 스위치 핀의 상태를 읽어서 스위치가 눌린 경우즉 swPin의 입력 값이 LOW인 경우에 bLedOn 값에 따라 LED를 켜거나 끈다. bLedOn false이면 LED를 켜고 bLedOn 값을 true로 변경아니라면 LED를 끄고 bLedOn 값을 false로 변경.

 

어렵지 않아요.




그럼 업로드 하기 전에 손 한번 들어볼까요~? 위 소스가 제대로 동작할 것이라고 생각하는 사람 손??

 


moon_and_james-39 

 

 


눈치 빠른 사람은 손 들어보라는 질문 자체에서 이미 동작이 안될 것이라는 것을 예상했을 것이고이미 왜 안 되는지 이유를 알고 있는 사람도 있을 것이여허허.

 

동작 안 된다.

 

스위치를 누르면 LED가 약간 어둡게 켜지거나 빠르게 깜빡이다가 스위치를 떼면 완전히 켜지거나 완전히 꺼진다왜요왜 때문이죠?


스위치가 눌려졌을 때의 입력 신호는 다음과 같다.

 

4724a2e37e705369232c640d8c25ab15.jpg


스위치가 눌리면 입력 값은 LOW로 떨어지고스위치에서 손을 뗄 때까지 LOW 값을 유지한다. loop()문에서 digitalRead() 함수가 반복되어 호출되므로 스위치가 눌려져 있는 동안은 LED가 계속해서 켜지고 꺼지는 동작을 반복하게 된다그리고 스위치에서 손을 떼면 마지막으로 변경된 LED의 상태가 지속되는 것이다.


이거 의외로 초보자들이 자주 하는 실수임. 

 

우리가 원하는 동작은 스위치가 눌렸을 때 한번만 LED의 상태가 바뀌는 건데그럼 어떻게 해야 하나요?

 



LED의 이전(previous) 상태를 알기 위해 변수를 하나 사용한 것처럼 스위치의 이전 상태를 알기 위한 변수를 하나 더 추가하면 된다다음 소스를 볼까?



 interruptTest02.ino


 ledPin = 13;

 int swPin = 2;

 boolean bLedOn = false;

 boolean bSwOn = false;

 

 void setup() {

   pinMode(ledPin, OUTPUT);

   pinMode(swPin, INPUT_PULLUP);

 

   digitalWrite(ledPin, LOW);

 }

 

 void loop() {

   if(digitalRead(swPin) == LOW) {

     if(bSwOn == false) {

       bSwOn = true;

       if(bLedOn == false) {

         digitalWrite(ledPin, HIGH);

         bLedOn = true;

       } else {

         digitalWrite(ledPin, LOW);

         bLedOn = false;

       }

     }

   } else {

     bSwOn = false;

   }

 }




빨간 색으로 굵게 표시된 부분이 추가된 부분이다.

 

“bSwOn”이라는 변수를 사용해서 스위치의 이전 상태를 확인하고 있다스위치가 눌렸을 경우(swPin LOW인 경우스위치의 이전 상태가 눌림 상태가 아닐 때(bSwOn 값이 false일 때) LED의 상태를 변경한다이 때 스위치의 상태를 눌림 상태(true)로 저장.

 

스위치의 상태가 눌림 상태로 바뀌었으므로 다시 loop() 함수가 돌아와 digitalRead(swPin) 함수로 읽어온 값이 여전히 LOW여도 LED의 상태를 변경하지 않는다스위치가 눌린 후 처음 조건문에 들어왔을 때에만 LED 상태를 변경하는 것그리고 swPin 상태가 HIGH가 됐을 때즉 스위치가 떨어졌을 때 다시 bSwOn 변수에 false 값을 저장해서 스위치가 눌림 상태가 아니라는 것을 기억한다.

 

이제 업로드 한 후 스위치를 눌러보자제대로 동작 해야 된대이hoppinmad_angry_line_characters-5

 

 

된다. brown_and_cony-76




오늘 실습 끝!

 

은 농담이고이거랑 인터럽트랑 무슨 상관??

 


스위치를 누를 때마다 LED를 켜고 끄는 간단한 동작을 만드는데소스가 좀 복잡해 보인다게다가 swPin 상태를 끊임없이계속쭈욱 확인해야 한다.

 



loop() 함수의 마지막 부분에 “delay(1000);”을 추가한 후 동작해보자


동작이 잘 안 된다반응이 느릴뿐더러 스위치를 짧게 누르면 아예 동작을 안 하기도 한다. 1초간 동작을 멈추는 동안 스위치의 상태를 읽어올 수 없어서 나타나는 현상이다. 만일 delay(1000)이 꼭 필요한 경우라면 어떻게 해야 하나?


 

이러한 상황을 위해 인터럽트가 있다. 똑같은 동작을 인터럽트를 사용한 소스로 바꿔보자. 아래 소스에서 swPin, 즉 스위치의 핀은 반드시 아두이노 보드의 2번 핀에 연결되어 있어야 한다.




 interruptTest03.ino

  

 int ledPin = 13;

 int swPin = 2;

 boolean bLedOn = false;

 

 void setup() {

   pinMode(ledPin, OUTPUT);

   pinMode(swPin, INPUT_PULLUP);

   attachInterrupt(0, swInterrupt, FALLING);

 

   digitalWrite(ledPin, LOW);

 }

 

 void loop() {

   delay(1000);

 }

 

 void swInterrupt() {

   if(bLedOn == false) {

     digitalWrite(ledPin, HIGH);

     bLedOn = true;

   } else {

     digitalWrite(ledPin, LOW);

     bLedOn = false;

   }

 } 




새로운 함수가 나왔어.

 

우선 동작부터 시켜볼까아까랑 똑같이 동작하는 걸 볼 수 있다. 어디에도 swPin의 상태를 확인하는 함수가 없는데도, 심지어 loop() 함수에 delay(1000) 구문이 있는데도 불구하고 버벅임이나 시간 지연 없이 자연스럽게 동작하는 것을 확인할 수 있을 것이다. 




attachInterrupt() 함수는 swPin의 상태를 확인해서 핀의 상태가 HIGH에서 LOW로 바뀔 때 swInterrupt() 함수를 자동 호출하도록 설정하는 함수이다. 


그래서 스위치가 눌려 swPin이 LOW로 변하면 loop() 문에 무슨 내용이 있든, 스위치가 눌린 후 계속 눌려져 있든, 금방 떨어지든 상관 없이, 딱 한 번만 swInterrupt() 함수가 호출되는 것이다. 




이제 인터럽트에 대해 조금은 이해가 되는가?




혹시 스위치를 눌렀을 때 swInterrupt() 함수가 여러 번 호출되는 듯한 느낌을 받는다면 아마 그건 채터링(Chattering)이라는 현상 때문일 것이다. 



attachInterrupt() 함수에 대한 자세한 내용과 채터링에 관련된 내용은 다음 강좌에서 살펴보도록 하겠다. 오늘은 여기까지. 안녕~!




뭔가 급하게 끝내는 기분..brown_and_cony-31

0
0
이 글을 페이스북으로 퍼가기 이 글을 트위터로 퍼가기 이 글을 카카오스토리로 퍼가기 이 글을 밴드로 퍼가기

임베디드 보드

번호 제목 글쓴이 날짜 조회수
118 아두이노 ESP32 Analog Inputs (ADC) +4 icon 양재동메이커 02-12 17,117
117 아두이노 TIP : Serial의 Port가 Open 시점 확인 icon 양재동메이커 01-21 13,813
116 아두이노 ESP32 Boot Mode icon 양재동메이커 12-28 13,749
115 아두이노 아두이노 에러 리스트(Arduino Error list) icon 양재동메이커 11-24 18,860
114 아두이노 ESP32 main.cpp +1 icon 양재동메이커 11-19 14,045
113 아두이노 ESP32 EEPROM 와 IR Remote icon 양재동메이커 08-06 13,911
112 아두이노 Learn ESP32 icon 양재동메이커 06-25 13,532
111 라즈베리 파이 라즈베리 파이 (Raspberry Pi) 기초 icon 양재동메이커 06-19 15,085
110 라즈베리 파이 (동영상 강의) 라즈베리 파이 강좌 Link icon 양재동메이커 06-17 14,073
109 STM32 / MBED [MED] Switch debouncing icon HellMaker 12-30 16,183
108 기타 [타이젠] 아두이노의 16x2 LCD Display라이브러리 LiquidCrystal_I2C의 타이젠 포팅 icon 양재동메이커 09-15 15,916
107 기타 [타이젠] GPIO의 디지탈 출력과 입력 인터럽트의 C++ Class 제작 icon 양재동메이커 09-12 15,199
106 마이크로비트 서보 모터 icon HellMaker 09-03 14,966
105 마이크로비트 아날로그 온도센서 (마이크로 비트 센서 활용) icon HellMaker 09-01 15,585
104 마이크로비트 터치센서 (마이크로 비트 센서 활용) icon HellMaker 09-01 14,576
103 마이크로비트 디지털 홀 센서 (마이크로 비트 센서 활용) icon HellMaker 08-29 13,794
102 마이크로비트 리니어 홀 센서 (마이크로 비트 센서 활용) icon HellMaker 08-29 13,191
101 마이크로비트 불꽃 감지 센서 (마이크로 비트 센서 활용) icon HellMaker 08-26 13,598
100 마이크로비트 로터리 엔코더 (마이크로 비트 센서 활용) icon HellMaker 08-25 13,775
99 마이크로비트 2컬러 LED(3mm) (센서 활용) icon HellMaker 08-22 13,721