이번시간에는 아두이노의 고급 기능 중 인터럽트에 대해 알아보겠습니다~


아두이노를 이용하여 Working prototype이나 기타 기능이 있는 기기를 제작하실 때, 가장 많이 쓰는 부분이


1) Analog Input을 이용한 센서값 획득과


2) 버튼을 이용한 digital Input


3) Digital Output을 이용한 LED나 모터의 제어


요렇게 세가지가 아닐까 합니다.


가끔 아두이노를 이용해서 뭔가 만들다보면,

제어해야할 부품들은 많은데, 이 많은 것들을 어떻게 컨트롤 해야하나 막막할때가 있죠?


예를들어 LED가 3개라면, 가장 단순하게는 버튼 3개를 이용해서 각각을 켰다 껐다 하면 되겠지요ㅎㅎ


그럼 만약 제어할게 10개가 넘어가면.....????



결국엔 이런 형태의 참사가 일어나지 않을까요ㅋㅋㅋㅋㅋㅋㅋㅋ



요즘 수많은 디자인 트렌드를 보더라도 단순한 외형이지만, 다양한 기능이 가능한 형태의 제품을 선호하는 것 같아요~

가장 쉽게 예를 들 수 있는건 누가 뭐래도 아이폰!!



단지 버튼 하나만으로 지문인식, 홈 버튼(짧게 누르면), 앱 리스트(두번 누르면), 시리(꾹 누르면), 스크린샷, 등등...


어떻게 저렇게 많은 기능들이 버튼 하나로 가능할까요??? 신기하지요...

그럼 아두이노에서는 이런 기능을 못만드는 걸까요??


가능합니다!


이번시간에 볼 내용이 바로 버튼 하나로 여러개의 기능기 가능하도록 코딩을 해보는 것입니다.


먼저 몇가지 준비물이 필요한데요,


1) 아두이노


2) 택트 스위치


3) 저항


4) LED 3개



# 1



먼저 버튼을 이용해서 digital Input에 연결해봅시다.


흔히 스위치를 세팅하는 방법에는 크게 두가지가 있어요!


1) 풀업 스위치(Pull-Up) : 누르지 않았을때 1의 값이 입력되고 눌렀을 때 0이 되는 세팅





2) 풀다운 스위치(Pull-Down) : 누르지 않았을때 0의 값이 입력되고, 눌렀을 때 1이 되는 세팅





어떤 세팅을 쓸지는 본인이 원하는데로 하면 되겠지만,

특별한 이유가 없다면, 풀다운 스위치를 쓰시길 추천합니다 (항상 5V의 전압때문에 전류를 낭비할 이유가 없겠지요...?)


이게 풀업, 풀다운이 되는 이유는 전기의 단순한 특성때문이에요~

전류는 저항이 작은쪽으로 흐르려하기때문에 이걸 잘 고려하시면 회로를 이해할 수 있을겁니다.



# 2


이제 3개의 LED와 저항을 이용해서 Digital Output 부분의 회로를 구성해봅시다,






자 이제 LED 세팅도 끝났으니, 코딩을 해볼까요?



# 3


우선 코딩을 하기에 앞서서 한 가지 생각을 해봅시다.


과연 버튼 하나를 이용해서 어떻게 멀티펑션을 할 수 있을까요?


그 키는 바로! 버튼을 누르는 시간횟수에 따라 설정할 수 있답니다.


짧게 누름, 길게 누름, 여러번 누름에 따라 기능을 나누려면 어떻게 해야할까요..?


바로 인터럽트(Interrupt)를 이용하는 것입니다.


인터럽트란, 영어로 '방해하다', '중단하다' 의 의미를 가지는데 


실제로 메인 코딩 "void loop()" 이 돌아 가는동안 이 인터럽트에 digital input이 생기면


메인 코딩에서 벗어나 지정된 특수 함수를 먼저 실행하고 다시 메인 코딩으로 돌아가게 된답니다.


그럼 이 인터럽트가 왜 필요하죠?




인터럽트 없이 버튼의 누름 시간만 카운팅해서 쓴다면 사실 코딩이 복잡해질 뿐만 아니라, 제대로 동작하지 않는 경우가 발생합니다.


우리가 버튼을 누르면, 메인코딩에서 벗어나 버튼을 누른 순간의 시간(T1)을 기록하는 함수를 실행하고,

다시 버튼에서 손을 뗄 때 시간(T2)을 기록하는 함수를 다시 실행하게끔 만듭니다.


그럼 T2-T1 이 일정시간을 못넘기면 짧은 버튼,

T2-T1이 일정시간을 넘기면 긴 버튼이 되겠지요ㅎㅎ


그럼 버튼을 누른 횟수는 어떻게 확인할까요?


단순합니다! 

카운팅 변수를 하나 생성하고,

버튼을 눌렀을때 카운팅 값을 하나씩 올려주면 되겠지요?


때문에 여기서는 스위치의 아웃풋을 digital input과 interrupt핀 두개에 동시에 연결해줘야 합니다.





# 4


자 그럼 코딩을 한번 살펴봅시다.


  1. /* Multi-function button program example.
     * 
     * This code is able to extend single digital button action to multi functional action
     * According to press time, and press number.
     * 
     * This code works with pull down button setting.
     * If you want to use pull up setting, 
     * 
     * change digitalRead(button) == HIGH
     * to digitalRead(button) == LOW
     * 
     * Copyrights @ Gerinimo
     * http://geronimob.tistory.com
     */
    //declare led connected pins
    uint8_t LED[] = {5,6,9};
    uint8_t i_led = 1;

    //mapping values of brightness
    uint8_t brightness[] = {B00000000,B00100000,B01000000,B01100000,
                            B10000000,B10100000,B11000000,B11111111};
    uint8_t i_brt = 0;

    //declare button( digital 16 = 
    const int button = 16;

    //stores if the switch was high before at all
    volatile int state = LOW;

    //storing the button state for short press mode
    volatile int state_short = LOW;

    //storing the button state for long press mode
    volatile int state_long = LOW;

    //stores the time each button went high or low
    volatile unsigned long current_high;
    volatile unsigned long current_low;


    void setup()
    {
      pinMode(LED[0], OUTPUT);
      pinMode(LED[1], OUTPUT);
      pinMode(LED[2], OUTPUT);
      pinMode(13, OUTPUT);

      pinMode(button, INPUT);
      attachInterrupt(0, read_button, CHANGE);
      Serial.begin(9600);

      digitalWrite(13,HIGH);
    }

    int i = 0;

    void loop()
    {
      if(state_short == HIGH)
      {
        //do something when button 0 was pressed short ...

        i_brt = (i_brt+1) %  8;
        state_short = LOW;
        
        //end
      }    
      if(state_long == HIGH)
      {
        //do something when button 3 was pressed long ...
        digitalWrite(LED[i_led],LOW);
        i_led = (i_led+1) % 3;    
        i_brt = 0;
        state_long = LOW;
        
        //end
      } 

      analogWrite(LED[i_led],brightness[i_brt]);
    }


    //is called when the Interrupt Pin is pressed or released (CHANGE Mode)
    void read_button()
    {
      //cycles through the buttons to find out which one was pressed or released

      //if this is true the button was just pressed down
      if(digitalRead(button) == HIGH)
      {
        //note the time the button was pressed
        current_high = millis();
        state = HIGH;
        return 0;
      }
      //if no button is high one had to be released. The millis function will increase while a button is hold down the loop function will be cycled (no change, so no interrupt is active) 
       if(digitalRead(button) == HIGH && state == HIGH)
      {
        current_low = millis();
        if((current_low - current_high) > 1 && (current_low - current_high) < 300)
        {
          state_short = HIGH;
          state = LOW;
        }
        else if((current_low - current_high) >= 300 && (current_low - current_high) < 4000)
        {
          state_long = HIGH;
          state = LOW;
        }
      }
    }



먼저 LED는 PWM으로 제어하기 위해서 5,6,9번 핀에 연결했습니다.


동작하는 순서는 단순해요ㅎㅎ


버튼을 짧게 누르면 이미 맵핑해둔 값을 이용해 PWM으로 LED의 밝기를 변화시키구요,


버튼을 길게 누르면 컨트롤이 현재 LED가 아니라 그 옆에 있는 다른 LED로 변하게 됩니다.


즉 짧게 누르면 6번 핀의 LED 밝기가 변하고,


길게 한번 누른 뒤에 짧게 누르면 9번 핀의 LED 밝기가 변하게 된답니다^^



아니 이게 대체 무슨소리여....라고 생각이 드시면


다른것 보다도 각각의 불리언들의 값이 언제 변하는지를 잘 살펴보세요!


언제, 어떻게 변하는지, 그리고 변하면 어떻게 되는지에 초점을 맞춰 코드를 살펴보시면 이해될겁니다!


아래 사진은 이해를 돕기위한 버튼과 언터럽트와 불리언의 타이밍 그래프 입니다.




모르시겠으면... 다시 읽어보시고,


그래도 모르시겠다면 댓글을 남겨주세용ㅎㅎ


- 끝 -

+ Recent posts