[아두이노] 뽑기기계 횟수 락 원리

IOT/아두이노|2019. 7. 29. 09:00

[아두이노] 뽑기기계 횟수 락 원리



오늘은 횟수 락이 걸린 뽑기기계에 대한 아두이노시각으로 그 원리를 이해하는 시간을 가져보도록 하죠. 꼭 이렇게 뽑기 기계가 만들어진게 아니고 비슷한 느낌으로 아두이노에서 표현하여 살펴보도록 하죠.

1. 뽑기기계의 가상 설정



대충 위그림과 같은 뽑기 기계가 있다고 가정해 봅시다. 화살 막대기가 좌에서 우로 이동하면서 사각구멍 위치에 정확히 멈출 때 상품을 꺼낼 수 있게 됩니다. 이런류 게임을 해보신 분들은 뽑기기계가 락이 걸려서 일정 횟수 이상 돈을 넣고 도전을 해야 뽑을 수 있게 되어 있다는 것을 유튜버들의 뽑기영상을 보시면 간접 체험을 여러분들은 해보신 분들이 많을 꺼에요.

유튜버가 하는 말이 정확히 멈췄는데 약간 락이 풀릴 때까지 계속 멈춘 위치에서 좀더 이동해서 멈춘다고 이야기를 하는 소리를 많이 들었을 꺼에요. 계속 정확히 멈추는데 밀린다고 락이 걸려서 일정 횟수 이상 계속 해야지 뽑을 수 있다고 뽑기 락에 이야기를 많이 들었을 꺼에요.

여기서 횟수 락은 도대체 어떻게 하는 것일까 아두이노 시각으로 관찰하고 유사한 실험을 해볼까 합니다.

[특징]

  • 일정 횟수가 안되면 못 뽑는다.
  • 부정확한 위치에서는 그상태로 멈추지만 뽑는 위치에 멈추면 약간 밀리는 느낌으로 좀 더 이동한다.

이 특징을 가지고 이제 실험을 해 보겠습니다.

2. 횟수 락 회로도


  • 준비물 : Servo모터 1개, 스위치 버턴 2개, 아두이노 우노
  • 내용 : 스위치버턴은 인터럽트함수를 이용하기 위해 2,3번에 연결하고 Servo모터는 7번에 연결하시오.

실제 뽑기 기계에는 Stepper Motor로 움직이지만 가상시뮬레이터에서 실험을 간단히 하기 위해서 Servo모터로 대신 실험을 합니다.


횟수 락을 실험하기 때문에 스위치 버턴 2개로 Servo Motor를 제어하하면서 회전을 하는데 특정 각도에 범위에 대한 횟수 락 실험을 하게 됩니다. 그래서 복잡한 회로도 설계를 할 필요가 없고 이 회로도만으로 충분히 횟수 락 실험이 가능합니다.

3. 코딩


[설계]

  • 3번 스위치 버턴은 게임 시작
  • 2번 스위치 버턴은 멈춤(정지)
  • 2번 스위치 버턴을 눌러 멈춘 위치가 상품 범위에 들 때 횟수 카운트 하기
  • 횟수 카운트 할 때 상품 뽑기 횟수가 부족하면 멈춤 위치를 좀더 이동 시킴
  • 상품 뽑기 횟수에 도달하면 멈춤 위치가 상품을 뽑는 위치면 성공

스위치 버턴 동작
3번 스위치 버턴은 뽑기 시작버턴이고 2번 버턴은 뽑기 멈춤 버턴입니다. 인터럽트 함수를 이용하기 때문에 코딩은 다음과 같습니다.

const byte interruptPin1 = 3;
const byte interruptPin2 = 2;
boolean stateStart = false;
boolean stateStop = false;

void setup()
{
  pinMode(interruptPin1, INPUT_PULLUP);
  pinMode(interruptPin2, INPUT_PULLUP);  
  attachInterrupt(digitalPinToInterrupt(interruptPin1), exchange1, FALLING);  //인터럽트 발생 시 호출
  attachInterrupt(digitalPinToInterrupt(interruptPin2), exchange2, FALLING);  //인터럽트 발생 시 호출
}
void loop(){

  if(stateStart==true){
    뽑기시작;   
  }
 if(stateStop==true){ //뽑기정지
    뽑기정지;
 }
}
void exchange1() { //인터럽트스위치버턴  이벤트1
  stateStart=true;  
  stateStop=false;
}

void exchange2() { //인터럽트스위치버턴  이벤트2
  stateStart=false;
  stateStop=true; 
}

위 코딩을 보시면 stateStart, stateStop 변수의 상태 값으로 두가지 뽑기시작과 뽑기정지 버턴의 동작을 수행하게 됩니다.

뽑기시작 코딩은
Servo모터의 회전을 시작하도록 코딩이 이뤄집니다.

Servo servo;
const byte servoPin = 7; 

void setup(){
  servo.attach(servoPin);   
  servo.write(0);
  delay(1000);
}

위의 코딩은 Servo모터 초기상태입니다. 회전이 시작되기전 0도의 위치가 시작지점입니다.

0~180도로 왔다 갔다 회전을 하도록 뽑기시작 명령을 코딩하면 다음과 같습니다.

  if(stateStart==true){ //뽑기시작
    val+=stateNum;
    Serial.println(val);

    if(val==180)stateNum = -1;
    if(val==0)stateNum = 1;    
    
    servo.write(val);
    delay(50);
  }

val은 회전각입니다. stateNum은 180도가 되면 -1로 바뀌고 0도가 되면 1로 바뀌게 if문으로 제어해서 0~180도 회전이 1도씩 움직이게 됩니다. 이렇게 해서 뽑기가 시작되는 걸로 간주하시면 됩니다.

뽑기정지 코딩은
뽑기가 시작되면 이제 Servo모터를 정지시켜야 합니다. 뽑을 각도에 멈춰야 상품을 뽑을 수 있겠죠. 여기에 뽑기 횟수 락을 코딩을 하게 됩니다.

횟수 락은

    if(val>95 && val<105){ //뽑기 성공각도
      if(cnt<2){ //cnt 횟수 락
        cnt++;
        val=106;      
      }
      else cnt++;
    }
    else if(val>80 && val<120){ //상품 A의 횟수 증가 범위
      cnt++;
    } 
        servo.write(val);
    delay(100);

뽑기 성공하는 각도 범위는 95~105도 사이가 되면 뽑기가 성공됩니다. 하지만 횟수 락으로 cnt변수값이 3회이상이여야지만 뽑을 수 있게 락이 걸리게 됩니다. 즉, 아무리 95~105도 사이에 멈추더라도 cnt(횟수) 3회 미만이 되면 강제적으로 106도 각도로 움직이게 하여 약간 밀리는 느낌으로 뽑기 실패가 됩니다.

여기서 여러개의 상품이 있는데 A상품을 뽑는다고 가정한다면 A상품에 대한 뽑기 횟수가 증가해야 겠죠. B상품은 B상품에 대한 카운터를 해야 됩니다. 그렇기 때문에 A상품에 대한 횟수 락을 카운트 할 범위를 지정해 줘야 합니다. 위 코딩은 cnt는 A상품으로 여기면 됩니다.

만약, 여러개의 상품을 한다면 cntA, cntB, cntC 이런식으로 횟수 증가 범위를 개별적으로 증가시켜서 코딩하시면 됩니다.

아무튼 위 코딩으로 횟수락을 완성했네요. 3회 이상이 되지 않는 다면 아무리 완벽하게 성공 범위 지점에 정지시켜도 회적각이 밀리게 됩니다. 뽑기가 어떤 느낌인지 아시겠지요.

종합해보면,

#include <Servo.h>

Servo servo;
const byte servoPin = 7; 
const byte interruptPin1 = 3;
const byte interruptPin2 = 2;

boolean stateStart = false;
boolean stateStop = false;

int val = 0;
int cnt = 0;
int stateNum = 1;

void setup()
{
  Serial.begin(9600);
    
  pinMode(interruptPin1, INPUT_PULLUP);
  pinMode(interruptPin2, INPUT_PULLUP);  
  attachInterrupt(digitalPinToInterrupt(interruptPin1), exchange1, FALLING);  //인터럽트 발생 시 호출
  attachInterrupt(digitalPinToInterrupt(interruptPin2), exchange2, FALLING);  //인터럽트 발생 시 호출
  
  servo.attach(servoPin);   
  servo.write(0);
  delay(1000);
}

void loop()
{
  if(stateStart==true){ //뽑기시작
    val+=stateNum;
    Serial.println(val);

    if(val==180)stateNum = -1;
    if(val==0)stateNum = 1;    
    
    servo.write(val);
    delay(50);
  }
  
  if(stateStop==true){ //뽑기정지
    if(val>95 && val<105){ //뽑기 성공각도
      if(cnt<2){ //횟수 락
        cnt++;
        val=106;      
      }
      else cnt++;
    }
    else if(val>80 && val<120){ //상품 A의 횟수 증가 범위
      cnt++;
    }    
    servo.write(val);
    delay(100);
    
        //결과
    Serial.print("End Val : ");
    Serial.println(val);
    Serial.print("Count : ");
    Serial.println(cnt);
    if(cnt>2 && val>95 && val<105){ //성공 메시지와 cnt 초기화
      Serial.println("success!");
      cnt=0;
    }
    else Serial.println("failure!"); //실패 메시지
    
    //초기화
    val=0;
    servo.write(val);
    delay(200);    
    stateStop=false;    
  }  
}

void exchange1() { //인터럽트스위치버턴  이벤트1
  stateStart=true;  
  stateStop=false;
}

void exchange2() { //인터럽트스위치버턴  이벤트2
  stateStart=false;
  stateStop=true; 
}

4. 결과


원래 뽑기 성공범위는 좀 더 좁은 범위로 해야 하는데 녹화를 딱 맞게 하기 위해서 성공 범위를 좀 넓게 지정했네요. 횟수 락의 카운트 값은 2입니다. 3회부터서 성공 범위에 들면 뽑기 성공이 됩니다. 성공 범위가 아닌 뽑기 범위면 카운트만 세고 성공 범위인데 횟수가 부족하면 강제적으로 성공 범위를 벗어나게 하는 동작 소스입니다.

횟수 락에 의해서 성공 범위인 103각도에 멈췄지만 106도 강제적으로 이동시켜 실패하게 만들었네요.


횟수 락이 풀리고 성공 범위인 97각도에 멈춰고 97각도로 최종적으로 완료 되어 3회만에 성공이 되었네요.


만약에 3회 이후에 성공 범위에서 멈추지 못했다면 계속 성공할 때까지 도전해야 합니다.

아래 도전 영상을 올려 놓았습니다.


마무리


원래는 다른 post를 준비 중이였는데 문득 뽑기 횟수 락이 떠올라서 작성 중인 post를 멈추고 뽑기 횟수 락 실험을 하게 되었네요. 실제 뽑기가 이렇게 코딩이 되어졌다는 의미는 아니고요 관찰을 통해서 대충 이런 느낌이 아닐까 하고 그 느낌을 코딩화 했을 뿐입니다.
아두이노는 재밌는 것은 주변 환경을 관찰하고 그 관찰된 현상을 코딩화를 쉽게 할 수 있다는 점입니다. 최근 post들이 주변에 접할 수 있는 한번쯤은 경험했던 상황들을 아두이노적 시각으로 실험하고 있는데 여러분들도 이런 감각을 배우셨으면 합니다.


댓글()

[아두이노] 타이머를 이용한 인터럽트(Interrupt) 제어

IOT/아두이노|2019. 3. 1. 09:00

[아두이노] 타이머를 이용한 인터럽트(Interrupt) 제어



어제는 인터럽트 핀을 이용한 하드웨어 인터럽트에 대해 살펴보았습니다. 오늘은 타이머 함수를 이용한 인터럽트를 배워보도록 하죠. 위 참고자료의 해당된 링크로 가시면 MsTimer2 and FlexiTimer2 라이브러리가 있는데 그중에서 MsTimer2 라이브러리를 선택하여 실험해 보도록 하겠습니다.

1. 타이머를 이용한 인터럽트


  • MsTimer2 함수
MsTimer2::set(unsigned long ms, void (*f)()) //타이머 세팅
MsTimer2::start() //타이머 시작
MsTimer2::stop() //타이머 종료

대충 보시면 함수가 그렇게 어렵지 않죠

예)

MsTimer2::set(500, flash) 

0.5초 간격으로 flash 함수를 호출한다고 세팅합니다. start() 함수는 타이머를 시작하라는 명령이고 stop() 함수가 선언되지 않는 이상 아두이노는 0.5초 간격으로 무조건 flash()함수를 호출하게 됩니다.

FlexiTimer2 라이브러리도 비슷하니깐 한번 링크된 곳에 가셔서 보시면 대충 이해가 되실꺼에요.

2. 회로도 구성


  • 준비물 : LED 2개, 저항 220옴 2개, 아두이노우노, 뻥판
  • 내용 : 타이머 인터럽트를 발생시킨 결과를 Blue LED(발광다이오드)에 불이 들어오게 하고 기본 동작은 Red LED(발광다이오드)에는 불이 들오게 한다.


회로도를 보면 간단합니다. 12번 핀에 MsTimer2를 이용해서 0.5초 시간이 되면 5V의 전류를 보내 Blue LED를 제어하고 13번 핀은 loop()함수에서 1초 단위로 불이 깜박이게 할 예정입니다. 여기서 loop()함수의 1초 단위로 깜박이는 기본동작과 상관없이 강제적으로 인터럽트를 발생시켜서 12번핀에 전류 공급을 공급하게 됩니다.
쉽게 말해서 1초 단위로 깜박이는 로직이 있는데 어떤 라인의 명령이 수해되고 있던 상관없이 타이머 시간이 되면 강제적으로 특정 동작을 수행하게 만든다고 생각하시면 됩니다.

3. 코딩


  • 사용함수 : pinMode(), digitalWrite(), MsTimer2::set(), MsTimer2::start();
  • 내용 : 간단히 가변저항 조절기로 조절하면 흐를 전류를 조절할 수 있고 그 조절된 전류 값을 3색 LED에 출력값으로 해서 색을 자유롭게 만들어 낸다.
  • 참고 : MsTimer2

복습

  • pinMode(사용핀, OUTPUT) : 사용핀은 출력모드
  • digitalWrite(사용핀, 상태) : 디지털출력핀에 상태가 HIGH(5V) or LOW(0V)를 선택한다.
  • MsTimer2::set(호출시간, 호출함수명) : 타이머 세팅(500은 0.5초라는 것만 기억)
  • MsTimer2::start() : 타이머 시작
  • MsTimer2::stop() : 타이머 종료

설계

  1. Red LED은 loop()함수에서 기본동작으로 1초단위로 깜박이게 해야지
  2. Blue LED은 0.5초 간격으로 깜박이게 해야지

코딩을 전체적으로 하면

이 예제가 너무 잘 코딩 되어있는 거라서 따로 코딩 예제를 안만들고 인용을 하겠습니다. 메인 동작은 Red 핀이 1초 단위로 loop()함수 내에서 반복합니다. 타이머 함수의 경우는 setup() 함수에서 한번만 선언하면 됩니다. 왜냐면 loop()에 선언한다고 생각을 해보세요. 매번 타이먼을 세팅하고 타이머를 시작하고 거기다가 중요한것은 loop()에 넣으면 타이머가 loop() 반복순환문에 일부가 되어서 타이머 자체가 loop()의 기본동작이 되어 버리게 됩니다. 결론은 setup()함수에서 타이머를 작동시키고 loop()은 자신의 기본동작만 수행해서 타이머는 별거의 존재로 동작하도록 배치해야겠죠.

하지만 MsTimer2::start() or MsTimer2::stop() 함수는 loop()안에 넣을 수 있습니다. 타이머를 무조건적으로 동작시킨다면 setup()함수에서 선언하는게 맞지만 loop()함수내에서 타이머가 원하는 조건을 충족하기 전까지는 타이머를 동작안시키고 충족되면 타이머를 동작하게 할 수 있는 로직으로 표현 할 때 loop()함수 내에서 선언하게 됩니다.

#include <MsTimer2.h> //가상시뮬레이터 경우는 삭제하고 해당 라이브러리 파일을 여기에다 복사

int red= 13;
int blue = 12;
  
void flash() {  
  static boolean output = HIGH;
  digitalWrite(blue, output);
  output = !output;
}

void setup() {
  MsTimer2::set(500, flash); // 500ms period
  MsTimer2::start();
}

void loop() {
  digitalWrite(red, HIGH);  
  delay(1000);              
  digitalWrite(red, LOW);   
  delay(1000);     
} 

4. 가상시뮬레이터에서 외부라이브러리 함수를 사용하기


가상시뮬레이터에서는 기본 아두이노우노에서 제공되는 라이브러리들을 그냥 쓸 수 있습니다. 하지만 특수한 라이브러리는 제공하지 않습니다. 그러면 가상시뮬레이터에서는 어떻게 실험해야 할지 성멸을 드리도록 하겠습니다.

우선 라이브러리 파일은 두개의 파일로 구성됩니다. 예로 MsTimer2 라이브러리에는 MsTimer2.h, MsTimer2.cpp 파일이 있습니다. 이 두개를 실제로 아두이노 IDE에서 라이브러리 추가해야 사용이 가능합니다.

실제 라이브러리 추가는 LCD16x2 I2C(LiquidCrystal_I2C) 제어(아두이노)의 포스팅에 라이브러리 추가하기를 보시면 됩니다.

하지만 가상시뮬레이터에서는 라이브러리 자체를 추가할 수 없습니다. 라이브러리 자체를 코딩해서 사용해야 합니다. 그럼 사용하기 위해서는 두 파일을 가상시뮬레이터 코딩창에 다 복사해야 합니다.


MsTimer2.h 파일을 전체 복사해서 가상시뮬레이터 코딩창에 붙여넣기 한다음 다음 MsTimer2.cpp 파일에서 

#include <MsTimer2.h>
 라인을 삭제하고 나머지 전체를 복사해서 가상시뮬레이터 코딩창에 이여서 붙여넣기 하시면 됩니다. 그리고 setup(), loop()함수 코딩을 하시면 해결 됩니다.


대충 이런식으로 복사하시면 특수 라이브러리 파일을 연결해서 사용할 수 있습니다.

5. 결과


회로도 설계부터 외부라이브러리 파일을 복사해서 붙이고 코딩을 한 결과를 돌렸을때 결과를 자세히 보시면 대충 어떤식으로 해야할지 감이 잡히실꺼에요. 타이머 라이브러리 함수를 사용해서 LED에 불이 들어오는게 가상시뮬레이터에서 좀 약하게 들어와서 동영상을 보면 잘 안보일 수 있지만 자세히 보시면 두개의 LED들이 따로 독립적으로 움직이는 것처럼 보이실 꺼에요.


마무리


인터럽트는 끼어들기 함수라고 생각 하라고 했죠. 하드웨어 인터럽트에서는 인터럽트 핀에 특정한 조건이 만족했을때 호출 되었습니다. 하지만 오늘 배운 내용에서는 특정한 조건이 만족했을때라기 보다는 타이머로 강제적으로 일정 시간이 되면 호출하는 소프트웨어 인터럽트 였습니다. 둘 차이를 한번 잘 생각해보시고 나중에 어디에 사용할지 상상을 펼쳐 보세요.

한번 둘을 합쳐진 로직을 설계해보면 어떨지 생각해 보세요. 가령 하드웨어 인터럽트의 핀에 상황이 발생했을때 MsTimer2::start(), MsTimer2::stop() 함수가 실행 되게 설계를 한번 해보세요.


댓글()

[아두이노] 인터럽트(Interrupt) 제어

IOT/아두이노|2019. 2. 28. 09:00

[아두이노] 인터럽트(Interrupt) 제어



오늘은 인터럽트에 대해서 배워보도록 하겠습니다. 아두이노에서 인터럽트를 이용해서 예의치 못한 상황이 발생할때 중간에 개입하여 해결하는데 사용됩니다. 계속 센서값을 읽는 것에 대한 주제로 부품의 사용 설명을 해야 하는데 중간에 좀 코딩에 관련된 주제로 포스팅을 하게 되었었네요. 우선 이부분을 알고 계속 부품 사용을 살펴보는게 더 나을것 같다는 생각에 먼저 소개 합니다.

1. 인터럽트


인터럽트는 현재 프로그램이 수행 도중에 어떤 도출 상황이 발생하면 수행중인 프로그램을 일시 중단 시키고 도출 상황에 대한 특정 해결 동작을 수행하도록 하는게 인터럽트라고 생각 하시면 됩니다.

예를 들면은 요리사가 요리을 만들어 A라는 사람에게 대접하고 A는 맛있게 요리를 먹습니다.

  • 인터럽트 발생 : 갑자기 B라는 사람이 왔다.
  • 특정 동작 수행 : 요리사는 숟가락 하나를 B에게 건내서 같이 먹도록 하게 한다.
  • A는 계속 요리를 맛있게 먹고 B도 숟가락을 받은 후 A랑 같이 많있게 요리를 먹는다.

어떤 의미인지 아시겠지요. loop()함수에서 기본 아두이노 동작을 수행합니다. 그 동작을 수행할 때에 예기치 못한 상황이 발생하면 그 문제를 해결하기 위한 처리 동작이 필요합니다. 그래서 인터럽트 함수를 사용하게 되는 것이죠.

아두이노우노는 2.3번핀 인터럽트 핀이고 아두이노 종류에 따라서 인터럽트에 사용되는 핀의 갯수와 핀 번호가 각각 다릅니다 아두이노 종류에 따라서 잘 확인하시고 인터럽트 함수를 사용하시면 됩니다. 자세히 알고 싶으면 위에 링크한 참고자료에 가시면 아두이노 종류별 인터럽트 핀에 대해 잘 나와 있으니깐 참고하시면 됩니다.

표현형식

attachInterrupt(digitalPinToInterrupt(pin), ISR, mode); //권장
attachInterrupt(interrupt, ISR, mode); 
attachInterrupt(pin, ISR, mode) ; 

세가지 방법이 있는데 첫번째 권장 함수를 사용하세요. 물론 아두이노우노에서 다른 형식도 동작은 하는데 모드마다 제약이 따르기 때문에 권장함수로 표현을 하고 이해하시는게 편하실꺼에요.

함수

attachInterrupt(digitalPinToInterrupt(interruptPin), exchange, FALLING);

attachInterrupt(인터럽트핀, 호출함수, 상태조건)로 해서 setup()함수에 선언하기만 하면 알아서 인터럽트가 발생하면 호출이 됩니다. 동작은 해당 인터럽트핀이 특정 상태조건이 되면 호출함수가 호출됩니다. 이것만 이해하시면 오늘은 내용은 끝입니다.

상태조건은

LOW    :   LOW 상태일 때
CHANGE :  입력 값이 변할때
RISING   :  LOW -> HIGH로 변할때
FALLING :  HIGH -> LOW로 변할때

HIGH      :  HIGH 상태일 때 (rduino Due, Zero, MKR1000 만 허용)

실험에서는 내부풀업저항을 사용하는 스위치 버턴이 초기 상태값이 HIGH이니깐 스위치를 누르면 LOW가 됩니다. 고로 스위치를 누른 순간 HIGH->LOW로 FALLING 상태가 되는 것이죠. 인터럽트핀 2 or 3번 핀에 FALLING상태가 되면 exchange()함수가 호출되는 게 기본 동작입니다. 여기서 exchange라는 단어가 함수명으로 고정이 아니라 마음대로 test1이라고 해도 됩니다.

아래 예제처럼 함수를 표현하시면 됩니다.

attachInterrupt(digitalPinToInterrupt(interruptPin), test1, FALLING);
void test1()
{
  동착;
}

어떤 느낌인지 아시겠지요.

2. 회로도 구성


  • 준비물 : LED 3개, 저항 220옴 3개, 스위치버턴 2개, 아두이노우노, 뻥판
  • 내용 : 인터럽트 발생을 스위치버턴을 활용하고 그 결과를 LED(발광다이오드)에 불이 들어오게 한다.

회로도를 보면 스위치버턴에 저항이 붙어있지 않다. 즉, 내부풀업저항을 이용한다는 것이고 11,12,13번 핀으로 출력값으로 LED에 불이 들어오게 하는 기본 회로도 입니다. 복습차원으로 LED 제어와 스위치버턴 제어를 합쳐서 인터럽트 실험을 하기 위한 회로도 입니다.

3. 코딩


  • 사용함수 : pinMode(), digitalWrite, attachInterrupt(),analogRead()
  • 내용 : 간단히 가변저항 조절기로 조절하면 흐를 전류를 조절할 수 있고 그 조절된 전류 값을 3색 LED에 출력값으로 해서 색을 자유롭게 만들어 낸다.
  • 참고 : [아두이노] LED 제어(아두이노)

복습

  • pinMode(사용핀, OUTPUT) : 사용핀은 출력모드
  • pinMode(사용핀, INPUT_PULLUP) : 사용핀은 내부풀업저항을 이용한 입력모드
  • attachInterrupt(digitalPinToInterrupt(2~3번핀), exchange1, FALLING) : 인터럽트 2~3번핀이 HIGH->LOW로 바뀌면 exchange1 함수를 호출한다.
  • digitalWrite(사용핀, 상태) : 디지털출력핀에 상태가 HIGH(5V) or LOW(0V)를 선택한다.

설계

  1. Red LED은 loop()함수에서 기본동작으로 1초단위로 깜박이게 해야지
  2. Green LED은 2번 인터럽트가 누르면 불이 들어오고 다시 누르면 꺼지게 해야지
  3. Blue LED은 3번 인터럽트가 누르면 불이 들어오고 다시 누르면 꺼지게 해야지
  4. 인터럽트 2,3번 핀을 변수로 선언하고 RGB핀을 각각 변수로 우선 만들어 놔야지
  5. 인터럽트 호출함수를 setup()내에 선언하고 두개를 사용하니깐 두개의 호출될 함수를 만들어 놔야 겠군.
  6. loop()함수 안에다가 Red LED가 기본동작으로 1초 깜박이는 로직을 표현해야지
  7. 인터럽트 호출 함수 exchange1,2는 누를때마다 불이 들어왔다 나갔다 해야하니깐 상태변수를 하나 선언해서 True(1)일때 불이 들어오고 False(0)일때 불이 꺼지게 if문으로 상태변환을 시킬 수 있게 조건문 만들어야 겠다. 그러면 초기 상태변수는 False로 해 놔야지 우선 꺼진상태가 되겠군
  8. 이제 이 글을 코딩으로 바꿔야겠다.

인터럽트 호출시 호출함수내에서 상태변환

  if(state1==false){
    digitalWrite(blue, HIGH);
    state1=true;
  }else{
    digitalWrite(blue, LOW);
    state1=false;
  }

인터럽트 호출된 함수 내에서 state1은 초기값이 false이면 true로 변환 state1이 true이면 false로 변환을 if문으로 바꾸게 됩니다.

더 쉽게 표현을 하자면

state=!state;
digitalWrite(blue,state);

이렇게하면 state의 현재상태를 계속 반전 시키게 됩니다.

코딩을 전체적으로 하면

int red = 13; 
int blue = 12;
int green = 11;
int interruptPin1 = 2;
int interruptPin2 = 3;
boolean state1 = false;
boolean state2 = false;

void setup() {
  pinMode(red, OUTPUT);
  pinMode(blue, OUTPUT);
  pinMode(interruptPin1, INPUT_PULLUP);
  pinMode(interruptPin2, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin1), exchange1, FALLING);
  attachInterrupt(digitalPinToInterrupt(interruptPin2), exchange2, FALLING);
}

void loop() {
  
  digitalWrite(red, HIGH);
  delay(1000);
  digitalWrite(red, LOW);
  delay(1000);
  
}

void exchange1() {
  if(state1==false){
    digitalWrite(blue, HIGH);
    state1=true;
  }else{
    digitalWrite(blue, LOW);
    state1=false;
  }
}
void exchange2() {
  if(state2==false){
    digitalWrite(green, HIGH);
    state2=true;
  }else{
    digitalWrite(green, LOW);
    state2=false;
  }
}

4. 결과


회로도와 코딩을 가상시뮬레이터에서 디자인하고 코딩을 복사해서 붙이고 실행 시켜보세요. 스위치 버턴을 누르면 인터럽트가 발생하하여 해당 LED에 불이 들어오는걸 확인하실 수 있을거에요. 여기수 주 동작인 Red LED는 인터럽트 발생과 상관없이 규칙적으로 1초 단위로 깜박입니다. 인터럽트가 어떤 느낌인지 잘 생각해보세요.

마무리


인터럽트는 끼어들기 함수라고 생각하시면 돼요. 기본 메인 동작을 수행하는 도중에 어떤 돌출된 상황이 발생하면 그 상황을 메인 동작에 영향을 안주는 선에서 끼여들어서 그 상황을 해결하는 특정 동작을 수행하고 그 뒤에 메인 동작은 연속해서 하고자 하는 일을 하게 됩니다.

이런 원리를 이용하여 아두이노에서 어떤곳에서 활용하면 좋을지 상상의 나래를 펼쳐보세요.


댓글()