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


댓글()

[아두이노] 인터럽트(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초 단위로 깜박입니다. 인터럽트가 어떤 느낌인지 잘 생각해보세요.

마무리


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

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


댓글()

[아두이노] 기울기센서(Tilt Sensor) 제어

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

[아두이노] 기울기센서(Tilt Sensor) 제어



오늘도 쉬운 난이도로 기울기센서를 이용한 실험을 다루겠습니다. 기울기센서는 기울기에 따라서 연결되고 끊어지는 두가지 상태를 나타내고 그 상태값을 기준으로 스위치 역활로 수행 할 수 있습니다. 실험에서는 스위치 역활로 기울기에 따라서 Red LED에 불이 들어오고 꺼지는 동작 제어를 통해 Title Sensor를 이해하는 시간을 갖도록 하겠습니다.

1. 기울기센서(Tilt Sensor)



Tilt Sensor는 안에 들어있는 전류를 흐를 수 있는 물질이 들어 있어서 기울기에 따라 센서안에 두 단자를 연결하거나 끊어지게 할 수 있습니다. 가상시뮬레이터에서 수평과 기울기 모양을 나타내는 조절이미지가 있는데 이걸로 Tilt Sensor를 조절하고 출력은 스위치버턴과 동일하게 출력값을 얻으시면 됩니다.

2. 기울기센서(Tilt Sensor) 동작 모습


수평기울어질때

그림에서 보는것과 같이 기울어질때 값을 기준으로 Red LED에 불이 들어오게 됩니다. 스위치 버턴 제어(아두이노)의 실험예제에서 스위치 버턴위치에 Tilt Sensor가 바뀌었을뿐 동일한 예제입니다. 어떤 동작을 하는 센서인지 대충 감이 잡히셧을꺼에요.

1. 회로도 구성


  • 준비물 : LED 1개, 저항 220옴 1개, 저항 10k옴 1개, Tilt Sensor 1개, 아두이노우노, 뻥판
  • 내용 : Tilt Sensor를 통해 기울어지는 상태값을 Red LED로 출력하게 하자.

(1) 기본(2) 내부풀업모드

두가지 형태로 표현해 볼 수 있습니다. 스위치버턴 예제를 다시 보시고 한번 풀다운모드 형태로 회로도를 한번 디자인 해보세요.

3. 코딩



복습

  • pinMode(사용핀, OUTPUT) : 사용핀은 출력모드
  • digitalWrite(사용핀, 상태) : 디지털출력핀에 상태가 HIGH(5V) or LOW(0V)를 선택한다.
  • digitalRead(사용핀) : 전기신호를 입력받는다.

설계

  1. Tilte Sensor에서 수평과 기울어졌을때의 값을 읽어들인다. => digitalRead(입력핀)
  2. 그 읽은 신호값을 기준으로 Red led에 불이 들어오게 한다. =>
    if(입력값==LOW) digitalWirt(출력핀,HIGH);
    else digitalWirt(출력핀,LOW);

코딩을 전체적으로 하면

(1) 기본 코딩은

void setup()
{
  pinMode(13, OUTPUT);      
  pinMode(7, INPUT);    
}

void loop()
{     
   if(digitalRead(7)==LOW) digitalWrite(13, HIGH);       
   else digitalWrite(13, LOW);     
}

(2) 내부풀업 코딩은

void setup()
{
  pinMode(13, OUTPUT);      
  pinMode(7, INPUT_PULLUP);    
}

void loop()
{     
   if(digitalRead(7)==LOW) digitalWrite(13, HIGH);       
   else digitalWrite(13, LOW);     
}

둘 차이는 PinMode() 함수에서 입력모드만 변경해주면 된다. 코딩 로직은 따로 수정할 게 없다.

5. 결과


간단히 디자인 하는 모습과 실행 결과를 만들어 놨으니 한번 보시고 따라 해보세요.

마무리


Tilte Sensor의 동작 제어를 해보았습니다. PIR Sensor는 두가지 상태값으로 스위치 역활을 이번 실험에서 실행해 보았습니다. 여기에 피에조부저를 부착해서 소리를 만들어 내면 경보기도 될 수 있겠죠. 아니면 어떤 물체의 특정 대상이 될때 대상이 된 물체가 기울어졌는지 수평인지를 체크하는 용도로도 사용할 수 있겠죠.

한번 기울기센서를 이용해서 어디에 적용해 볼까 상상의 나래를 펼쳐보세요.


댓글()

[아두이노] 인체감지 센서(PIR Sensor) 제어

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

[아두이노] 인체감지 센서(PIR Sensor) 제어



오늘은 좀 난이도 낮춰서 쉬운 인체감지 센서(PIR Sensor) 작동원리를 배워 보도록 하겠습니다. 흔히 아파트 통로나 현관문에 저녁때 들어서면 잠시 조명에 불이 들어오는걸 많이 경험해 보셨을 꺼에요. 그리고 자세히 보면 둥근 모양의 물체가 부착되어 있는 것을 아마 한번쯤은 보셨을 거라 생각됩니다. PIR Sensor는 사람이나 동물의 움직임을 감지하는 센서입니다. 이 감지된 신호를 가지고 아두이노에서 실험를 해보겠습니다.

1. 인체감지 센서(PIR Sensor)




가상시뮬레이터에서 제공되는 PIR Sensor에는 총 3개의 핀이 있습니다. 어떤 센서이든 전원을 담당하는 Vcc, Gnd핀과 출력을 담당하는 Signal 핀으로 대부분 구성되어 있습니다. 여기서 PIR Sensor에서 인체의 움직임을 감지하면 전기신호로 Signal핀을 통해 출력된다는 것을 기억해 두세요. 인체의 움직임 감지되면 전기신호값은 하나의 전류값으로 가상시뮬레이터에서 거의 5V의 가까운 신호값이 발생하고 움직임이 없으면 0V로 고정됩니다. 즉, 인체가 감지되면 전류가 흐르고 인체가 감지되지 않으면 전류가 흐르지 않는 2가지 상태값이 Signal에서 발생하는 것이죠.

2. 인체감지 센서(PIR Sensor) 동작 모습


작동중움직임감지



그림에서 보는 것 처럼 움직임이 감지 되면은 Red Led에 불이 들어오게 됩니다. 계속 들어오는게 아니라 일정시간동안 들어왔다가 다시 꺼지게 됩니다.

1. 회로도 구성


  • 준비물 : LED 1개, 저항 220옴 1개, PIR Sensor 1개, 아두이노우노
  • 내용 : PIR Sensor를 통해 움직임이 감지되면 그 결과를 LED로 출력


최대한 원리 실험을 목적으로 단축표현한 회로도 입니다. 위에서 인체 감지 센서 동작과 같은 표현입니다. 구지 아두이노를 사용할 필요는 없지만 중요한것은 이 신호값을 받으면 아두이노에서 LED로 특정 동작을 수행하게 했다는 것에 실험의 목적입니다. 즉, A라는 신호를 받아서 B라는 동작을 지시한다란 개념을 머리속에 넣어 두세요.

3. 코딩


  • 사용함수 : pinMode(), digitalWirte(), analogRead()
  • 내용 : PIR Seneor를 통해 움직임을 감지되면 Red LED에 불이 잠시 들어오게 한다.
  • 참고 : [아두이노]LED 제어

복습

  • pinMode(사용핀, OUTPUT) : 사용핀은 출력모드
  • digitalWrite(사용핀, 상태) : 디지털출력핀에 상태가 HIGH(5V) or LOW(0V)를 선택한다.
  • analogRead(사용핀) : 아날로그신호를 입력받는다.
  • delay(시간) : 1000은 1초

설계

  1. PIR Sensor에 움직임이 감지되면 아두이노에서 그 신호 값을 읽는다.
  2. 그 신호값이 입력되면 Red LED에 불이 들어오게 한다.

코딩을 전체적으로 하면

void setup()
{
  pinMode(13, OUTPUT);  
}

void loop()
{
  digitalWrite(13, analogRead(A0)); 
  delay(10); 
}

디지털핀은 입력/출력모드를 선언해야하지만 아날로그 입력은 구지 선언 안해도 됩니다. 입력전용으로 쓰기 때문에 그렇습니다. 만약에 출력모드로 아날로그 입력핀을 사용할 경우는 pinMode()에서 선언하여 디지털핀처럼 사용이 가능합니다.

여기서,

digitalWrite(13, analogRead(A0)); 

이렇게 표현한 이유는 digitalWrite(13,1) or (digitalWrite(13,1023) 이든 상관없이 0이 아닌 정수로 참임으로 전부다 5V가 출력이 됩니다. digitalWirte(13,0)이여야만 0V가 출력되고 그 외는 다 5V만 출력된다는 점을 이용해 코딩량을 대폭 줄였습니다. 즉, digitalWirte()출력은 0이 아니면 모든 숫자는 참으로 5V가 출력되고 0만 0V가 출력됩니다.
원래 이렇게 코딩하면 안됩니다. 그냥 억지로 끼워 맞춘 코딩입니다. 원래는 입력된 값을 기준으로 해서 if 조건문을 세우고 그 조건문을 기준으로 Red LED를 일정시간 동안 딜레이를 줘서 아파트 복도나 현관문처럼 좀 긴 시간을 줘서 비슷한 효과를 부여할 수 있지만 오늘 포스팅은 PIR Sensor의 원리를 이해하는게 목적임으로 최대한 줄여서 그 의미만 전달하고자 표현한 코딩이라는 점을 참고하세요.

5. 결과


이 실험을 할 당시 가상시뮬레이터 사이트에 아두이노 컴파일러가 버그가 발생해서 동영상 촬영을 포기했는데 올리기전에 다행히 사이트 복구가 되어 정상적으로 간단히 실험했네요. 최대한 코딩을 줄여서 복잡한 부분을 줄여 이해도를 높였네요. 간단한 코딩과 결과만 쉽게 실험했으니 이번 포스팅 내용은 쉬울꺼에요.


마무리


PIR Sensor의 동작 제어를 해보았습니다. PIR Sensor는 아파트 복도나 현관문에 조명을 제어하는 목적으로 사용할 수 있지만 여기에 피에조부저를 부착하여 소리를 발생시키면 어떻게 될까요. 바로 경보기로도 만들 수 있겠죠. 그렇다면 여러분들은 PIR Sensor로 인체 감지를 할 수 있으면 어떤걸 해보고 싶으신가요.

한번 상상의 나래를 펄쳐보세요.


댓글()

[아두이노] LCD16x2 I2C(LiquidCrystal_I2C) 제어

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

[아두이노] LCD16x2 I2C(LiquidCrystal_I2C) 제어



어제 가상시뮬레이터에서 LCD 16x2를 제어를 해보았는데 오늘은 실제 LCD 16x2 I2C을 이용해서 동일한 코딩 로직으로 결과를 출력하는 실험을 해보겠습니다. 사실 LCD 16x2를 가지고 있어 그것도 보여드리면 좋았겠지만 그냥 편하게 실험하기 위해서 LCD 16x2 I2C를 사용해서 실험 했네요.

1. LCD 16x2 I2C



LCD 16x2 I2C의 뒤면 검은색 모듈이 추가되어 있는데 I2C 통신을 하기 위한 모듈입니다. 간단히 4핀으로 구성되어 있으면 아두이노에 연결할때도 그리 어렵지 않게 연결할 수 있습니다.


제가 소유한 LCD 16x2와 LCD 16x2 I2C 인데 보는것 같이 핀 4개짜리를 사용하는게 훨 편하겠죠.

LCD 16x2 I2C 핀 4핀으로 구성

  • Gnd
  • Vcc(5V)
  • 데이터핀(A4)
  • 클럭핀(A5)

LCD 16x2 I2C의 뒷면에 보시면 적혀있기 때문에 쉽게 연결 할 수 있습니다.

LCD 16x2 I2C 주의사항

  • 부품마다 주소가 다를 수 있다. : 제가 사용한 부품의 주소는 LiquidCrystal_I2C 라이브러리 에서 이 클래스를 사용하기 위해서 사용하는 LCD 16x2 I2C의 주소값이 필요한데 처음에 작동을 안해서 불량품인 줄 알았어요. 구글링해서 주소가 따로 있고 다르면 출력이 안된다는 사실을 나중에 알게 되었죠.
  • 가변저항을 조설해야 한다. : 파란색 작은 사각모형에 십자나사 모양이 있는데 첨에는 한쪽으로 감겨져 있어서 이걸 돌릴 생각없이 LCD에 불이 안들어와서 불량품인 줄 알고 삽질을 한 기억이 있네요. 이걸 돌려서 밝기를 조절해야하는데 처음 만질때는 생각을 못했네요.

LCD 16x2 I2C 주소 확인법

아두이노에서 I2C에 잡혀있는 주소를 알아볼 수 있습니다. 예제가 있으니 그걸 복사하셔서 자신이 사용하는 부품의 주소를 확인하시면 됩니다.

LCD 16x2 I2C 데이터 시트

이곳에 가셔서 LCD 16x2 I2C의 데이터 시트를 확인하시면 됩니다. 아주 간단하게 소개되어 있어서 보기 편할꺼에요. 이곳에 가시면 이표가 있는데 LCD 16x2 I2C 주소가 어떻게 지정되는지 확인 할 수 있습니다.


위에 LCD 16x2 I2C 뒤면 사진에서 파란사각모양(가변저항) 밑에 3개의 작은 사격형 모양으로 모듈 회로에 표시되어 있을꺼에요 각각 A0, A1, A2로 납땝이 어떤식으로 되어 있느냐에 따라서 주소가 바뀌게 됩니다. 인두가 있는분들은 주소를 변경해 볼 수 있겠죠. 그런데 별로 추천드리지 않고요 그냥 만들어져 있는 형태로 실험하세요.

하지만 2개이상을 쓸때 같은 주소인데 2개가 다른 용도로 개별적으로 출력을 하고자 할때는 한개 주소를 변경해줘야 겠죠. 변경해주면 해당주소에 해당값만 출력되게 됨으로 여러개를 같은 라인에 연결하여 사용할 수 있겠죠.

2. 회로도 구성


  • 준비물 : LCD 16x2 I2C 1개, 아두이노우노
  • 내용 : LiquidCrystal_I2C 라이브러리를 사용하며 값을 출력하기 위해서 LCD 16x2 I2C 회로도를 표현을 하자.


상단에 표시한 아무것도 적혀있지 않는 핀 두개가 있습니다. 거기 핀은 A5, A4라고 참고로 알아두시면 돼요. 위로 연결을 하던 아래로 연결을 하던 동일하니깐 아무곳이나 연결하세요.

3. 코딩



LiquidCrystal 함수

LiquidCrystal_I2C lcd(0x3F,16,2);  // 0x27 or 0x3F
  • LiquidCrystal_I2C lcd(주소,가로,세로) : LCD 16x2 I2C 부품의 주소와 출력사이즈값을 지정합니다.

이전 실험해서는 LiquidCrystal(rs, enable, d4, d5, d6, d7) 함수만 사용하였지만 LiquidCrystal_I2C클래스에는 생성자 함수 인자가 주소랑 가로x세로 값을 던져 줍니다. LiquidCrystal 클래스처럼 함수 선택장애는 없겠죠. 그외 함수들은 대충 비슷함으로 생략합니다.

설계는 이전 LCD16x2 (LiquidCrystal) 제어(아두이노) 소스랑 동일합니다. 동일한 형태로 진행했습니다.

혹시 함수를 자세히 보고 싶으시다면https://github.com/marcoschwartz/LiquidCrystal_I2C 가셔서 LiquidCrystal_I2C.h 파일을 살펴보세요. 그리고 함수 내부동작을 자세히 보기 위해서는 LiquidCrystal_I2C.cpp 파일을 열어보시면 됩니다.

코딩을 전체적으로 하면

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
 
LiquidCrystal_I2C lcd(0x3F,16,2);  // 0x27 or 0x3F

void setup()
{
  lcd.init(); //초기화
  lcd.backlight(); //배경불켜기
  lcd.setCursor(0, 0);
  lcd.print("Hello World");
  delay(1000);
  lcd.clear();
}

void loop() {
  lcd.setCursor(0, 1);
  lcd.print("COUNT : ");
  for(int i=0;i<10;i++){ 
    lcd.setCursor(9, 1);
    lcd.print(i);    
    delay(1000);    
  }    
}

4. 라이브러리 추가하기


우선 LiquidCrystal_I2C 라이브러리를 사용하기 위해서는 아두이노 IDE에 라이브러리로 등록해 줘야 합니다. 나중에 다른 부품을 사용할때도 이 과정을 계속 수행해야 하기 때문에 잘 알아 두세요.

  • PC에 아두이노 IED 설치된 경우


라이브러리 관리를 누르고 검색어로 LiquidCrystal_I2C를 치시면 설치가능한 라이브러리 파일들이 나타납니다. 이렇게 설치해도 되고요 구글링하셔서 해당 라이브러리파일을 다운 받은 후 .zip 라이브러리추가하시면 됩니다. 그러면 파일->예제 열기가 있는데 추가되어 있을꺼에요. 그 예제로 실험하셔도 됩니다.

  • RaspberryPi3에다 아두이노 IED를 설치된 경우

제가 RaspberryPi3에 아두이노 IED를 설치해서 아두이노를 원격으로 실험하고 있는데요. 문제는 라이브러리 관리 항목이 없어서 일일히 다운 받아야 하는게 귀찮더군요.

구글 검색을 통해 해당 라이브러리 파일이 있는 GitHub 경로를 찾아야 합니다.


이렇게 페이지에 들어가면 Clone or download를 클릭하시면 경로가 나오고 그걸 복사를 합니다. 그리고 라이브러리파일을 저장할 디렉토리를 만든 후 그 위치에서 다운받습니다.

git clone https://github.com/marcoschwartz/LiquidCrystal_I2C.git

그리고 나서 아두이노 IED에서 Add Libray... 를 눌러 다운받았던 경로의 라이브러리파일을 등록해야 사용할 수 있습니다.


파일->예제 누르니 3개의 샘풀 예제가 등록되어 있네요. HelloWorld 예제로 실험하시거나 아니면 위 코딩으로 정상적으로 출력되는지 복사하셔서 실험하시면 됩니다.

5. 결과


동영상 결과는 간단히 실제 결과만 출력되는 걸 보여줍니다. 여기에 코딩된 것은 실행 시키고 달려가서 아두이노우노가 있는 위치까지 가서 촬영을 해야 했기 때문에 "Hellow World"의 출력 메시지를 최대한 딜레이 시간을 준 코딩으로 촬영 했네요.

마무리


오늘은 가상시뮬레이터에서는 실험 할 수 없습니다. 어제 LCD 16x2 로 출력은 가능했지만 실제 LCD 16x2 I2C가 가상시뮬레이터에는 없기 때문에 아쉽게도 오늘 실험은 실제 아두이노 부품이 있는분만 가능할 듯 싶네요.

대충 이런식으로 제어를 한다는 것만 보여 드렸으며 자세한 함수 설명은 생략했습니다. 계속 가상시뮬레이터 실험을 주된 실험으로 이루어지기 때문에 가상시뮬레이터에만 초점을 두겠습니다.

이제 LCD 16x2 로 출력을 할 수 있게 되면은 측정센서 부품을 사용할때 그 결과를 LCD 16x2로 출력시키면 좀 더 재미 있겠죠.


댓글()

[아두이노] LCD16x2 (LiquidCrystal) 제어

IOT/아두이노|2019. 2. 24. 17:07

[아두이노] LCD16x2 (LiquidCrystal) 제어



오늘은 LCD 16x2 에 값을 출력하는 실험입니다. 회로도는 arduino.cc에서 제공되는 샘플을 그대로 따라 실험을 하였습니다. 저도 LCD 16x2 부품을 사용할때마다 이전에 실험했던 디자인을 찾아서 보고 회로도를 표현만드네요. 우선 사용하는 핀이 많아서 좀 햇갈리고 잘못 표현할 수 있어서 그냥 예제의 표현을 기반으로 가상시뮬레이터로 정상적으로 결과가 나오는지 실험해 보는걸로 하겠습니다.

1. LCD 16x2



15, 16핀은 백그라운드 밝기라서 220옴을 달았더군요. 1번 Gnd, 2번 Vcc, 3번 Vo로 여기에 출력 글자의 밝기가 결정되더군요.
DB0~7까지 데이터 핀이고, 나머지 RS, R/W, Enable핀으로 구성되어 있습니다.

2. 회로도 구성


  • 준비물 : LCD 16x2 1개, 저항 220옴 1개, 10k 가변저항기 1개, 아두이노우노, 뻥판
  • 내용 : LiquidCrystal(rs, enable, d4, d5, d6, d7) 을 사용하여 값을 출력하기 위해서 16x2 회로도를 표현을 하자.
  • 인용자료 : https://www.arduino.cc/en/Reference/LiquidCrystal(아무 예제나 클릭해도 됨)

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

우선 이 함수를 사용하기 위해서 rs, enable핀과 데이터 데이터 4,5,6,7번 핀을 사용을 해야합니다. 회로도 디자인은 적당한 핀으로 디자인이 깔끔하게 보이게 하기 위해서 3, 4, 9, 10, 11, 12핀에 연결했습니다. 그리고 15(Vcc)번과 16(Gnd)핀이 있는데 15번에 220옴을 붙여서 적당히 백그라운의 밝기를 고정시켰습니다. 그리고 전원으로 1번은 Gnd 2번 Vcc로 연결하는데 3번에 10k 가변저항을 붙여서 글자의 밝기를 조절하도록 배치된 회로도 만들어 보도록 하겠습니다.


우선 가장 심풀하게 표현된건데 사실 실제로 LCD 16x2를 구매하실때 이 부품을 잘 안사고 LCD 16x2 I2C 를 이용합니다. LCD 16x2 뒷면에 I2C모듈이 붙어 있어서 아두이노에서 필요한 핀이 2개뿐이 안필요해서 여러개의 부품 제어때 LCD 16x2 I2C를 주로 사용합니다. 기본 제어 부품들이 LCD 16x2 뒷면에 모듈로 다 붙어 있어서 따로 복잡하게 회로도를 만들 필요가 없어서 많이 사용합니다.


총 4핀에서 전원핀 2개를 제외하면 아두이노에서 사용할 2핀만 연결하시면 됩니다. 힘들데 선을 연결할 필요없이 4개의 핀만 연결하니 실제로 실험할 경우 저 부품을 사서 실험하겠죠. 문제는 가상시뮬레이터에서는 힘들게 선을 다 배치해야 합니다. 하지만 선을 배치함으로 LCD 16x2의 부품에 대해서 보다 자세히 이해할 수 있기 때문에 귀찮아 하지 마시고 한번 디자인 해보세요.

3. 코딩



LiquidCrystal 함수

LiquidCrystal(rs, enable, d4, d5, d6, d7) 
LiquidCrystal(rs, rw, enable, d4, d5, d6, d7) 
LiquidCrystal(rs, enable, d0, d1, d2, d3, d4, d5, d6, d7) 
LiquidCrystal(rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7)

아두이노의 핀 회로도 배치가 달라지겠죠. 실험해서는 LiquidCrystal(rs, enable, d4, d5, d6, d7) 함수만 사용합니다.

그외 함수들

제블러그에서 대충 함수를 요약한 건데 가져왔네요.https://www.arduino.cc/en/Reference/LiquidCrystal 보시면 오른쪽에 함수목록들이 있는데 가서 함수들을 읽어보시면 됩니다. 간단히 요약하면은

begin(가로,세로) => 화면나누기
setCursor(가로,세로) => 커서의 위치
print(출력문자열) => 출력
write(출력문자) => 출력
clear() => 화면지우기
noDisplay() => 끄기
display() => 켜기
scrollDisplayRight() => 오른쪽으로 한칸이동
scrollDisplayLeft() => 왼쪽으로 한칸이동
autoscroll() => 자동으로 왼쪽이동
lcd.createChar(0, 문자배열값) => 직접 문자를 만듬(write(byte(0))출력)

외우지 마시고 대충 정리했다가 LCD 16x2를 사용하실때 이 함수들을 적어놨다가 사용하시면 됩니다.

설계

제 블로그에서 간단히 실험한 예제을 그대로 사용했네요. LCD 16x2에 "Hello World"를 출력해보고 "COUNT : 숫자"로 출력되게해서 카운터를 세보자.

  1. LiquidCrystal를 사용하기 위해서 객체를 선언해야지. 그런데 클래스 보니깐 선언때 생성자함수이네! 사용할 핀을 넘겨줘야 하는군!
  2. 초기작업이 끝났으니 이제 lcd 객체변수로 화면을 16x2로 세팅해야지
  3. 이제 LCD 16x2의 값을 출력할 커서의 위치는 잡아야 줘야지.
  4. "Hello World" 출력해야지
  5. 다음 "COUNT: 숫자"로 카운트를 세면서 값을 출력해야지. 그런데 그냥 출력하면 기존의 쓰여진 값에 덮어씌워지니깐 clear()함수로 화면을 지워야지
  6. "COUNT: 숫자" 숫자를 매번 clear하고 지우기 그러니깐 "COUNT : "한번만 하고 숫자만 갱신하는게 실속 있겠다. 그러면 바로 카운터 숫자가 나오는 위치만 갱신하면 되겠죠. 아까 글자가 출력할 커서의 위치를 지정하는 함수가 있었죠. 그 함수로 숫자의 위치 "COUNT : "은 공백포함 8자리니깐 setCursor(9, 1)를 이용해서 갱신하면 쉽게 표현되겠군.

코딩을 전체적으로 하면

#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("COUNT : ");
  for(int i=0;i<10;i++){ 
    lcd.setCursor(9, 1);
    lcd.print(i);    
    delay(1000);    
  }    
}

for문을 이용해서 0~9까지 i의 값이 1씩 증가하고 그 값이 커서(setCursor(9,1)로 두번째 줄의 9번째칸에 i값을 출력이 됩니다.
0~9까지 아니는 1초 단위로 그 값을 찍게되는 것이죠. 자세히 보시면 위에서 함수에 대한 요약된거랑 매칭해서 이해하세요.
대충 이런식으로 값들을 찍어낼 수 있습니다. 나중에 센서값을 측정하면 바로 LCD 16x2로 출력할 수 있겠죠.

4. 결과


동영상 결과를 회로도를 최대한 보기 편하게 배치하다 보니깐 LCD 16x2가 거꾸로 배치했네요. 그래서 글자가 거꾸로 나오는 것처럼 되었네요.

마무리


LCD 16x2 만 잘 사용하시면 이제 다양한 실험을 작은 LCD 모니터로 그 값을 출력할 수 있어서 보기 편하실꺼에요. 이걸 모니터 대용으로 아두이노상에서 모든걸 해결 할 수 있게 되겠죠. 한번 초음파센서와 결합해서 거리값을 출력시켜보세요. 다음편에 이 두 부품을 결합한 에제로 복습 실험을 할지 아니면 실제로 LCD 16x2 I2C 를 이용해서 2핀으로만 제어하는 걸 보여드릴때 고민해봐야 겠네요.
암튼 LCD 16x2를 연습을 하시고 다 소개하지 못했지만 참고자료에 링크한 곳에 가셔서 함수들을 한번 읽어보시면 표현을 해보세요.

오늘은 LiquidCrystal 에서 사용함수들만 이해만 해주세요. 그리고 예제가 어떻게 출력되는지만 잘 살펴보시면 그냥 무난히 LCD 16x2를 사용하실 수 있을꺼에요.


댓글()

[아두이노] 가변저항을 이용하여 3색 LED 제어

IOT/아두이노|2019. 2. 23. 10:17

[아두이노] 가변저항을 이용하여 3색 LED 제어



오늘은 가변저항 부품을 이용해서 3색 LED의 색상을 마음대로 조절하는 실험을 하겠습니다. 오늘의 주제는 가변저항입니다. 지금까지 실험에서는 고정저항으로 LED에 연결하여 불을 켜거나 다른 부품의 전류를 조절하기 위해서 써왔습니다. 이제는 고정저항 대신에 가변저항을 써서 유동적으로 제어할 수 있는 방법을 배워보도록 하겠습니다.

1. 가변저항


모양은 대충 이렇게 Termial1,2와 Wiper로 핀이 구성되어 있습니다. 실험에서는 Terminal2(5V), Terminal1(Gnd), Wiper(저항값추출)로 구성합니다. 가정에 보시면 형광등에 돌려서 밝기 조절하는 스위치를 보시거나 있으신분들 아마 있을거에요. 바로 그게 가변저항스위치 입니다. 가정 형관등 보시면 돌려서 저항이 작으면 전류가 통과하는 양이 많아 형광등이 밝아지고 저항이 크면 전류가 통과하는 양이 적어져서 형광등이 어두어집니다. 대충 가변저항 부품에 대해서 이해가 되시죠. 참고로 여기서 Terminal1과 Terminal2의 Vcc와 Gnd 연결 순서는 고정된 것이 아닙니다. 반대로 연결하더라도 작동은 됩니다. 자신이 연결했을때 Wiper의 값이 큰값이면은 반대로 연결하게 되면 Wiper의 값은 작은값으로 바뀌에 됩니다. Terminal1,2의 선을 어떻게 연결하느냐에 따라서 Wiper의 나오는 전류값은 서로 반대값이라고 생각하시면 됩니다. 쉽게 말해서 자신이 연결한 선에서 돌리면 0~1023으로 순차적으로 출력된다면 반대로 연결하여 돌리면 1023~0으로 순차적으로 출력됩니다. 참쉽죠.

1. 회로도 구성


  • 준비물 : 가변저항 3개, 3색 LED 1개, 저항 220옴 3개, 아두이노우노, 뻥판
  • 내용 : 가변저항스위치는 각각 RGB의 저항값을 추출하고 그 값을 토대로 RGB의 색상값으로 출력하도록 하는 실험


가변저항 부품을 보시면 Wiper에서 나오는 선이 아날로그 A0, A1, A2에 입력으로 들어옵니다. Wiper은 가변저항 부품에 흐를 전류의 값을 출력합니다. Terminal1은 Gnd, Terminal2은 5V에 연결합니다. 그러면 가변저항기에 전류가 공급되고 조절기로 돌리면 저항값이 변화되고 Wiper로 그 변화된 전류가 출력됩니다. 그 출력값이 A0, A1, A2에 아날로그 값으로 읽게 되고 그 값은 다시 3색 LED의 아날로그 신호값으로 출력되여 색이 결정됩니다. 하지만 아두이노는 아날로그 출력이 없으며 아날로그 출력과 비슷한 형태로 출력되는 PWM 출력으로 대신하는데 그냥 단순하게 PWM디지털핀으로 아날로그 신호를 내보낸다고 생각 하시면 돼요.

3. 코딩


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

복습

  • pinMode(사용핀,모드) : 사용할 핀을 입력/출력모드(INPUT/OUTPUT) 인지 선언한다.
  • analogWrite(출력핀,상태) : 출력핀에 0~255 사이의 아날로그신호(PWM)를 내보낸다.(3색 LED에 출력용)
  • analogRead(입력핀) : 입력핀을 0~1023 사이의 아날로그 신호값을 읽어들인다.

설계

(1) 가변저항기 읽기

color_value[0] = analogRead(A0)/4; //(0~1023 => 1024/4=256)
color_value[1] = analogRead(A1)/4;
color_value[2] = analogRead(A2)/4;

analogRead()함수로 각 Wiper핀에서 발생된 가변저항값을 읽게 됩니다. 0~1023 사의 값을 가져오는데 3색 LED의 입력값은 0~255사이이기 때문에 나누기 4를 해줘야 되겠죠. 왜 나루기를 했는지는 아시겠죠.

color_value[0]=map(analogRead(A0),0,1023,0,255)

원래는 이렇게 코딩해야합니다. map()함수로 효율적으로 코딩해야 합니다. 하지만 대충 어떤 값이 들어가는지 직관적으로 이해 시키기 위해서 map()함수를 생략했네요.

  • map(입력값,입력최소,입력최대,출력최소,출력최대) : analogRead(A0)에서 읽은 값이 방금전 0~1023이라고 했죠. 그걸 입력최소, 입력최대로 범위를 지정해주고 이 값을 기준으로 출력값의 범위는 0~255니깐 출력최소 0과 출력최대 255로 지정하면 함수 하나로 쉽게 매핑 시킬 수 있습니다. 둘 중 아무거나 사용해서 이용하시면 돼요.

(2) 색 결정

우선 3색 LED에서 따로 Color()함수를 직접 만들었습니다. 이렇게 만들어 놓으면 3색 LED 부품을 사용하면 이 함수만 복사해오면 번거로운 코딩을 할 필요 없겠죠. 3색핀에 값이 결정되면 그 값을 color(Red, Green, Blue) 값을 넣으면 3색 LED에 색이 출력됩니다.

void Color(int red, int green, int blue)
{
  analogWrite(rpin, red);
  analogWrite(gpin, green);
  analogWrite(bpin, blue); 
}

코딩을 하면

  1. 3색 LED에 RGB 핀에 제어할려면 3핀이 필요하니깐 우선 3핀을 변수로 선언해야지(9,10,11)
  2. 가변저항1,2,3이 있는데 이걸 저장할 변수가 필요해! 3개가 필요하니 그냥 배열변수로 하지. (color_value[3])
  3. 3색 LED에 사용할 핀이 3개니깐 변수도 선언했고 그러면 이 핀이 출력으로 사용할려면 우선 선언해야지.
  4. 자! 가변저항을 읽어와서 배열변수에다 순서대로 저장하자.
  5. 이제 3색 LED에 저장된 값인 가변저항값으로 색을 만들자
int rpin = 11;
int bpin = 10;
int gpin = 9;
int color_value[3];
 
void setup()
{
  pinMode(rpin, OUTPUT);
  pinMode(gpin, OUTPUT);
  pinMode(bpin, OUTPUT);
}

void loop()
{
  color_value[0] = analogRead(A0)/4; //(0~1023 => 1024/4=256)
  color_value[1] = analogRead(A1)/4;
  color_value[2] = analogRead(A2)/4;
  Color(color_value[0],color_value[1],color_value[2]);
}

void Color(int red, int green, int blue)
{
  analogWrite(rpin, red);
  analogWrite(gpin, green);
  analogWrite(bpin, blue); 
}

5. 결과


그냥 가변저항 예제로 LED 1개, 가변저항 1개를 이용해서 밝기를 조절하는 실험을 해도 되는데 좀 더 복습하면서 3색 LED의 색을 만들어내는게 시각적으로 보기도 좋고 실험이 재밌을 것 같아서 선택했습니다.

마무리


가변저항을 이용해서 조절하니깐 시각적으로 3색 LED의 색의 변화를 체험하셨을 거라 생각합니다. 3색 LED의 색의 변화를 통해서 뭔가 재밌는 소재가 없나 한번 떠올려 보세요. 예전에 어떤분의 블로그 글을 본적 있는데 3색 LED를 이용한 실험이였습니다. 참 참신하더군요. 비닐인가 솜인가 구름의 형태로 만들어서 그 안에 3색 LED를 넣고 wifi쉴드를 이용해서 날씨 정보를 읽어오게 했는데 그 정보를 이용해서 현재의 날씨 상태를 3색 LED의 색으로 나타냈는데 참 재밌어 보이더군요.
한번 이런건 어떨까요. 토양습도센서를 아두이노에 연결해서 식물이 물이 부족할경우 그걸 시각적으로 3색 LED로 식물의 감정을 표현한다면 괜찮겠지요.

이야기가 삼천포로 빠졌지만 가변저항을 조절할 수 있다면 과연 일상에서 어떤것들이 있는지 찾아보고 또 어디에다 이 부품을 사용하면 재미 있을지 한번 상상의 나래를 펼쳐보세요.


댓글()

[아두이노] RC카 장애물 감지시 방향 전환 기초

IOT/아두이노|2019. 2. 22. 11:52

[아두이노] RC카 장애물 감지시 방향 전환 기초



초음파레이더의 원리는 지난 시간에 기초 실험으로 살펴 보았습니다. 하다보니깐 RC카 자율주행할 때 초음파 센서로 장애물 감지을 할 경우가 문득 떠오르더군요. 그래서 초음파레이더 만들기 소스를 그대로 이용하여 몇부분만 추가하여 코딩을 완성했습니다. 그냥 갑자기 떠오른 생각이라서 코딩은 깔끔하지 않네요. 막 떠오르는데로 코딩한거니 그 점을 감안해서 코딩을 보시기 바랍니다.

1. 회로도 구성


  • 준비물 : 서보모터 2개, 초음파센서 1개, 아두이노우노
  • 내용 :45~ 125도 서보모터를 회전시키면서 초음파센서로 거리를 측정부분은 그대로 유지한 상태에서 RC카 앞바퀴 방향 제어용 서보모터를 추가하자.


머리속에서 각 부품을 실제 RC카에 배치를 상상해 보세요. 첫번째 초음파센서가 서보모터에 부착되어 있고 두번째 서보모터는 RC카 앞바퀴에 연결되었다고 상상 해보세요.

3. 코딩


  • 사용함수 : attach(사용핀), write(각도), pulseIn(입력핀, HIGH), Serial.begin(9600), Serial.print(출력값),Serial.println(출력값)
  • 내용 : 간단히 서보모터가 회전은 45~125도 범위를 잡고 전방의 장애물 탐지를 초음파센서가 담당하게 코딩하고 앞바퀴담당 서보모터는 거리 50이하 일때 전방 90도 기준으로 좌측에 장애물 발견시 우측으로 우측 장애물 발견시 좌측으로 회전시키는 코딩을 한다.

설계

앞바퀴 방향 제어를 하기 위해서 서보모터를 제어해야겠죠.

그래서 서보모터 객체를 하나 더 선언합니다.

Servo servo2;

그리고 핀을 10번을 사용하기 위해서 연결합니다.

int servoPin2 = 10;
servo2.attach(servoPin2); //angle (0~180)

앞바퀴 장애물 방향전환 조건문을 만듭니다.(하나의 패턴으로 자율주행 첫단추로 접근하는 시작 코딩)

  if(m_distance<=50 && m_angle>90) {    
    servo2.write(45);
    delay(50);   
  }
  else if (m_distance<=50 && m_angle<90){
    servo2.write(125);
    delay(50);   
  }
  else {
    servo2.write(90);
    delay(50);   
  }
  if(m_distance<=50 && m_angle>90) {    

if조건문

  • 첫번째 조건식 : "장애물(벽) 거리가 50cm 이하이고 각도가 90도 보다 큰가?" (왼쪽장애물확인)
    그러면 왼쪽 장애물이 너무 가까우니깐 오른쪽으로 핸들을 꺽어야 겠죠.
  • 두번째 조건식 : "그게 아니면 장애물(벽) 거리가 50cm 이하이고 각도가 90도보다 작은가?"(오른쪽장애물확인)
    그러면 오른쪽 장애물이 너무 가까우니깐 왼쪽으로 핸들을 꺽어야 겠죠.
  • 거짓이면 : 그냥 앞바퀴 방향각 90도로 정중앙 정면을 향하게 한다.

즉, 조건식으로 50cm이하일때 현재 방향에 따른 핸들의 방향을 결정하게 됩니다. 50cm이하에 장애물이 없으면 그냥 정면으로 계속 진행하도록 로직을 짜봤습니다.
여기서 핸들 각도를 변수로 빼면 중복되는 코딩이 3번 반복되는데 이걸 하나로 줄일 수 있겠지만 우선은 동작을 좀 더 직관적으로 이해할 수 있도록 하기 위해서 수정은 안했습니다.

초음파레이더 소스와 위에 방향전환 로직을 합쳐서 전체코딩을 을 살펴보면

#include <Servo.h>

Servo servo1;
Servo servo2;
int servoPin1 = 9;
int servoPin2 = 10;
int m_distance=0;
int m_angle=45;
int m_chk=0;

void setup() {
  Serial.begin(9600);
  servo1.attach(servoPin1); //angle (0~180)
  servo2.attach(servoPin2); //angle (0~180)
}

void loop() {
  
  //초음파센서 몸체 회전
  servo1.write(m_angle);
  delay(50);
  
  m_distance=CalDistance(7);  //초음파센서로 거리계산함수   
  Serial.print("d : ");
  Serial.println(m_distance);
  
  //앞바퀴 장애물 방향전환
  if(m_distance<=50 && m_angle>90) {    
    servo2.write(45);
    delay(50);   
  }
  else if (m_distance<=50 && m_angle<90){
    servo2.write(125);
    delay(50);   
  }
  else {
    servo2.write(90);
    delay(50);   
  }
  
  //초음파센서 회전각
  if(m_chk==0){
    if(m_angle<125)m_angle+=1;
    else m_chk=1;
  }
  else{
    if(m_angle>45)m_angle-=1;
    else m_chk=0;
  }
  
}

int CalDistance (int Pin){  //초음파센서(3핀) 예제를 그대로 외부함수로 빼냄
  pinMode(Pin,OUTPUT); //출력모드로  사용
  digitalWrite(Pin, LOW); 
  delayMicroseconds(2); 
  digitalWrite(Pin,HIGH); 
  delayMicroseconds(10); 
  digitalWrite(Pin,LOW); 
  
  pinMode(Pin,INPUT);    //입력모드로 사용
  int duration = pulseIn(Pin, HIGH);
  
  int distance = duration / 57.5;  //가상시뮬레이션의 오차율을 줄이기 위해 이걸로 테스트 함.

  return distance; //거리값 리턴
}

5. 결과


설계과정은 이번에 생략하고 결과만 시뮬레이터로 돌려 보는 장면만 보여 드립니다. 지난시간에 회로도 만드는 과정을 해봤으니 구지 중복해서 다시 똑같은 것을 찍을 필요는 없고 서보모터만 하나 추가했기 때문에 결과만으로 충분해서 회로도 배치과정은 생략했네요.

마무리


오늘은 아두이노 RC카에 주행에 관한 첫 단추인 방향전환에서 하나의 패턴을 기초 패턴으로 로직을 만들었습니다. 이걸로 주행이 가능하지 않습니다. 단지 이렇게 코딩해 놓고 조금씩 패턴을 늘리고 로직을 늘려가야 합니다.

여기서는 단적으로 왼쪽 장애물 감지시 레드존에 들어가고 바로 오른쪽으로 45도 회전을 시켜서 그린존으로 탈출하는 코딩입니다. 어떤 문제가 있을까요 바로 현재 RC카의 주행 속력에 대한 장애물과의 거리별로 방향전환 각도를 가변적으로 해야합니다. 그래야 매끄렇게 회전이 됩니다. 그리고 또 문제는 가령 전방 직선도로로 달릴때 통과 할 수 공간이 충분하지만 가력 왼쪽이나 오른쪽 방향에 장애물이나 벽과의 거리가 50 이하면 그냥 방향핸들을 반대 방향으로 꺽어버리는 문제가 방생합니다. 즉, 전방에 안전거리 확보가 확인되면 그상태로 주행하고 안전거리가 미확인시 좌우측에 위험거리가 감지되면 방향을 전환하더록 로직을 수정해야겠죠.

이렇게 주행에서의 문제들을 하나씩 찾아내고 그걸 해결하는 패턴들을 하나씩 만들어 내야합니다. 그래야 자율주행이 가능해지는 것이죠. 다른 방식으로 장애물 감지되면 그상태에서 주행이 정지되고 안전거리 확보 패턴로직 주행을 하고 다시 안전거리가 확보되면 주행을 다시 시작하는 방식으로도 변경할 수 있겠죠.

코딩을 쉽게 하기 위해서는 실제 장난감 자동차를 방에서 손으로 밀면서 주행을 시켜보세요 그리고 관찰하면 이런 상황일때 이걸 어떻게 어떻게 빠져나올지 손으로 자동차를 움직이시고 그 움직을 잘 기억했다가 그 움직이는 동작 패턴을 코딩화 하시면 됩니다.

암튼 집에 굴러다니는 장단감을 가지고 한번 손으로 밀면서 띠따! 빵빵! 하면서 가지고 노세요. 그리고 나서 그 움직임을 기역했다가 코딩을 상상해보세요.


댓글()

[아두이노] 초음파레이더 만들기(기본동작제어)

IOT/아두이노|2019. 2. 21. 10:16

[아두이노] 초음파레이더 만들기(기본동작제어)



이번시간에 초음파레이더를 기본동작 원리를 실험하는 시간을 갖도록 하겠습니다. 가장 많이 검색되는 주제이기도 하죠. 현재 초음파센서가 없는 관계로 실제 구동 장면은 추가하고 싶었는데 아쉽게 못 보여 드리네요. 그래도 가상시물레이터에서 충분히 표현이 되니깐 실제 만드는 것은 그리 어렵지 않을꺼에요. 물론 거리계산에 따른 오차율 보정 작업이 필요하지만요. 오늘은 서보모터를 회전시키면서 초음파센서로 거리를 측정하고 그 값을 아두이노 IDE 시리얼모니터로 거리 값이 동시에 출력되게 표현 함으로 초음파레이더의 기본 원리를 배워보도록 하죠.

1. 초음파센서 복습


제 블로그에서 정리할 때 함수로 표현했었습니다. 초음파센서로 거리를 측정하는 로직을 따로 외부함수로 만든 것을 그대로 인용해서 적용하겠습니다.int distance = duration / 57.5; 이것은 가상시뮬레이터에 대충 거리를 보정한 값이고 실제로는 공식을 해보고 거리값의 오차가 있으면 약간씩 값을 바꾸면서 거리값을 보정하시면 됩니다.

  • 공식 : ((float)(340 * duration) / 10000) / 2; (340은 초음기종에 따라 달라질 수 있는점 참고)
int CalDistance (int Pin){  //초음파센서(3핀) 예제를 그대로 외부함수로 빼냄
  
  pinMode(Pin,OUTPUT); //출력모드로  사용
  digitalWrite(Pin, LOW); 
  delayMicroseconds(2); 
  digitalWrite(Pin,HIGH); 
  delayMicroseconds(10); 
  digitalWrite(Pin,LOW); 
  
  
  pinMode(Pin,INPUT);    //입력모드로 사용
  int duration = pulseIn(Pin, HIGH);
  
  int distance = duration / 57.5;  //가상시뮬레이션의 오차율을 줄이기 위해 이걸로 테스트 함.

  return distance; //거리값 리턴
}

이렇게 함수로 만들어 놓으면 나중에 초음파센서를 사용할 때 이 함수를 복사하시면 되겠죠. 이건 3핀 초음파센서여서 사실 4핀 초음파센서에서는 TRIG, ECHO핀이 따로 존재하기 때문에 setup()함수에서 각 핀을 선언해주시면 되기 때문에 CallDistance()함수에서 핀의 출력/입력모드를 선언할 필요가 없습니다. 가상시뮬레이터에서는 3핀이여서 어쩔 수 없이 추가된 것이기 때문에 실제로 1200원 짜리 4핀 초음파센서를 사용하시면 핀모드 선언을 지워주셔서 함수를 사용하시면 됩니다.
쏘는것은 TRIG, 받는 것은 ECHO 핀인 것만 기억하시면 쉽게 변경되시겠지요. 즉, 3핀 초음파센서에서 출력모드일 때 TRIG이고 입력모드일 때 ECHO라고 생각하시면 됩니다.

2. 서보모터 복습


#include <Servo.h>
 
 Servo servo;
 int servoPin = 9;
 
 servo.attach(servoPin); //angle (0~180)
 servo.write(m_angle);
 delay(50);
 
 m_angle+=1; or m_angle= m_angle+1;

9번핀을 servo모터의 출력핀으로 연결하고 servo.write()로 각도(angle)만큼 이동하는데 마지막 라인의 m_angle은 +1씩 증가합니다. 즉 0도에서 1도씩 계속 servo모터를 회전하게 되는 것이죠. 딜레이시간은 1도여서 아주 짧게 0.05초를 줬습니다.

3. 회로도 구성


  • 준비물 : 서보모터 1개, 초음파센서 1개, 아두이노우노
  • 내용 : 0~180도 서보모터를 회전시키면서 초음파센서로 거리를 측정해보자.


가장 간단한 회로도 입니다. 대충 회로도를 보시고 해당 위치의 핀에 선을 연결하시면 됩니다.

4. 코딩


  • 사용함수 : attach(사용핀), write(각도), pulseIn(입력핀, HIGH), Serial.begin(9600), Serial.print(출력값),Serial.println(출력값)
  • 내용 : 간단히 0~180의 범위를 1도씩 회전하면서 초음파로 거리를 측정하여 아두이노시리얼모니터에 거리값을 출력한다.

설계는 위의 1, 2에서 복습 차원의 코딩을 그대로 사용했습니다. 중요한 것은 0에서 180도 까지 1도씩 회전시키고 다시 180에서 0도까지 1도씩 회전하는 것이죠.

설계

(1) 제어 변수를 만든다.

Servo servo; 
int servoPin = 9;

int m_distance=0;
int m_angle=0;
int m_chk=0;
  • servo : 서보클래스 객체 선언
  • servoPin : 서보모터 제어하는 핀번호
  • m_distance : 거리 계산값(초음파센서로 거리측정동작을 수행하는 CalDistance()함수로 구한 값이 저장)
  • m_angle : 서보모터의 회전각(write()함수로 서보모터를 실제 회전)
  • m_chk : 회전 방향 상태값(초기값 0은 0에서 180도로 회전을 뜻하고 1은 180도에서 0도로 회전을 뜻한다.)

(2) m_chk 변수가 회전 방향 상태를 나타내고 제어하는 방법

if(m_chk==0){
    if(m_angle<180)m_angle+=1;
    else m_chk=1;
  }
  else{
    if(m_angle>0)m_angle-=1;
    else m_chk=0;
  }

if 조건문으로 m_chk변수의 초기값이 0이다 m_angle(각)도 0도이다. 조건식이 m_chk==0 으로 m_chk가 0과 같은가 아닌가로 물어본다. 두가지 패턴으로 분리되는 순간이다. 0가 같다면 참인문장이 1이면 거짓문장이 수행 되겠죠. m_chk변수가 초기값으로 0임으로 참이 된다. 그 안에 다시 if문으로 m_angle(각)이 180도보다 작은가가 조건식이 걸려있다. 180도보다 작으면 m_angle+=1;로 m_angle=m_angle=+1과 같은 문장이다. 즉, m_angle(각)은 1도ㅀ 증가하게 된다. 그런데 만약에 m_angle(각)가 180도 이상이 되면 else 이하 문장이 수행됩니다. m_chk=1로 회전 방향 상태값이 바뀌게 됩니다. 그러면 다음 루프때 if 조건문 m_chk가 0이 아니기 때문에 else 이하 문장이 수행되고 반대로 m_angle 변수가 0보다 크냐고 붇고 크면은 m_angle-=1로 -1도로 감소하게 된다. 위 코딩하고는 반대 동작을 수행하는 것이죠.

다시 종합해서 설명하자면 m_chk변수 기준으로 0이면 m_angle 값이 180도가 될때까지 1씩 증가하고 180도가 되면은 m_chk변수를 1로 변경하고 m_chk변수가 1이면 m_angle 값이 0도가 될때까지 -1씩 감소하게 된다. 그리고 0도가가 되면 m_chk변수를 0으로 변경한다. 이렇게 무한 반복하게 되는 로직입니다.

(3) 결과는 아두이노 IDE 시리얼모니터로 출력

Serial.begin(9600);

Serial.print("d : ");
Serial.println(m_distance);

begin(9600)은 setup()함수에 선언하고 나머지 모니터 출력은 print(출력값)와 printIn(출력값)함수가 있는데 print()은 출력값을 출력하고 새로운 라인으로 넘어가지 않고 현재 라인에 머문다. printIn()은 출력값을 출력한뒤에 새로운 라인으로 넘어가라는 의미 입니다. 문서 장성할 때 키보드 Enter 명령으로 생각하시면 됩니다. C언어에서는 '\n'로 생각하시면 됩니다.

Serial.print("d : ");
Serial.println(110);

결과 => d : 110

대충 의미를 이해하셨겠죠.

코딩을 하면

#include <Servo.h>

Servo servo; 
int servoPin = 9;
int m_distance=0;
int m_angle=0;
int m_chk=0;

void setup() {
  Serial.begin(9600);
  servo.attach(servoPin); //angle (0~180)
}

void loop() {
  servo.write(m_angle);
  delay(50);
  
  m_distance=CalDistance(7);  //초음파센서로 거리계산함수   
  Serial.print("d : ");
  Serial.println(m_distance);
    
  if(m_chk==0){
    if(m_angle<180)m_angle+=1;
    else m_chk=1;
  }
  else{
    if(m_angle>0)m_angle-=1;
    else m_chk=0;
  }
}

int CalDistance (int Pin){  //초음파센서(3핀) 예제를 그대로 외부함수로 빼냄
  pinMode(Pin,OUTPUT); //출력모드로  사용
  digitalWrite(Pin, LOW); 
  delayMicroseconds(2); 
  digitalWrite(Pin,HIGH); 
  delayMicroseconds(10); 
  digitalWrite(Pin,LOW); 
  
  
  pinMode(Pin,INPUT);    //입력모드로 사용
  int duration = pulseIn(Pin, HIGH);
  
  int distance = duration / 57.5;  //가상시뮬레이션의 오차율을 줄이기 위해 이걸로 테스트 함.

  return distance; //거리값 리턴
}

5. 결과


가상시뮬레터에서 실험 결과는 깔끔하게 나왔는데 실제 표현에서는 보정 작업이 꼭 필요 합니다.

그리고, 원래 실제로 초음파레이더를 만든다면 그래픽작업으로 레이더를 만들어 레이더에 검색된 물체를 현재회전각과 거리값으로 (x,y)의 좌표를 구할 수 있고 그걸 그래픽작업한 모니터에 원하는 형태로 그래픽모양을 출력하면 좀 더 그럴싸해 지겠죠.

여기에서는 단지 아두이노 IDE 시리얼모니터에 거리값만 출력했습니다. 그게 기본 초음파레이더의 정보입니다. 서보모터의 각도와 거리만 있으면 측정된 물체의 (x,y) 좌표를 구할 수 있고 그것을 프로세싱이나 스크래치로 이미지화 하면 보기가 더 좋겠지만 핵심은 그게 아니로 회전과 거리 측정을 동시에 수행한다는 것에 있습니다. 이미지 시각화를 단지 보여주는 부수적인 효과일뿐이죠. 동영상을 보시고 서보모터가 회전하면서 시리얼모니터에 초음파 센서의 거리가 측정되어 출력되는 걸 잘 보시고 상상을 해보세요. 서보모터에 초음파센서가 부착되어 회전되는데 그 회전하는 각도에 정면의 물체와의 거리를 측정하는 모습을요. 그러면 아마 대충은 이해가 되실 꺼에요.

마무리


간단히 초음파레이더의 기본 로직만 설명했습니다. 그리고, 오늘 포스팅한 코딩은 사실 정교한 제어라고 할 수 없습니다. 왜냐면 서보모터 종류에 따라 좀 다르게 회전이 되는 경우가 있습니다. 참고로 코딩에서 servo.attach(servoPin, Min, Max)로 범위를 설정하고 servo2.writeMicroseconds(각도시간값)으로 제어하시면 더 정교하게 제어가 가능할꺼에요. 실제로 테스트 할때는 위 방식대로 해보다가 안되면 이 방식으로 바꿔서 서보모터의 각도를 제어하시면 됩니다. 4핀이였으면은 현실 4핀 서보모터랑 동일해서 더 편했을텐데 3핀 초음파센서여서 약간 코딩이 아쉽습니다.

추가로 스크래치나 프로세싱 프로그램을 다룰 수 있는 분이라면 그걸 통해서 초음파레이더에 그래픽처리를 통해 실제 레이더처럼 표현이 가능할 꺼에요. 프로세싱을 제대로 공부한적이 없고 잠깐 맛보기로 함수만 몇개 써본게 전부라 프로세싱 프로그램을 사용하여 레이더 그래픽효과를 다음편에 추가해서 보여주고 싶긴 하는데 할까 말까 고민되네요. 잠깐 프로세싱에서 레이더 표현 그래픽 함수 몇개만 공부해서 로직을 짜면 되기는 한데 프로세싱을 새로 설치하고 공부하기가 좀 귀찮아서 생략할지 아니면 표현을 할지 고민을 해 봐야 겠네요.

오늘의 포스팅의 내용은 서모모터회전을 하면서 초음파센서로 거리를 측정한다 이것만 머리속에 넣으시면 됩니다.


댓글()

[아두이노] Servo.h 없이 직접 서보모터를 회전

IOT/아두이노|2019. 2. 20. 13:38

[아두이노] Servo.h 없이 직접 서보모터를 회전



이번에 서보모터의 단순히 전원 공급으로만로 회전을 시켜보는 걸 해보겠습니다. 이것도 오래전 Servo.h 없이 제어를 할 수 있는 방법이 없을까 하고 고민을 좀 했었습니다.
https://github.com/esp8266/Arduino/blob/master/libraries/Servo/src/Servo.h 에서 Servo 클래스에 대해 분석도 하고 했지만 너무 복잡하더군요. 그냥 단순 제어를 해볼려고 조사하다가 전기 신호 파형에 따라 각도를 제어할 수 있다고 해서 digitalWrite()함수 하나로 제어하는 실험을 하게 되었습니다. 혹시 서보모터의 원리를 보다 자세히 알고 싶다면 구글링 서보모터원리라는 단어로 하시면 쉽게 찾을 수 있을거에요. 이번 실험은 전류를 서보모터에 보내고 펄스 간격을 시간값으로 해서 쪼개서 전류공급과 차단을 하면 서보모터의 회전을 시키는 실험으로 진행됩니다. 그리고 이전에 포스팅한 Ardunio min = 544, max=2400 값을 기준으로 이번에 가상시뮬테이의 회전 실험을 해보도록 하죠. 제 블로그의 있던 소스를 그대로 가져와서 실험 포스팅을 하도록 하겠습니다. 고치자니 귀찮니즘이 밀려와서 구지 고칠 필요가 없다고 생각되어 그냥 소개합니다.
그리고 가상시뮬레이터에서 실험하던 당시 서보모터가 다른 기종이여서 min=1000, max=2000을 기준으로 회전시켰지만 이번 실험은 544~2400 값으로 해서 회전이 되는 서보모터를 사용하여 기준은 544~2400으로 실험했습니다.

1. 서보모터의 회전 이해


구글링 검색하시면 서보모터 원리에 대해서 자세히 소개되어 있는데 그냥 아래의 그림처럼 단순하게 생각하시고 넘어가시면 됩니다. 전기 신호는 일정한 간격으로 해서 아래와 같은 파형을 만들어 냅니다. 전류가 공급되고 차단하는 그 시간차 값으로 서보모터의 각도를 만들어 낸다고 가단히 생각하세요. 전류 공급(5V)가 짧은 간격으로 공급된다면 회전하는 각이 그 시간만큼만 회전한다고 생각하면 됩니다.


파형을 아두이노에서 만든다면( Ardunio min = 544, max=2400 값을 기준)

   digitalWrite(servoPin, HIGH);  
   delayMicroseconds(1500);     
   digitalWrite(servoPin, LOW);   
   delayMicroseconds(펄스간격남은값);   

즉, 서보모터 핀에 HIGH(5V)의 전류를 1500마이크로초 동안 전류를 공급하고 LOW(0)로 전류를 차단을 펄스간격남은값(max-회전시간값)만큼이란 표현입니다. 현실 구동은 스피드하게 회전하지 않겠지만 가상시뮬레이터에서 저리 코딩하면 순간 90도정도의 각도로 회전해버립니다. 가상시뮬레이터에서 서보모터라이브러리에서 제공되는 함수와 비슷하게 회전을 보여줄려면은 대충 delay()함수로 시간을 좀 더 크게 대기시켜서 보면은 최대한 비슷하게 회전합니다.

대충,

void setup() {
  pinMode(9, OUTPUT);
}
void loop() {
   digitalWrite(9, HIGH);  
   delayMicroseconds(1500);     
   digitalWrite(9, LOW);   
   delayMicroseconds(2400-1500);   
   delay(100);
}

이정도만 코딩해서 아래 회로도 디자인한 곳에다 코딩을 넣어보세요. 1500시간값만큼의 각도까지 움직이다가 그 각도에서 덜덜덜 떨고 있을꺼에요. 정상적으로 동작되는걸 보실꺼에요

여기서 펄스간격남은값 2400-1500으로 해서 펄스 간격을 일정하게 만들었습니다. 그냥 아두이노의 최대값 2400을 펄스간격 기준값으로 설정했네요. 펄스간격 기준값 2400을 기준으로 얼마만큼의 시간이 5V와 0V가 되었는지의 시간입니다. 그래서 1500만큼의 전류가 공급되었으니 나머지 시간은 LOW에 할당해야겠죠.

쉽게말해서, 회전 파형을 만든다고 생각하시면 됩니다. 구지 자세히 생각하지 마시고요. 이런게 있다는 정도만 이해하시고 오늘 포스팅을 깊게 이해하실 필요 없습니다. 그냥 Servo 라이브러리 파일이 오픈소스로 제공되는데 구지 힘들게 만들 필요는 없겠죠. 이렇게 만들었다고 해서 정교한 컨트롤은 되지 않으며 단지 이런식으로 회전이 이뤄지는 거구나 정도용이니 깊게 생각하지 마세요.

2. 회로도 구성


  • 준비물 : 서보모터 1개, 아두이노우노
  • 내용 : 서보모터 회전 시키자


서보모터는 Vcc(5V), Gnd, Signal(입력신호)로 3핀이로 구성되어 있고 아두이노에서 Signal핀에 신호를 보냄으로써 각도를 제어는 지난시간과 동일합니다.

3. 코딩


  • 사용함수 : pinMode(사용핀, 모드), digitalWrite(사용핀, 상태), delayMicroseconds(시간값), delay(시간값)
  • 내용 : 간단히 180도 회전만 시키자.

설계

우선 delayMicroseconds() 함수를 사용한 목적은 서보모터를 회전시킬 시간값이고 지연시간도 이 함수로 사용했습니다. 그리고 0~180도까지 회전이 끝나면 delay()로 1초동안 잠시 대기는 목적으로 사용합니다.

그리고 digitalWrite()함수를 사용하기 위해서는 pinMode()함수로 핀모드를 설정해야 합니다. 그리고 digitalWrite()함수로 서보모터에 신호값으로 전류 공급과 차단으로 전기신호파형을 만들어 특정 각으로 회전시킵니다.

코딩을 하면

int servoPin = 9;
int m_max=2400;

void setup() {
  pinMode(servoPin, OUTPUT);
}

void loop() {
  for(int i=544;i<2400;i++){
   digitalWrite(servoPin, HIGH);  
   delayMicroseconds(i);     
   digitalWrite(servoPin, LOW);   
   delayMicroseconds(m_max-i);    
  }
  delay(1000);

  for(int i=2400;i>544;i--){
   digitalWrite(servoPin, HIGH);  
   delayMicroseconds(i);     
   digitalWrite(servoPin, LOW);   
   delayMicroseconds(m_max-i);    
  }
  delay(1000);
}
}

for문으로 사용해서 min(544)값에서 max(2400)값이 될때까지 delayMicroseconds(i)로 전류의 공급 간격입니다. 이게 바로 각도이고요. delayMicroseconds()함수을 이용하여 전기 파형을 만들어 냅니다. 전류 공급시간이 작을 경우 펄스간격 시간단위로 짧은 파형이 작게 형성됩니다. 그럴때 서보모터의 움직이는 회전이 짧아서 그 상태를 유지하는거고요 i값이 클경우 그 파형이 크게 형성됩니다. 서보모터의 움직이는 회전각 커집니다. 그리고 그 회전에 도달하면 더이상 회전을 하지 않으며 그 회전각을 계속 유지하게 됩니다. 544에서 2400될때까지 전원 공급 간격이 점차적으로 커져가니깐 결과적으로 0~180도로 회전을 시키게 되는 것이죠. 두번째 for문은 2400에서 544가 될때까지 i의 전원 공급 간격이 적어지니깐 180~0도로 회전을 시키게 됩니다.

이해가 안된다고 생각하시면 쉽게 delayMicroseconds(i) 각도로 생각하시고 전원 공급과차단의 간격을 펄스간격 기준값(m_max)값이라고 생각하시면 됩니다. 펄스간격동안 delayMicroseconds()함수로 전류의 파형을 만들고 그 파형만큼의 각도로 회전을 시킨다고만 이해하시면 됩니다.

4. 결과


따로 제작과정없이 그냥 코드만 삽입해서 그 결과를 보여드립니다. 한번 서보모터 회전를 이해하기 위해서 동영상에서 과연 1500마이크로초 동안 공급될때 어느정도의 회전이 되고 그 상태를 유지할때 서보모터의 움직임을 유심히 살펴보시면서 회전을 어떤 느낌으로 회전되는지 이해하시면 되겠습니다. 그리고 본론으로 들어간 실험 코딩은 0~180도까지 회전 시키고 1초 대기했다가 180~0도까지 회전 시키는 과정을 반복합니다. 그리고 여기서는 아두이노우노의 2400의 값을 펄스파형을 이 일정하게 증가하다가 일정하게 감소하는 과정에서 전류를 시간값으로 해서 파형을 만들어내고 그 파형에 따라서 각도가 발생하는 점을 생각하시고 동영상의 서보모터의 회전을 보시면 되겠습니다.

마무리


쉬울 것 같아서 소개했는데 하고나니깐 이거 전기 신호의 파형을 봐야하고 서보모터의 동작원리를 자세히 알아야하는데 그렇게 자세히 설명을 하자니 삼천포로 빠질 가능성이 있어서 기본만 설명하다보니 좀 애매하게 됐네요.
오늘 포스팅 내용은 그냥 이런게 있구나 정도로만 하고 그냥 넘어가시고 구지 깊게 생각할 필요 없고요 편하게 Servo.h 의 Servo 클래스를 이용하시면 됩니다.
그냥 예전에 호기심에서 시작해서 그냥 제어만 해본거라 오늘 포스팅은 가볍게 읽고 이해가 안되더라도 무시하고 넘어가시면 됩니다.


댓글()

[아두이노] 서보모터 제어

IOT/아두이노|2019. 2. 19. 09:18

[아두이노] 서보모터 제어



이전 시간까지는 칩과 관련해서 제어를 하다보니 복잡한 주제를 포스팅 했었습니다. 이번에는 좀 쉬운 주제를 다루고자 합니다. 기본 서보모터 동작 제어만 다루기 때문에 별거 아니라고 생각 할 수 있지만 서보모터 제어는 나중에 아두이노로 작품을 만들때 가장 많이 사용하는 부품입니다. 그리고 사용 목적에 따라서 코딩 능력을 필요로 하는 부분이기도 하기 때문에 사용목적에 따라 좀 어려울 질 수 있는 부품이기도 합니다. 하지만 오늘 포스팅은 단순한 제어를 통해 서보모터를 체엄하도록 하죠.

1. 서보모터



서보모터는 Vcc(5V), Gnd, Signal(입력신호)로 3핀으로 구성되어 있습니다. 아두이노에서 Signal핀에 신호를 보냄으로써 각도를 제어하게 됩니다.

2. 회로도 구성


  • 준비물 : 서보모터 1개, 아두이노우노
  • 내용 : 서보모터 회전 시키자


가장 간단한 회로도 입니다. Vcc은 5V에 Gnd은 Gnd에 Signal은 9핀에 연결하면 완료입니다. 원래 모터제어를 할때는 모터쉴드보드가 필요합니다. 하지만 서보모터의 경우는 아두이노에서 직접 제어해도 됩니다.

3. 코딩


  • 사용함수 : attach(사용핀), write(각도), writeMicroseconds(각도시간값)
  • 내용 : 간단히 180도 회전만 시키자.

설계

(1) 서보모터객체 선언

서보모터를 사용하기 위해서는 제어함수들이 있는 Servo클래스를 객체로 선언합니다. 이말은 예전에 변수 선언과 같은 의미로 생각하시면 됩니다. Servo 클래스를 하나의 변수에 저장되었다고 생각하시면 됩니다.

#include <Servo.h> 
Servo servo1; 

Servo.h 파일에 있는 Servo 클래스를 servo1이라는 객체변수로 선언합니다. 그래서 servo1 객체를 통해서 Servo 클래스 안에 함수들을 사용하게 됩니다. 쉽게말해서 servo1.함수() 이렇게 Servo클래스의 함수를 사용할 수 있게 됩니다.

(2) 서보모터객체 연결

servo1.attach(사용핀);
servo1.attach(사용핀,min,max); //Ardunio min = 544, max=2400

attach()함수는 해당핀을 서보모터를 제어하는 핀으로 사용하겠다는 의미로 받아 들이시면 됩니다. 여기서, 두가지 방식이 있는데 첫번째, 사용핀만 인자로 넘겨주면 기본값으로 자동으로 세팅됩니다. 두번째, min, max로 범위를 따로 지정해 줄 수 있습니다. 두번째 방식이 좀 더 서보모터를 정교하게 제어할 수 있습니다.

과거 tinkercad.com 사이트로 옮기전 사이트에서는 서보모터가 다른 종류가 한개 더 있었는데 그 모터에서는 min, max값을 1000, 2000으로 줘서 1500일때 90도 회전이였습니다. 가상시뮬에터에서는 그냥 544, 2400으로 맞춰서 실험했네요. 서보모터마다 제어하는 각도가 차이가 있기 때문에 조정 작업이 필요합니다. 그래서 범위를 지정해서 하실때는 사용하시는 서보모터의 종류에 따라 다르니깐 꼭 보정을 하셔야 합니다.

(3) 서보모터객체 제어

servo1.write(180); 
servo1.writeMicroseconds(2400);

여기에서 write(각도)로 제어하시면 서보모터 기종에 따라서 약간 차이를 보이게 됩니다. 정확하게 제어가 안될 수 있습니다. 하지만 writeMicroseconds(2400)로 제어하시면 오차율을 줄일 수 있습니다. 하지만 보정을 해야하기 때문에 좀 귀찮은 점이 있지요.

(3) delay()함수 사용

delay(2000);

180도를 회전 시킬려고 하는데 일정 시간이 필요합니다.

만약에,

servo1.write(180); 
delay(500);
servo1.write(0); 
delay(500);

delay(500)으로 할 경우 0.5초동안 180도로 갈려고 회전하는 도중에 딜레이 시간이 끝나면 0도로 가는 명령라인이 실행됩니다. 그러면 180도 회전이 안된 상태에서 다시 0도로 회전되어 버리는 현상이 발생합니다. 그래서 각도별 delay()함수로 시간 조정이 필요합니다.

코딩을 하면

첫번째,

#include <Servo.h> 

Servo servo1; 
int servoPin1 = 9;

void setup() 
{ 
    servo1.attach(servoPin1); 
}

void loop() 
{
    servo1.write(180);     
    delay(2000);
    servo1.write(0);     
        delay(2000);
}

두번째,

#include <Servo.h> 
 
Servo servo1; 
int servoPin1 = 9;

void setup() 
{ 
    servo1.attach(servoPin2,544,2400); //Ardunio min = 544, max=2400
}


void loop() 
{
    servo1.writeMicroseconds(2400);
    delay(2000);
    servo1.writeMicroseconds(544);
    delay(2000);   
}

5. 결과




가장 빠르게 작업했네요.

마무리


그러면 서보모터로 제어할 수 있는게 뭐가 있을까요. 지금까지 다룬 부품중에 이거랑 같이 쓸 수 있는게 뭐가 있을지 곰곰히 생각해 보세요.

가령 초음파센서를 여기에다 붙이여 어떻게 될까요. 서보모터로 각도가 제어된다면 거기에 초음파센서가 부착된다면 초음파 센서를 회전 시킬 수 있다는 의미가 됩니다. 회전 각도에 따른 거리측정이 이루어지면 어떤 일이 할 수 있을가요. 가장 많이 알려진게 레이더 입니다. 즉, 각도별 거리를 측정해서 모니터에 초음파센서에 감지된 장애물을 표시 할 수 있습니다. 또 하나는 자율주행차 입니다. 주변의 장애물을 측정해서 미로 같은 곳을 주행하면서 혼자서 피해다니면서 주행을 할 수 있게 되겠죠. 또 한가지는 180도 각도의 거리를 측정하여 그 거리들을 일정한 간격으로 게속 누적 측정한다면 그 데이터로 3D Rendering도 수행이 가능합니다. 그외로 서보모터와 초음파센서가 결합하면 다양한 표현이 가능합니다.

그러면 서보모터만으로 제어할 수 있는 다른 것들은 뭐가 있을까요. 이 글을 읽으시는 당신의 가장 가까운 곳에 정답이 있습니다. 바로 당신이 하는 행동을 비슷하게 제어할 수 있습니다. "뭘까요!" 그것은 바로 관절입니다. 관절 꺽기가 된다는 것이죠. 당신의 손을 바라보세요. 그리고 둘째(집게) 손가락을 한번 구브렸다 펴보세요. 둘째 손가락은 3마디이고 그 중간 관절을 중심으로 각 마디가 구브러졌다 펴질 꺼에요. 바로 그게 회전입니다. 그 관절 부위를 서보모터로 제어한다고 생각하시면 됩니다. 손가락 하나를 제어하게 되면 손을 제어할 수 있게 됩니다. 그러면 한쪽 팔을 제어할 수 있게 되고 그러면 로보팔을 만드는데 이용하면 되겠죠. 보다 정교하게 제어하고 싶을때 360도 회전하면서 하고 싶다면 스템모터로 제어하면 됩니다.

기본 제어로 180도 회전이였지만 좀 더 전문적으로 제어하기 위해서는 현실에서 곤충의 보행을 관찰하면서 관절의 각도를 계산해서 4,6,8축 로못으로 보행을 시킬 수 있고 사람의 손 동작의 움직일때 각 마디의 각도를 관찰하여 각도를 계산하시면 로봇팔을 만들 수 있습니다.

마지막으로 본인의 움직임의 각도를 측정해서 그걸 아두이노로 서보모터로 회전시켜 비슷하게 표현 하는 것을 상상해 보세요. 참고로 여러개의 서보모터를 아두이노에서 제어가 가능하지만 서보모터의 전류를 아두이노에서 전부 공급하면 안됩니다. 가상시뮬레이터에서는 가능하지만 현실에서는 모터에게 전류를 순간 많이 공급하면 아두이노에 불안정 전류 공급이 이루어질 수 있기 때문에 안좋습니다. 외부전류 공급을 추천 드려며 많은 모터를 제어하고자 할때는 따로 여러모터를 한번에 제어할 수 있는 보드가 있는데 오래전에 본거라 보드 이름이 생각 안나네요. 한번 구글링 하셔서 여러 모터를 제어할 수 있는 보드를 찾아보세요.


댓글()

[아두이노] 74HC595+CD4511+7SegmentLED 제어

IOT/아두이노|2019. 2. 18. 08:19

[아두이노] 74HC595+CD4511+7SegmentLED 제어



최종적으로 쉬프트레지스터(74HC595)와 7 segment Decoder(CD4511)를 결합하여 7 Segment LED를 제어하는 실험을 하고자 합니다. 아두이노에서 7 Segment LED를 제어하는 실험에서 출발하여 74HC595, CD4511 칩들을 개별적으로 이용하여 7 Segment LED를 제어 했었습니다. 이 두 칩을 연결하여 제어를 통해 7 Segment LED 실험을 마루리 하고자 합니다.

1. 7 74HC595 + CD4511 연결



위 그림에서 보면 아두이노에서 74HC595 칩으로 3개의 핀으로 입력을 하면 74HC595 칩에서는 8개의 출력 신호를 만들어 냅니다. 8개의 출력 신호에서 4개의 출력로 나눠서 각 CD4511 칩에 입력으로 들어가고 CD4511 칩에서 7개의 출력 신호를 최종적으로 만들어 냅니다.

여기서 출력핀을 제외한 나머지 핀들은 Vcc, Gnd에 연결되는 핀인데 그림에서는 생략 했습니다. 혹시 이해가 안되시는 분들은 위의 참고자료를 보시고 각 칩에 대한 연결을 다시 공부하셔야 합니다.

2. 회로도 구성


  • 준비물 : 74HC595 칩 1개, CD4511 칩 1개, 7 Segment LED 2개, 저항 330옴 2개, 저항 10k옴 8개, 아두이노우노, 뻥판
  • 내용 : 74HC595+CD4511 칩을 연결하여 7 Segment LED에 숫자를 출력하게 하자. 참고로 7 Segment LED(캐소드형)


전체 회로도 구성을 보시면 머리가 복잡해질 꺼에요. 이것은 개별적으로 이해 하시면 쉬울 꺼에요.

첫번째, 74HC595 칩을 제어하기 위해서 9,11,12핀을 이용한다. 회로도 74HC595 칩에 입력선과 Vcc, Gnd 선 연결만 생각하시고 출력선은 잠시 잊어주세요.

두번쨰, CD4511 칩을 제어하기 위해서는 4개의 입력이 필요합니다 하지만 회로도에서 입력선을 제외한 나머지 Vcc, Gnd 선 연결만 생각하시고 입력선, 출력선은 잠시 잊어 주세요.

세번째, CD4511 칩 입력 4개의 핀이고 8421(BCD) 코드표의 기준으로 배치하니깐 '0000'은 74HC595 출력핀 기준으로 '4321' 핀 순서로 입력을 넣어야 합니다. 그래서 1=A, 2=B, 3=C, 4=D 핀끼리 연결합니다. 나머지 CD4511 칩에다도 '0000'은 '8765' 핀 순서로 입력을 넣어야 겠죠. 5=A, 6=B, 7=C, 8=D 핀끼리 연결합니다.

네번째, 7 Segment LED은 CD4511칩의 출력 A,B,C,D,E,F,G핀에서 7 Segment LED의 입력 a,b,c,d,e,f,g핀으로 순서대로 A=a, B=b, C=c, D=d, E=e, F=f, G=g로 연결하면 됩니다.

다섯번째, 7 Segment LED은 캐소드형으로 변경 해주세요. 보고 똑같이 선 연결했는데 왜! 안돼! 이럴 수 있습니다. 애노드형인지 캐소드 형인지 꼭 확인이 필요합니다. 7 Segment LED은 캐소드형이여서 COM2의 핀에 Gnd로 연결을 하게 됩니다. 딱 볼때 COM1 or COM2가 Vcc로 연결되면 애노드형, Gnd로 연결되면 캐소드형으로 생각하시면 됩니다.

보시면 선연결이 많다 보니깐 복잡해 보이는데 개별적으로 하나씩 선 연결하시면 그리 어렵지 않을거라 생각 되네요.

3. 코딩


  • 사용함수 : pinMode(출력핀, 모드), digitalWrite(결쇠핀, 열림/잠금), shiftOut(데이터입력핀, 클럭핀, 순서, 데이터전송값)
  • 내용 : 쉬프트레지스터(74HC595)에 맞춰서 2개의 7 Segment LED에 숫자를 출력해 보자.
  • 참고 : 쉬프트레지스터(74HC595) 제어(아두이노)

설계

(1) 숫자패턴 배열변수 만든다.

byte data[]={
0B00000000,
0B00000001,  
0B00000010,
0B00000011,
0B00000100,  
0B00000101,  
0B00000110,  
0B00000111,
0B00001000,  
0B00001001,  
};

지난 시간의 쉬프트레지스터(74HC595) 코딩을 기준으로 약간만 수정하여 의미만 전달하도록 코딩했습니다. 8개의 비트값이 있습니다. 왼쪽 4개는 왼쪽 CD4511 칩에 입력값이고 오른쪽 4개는 오른쪽 CD4511 칩에 입력값이 됩니다.

즉,

0000 0001 => '0' 과 '1' 이 7 Segment LED에 출력됩니다.

만약에 '1'과 '2'을 출력하고 싶다면 바이트 값이 어떻게 바꿔야 할까요.

0001 0010 => 0B00010010

이해가 되셨죠.

(2) 숫자 출력

digitalWrite(latchPin, LOW); //열림
shiftOut(dataPin, clockPin, MSBFIRST, data[i]); //패턴입력
digitalWrite(latchPin, HIGH); //닫힘

코딩을 하면

byte data[]={
0B00000000,
0B00000001,  
0B00000010,
0B00000011,
0B00000100,  
0B00000101,  
0B00000110,  
0B00000111,
0B00001000,  
0B00001001,  
};

int latchPin = 11; //ST_CP Pin
int clockPin = 12; //SH_CP Pin
int dataPin = 9; //DS Pin

void setup(){
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
}
void loop(){
 for(int i=0;i<10;i++){
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, data[i]);
    digitalWrite(latchPin, HIGH);       
    delay(1000);
  }  
}

4. 추가 코딩(프로그램영역이라 생략하셔도 됨)


본 코딩은 제 블로그에 올렸던 코딩으로 설명 드리겠습니다.

0B00000000을 16진수로 표현할 수 있다고 했죠. 16진수로 '0x00'로 표현이 됩니다.
그러면 위 값들을 다시 표현을 하면은 다음과 같습니다.

0x00
0x01
0x02
0x03
0x04
0x05
0x06
0x07
0x08
0x09

자세히 보시면 한자리씩 증가되는걸 보실 수 있을꺼에요. 그러면 11이면'0x11'로 표현이 되면 '0x' 이것만 빼면은 그냥 숫자로 생각해도 되겠다는 생각이 아마 들꺼에요. 이걸 이용해서 숫자를 쉽게 만들어보자는 생각을 하셔야 합니다.

7 Segment LED가 2개를 사용하니깐 16진수를 사용하면 2자리 숫자를 쉽게 표현이 되겠죠.

byte total=0x00; //출력
byte A=0x00; //1의 자리
byte B=0x00; //10의 자리

이렇게 3개의 변수를 선언합니다. loop()함수 내에서

A=A+0x01;  or A+=0x01;

이렇게 하면 A은 0x01씩 증가합니다. delay(1000) 함수로 1초 단위로 저 명령문을 수행하면 1초 단위로 '0x01'씩 숫자를 증가 시키고 그 값은7 Segment LED로 숫자 1씩 증가한 숫자가 출력되겠죠.

1분짜리 시간을 카운터 한다고 해봅시다.

void loop(){
  
  total = A+B;  
  현재 total값 74HC595에 출력;

  delay(1000);
    
  A=A+0x01; 
  if(A==0x0A){
    A=0x00;
    B=B+0x10;
  }
    
  if(total==0X59) B=0x00;
}

A을 '0x01'증가 시킵니다. if 조건문으로 '0x0A' 이면 '0x00' 초기화 합니다. 여기서 '0x0A'은 10을 나타냅니다. 16진수는 9까지는 숫자로 나타내고 10부터 A,B,C,D,E,F로 0~15까지 숫자를 한자리에 표현을 할 수 있습니다. 그래서 16진수인거죠. 우리가 일상에서 쓰는 0~9까지 10진수 입니다. 그렇다고 10진수라고 부르며 쓰지는 않죠. 생략해서 그냥 숫자를 쓰는 것 뿐이죠. 16진수는 0~15까지 한자리에 표현할 수 있는 숫자라는 것만 머리속에 담아 놓으시면 됩니다.

다시 돌아와서 A은 일의 자리이기 때문에 0~9까지 숫자가 표현되고 10(0x0A)가 되면 안되겠죠. 딱 9(0x09)까지만 출력되여야 하기 때문에 조건문으로 10인지 체크하는 것이죠. 10이면 B가 10의 자리이기 때문에 그때 두번째 자리에 '0x10'을 더하게 됩니다. 조건문에서 10이 되니깐 1의 자리는 '0x00'으로 초기화 하고 10의 자리는 '0x10'으로 1이 증가 시키는 로직으로 표현된 것이죠.

마지막으로 if문은 total이 0x59이면 이전에 delay()함수로 1초가 지났기 때문에 실제는 60초가 됩니다. 하지만 loop()함수가 다음 호출되어 반복하기 전이기 때문에 total값은 59초값을 가지고 있기 때문에 if 조건문에서 '0x59' 인가라고 조건을 단것이지요. 실제로는 60초인가라는 조건문으로 생각하시면 됩니다. 60초면 B를 초기화 시키기 위해서 B=0x00로 표현하게 됩니다.

결론은 첫번째 if문은 A을 증가시킨값이 10초 되면 A를 초기화 후 B를 1씩 증가시키고 두번재 if문 B가 60초가 되면 B를 초기화 시키라는 로직입니다. 60초 되면 A은 10초가 되고 A는 초기화 되고 B은 60초 되면 당연이 B도 초기화 됩니다. 다음 루프함수는 total = 0x00 + 0x00; 이 됩니다. 결론은 00이 7 Segment LED에 출력이 됩니다.

이걸 이용하시면 시계를 만들 수 있겠죠. 초기값을 현재 시간값으로 저장시키면 자동으로 그 시간을 기준으로 시간을 계속 출력시킬 수 있겠죠.

코딩을 수정을 하면

byte total=0x00;//출력
byte A=0x00; //1의 자리
byte B=0x00; //10의 자리

int latchPin = 11; //ST_CP Pin
int clockPin = 12; //SH_CP Pin
int dataPin = 9; //DS Pin

void setup(){
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
}

void loop(){

  total = A+B;  
   
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, total);
  digitalWrite(latchPin, HIGH);       
  
  delay(1000);
    
  A=A+0x01; 
  if(A==0x0A){
    A=0x00;
    B=B+0x10;
  }
    
  if(total==0X59) B=0x00;
}

5. 결과


회로도를 만드는 과정을 영상으로 만들려고 하니깐 너무 심한 노가다여서 그냥 마지막 출력된 영상만 보여줄까도 고민하다고 그래도 전과정을 보여주는게 나을 것 같아서 이미 회로도를 만들어 놓은게 있었지만 한번 더 작업을 했네요.


마무리


드디어 7 Segment LED를 아두이노 제어에서 여기까지 왔습니다. 다른 칩까지 가면 너무 힘들 것 같아서 여기서 최종적으로 마무리 할까 합니다. 원래는 74HC595, CD4511 칩들은 대량의 LED를 제어할 목적으로 많이 쓰는 것 같더군요. 이 칩만 잘 활용해도 아두이노우노의 적은 핀을 가지고도 많은 부품들을 제어할 수 있어 확장성이 엄청 좋습니다. 한번 힘들더라도 부품의 데이터시트나 여러 블로그의 예제들을 보고 연구해 보셨으면 합니다.
이것만 알아도 표현할 수 있는 것들이 무궁무진 하니깐 상상의 나래를 펼쳐 보세요.


댓글()

[아두이노] 스위치버턴으로 CD4511를 제어해 보자

IOT/아두이노|2019. 2. 17. 17:31

[아두이노] 스위치버턴으로 CD4511를 제어해 보자



지금까지 7 Segment LED를 제어하는데 필수적으로 아두이노를 사용했습니다. 하지만 이번에 아두이노 없이 4x스위치버턴으로 CD4511 칩의 입력값을 제어하여 그 결과를 7 Segment LED로 출력하는 실험입니다. 보다 쉽게 CD4511 칩 제어하는 원리를 이해하실 수 있을거에요.

1. 회로도 구성


  • 준비물 : CD4511 칩 1개, 7 Segment LED 1개, 저항 330옴 1개, 저항 10k옴 4개, 파워서플라이. DIP Switch SPST x 4
  • 내용 : CD4511 칩을 이용해서 7 Segment LED에 숫자를 출력하게 하자. 참고로 7 Segment LED(캐소드형)

지난 시간의 회로도에서 아두이노를 뺀 부분에 파워서플라이. DIP Switch SPST x 4를 연결한 회로도입니다.


2. 스위치버턴와 CD4511 칩의 동작 원리


스위치 버턴(DIP Switch SPST x 4)의 동작 원리는 지난 시간의 아두이노코딩에서 패턴을 생각하시면 됩니다.

int data[10][4]={
  {0,0,0,0}, //0
  {0,0,0,1}, //1
  {0,0,1,0}, //2
  {0,0,1,1}, //3
  {0,1,0,0}, //4
  {0,1,0,1}, //5
  {0,1,1,0}, //6
  {0,1,1,1}, //7
  {1,0,0,0}, //8
  {1,0,0,1}  //9
};

이렇게 2차배열변수로 패턴을 저장했었죠. 이 값은 8421(BCD) 코드값입니다.

0000 //0
0001 //1
0010 //2
0011 //3
0100 //4
0101 //5
0110 //6
0111 //7
1000 //8
1001 //9
....
1111 //F

이렇게 8421(BCD) 코드에서 0~9까지만 사용 합니다. 그리고 자세히 보시면 네자리로 구성되어 있는걸 보실거에요. 회로도에 보시면 4x스위치 버턴을 구성되어 있습니다. 여기서 눈치가 빠른분들은 아 8421 코드표랑 4x스위치버턴과 연관있지 않을까 생각하실 겁니다.
회로도의 스위치 버턴을 자세히 보시면 8421 코드표랑 4x스위치버턴을 일치시켰습니다. 그리고 4x스위치버턴의 방향이 전부 아래 방향으로 향하고 있는데 이상태는 전류가 차단 된 0V의 상태이고 버턴이 위로 향할때 CD4511 칩에 Vcc의 전류가 흘러 들어가 됩니다.

4x스위치 버턴의 위치에 따라 동작은 -

  • 0000 상태 : CD4511(7 Segment Decoder) 칩의 출력은 7 Segment LED의 0의 LED가 불이 들어오도록 출력
  • 0001 상태 : CD4511(7 Segment Decoder) 칩의 출력은 7 Segment LED의 1의 LED가 불이 들어오도록 출력

설명보다도 실제 가상시뮬레이터로 4x스위치 버턴을 한번 위아래로 8421 코그 값대로 1이면 위로 올리고 0이면 아래로 내리면서 스위치 버턴을 조작하시면 CD4511 칩의 입력신호에 따른 7 Segment LED로 어떻게 출력되는지 쉽게 확인할 수 있을꺼에요.

좀 더 CD4511(7 Segment Decoder) 칩의 출력 상태를 알고 싶다면 7 Segment LED 대신에 7개의 LED를 배치하여 정확히 CD4511(7 Segment Decoder) 칩의 7개의 출력 값들의 변화를 확인할 수 있습니다.

예)

0은 0000 => 출력값은 1111110 됩니다.

3. 결과


가상시뮬레이터에 회로도를 배치하는 과정과 결과가 어떻게 출력되는지 보여주는 영상입니다. 잘 모르셔도 그대로 따라서 회로도를 만들어 보시면 글을 읽는것보다 싶게 동작 원리가 이해가 되실 꺼에요.


마무리


여기서, 4x스위치 버턴을 통해 CD4511 칩을 제어하는 회로도를 소개하는 이유는 CD4511 칩의 입력신호에 대한 출력신호를 쉽게 이해하기 위해서 입니다. 그리고, 4x스위치 버턴을 통한 실제 수동 제어를 해보면서 이런 동작을 지난시간에 아두이노 코딩제어를 통해 7 Segment LED 숫자를 만든 것을 직접 수동제어를 통해 느끼게 하는게 목적이기도 합니다. 또한, 지난시간에 명령 로직 코딩을 통해 쉽게 0~9까지 출력했던 아두이노와 비교를 통해 현실의 동작을 프로그램화 하면 얼마나 편하게 제어가 되는지 보여줄려는 의도도 있지요.


댓글()

[아두이노] 7 Segment Decoder(CD4511) 제어

IOT/아두이노|2019. 2. 16. 14:57

[아두이노] 7 Segment Decoder(CD4511) 제어



이번에도 새로운 칩을 소개 합니다. 7-segment Decoder(CD4511)은 7 Segment LED를 제어하는데 효율적인 칩입니다. 다른곳에서 원리만 이해하셨다면 사용 가능합니다. 이 칩은 4가지 값에 의해서 7개의 출력값을 만들어 낼 수 있습니다. 이 칩도 제 블로그에서 소개했던 내용인데 7 Segment LED를 포스팅 할때 한번에 소개하는게 나을 것 같아서 가상시뮬레이터에서도 제공되는 칩으로 이번에는 CD4511 칩을 이용해 실험하고자 합니다.

1. 7 segment Decoder(CD4511)



위 그림에서 보는것 처럼 입력 A,B,C,D 핀으로 아두이노에서 4개의 핀의 출력값을 CD4511 칩에 입력으로 받게 됩니다. CD4511 칩의 연결은 다음 과 같습니다.

  • Vcc핀 과 Gnd핀은 아두이노에 5V와 Gnd 핀에 연결
  • LT핀와 BI핀은 Vcc로 연결
  • LE핀은 Gnd로 연결
  • 입력 A,B,C,D핀은 아두이노 디지털핀 4개 연결(실험에서는 2,3,4,5핀 사용)
  • 출력 a,b,c,d,e,f,g핀은 7 Segment LED의 DP핀을 제외한 나머지 순차적으로 A,B,C,D,E,F,G핀에 연결

여기서 회로도 설계할때에 선 연결이 노가다 작업으로 좀 힘들지만 그래도 한번 이해하면 나중에 쉽게 사용이 가능해 집니다. CD4511 칩에 선들을 어떻게 연결하는지가 숙지하시면 됩니다.

2. 회로도 구성


  • 준비물 : CD4511 칩 1개, 7 Segment LED 1개(캐소드형임), 저항 330옴 1개, 저항 10k옴 4개, 아두이노우노, 뻥판
  • 내용 : CD4511 칩을 이용해서 7 Segment LED에 숫자를 출력하게 하자. 참고로 7 Segment LED(캐소드형)


CD4511 칩에 입력을 바로 아두이노의 출력값 5V를 보내지 않고 10K옴의 저항을 붙여줍니다. 스위치 버턴을 연상하시면 됩니다. 어짜피 상태값만 보내주면 되기 때문인거죠. 정확히 CD4511 칩의 허용 전압이 기억이 안나서 안전하게 저항을 붙였습니다. 데이터시트를 인터넷에서 찾아보셔서 허용 전압을 참고하시면 되겠습니다. 위에서 설명한 CD4511 칩의 핀들이 어디에 연결하는지 설명한대로 실제 선을 연결하시면 됩니다. 그리고 주의할 것은 7 Segment LED은 캐소드형 입니다.

처음에만 복잡해 보일뿐 익숙해지면 단순합니다. 핀에 마우스를 대면 핀 이름이 나오고 해당된 부품과 연결하시면 됩니다.

3. 코딩


  • 사용함수 : pinMode(출력핀, 모드), digitalWrite(출력핀, 상태값)
  • 내용 : 아두이노에서 4개의 출력 상태를 값을 CD4511 칩을 제어하여 7 Segment LED에 숫자를 0~9까지 순차적으로 출력해보자.(7 Segment LED은 캐소드형으로 이 기준으로 코딩함)

  • CD4511 제어 :
    • digitalWrite(출력핀, 상태값)으로 CD4511 칩의 출력값을 결정

참쉽죠. LED 제어할대 배운 PinMode()와 digitalWrite()함수만 사용하시면 됩니다.

설계

(1) 숫자 패턴만들기

CD4511 4개의 입력값을 받습니다. 그러면 4개의 상태를 8421 BCD 코드표를 참조하시면 좋습니다. 캐소드형 7 Segment LED를 하면 정확히 아두이노 핀의 역순으로 코딩하면 일치하게 됩니다. 그래서 이번 실험은 이해하기 쉽게 캐소드형 코딩을 선택했습니다.

0000 => 0
0001 => 1
0010 => 2
...

0은 0000 => 출력값은 1111110 됩니다.
0은 A[4] = {0,0,0,0}
그러면 0~9까지 10개의 패턴이니깐 2차배열변수로 만들면은 아래와 같이 만들어 지겠죠.

int data[10][4]={
   {0,0,0,0}, //0
   {0,0,0,1}, //1
   {0,0,1,0}, //2
   {0,0,1,1}, //3
   {0,1,0,0}, //4
   {0,1,0,1}, //5
   {0,1,1,0}, //6
   {0,1,1,1}, //7
   {1,0,0,0}, //8
   {1,0,0,1}  //9
};

(2) 숫자 출력

0은 A[4] = {0,0,0,0} 이고,
datapin은 datatpin[4] = { 5,4,3,2} 하면

 for(int j=0;j<4;j++){
    digitalWrite(datapin[j],A[j]);
 }

이렇게 됩니다. 하지만 10개의 패턴과 각 패턴의 상태값 4개를 2차 배열 위의 date[10][4]로 만들면 2차 for문을 사용하면

  for(int i=0;i<10;i++){
     for(int j=0;j<4;j++){
       digitalWrite(datapin[j],data[i][j]);
     }
     delay(1000);
  }     

여기서 delay(1000)을 두어 1초 단위로 0~9까지 7 Segment LED에 출력되게 됩니다.

코딩을 하면

int data[10][4]={
   {0,0,0,0}, //0
   {0,0,0,1}, //1
   {0,0,1,0}, //2
   {0,0,1,1}, //3
   {0,1,0,0}, //4
   {0,1,0,1}, //5
   {0,1,1,0}, //6
   {0,1,1,1}, //7
   {1,0,0,0}, //8
   {1,0,0,1}  //9
};
int datapin[4] ={5,4,3,2};

void setup(){
  for(int i=0;i<4;i++){
    pinMode(datapin[i],OUTPUT);
  }
}
void loop(){
   for(int i=0;i<10;i++){
     for(int j=0;j<4;j++){
       digitalWrite(datapin[j],data[i][j]);
     }
     delay(1000);
  } 
} 

4. 결과


결과 동영상을 보면 다이렉트로 전 과정을 동영상 촬영을 했는데 회로도를 만드는 과정에서 Vcc 선을 Gnd로 잘못 연결해서 가상시뮬레이터 처음 실행에서 CD4511 칩이 망가졌습니다. 가상시뮬레이터라서 실제로 CD4511 칩이 망가지는 것이 아니기 때문에 그렇게 큰 의미는 없지만 이걸 실제로 선을 잘못 연결한다면 칩에 문제가 생기겠지요. 다시 동영상으로 촬영할려다가 선 연결의 중요성과 이런 점에서 가상시뮬레이터를 사용의 장점이 될 것 같아서 그냥 올립니다.(실제로 다시 촬영하기 귀찮음!)

마무리


74HC595 칩은 3핀을 사용했지만 CD4511 칩은 4핀을 사용합니다. 그러면 이전 시간에 배운 74HC595 칩으로 하는게 좋을 것 같다는 생각을 하실 수 있습니다. CD4511 칩을 제어는 무지 간단 합니다. 아두이노 없이도 이 칩을 이용해서 7 Segment LED를 제어가 가능합니다.

그리고 74HC595+CD4511으로 7 Segment LED를 제어를 한번 해보세요. 이 두 칩을 배우고 나서 이걸 합쳐서 실험해보고 싶어져서 7 Segment LED를 제어 해보았어요. 이 내용은 다음 포스팅에 쓰도록 할께요. 한번 두 칩에 동작 원리를 생각하고 회로도를 구성하고 코딩해보세요.

한번 74HC595칩과 CD4511을 결합을 하면 어떻게 회로도가 표현 되는지 상상의 나래를 펼쳐보세요.


댓글()