[아두이노] Processing를 이용한 아두이노 제어 II

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

[아두이노] Processing를 이용한 아두이노 제어 II 



두번째 시간으로 프로세싱을 통해 아두이노를 직접 제어하는 방법을 살펴보도록 하겠습니다.

1. Processing 세팅


[1단계] 도구->추가도구 설정 눌러 줍니다.


[2단계] 라이브러리에서 arduino라고 치시면 아래 그림처럼 검색되는데 하당 라이브러리를 선택하시고 Install 하시면 됩니다.


[3단계] 프로세싱 편집기를 종료하시도 다시 실행 시킵니다. 그리고 파일->예제를 누르시면 따로 창이 뜨고 Arduino(Firmata) 가 추가된 것을 보실 수 있을거에요.


아무 예제나 클릭하시면 되는데 좀 코딩량이 많습니다. 그래서 간단히
[4단계] https://playground.arduino.cc/Interfacing/Processing 이곳 주소로 가시면 프로세싱 예제가 있습니다.

프로세싱 편집기에 그래도 코딩하시면 됩니다.


2. 아두이노 세팅


[1단계] 파일->예제->Firmata -> StandardFirmata 를 눌러줍니다.


[2단계] 예제가 뜨고 이걸 아두이노에 이식 시키면 됩니다.


3. Processing + Arduino


아두이노에서 StandardFirmata를 아두이노에 이식 시키고 Processing은 Arduino(firmata) 라이브러리를 설치해서 아두이노 라이브러리를 통해서 실제 아두이노를 직접 제어하게 됩니다.


쉽게말해서 아두이노는 프로세싱을 받을 준비를 해놓고 프로세싱에서는 직접 아두이노 함수를 통해 제어를 하게 된다고 생각하시면 됩니다.

4. Processing에서 아두이노 문법


import processing.serial.*;
import cc.arduino.*;

Arduino arduino;
int ledPin=13;

void setup() {  
  println(Arduino.list());
  arduino = new Arduino(this, Arduino.list()[0], 57600);
  arduino.pinMode(ledPin, Arduino.OUTPUT);
}

void draw() {
  arduino.digitalWrite(ledPin,Arduino.HIGH);
  delay(1000);
  arduino.digitalWrite(ledPin, Arduino.LOW);
  delay(1000);  
}

소스로 설명드리겠습니다. 아두이노 LED 깜박이는 기본베이스 소스입니다.

기본적으로

import processing.serial.*;
import cc.arduino.*;

통신과 아두이노 라이브러리를 가져오게 와야겠죠. 그리고 아두이노 클래스를 사용할때 클래스 객체를 선언해야합니다.

Arduino arduino;
arduino = new Arduino(this, Arduino.list()[0], 57600);

클래스 객체를 선언하고 객체를 인스턴트 합니다. 쉽게 말해서 객체를 만들고 초기화 한다고 생각하세요.

그다음 아두이노에서 쓰던함수들은 객체명.함수 함수로 객체가 앞에 연결자로 모두 표현해야 합니다. 아두이노 클래스내에 아두이노 함수들이 있으니깐 객체.함수() 해야지 객체속의 함수를 호출할 수 있게 됩니다.

pinMode(13,OUTPUT) => arduino.pinMode(13,Arduino.OUTPUT);

됩니다. 무슨 의미인지 아시겠지요. delay(1000) 이것은 왜 안붙이냐 오타이냐 할 수 있는데. 프로세싱에서도 있는 함수임으로 붙이지 않습니다.

임포턴트하는 것과 객체 선언한것만 이해하시면 간단 합니다.

5. 간단한 버턴클릭 예제로 아두이노 LED 제어


지난시간에 만들어 봤던 작은사각형 클릭했을때 사각형들의 색상을 바꾸는 예제를 아두이노 LED를 On/Off 시키는 스위치 버턴으로 사용하겠습니다.

예제)

boolean cnt = false;

void setup() {  // this is run once.   
    
    // set the background color
    background(255);
    
    // canvas size (Integers only, please.)
    size(600, 600);       
    
} 

void draw() {  // this is run repeatedly.  
    rect(10,10,580,300,10);    
    rect(200,350,200,100,10);    
}

void mousePressed(){
 if(mouseX>200 && mouseX<400 && mouseY>350 && mouseY <450){
     cnt=!cnt;
 }
 if(cnt==true)fill(255,0,0);
 else fill(0,0,0);
}

이 소스에서 프로세싱에서 아두이노 문법을 위에서 설명했으니 해당 위치에 넣으시면 됩니다.

mport processing.serial.*;
import cc.arduino.*;

Arduino arduino;
int ledPin=13;

boolean cnt = false;

void setup() {  // this is run once.   
    
    // set the background color
    background(255);
    
    // canvas size (Integers only, please.)
    size(600, 600); 
        
    //println(Arduino.list());
  arduino = new Arduino(this, Arduino.list()[0], 57600);
  arduino.pinMode(ledPin, Arduino.OUTPUT);
    
} 

void draw() {  // this is run repeatedly.  
    rect(10,10,580,300,10);    
    rect(200,350,200,100,10);    
}

void mousePressed(){
 if(mouseX>200 && mouseX<400 && mouseY>350 && mouseY <450){
     cnt=!cnt;
 }
 if(cnt==true) {
   arduino.digitalWrite(ledPin,Arduino.HIGH);
   fill(255,0,0);
    }
 else{
   arduino.digitalWrite(ledPin,Arduino.LOW);
   fill(0,0,0);
 }
}

버턴을 눌렀을때 색상을 바꾸는 곳에다 LED 제어해야겠죠.

if(cnt==true) {
   arduino.digitalWrite(ledPin,Arduino.HIGH);
   fill(255,0,0);
    }
 else{
   arduino.digitalWrite(ledPin,Arduino.LOW);
   fill(0,0,0);
 }

딱히 수정할 것은 없습니다. 아두이노 소스를 해당 위치에다만 삽입하면 됩니다.

6. 결과


프로세싱과 아두이노에 코드를 복사하고 실제 동작하는 전과정을 담았습니다. 동영상을 보는게 더 쉽게 와 닿을지 모르겠네요.

마무리


종합해 보면, 아두이노에서 StandardFirmata를 아두이노에 이식 시키고 Processing은 Arduino(firmata) 라이브러리를 설치해서 아두이노 라이브러리를 통해서 StandardFirmata를 이식된 아두이노를 직접 제어를 하게 됩니다.

이 방법은 아두이노에서 코딩을 할 필요가 없습니다. 프로세싱에서 그래픽 시각화와 아두이노 제어를 둘 다 할 수 있습니다.

또 다른 방법은 시리얼통신으로 서로 데이터를 주고 받는 방법이 있습니다. 프로세싱과 아두이노가 데이터를 주고 받으면서 제어할 데이터 또는 시각화 데이터를 서로 시리얼통신으로 통해 주고 받는 방식이 있습니다.
이 경우는 아두이노는 아두이노 코딩만 하면 되고 프로세싱은 프로셋이 코딩만 하면 됩니다. 그 중간 연결을 통신이 대신 하는 것이죠.

우선은 오늘 배운 프로세싱에서 아두이노를 제어하는 방법만 이해해 주시고 다음에 따로 통신을 통해 데이터를 주고 받는 방식을 살펴보도록 하겠습니다.


댓글()

[아두이노] Processing을 이용한 아두이노 제어 I

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

[아두이노] Processing을 이용한 아두이노 제어 I 



오늘은 즐거운 토요일입니다. 매주 토요일이면 재밌는 프로그램을 소개하는 날입니다. 이번주 소개 할 프로그램은 아두이노와 연결해서 재밌게 시각화 실험을 할 수 있는 프로그램입니다. 스크래치나 프로세싱으로 아두이노 제어하거나 결과를 시각화 하는데 많이 사용합니다. 잘 알려진 프로그램 툴이고 컴퓨터 공부를 좀 하신분들은 한번쯤은 다뤄봤을 툴이라고 생각되네요. 아두이노 처음 입문자분들은 아직 프로세싱에 대해서 잘 모르고 프로그램 언어 영역이라서 다루기 불편하실 수 있지만 그래픽 툴로서는 쉬운 편에 속하고 함수만 잘 활용한다면 재밌는 시각화 프로그램을 만들 수 있으니깐 한번 참고하시면 좋을 듯 싶네요.

좀 포스팅 내용이 길어질 수 있어서 나눠서 소개할까 합니다. 오늘은 간단히 프로세싱 소개를 하는 시간으로 채울 듯 싶네요.

1. Processing 다운로드


[ PC에 실치 ]


위에 공식 홈페이지에 다운로드 주소까지 링크 걸려있습니다. 들어가시면 자신의 운영체제에 맞게 다운로드 하시면 됩니다. 압축(zip) 파일을 다운로드 하시면 폴더를 만드시든 그냥 압축 파일명으로 압축된 파일을 푸시면 됩니다. 설치는 따로 사실 필요없이 폴더 안에 들어가서 실행파일을 누르시면 자동으로 실행 됩니다.

[ 라즈베리파이에 설치 ]

$ curl https://processing.org/download/install-arm.sh | sudo sh 

[출처] 라즈베리파이에 프로세싱 설치하기(작성자 코스모스)

라즈베리파이에 설치할때 잘 몰라서 이건 배우는 단계라서 두가 설치법이 있는데 구글링 해서 보니깐 코스모스님이 블로그에 간단하게 설치하는 법을 소개했네요. 이 한줄로 라즈베리파이에 프로세싱을 설치하여 현재는 재밌게 사용하고 있네요.

2. Precessing 웹 편집기


위에 링크된 sketchpad 사이트 가시면 온라인 상에서 프로세싱을 즐길 수 있습니다. 다운 받을 필요도 없고 회원가입을 할 필요도 없이 그냥 코딩 하고 싶을때 가셔서 코딩 하시면 됩니다.


3. 편집창


[ PC 편집기 ]


다운로드 받은후 압출파일을 풀고 실행파일을 실행 시키면 실행됩니다. 간단한 코딩을 넣고 실행한 창입니다.
나중에 아두이노 연결에 이 편집기를 이용할 예정입니다.

[ 온라인 편집기 ]



뭔가 코딩 되어 있으며 실행 버턴을 눌러보세요. 간단한 그래픽 쇼가 보여집니다. 간단한 예제로 시뮬레이터가 돌아간 모습을 보시고 코딩이 어떻게 했는지 한번 잘 살펴보세요.

4. Precessing의 문법 구조


void setup()
{
     초기화 명령이나 한번만 수행하는 명령들을 코딩;
}
void draw(){
    반복적으로 계속 그리는 동작명령들을 코딩;
}

아두이노랑 구조가 같습니다. 아두이노에서는 loop()함수이지만 프로세싱에서는 draw()함수입니다. 프로그램이 종료되기 전까지는 반복 호출되는 함수인 것죠.

5. Precessing의 간단한 버턴 예제


  • 사용함수 : background(), size(), rect(), fill(), mousePressed()
  • 내용 : 버턴 클릭 이벤트로 사각형의 색을 변경한다.

사용함수

  • background(255) : 배경색인데 0~255로 검색에서 흰색사이의 색을 지정해줍니다.
  • size(600,600) : 윈도우 사이즈
  • rect(100,200,100,200,10) : 사각형을 그리기인데 rect(x1,y1,x2,y2,모서리)를 나타냅니다. 시작꼭지점(100,200) 얼마만큼 이동한 끝점(100,200)을 나타냅니다. 그리고 마지막 인자 10은 모서리를 매끄렇게 하는 값인데 안써도 상관없습니다. 그냥 rect(100,200,100,200)이렇게 해도 됨.
  • fill(255,0,0) : 채우기 함수입니다. fill(R,G,B)값으로 생각하시면 됨
  • mousePressed()은 마우스 버턴을 눌렀을 호출하는 함수임(다른 표현도 있지만 이정도만 이해하세요.)

간단한 버턴 클릭 예제

boolean cnt = false;

void setup() {  // this is run once.   
   
   // set the background color
   background(255);
   
   // canvas size (Integers only, please.)
   size(600, 600);       
   
} 

void draw() {  // this is run repeatedly.  
   rect(10,10,580,300,10);    
   rect(200,350,200,100,10);    
}

void mousePressed(){
if(mouseX>200 && mouseX<400 && mouseY>350 && mouseY <450){
    cnt=!cnt;
}

if(cnt==true)fill(255,0,0);
else fill(0,0,0);
}

코딩을 보시면 총 세개로 나눠 졌습니다. 온라인 편집기에 있는 소스를 최대한 안건들고 간단한 버턴 클릭하는 예제를 코딩해 봤습니다.

setup() 함수에서 윈도우 설정을 했는데 배경을 background(255)로 흰색을 지정하고 크기를 size(600,600)으로 600x600 크기로 만들었습니다.

draw()함수에서는 만든 윈도우에서 rect()함수로 사각형을 두개 그렸습니다.


대충 위 그림처럼 윈도우 600x600 크기의 창이 뜹니다. 그리고 그 안에 rect()로 만든 사각형이 2개 보이시죠. 여기서 아래 작은 사각형을 버턴으로 이용할 예정입니다.

작은사각형 이미지를 버턴이라고 생각하고 해당 버턴을 누를려면 마우스 버턴을 클릭했을때 이벤트가 발생해야 겠죠. mousePressed()함수를 사용합니다. 이 함수는 마우스가 클릭했을때 호출되는 함수입니다. 그안에 버턴을 클릭했을때의 이벤트 로직을 작성해야 합니다.

void mousePressed(){
  마우스 클릭했을 때 호출;
}

위 마우스가 클릭했을때 호출되는 함수인데 간단하죠.
작은사각형 이미지가 버턴으로 사용되기 때문에 작은사각형 이미지 안을 마우스로 클릭했을때 이벤트를 실행시키면 됩니다.

쉽게 설계를 하면

  1. 사각이미지를 영역을 마우스로 클릭한다.
  2. 마우스 클릭 이벤트 발생한다.

그러면 사각형을 마우스클 클릭했을때 이벤트가 발생해야 합니다. 여기서 마우스가 아무곳이나 클릭한다고 해서 클릭 이벤트가 발생하면 안됩니다. 마우스를 클릭했을때 mousePressed()함수가 호출된다고 해서 무조건 동작해서는 안되고 사각형 안에서만 클릭하도록 코딩을 짜야 됩니다. 클릭했을때 호출되니깐 그 마우스 클릭한 좌표(mouseX,mouseY)가 작은 사각형버턴 영역에서 클릭했냐로 체크하는 로직을 짜면 쉽게 사각형을 버턴으로 만들 수 있겠죠.

버턴을 마우스 클릭했을때 원리

   rect(200,350,200,100,10);    

이 사각형을 클릭하기 위해서 사각형의 영역을 클릭하는 영역으로 잡아 줘야 합니다.


X축을 기준으로 하면 초록색 범위가 마우스 클릭 할 X축의 영역이 됩니다. 즉, 꼭지점 x1에서 x2까지이죠.
Y축을 기준으로 하면 노란색 범위가 마우스를 클릭 할 Y축의 영역이 됩니다. 즉, 꼭지점 y1에서 y2까지이죠.

그러면 사각형이 그러진 영역은 X축과 Y축이 겹쳐지는 저 영역이 바로 버턴의 영역이 되는 것이죠.

이걸 코딩으로 하면

if(mouseX>x1 && mouseX<x2 && mouseY>y1 && mouseY <y2){
        사각버턴 영역을 클릭 했을때 처리문;
}

코드를 분석으을 해보죠.

먼저 윈도우 상에서 마우스 좌표(mouseX,mousY) 추출 할 수 있습니다. 즉, 이 변수명으로 현재 마우스가 위치를 알 수 있게 됩니다.

if(mouseX>x1 && mouseX < x2)

이게 뭘 말할까요. X축 기준으로 클릭 범위가 초록색 범위여야 하잖아요. 그러면 마우스가 클릭한 mouseX의 값은 x1보다 크고 x2보다는 작을때 위 그림에서의 초록색 영역이 됩니다. 그래서 두 조건식으로 클릭한 마우스 mouseX좌표가 x1보다 크고 x2보다 작은가를 조건문으로 해서 작은사각형 이미지의 X축 영역을 체크하는 것이죠. 마우스 Y좌표도 이와 같습니다.

참고로 '&&' 기호는 "그리고" 이고 '||' 기호는 "또는"라는 뜻입니다.

if(mouseX>x1 && mouseX<x2 && mouseY>y1 && mouseY <y2)

총 4개의 조건식으로 모두 만족한 영영이 바로 X축 영역과 Y축 영역이 겹쳐지는 교집합 영역으로 바로 윈도우창의 작은 사각형의 영역이 됩니다. 이 조건을 만족하면 마우스 좌표는 작은 사각형 영역에 위치해 있다는 의미가 됩니다.

 rect(200,350,200,100,10);    

윈도우에서 작은사각형은 P1(200,400), P2(350,450) 꼭지점의 영역을 갖습니다.
이부분을 햇갈리시는 분들이 있습니다. 시작점 P1은 (200,350) 입니다. P2은 (x1+x2,y1+y2) 입니다. 사각형의 시작점을 기준으로 하는게 아니라 윈도우상에서 작은사각형이 위치좌표는 윈도우좌표에서 접근해야 하기 때문에 윈도우 상에서 작은사각형의 좌표를 지정해야 합니다.

rect()함수는 시작점(x1,y1)을 기준으로 끝점(x2,y2)만큼 크기의 사각형이냐의 표현입니다. 즉, 끝점은 윈도우 좌표에서 시작점 (x1,y1)이 이동했고 거기서 다시 사각형이 끝점으로 이동하기 때문에 시작점까지 이동한 거리를 더해줘야 합니다. 그래서 P2(200,100)이 아니라 (200+200,350+100)해서 (400,450)이 끝점이 되는 것이죠.

그러면 윈도우 상에서 마우스(mouseX,mouseY)가 작은사각형의 좌표 영역에 들어갔는지 if문으로 아래와 같이 표현이 됩니다.

 if(mouseX>200 && mouseX<400 && mouseY>350 && mouseY <450)

마우스를 클릭했을때 mousePressed()함수가 호출되고 위 if문을 통해서 작은 사각형 영역에 마우스 좌표가 현재 위치해 있는지 확인하는 문장이 됩니다. 이렇게 해서 작은사각형 이미지는 버턴의 능력을 갖게 됩니다.

작은사각형을 버턴으로 표현을 했으면 실제로 간단하게 색상을 변경하는 명령을 내려봅시다. 2가지 색을 교대로 바꾸게 할려고 별도로 cnt라는 변수를 하나 선언 했네요. 참/거짓으로 부울변수를 만들어서 참일때 빨강색, 거짓일때 검은색으로 바꿔 볼려고 합니다.

boolean cnt =fasle;

체크변수로 초기값으로 false를 주고 클릭했을때

cnt=!cnt;

이 문장으로 변수값을 반전 시켰습니다. 거짓이면 참으로 참이면 거짓으로 반전 문장입니다. 이코딩은 작은 사각형을 클릭했을때 발동해야 하기 때문에 마우스클 클릭했을때 호출되는 함수에서 다시 if문 사각형 영역에 있는 지 확인 되었을때 그 안에다가 표현 해야겠죠. 간단히 그안에다 이 한줄을 삽입하면 됩니다. 참 쉽죠.

그다음 채우기 fill()함수를 이용해 사각형을 채우는 로직을 if문으로 간단히 표현했습니다.

 if(cnt==true)fill(255,0,0);
 else fill(0,0,0);

if문으로 cnt가 참이면 색채우기를 빨강색으로 fill(255,0,0)으로 cnt가 거짓이면 검정색으로 fill(0,0,0)으로 바꿔줍니다. 색을 작은사각형 버턴을 클릭할때마다 빨강색과 흰색이 계속 바뀌게 됩니다.

이렇게 해서 간단한 로직에 대해서 설명했습니다. 그런데 왜 fill()함수만으로 색이 바꿔지는이 햇갈리는 분들이 아마 있을거에요. draw() 함수에서 매번 호출된다고 했는데 그안에서는 사각형 2개를 그립니다. 그리기 전에 사각형의 채우기 색을 지정해주면 그릴때마다 사각형의 색을 바꿀 수 있게 된다는 원리를 이용한거니 어렵게 생각하지 마세요.

쉽게 말해서,

  • cnt가 true 인 경우
fill(255,0,0)
rect(10,10,580,300,10);    
rect(200,350,200,100,10);  
  • cnt가 false 인 경우
fill(0,0,0)
rect(10,10,580,300,10);    
rect(200,350,200,100,10);  

이렇게 마우스를 클릭할때마다 색이 변경되어 그려진다는 것이죠. 어떤 느낌이신지 아시겠지요.

그래서 마우스클릭 이벤트 함수에서 작은사각형의 이미지를 클릭했다면 그안에다가 fill()함수로 draw()함수로 그리기 전에 채우기 색을 지정하면 쉽게 색상을 바꾸게 되는 것이죠.

결과



이걸로 아두이노랑 연결해서 버턴이미지를 클릭 할 때 빨강색으로 바꾸고 Red LED에 불이 들어오게 하고 다시 클릭 하면 검정색으로 바뀌게 해서 Red LED를 깜박이게 제어할 예정입니다.


마무리


많은 예제 중에서 왜 이런 예제를 설명하냐면요 다음편에 아두이노와 연결해서 이 예제로 간단히 LED를 On/Off 버턴으로 활용하기 위해서 입니다.
작은사각형 이미지를 클릭이벤트를 활용하여 큰 모니터 사각형과 버턴 사각형이 색이 빨강색으로 바뀌면 Red LED에 불이 들어오고 검은색으로 바뀌면 Red LED가 꺼지는 스위치버턴으로 활용하기 위해서이죠.
바로 프로세싱으로 간단히 아두이노를 제어하고 그 제어하는 방법을 이해하면 프로세싱을 통해서 아두이노를 시각화 할 수 있다는 것을 이 예제를 통해 소개하기 위해서 입니다.

오늘은 온라인 상에서 프로세싱을 간단히 다뤄보세요. 구글링 치면 강좌도 많고 간단히 함수들을 불러다가 배치해서 시각화 해보세요.

댓글()

[아두이노] 온도센서(TMP36) 제어

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

[아두이노] 온도센서(TMP36) 제어



오늘은 온도센서(TMP36)를 제어 해보는 시간을 가지도록 합시다. 원래 예전에 공부할때 온도계산에 대한 부분은 다른분의 블로그를 보고 했는데 기억이 안나네요. 암튼 온도 계산식을 제가 만든것도 아니고 기존에 공식이 있는 거라서 제가 참조한 출처는 못찾아서 해당 온도계산식이 나와 있는 블로그를 하나 링크를 걸어 놓았네요.

1. 온도센서(TMP36)



대부분의 측정센서는 Vcc, Gnd로 전원을 공급하고 센서에서 측정한 값은 Vout 출력됩니다. Vout은 온도에 따른 전류를 측정하는 것이죠. 그래서 전류를 계산하는 공식이 필요합니다.

 float V = analogRead(A0)*5.0/1023;
 float C = (V-0.5)*100;  //섭씨 C = (F-32)*1.8;
 float F = C*9.0/5.0+32; //화씨 F = C*1.8+32;

이게 기본베이스 입니다. 제가 만든건 아니고 기본적으로 이 공식으로 섭씨와 화씨를 측정하더군요.
제 블로그에서는 약간 수정하여 map()함수를 응용해서 함수를 따로 만들었습니다. 정수를 실수형으로 변수를 바꾼것 밖에 없지만요,

float fmap(long x, long in_min, long in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) /(float) (in_max - in_min) + out_min;
}
<

V 계산을 map()함수 로직에다 삽입해서 바로 V값이 나오도록 했죠. 그냥 이렇다는 것이고 위의 공식으로 그냥 하셔도 됩니다.

2. 회로도 구성


  • 준비물 : TMP36 센서, 아두이노우노
  • 내용 : 온도센서에서 읽어들인 값을 아두이노 IDE 시리얼모니터로 출력시키기 위한 회로도 만들자.


선 연결 참 쉽죠. 원래는 LCD16x2로 온도값을 출력할려고 했는데 그러면 TMP36 제어를 어려워 할 것 같아서 최소한 코딩으로 원리만 전달하고자 간단히 표현했네요.

원리를 이해했으면 LCD16x2로 출력해 보세요. 아두이노는 하나의 부품을 배우면 지난 시간에 배운 부품들과 계속 결합해서 응용력을 키워야 실력이 늘어 납니다.

3. 코딩


  • 사용함수 : analogRead(), map(), Serial.begin(9600), Serial.print(), Serial.println()
  • 내용 : 온도계산공식을 이용하여 간단히 아두이노 IDE 시리얼모니터로 현재 온도를 출력하자.

복습

  • analogRead(A0) : A0핀으로 아날로그 값을 읽음
  • map(입력값,입력최소값,입력최대값,출력최소값,출력최대값) : 입력값이 입력범위에 기준에 맞게 출력범위의 해당값을 출력.
  • Serial.begin(9600) : 시리얼 통신 시작
  • Serial.print(출력값) : 출력값을 시리얼 모니터로 출력하는데 새로운 라인으로 안넘어가고 현재라인에 커서가 위치함.
  • Serial.println(출력값) : 출력값을 시리얼 모니터로 출력한 다음 새로운 라인으로 커서가 이동하는데 Enter(\n) 의미로 이해

설계

  1. 온도센서값을 읽어옴
  2. 섭씨와 화씨를 구함
  3. 시리얼모니터로 출력

온도센서는 analogRead(A0)로 읽어온다. 0~1023값을 읽어오는데 V를 구해야한다. 0~5V의 아두이노는 흐른다. 즉, 0~1023의 수치를 0~5V 값으로 출력을 맞춰야 합니다.

가령, map()함수라는 것은 0~100까지의 입력 범위가 있으면 출력을 0~10사이로 맞출때 사용합니다.

입력이 10이면 출력은 1
입력이 20이면 출력은 2

...

입력이 100이면 출력은 10

이렇게 되게죠. map()함수에 대해서 이해 하셨을거라 생각 합니다. 그런데 map()함수는 정수값으로 나오기 때문에 실수값으로 0~5V사이 값이 나오기 때문에 기존의 map()을 그대로 쓰면 안됩니다. 변수를 실수형태로 변경해 줘야 합니다. 실수형으로 변수를 선언해주면 간단히 해결 됩니다.

float V =fmap(analogRead(A0),0,1023,0,5); //map함수 원리를 이용한 다이렉트 Voltage계산

V값이 구해지면 섭씨(C)와 화씨(F)를 공식에 대입하면

float C = (V-0.5)*100;  //섭씨 C = (F-32)*1.8;
float F = C*9.0/5.0+32; //화씨 F = C*1.8+32;

이렇게 섭씨(C)와 화씨(F)가 구해지겠죠. Serial.print(), Serial.println()함수로 좀 이쁘게 그 값을 출력하면 됩니다.

코딩을 전체적으로 하면

void setup() {
  Serial.begin(9600); //시리얼통신 시작
}

void loop() {
 
  float V =fmap(analogRead(A0),0,1023,0,5); //map함수 원리를 이용한 다이렉트 Voltage계산
 
  //공식
  //float V = analogRead(A0)*5.0/1023;
  float C = (V-0.5)*100;  //섭씨 C = (F-32)*1.8;
  float F = C*9.0/5.0+32; //화씨 F = C*1.8+32;
  
  Serial.print("V : ");
  Serial.println(V);
  Serial.print("C : ");
  Serial.println(C);
  Serial.print("F : ");
  Serial.println(F);
  
  delay(1000);  
}

float fmap(long x, long in_min, long in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) /(float) (in_max - in_min) + out_min;
}

4. 결과


가상시뮬레이터에서지만 약간은 오차가 발생 하네요. 실제로 하더라도 보정이 좀 필요할 듯 합니다.

마무리


오늘은 온도센서(TMP36)을 이용해서 아두이노에서 간단히 계산하니깐 온도계가 되었네요. 온도를 측정할 수 있다는 것은 많은 것들을 할 수 있게 됩니다.

가령 방마다 온도를 측정한다 그리고 무선통신을 이용해서 그 값을 따로 컴퓨터에 저장시켜서 4계절 집안 온도의 데이터를 수집할 수 있게 되고 그걸 통해서 집안 난방을 관리할 수 있게 되겠죠. 또 다른 예로 식물재배에서도 온도를 측정하면 온도에 맞게 자동으로 제어를 할 수 있겠죠.

온도를 측정한 다는 것은 그 데이터를 수집해서 다른 용도로 사용할 수 도 있고 아니면 현재의 온도에 맞게 특정한 동작을 수행하도록 하는 목적으로 사용할 수 도 있겠죠.

암튼 온도를 측정할 수 있으면 여러분들은 뭘 하고 싶을지 상상의 나래를 펼쳐보세요


댓글()

[아두이노] 스위치버턴을 이용한 Keypad 제어

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

[아두이노] 스위치버턴을 이용한 Keypad 제어



오늘은 KeyPad의 내부 동작을 살펴보도록 하죠. 가장 잘 알려진게 스위치버턴으로 표현한 예제입니다. 아래 스위치 버턴의 연결한 회로도를 잘 살펴보세요. 이 원리를 이해하시면 나중에 3x3x3 LED CUBE를 만드는데 활용되는 원리니깐 꼭 이해해 주세요.

1. 스위치버턴을 이용한 KeyPad



스위치 버턴은 기본 눌렀을때 전류가 흐르잖아요. 이걸 16개의 버턴을 연결한 것이죠. 그리고 각 스위치 버턴의 입력을 내부풀업저항을 이용해서 스위치 누른 위치의 상태값을 통해서 몇번째 스위치가 눌러졌는지 알게 됩니다.


우선 선 4x4 스위치 버턴을 배치한뒤에 선을 그림과 같은 형태로 연결하세요. 그리고 스위치 버턴에 내부풀업저항을 이용한다고 가정해 봅시다. 여기서, 가로 라인을 1층으로 생각하시고 세로는 각 호실이라고 했을 때 그러면 1층 2호실을 눌렀을 경우를 생각해보세요.

어떤 경우에 1층 2호실이 눌러졌는지 알 수 있을까요.


하나만 쪼개서 다시 살펴보세요. 1층 2호실은 6번핀이 Gnd이고 4번핀은 LOW 상태일때 입니다. 좀 햇갈리 수 있는데 내부풀업저항 모드일대는 초기 스위치 값은 HIGH(1)인 상태가 되고 스위치를 누르면 전류가 흘러 가기 때문에 해당 4번핀은 LOW(0) 상태가 됩니다. 결론은 1층 2호실 스위치를 누르면 6번핀이 Gnd일때 4번핀의 입력핀이 LOW일때입니다.

이걸 어떻게 찾아내느냐 하면

  for(int y=0;y<rows;y++){
    digitalWrite(rowPins[y], LOW);   
    for(int x=0;x<cols;x++){     
        if(!digitalRead(colPins[x]))val = keys[y][x];
    }        
    digitalWrite(rowPins[y], HIGH);      
  
  }

2중 for문을 이용해서 각 층별에 대한 해당 호별로 순차적으로 체크하면 됩니다. 초기로 모든 층은 HIGH 상태로 세팅한 후에
1층(LOW)부터서 1호실, 2호실, 3호실, 4호실 체크해서 스위치가 눌러졌는지 확인한 뒤에 1층은 HIGH로 다시 잠궈집니다.
2층(LOW)부터서 1호실, 2호실, 3호실, 4호실 체크해서 스위치가 눌러졌는지 확인한 뒤에 2층은 HIGH로 다시 잠궈집니다.
...
이렇게 초기값으로 각 층은 HIGH로 해놓으면 LOW로 된 층의 각 호실만 체크할 수 있게 됩니다.

설명이 어려울 수 있는데 쉽게 말해서 HIGH은 각 층이 닫혀진 상태이고 LOW되면 LOW된 층이 개방되게 됩니다.

만약에 각 층이 전부다 LOW라고 생각해보세요. 가령 2층 1호실을 눌렀습니다. 그러면 5번 핀은 digitalRead(5)핀의 값은 LOW가 됩니다. 하지만 누른 위치가 1층 1호실인지 2층 1호실인지 알 수 없게 됩니다. 만약 for문이 1층부터 체크한다면 1층 1호실에서 출력값이 LOW되기 때문에 1층 1호실로 인식하게 되고 만약에 for문이 4층부터 순차적으로 체크했다면 4층 1호실에서 LOW가 되기 때문에 4층 1호실로 인식하게 됩니다.

각 층을 체크할때는 체크하는 층만 LOW가 되고 나머지 층은 HIGH로 잠궈놔야 됩니다.

이해가 안되시면은 그냥 HIGH일때 잠겨지고 LOW일때 열린다고 생각하시면 되겠습니다. 이게 스위치에 전류의 흐름을 이해하면 쉽게 이해되는데 약간 설명이 어렵네요.

만약 1층(6번)이 HIGH일때 1층 1호실을 누르나 안누르나 1층 1호실 digitalRead(5)의 출력값은 무조건 HIGH입니다. 스위치를 누른다고 LOW되지 않습니다. 1층(6번) 핀이 LOW일때 누른 호실의 digitalRead(호실)의 출력값이 그제서아 LOW 됩니다.
풀업저항스위치버턴의 기본 동작을 이해하셔야 이 원리를 이해하실 수 있습니다.

2. 회로도 구성


  • 준비물 : 스위치버턴 16개, 아두이노우노
  • 내용 : 키를 누르면 그 값을 시리얼모니터로 출력할거기 때문에 간단히 회로도 구성함.


선 연결만 주의하시면 그럽게 어렵지 않습니다.

3. 코딩


  • 사용함수 : Serial.begin(), Serial.println(), keypad.getKey()
  • 내용 : Keypad에 누른 값을 아두이노 IDE의 시리얼 모니터로 간단히 출력하자.
  • 참고출처 : http://playground.arduino.cc/Code/Keypad

복습

  • Serial.begin(9600) : 시리얼 통신 시작
  • Serial.println(출력값) : 출력값을 시리얼 모니터로 출력
  • keypad.getKey() : 키값 읽기

그외 함수들은 참고출처에 가셔서 한번 읽어보시길 바래요.

설계

  1. 스위치 버턴으로 읽기
  2. 아두이노 IDE 시리얼모니터로 키 값 출력한다.

코딩을 전체적으로 하면

#include <Keypad.h>

const byte rows = 4; //four rows
const byte cols = 4; //four columns

byte rowPins[rows] = {9,8,7,6};
byte colPins[cols] = {5,4,3,2};

char keys[rows][cols] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};

Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, rows, cols);

void setup(){
  Serial.begin(9600);  
}

void loop(){
  
   char key = keypad.getKey();

   if (key != NO_KEY){      //키값이 눌렀는지 확인문
      Serial.println(key);
   }
}

4. 라이브러리 없이 코딩


스위치버턴 Keypad에서 설명한 방식으로 코딩을 하면 제블러그에 있던 코딩인데 그대로 인용합니다. 로직을 자세히 살펴보시면 이해가 되실꺼에요.

const byte rows = 4; //4 rows
const byte cols = 4; //4 columns

byte rowPins[rows] = {9,8,7,6};
byte colPins[cols] = {5,4,3,2};

 char keys[rows][cols] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};

void setup(){
  Serial.begin(9600);
  
  for(int i=0;i<rows;i++){
    pinMode(rowPins[i], OUTPUT);
    digitalWrite(rowPins[i], HIGH);   // 각층 초기화로 잠금
  }
  for(int i=0;i<cols;i++){
    pinMode(colPins[i], INPUT_PULLUP); //각호실 내부풀업저항모드로 읽기
  }  
}

void loop(){
  
  char val = '\0';
 
  for(int y=0;y<rows;y++){
    digitalWrite(rowPins[y], LOW);   //해당층 개방
    for(int x=0;x<cols;x++){     
        if(!digitalRead(colPins[x]))val = keys[y][x];
    }        
    digitalWrite(rowPins[y], HIGH);  //해당층 잠금
  
  }

 if(val!='\0'){
    Serial.println(val);
   delay(300);
 }      
}

5. 결과


선 배치가 제일 귀찮았네요.


마무리


오늘은 Keypad를 스위치버턴으로 대신 했습니다. 그리고 라이브러리 없이 직접 코딩을 사용하여 동작을 제어 했네요.

스위치버턴에서 층과 호실에 관한 전류 흐름의 체크에 대해서 꼭 이해해 주세요. 왜냐면 나중에 응용편에서 거론한 3x3x3 LED CUBE에 원리가 같습니다.

원래 LED 제어를 한뒤에 응용편으로 미리 다루어야 했는데 응용편이고 코딩쪽이여서 다소 어려울 수 있어서 스위치버턴에서 먼저 그 원리를 사용하게 되었네요.
꼭 층과 호실의 관계를 이해해 주세요. 입력을 층과 호실로 받았지만 반대로 출력을 층과 호실로 보낼 수 있습니다. 그게 바로 3x3x3 LED CUBE의 기본 원리입니다.

이 원리를 깨우치면 진짜 화려하고 재밌는 작품을 만들 수 있으니깐 꼭 이해해 주세요.

궁금하시면 구글검색으로 3x3x3 LED CUBE를 쳐보세요 만들고 싶은 충동이 느껴질꺼에요.


댓글()

[아두이노] Keypad 제어

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

[아두이노] Keypad 제어



오늘은 간단히 KeyPad를 사용하는 법을 살펴보도록 하겠습니다. 아두이노 선 연결하는 것은 별로 어렵지 않습니다. 그리고 Keypad 라이브러리만 잘 연결하면 딱히 사용하는 것도 어렵지 않고 쉽게 사용 가능합니다. 이번 포스팅은 아주 간단한 내용입니다.

1. KeyPad



총 8개의 핀으로 구성되어 있으며 내부 구조는 다음 포스팅에 설명하겠지만 우선은 간단히 가로4핀 x 세로4핀으로 선이 연결되었다고 생각하시면 됩니다. 4x4로 행과 열을 나타낸다고 생각하시면 됩니다. 우선 배열로 KeyPad[4][4]로 생각하시면 될 듯요.
핀 연결은 아두이노 디지털핀 아무곳이나 8핀을 연결하시면 돼요.

2. 회로도 구성


  • 준비물 : KeyPad, 아두이노우노
  • 내용 : 키를 누르면 그 값을 시리얼모니터로 출력할거기 때문에 간단히 회로도 구성함.


진짜로 간단하지요. 그냥 순서대로 0부터 7핀으로 아두이노에 그냥 Keypad를 붙이여 연결되어 버립니다. 하지만 그렇게 하지 않고 2번핀부터 연결했습니다. 왜냐면 시리얼통신으로 그 결과를 출력하기 때문에 시리얼통신을 담당하는 0, 1핀 때문에 Keypad가 0, 1핀에 연결된 위치값이 가상시뮬레이터에서 작동을 하지 않습니다. 그래서 어쩔 수 없이 회로도 그림처럼 연결해야겠죠.

3. 코딩


  • 사용함수 : Serial.begin(), Serial.println(), keypad.getKey()
  • 내용 : Keypad에 누른 값을 아두이노 IDE의 시리얼 모니터로 간단히 출력하자.
  • 참고출처 : http://playground.arduino.cc/Code/Keypad

복습

  • Serial.begin(9600) : 시리얼 통신 시작
  • Serial.println(출력값) : 출력값을 시리얼 모니터로 출력
  • keypad.getKey() : 키값 읽기

그외 함수들은 참고출처에 가셔서 한번 읽어보시길 바래요.

설계

  1. KeyPad 읽기
  2. 아두이노 IDE 시리얼모니터로 키 값 출력한다.

KeyPad를 사용하기 위해서는 가상시뮬레이터에서는 제공됩니다

#include <Keypad.h>

Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, rows, cols);

이렇게 KeyPad 클래스의 변수를 선언합니다.

Keypad(makeKeymap(keys), rowPins, colPins, rows, cols);
Keypad(키값배열, 열핀, 행핀, 열수, 행수);

Keypad의 출력할 키값 keys[4][4]로 전부 사용할 예정입니다. 그 값을 생성자 함수를 통해서 사전에 미리 만들어 놓게 됩니다. 즉, Keypad를 누른다고 알아서 그 값을 찍어주는게 아니라 출력할 값을 미리 지정해놓은 출력값과 사용할 행과 열의 핀과 행과 열의 숫자를 Keypad 객체변수를 선언할때 인자로 넘겨주게 됩니다.

이렇게 함으로써 특정 행과열 위치의 key를 누르면 keys[4][4] 해당된 위치의 값을 출력으로 나오게 됩니다.

여러 함수들이 있는데 여기에서는

keypad.getKey();

이 함수를 통해서 눌러진 키 값을 읽어오게 됩니다.

코딩을 전체적으로 하면

#include <Keypad.h>

const byte rows = 4; //four rows
const byte cols = 4; //four columns

byte rowPins[rows] = {9,8,7,6};
byte colPins[cols] = {5,4,3,2};

char keys[rows][cols] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};

Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, rows, cols);

void setup(){
  Serial.begin(9600);  
}

void loop(){
  
   char key = keypad.getKey();

   if (key != NO_KEY){      //키값이 눌렀는지 확인문
      Serial.println(key);
   }
}

4. 결과


그냥 선만 대충 순서대로 연결하면 끝나고 그 결과는 위 코딩을 복사해서 시뮬레이터를 돌리면 아두이노 IDE 시리얼모니터에 키값이 출력되는걸 확인하실 수 있을꺼에요.

마무리


오늘은 Keypad를 라이브러리를 사용해서 Keypad 클래스 변수를 선언하고 이 클래스 안에 키를 읽어오는 함수를 이용해서 키가 눌렀을때 키값을 가져오게 됩니다.

그냥 선 연결을 잘하고 Keypad 클래스 변수 선언과 읽을 함수명만 기억하시면 쉽게 Keypad를 사용하실 수 있을꺼에요.

이걸 이용하면 가령 LCD16x2에 붙이면 키로 누른걸 LCD16x2로 출력시킬 수 있겠죠. 그러면 계산기를 만들고 싶은 충동이 안느껴지나요. LCD16x2 (LiquidCrystal) 제어(아두이노) 이걸 다시 보시고 회로도를 수정하시고 계산기를 한번 연구를 해보세요.


댓글()

[아두이노] GAS Sensor

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

[아두이노] GAS Sensor



이제 다시 쉬운 주제로 Gas Sensor를 다루는 것을 배워 보도록 하겠습니다. 가상시뮬레이터에서 GAS Sensor는 좀 회로도 연결해야하는 핀이 많아서 불편할 수 있을꺼에요. 만약 실제로 MQ-2 같은 센서를 사용하면 핀 연결이 쉬울 수 있는데 가상시뮬레이터에서 실험해야하기 때문에 약간은 불편함을 감수해야 할 듯요. 암튼 회로도 구성만 좀 어려울뿐 나머지는 코딩은 쉬우니깐 간단히 원리만 이해하시고 넘어가시면 됩니다.

1. GAS Sensor



어느방향이든 상관없이 한쪽 방향이 Vcc이면 반대편 방향이 Gnd 쪽으로 연결하고 한개만 GAS 측정값을 출력하는 핀으로 사용하면 됩니다. 대충 실험에서는 그림에서 볼때 하단을 Vcc로 3핀을 전부 열결했으며 상단 왼쪽핀 저항을 붙여서 Gnd로 연결하고 가운데는 Gnd 연결 오른쪽을 출력핀으로 사용하였습니다. 햇갈리시면 회로도 구성을 살펴보시면 됩니다.


실제 MQ-2 모델을 구입해서 많이 사용하는데 위 그림을 자세히 살펴보면 Gnd, DO, AO, Vcc 핀으로 구성되어 있습니다. 출력핀이 2개인데 디지털 출력이나 아날로그 출력이냐로 구분되는데 디지털이든 아날로그든 하나를 선택하고 나머지 Vcc, Gnd를 사용하여 총 3핀만 아두이노우노에 연결해서 실험하시면 됩니다.

하지만 가상시뮬레이터에서는 총 6핀으로 구성되고 핀 연결을 어쩔 수 없이 복잡하지만 회로도를 만들어야 겠죠.

2. 회로도 구성


  • 준비물 : GAS Sensor, 저항 1K옴 1개, 아두이노우노, 뻥판
  • 내용 : 간단히 GAS 측정하여 IDE 시리얼 모니터로 측정된 값을 출력하도록 설계


회로도를 보면 간단합니다. 회로도에서 위아래가 반대로 연결해도 됩니다. 참가로 가운데 핀은 고정이고요 사이드 핀은 저항을 세번째로 옮기고 A0핀을 입력받는 핀을 GAS Sensor 첫번째로 핀으로 연결해도 됩니다. 쉽게 가운데 핀은 고정이고 위아래는 한쪽 방향으로 Vcc, Gnd로 나뉘고 양쪽 사이드 핀은 서로 바꿀 수 있다는 것만 알아 두시면 됩니다.

그리고 참고하셔야 할 것은 GAS Sensor에 연결된 저항r값에 따라서 측정되는 값이 달라집니다. 한번 나중에 시뮬레이터를 돌릴때 저항값을 바꿔 보세요.

3. 코딩


  • 사용함수 : Serial.begin(), Serial.println(), analogRead()
  • 내용 : GAS Sensor에서 측정된 값을 아두이노 IDE의 시리얼 모니터로 간단히 출력하자.

복습

  • Serial.begin(9600) : 시리얼 통신 시작
  • Serial.println(출력값) : 출력값을 시리얼 모니터로 출력
  • analogRead(아날로그핀) : 아날로그 값을 읽음

설계

  1. GAS Sensor의 값을 읽자.
  2. 아두이노 IDE 시리얼모니터로 GAS 값 출력한다.

코딩을 전체적으로 하면

void setup() {
  Serial.begin(9600);
}

void loop() {  
  Serial.println(analogRead(A0));
  delay(1000);
}

4. LCD16x2로 GAS Sensor 값을 출력해보자.



지난 시간에 다뤘던 LCD16x2로 출력을 한다면 어떻게 해야 할까요. 지난 포스팅한 참고자료에 보시면 됩니다. 여기서 필요한 것은 지난 코딩 소스에서 출력값을 analogRead(A0)만 삽입하면 그냥 간단히 해결 됩니다. 원래는 변수를 선언하고 변수에 저장된 값을 출력해야 하는데 정석이지만 최대한 코딩로직을 출이고 원리만 전달하는 목적으로 표현한 점을 이해해 주세요.

회로도 보면


LCD16x2 회로도와 오늘 포스팅한 GAS Sensor 회로도를 하나로 결합한 형태입니다.

코딩도 합치면

#include <LiquidCrystal.h>

//LiquidCrystal(rs, enable, d4, d5, d6, d7) 
LiquidCrystal lcd(3, 4, 9, 10, 11, 12);

void setup()
{
  lcd.begin(16,2);
  lcd.setCursor(0, 0);
  lcd.print("Hello World");
  delay(1000);
  lcd.clear();
}
void loop() {
  lcd.setCursor(0, 1);
  lcd.print("Sensor : ");
  lcd.setCursor(10, 1);
  lcd.print(analogRead(A0));   
  delay(20);      
  lcd.print("            ");   
}

간단히 이부분에 analogRead(A0) 함수만 추가되었네요. " "로 공백문자를 출력시킴으로 지우는 효과를 부여 했습니다. 가상시뮬레이터에서 lcd.clear()함수를 사용할때 좀 문제가 있어서 출력한 라인을 공백문자로 덮여서 지우는 효과를 대신했습니다.

  lcd.print(analogRead(A0));
  delay(20); 
  lcd.print("            ");  

참 쉽죠.

5. 결과


실험 영상은 GAS Sensor 실험과정의 내용만 담았습니다. 그리고 LCD16x2로 출력하는 실험결과를 마지막에 시뮬레이터 결과만을 영상에 포함 시켰습니다.


마무리


GAS Sensor는 거실이나 부엌 천장에 보면 가정집마다 다 붙어 있는 걸 확인 확인 할 수 있을꺼에요. 가스 검침원이 오면 측정기로 GAS가 새는지 확인하는 경우도 경험 하셨을꺼에요. 일상에서 자주 사용되는 부품이지요. 단순히 수치로 시리얼모니터로 출력을 하고 복습차원으로 LCD16x2로 출력 실험을 했습니다.

여기서 측정된 수치값을 기준을 정하여 위험수치가 되면 경보기가 울리게 한번 설계해 보세요. 피에조부저를 연결 하시면 경보기를 쉽게 만들 수 있겠죠.

[아두이노] 피에조부저 제어 포스팅의 내용을 오늘 배운 회로도에 추가하여 경보기를 만들어 보세요.


댓글()

[아두이노] 타이머를 이용한 인터럽트(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() 함수가 실행 되게 설계를 한번 해보세요.


댓글()