[아두이노] 아두이노 코딩 변수

IOT/아두이노기초문법|2019. 4. 10. 09:00

[아두이노] 아두이노 코딩 변수



오늘은 예전에 아두이노 변수란 포스팅을 한 적이 있습니다. 불가피하게 이번 연재한 포스트의 흐름을 이여가기 위해서 약간은 중복된 내용이 포함되게 되었네요. 참고로 오늘 내용은 변수에 대해서 간단히 살펴보고 변수를 사용하여 코딩하는 것 까지 다루도록 하겠습니다.

1. 아두이노의 변수


이 부분은 자세히 참고 포스트에서 설명했지만 처음부터 다시 시작한다는 기분으로 간단히 복습 차원으로 짧게 기초만 알아둘 것만 정리하겠습니다.


자료형은 담을 수 있는 그릇이고 변수는 그 그릇의 이름입니다. C에서는 변수를 선언할때 변수의 크기인 자료형을 선언해줘야 합니다. 사용할 변수에는 자료형이 무조건 선언된다고 암기해 주세요.

char A = 'a';

char은 문자형 그릇이고 A라는 이름을 가집니다. A라는 그릇에 'a'라는 문자를 저장합니다.

int B = 123;

int은 정수형 그릇이고 B라는 이름을 가집니다. B라는 그릇에 '123' 이라는 숫자를 저장합니다.

float C = 123,12;

float은 실수형 그릇이고 C라는 이름을 가집니다. C라는 그릇에 '123.12'이라는 실수를 저장합니다.


위의 그림처럼 그릇의 크기가 대충 이런 느낌이라고 생각하시면 됩니다.


자료형 범위

  • 1 Bytes => -128~127
  • 2 Bytes => -32768~32767
  • 4 Bytes => -2147483648 ~2.147.483.647

그냥 작은수, 큰수, 실수 이정도로만 생각하시고 넘어가세요. 나중에 코딩하다보면 자연스럽게 자료형을 뭘 써야지 알게 됩니다. 아두이노에서 핀번호를 지정한다면 byte로 하면 가장 알맞겠죠. 그리고 아날로그 출력은 0~255 사이의 값이니깐 대충 int 변수겠죠. 아날로그입력도 0~1024니깐 int 정도면 되겠죠. 뭔가 복잡한 실수 계산이 들어가면 float 실수형으로 선언하면 되겠죠.

간단히, 작은 정수는 byte, 큰 정수면 int or long , 실수면 float or double 형으로 선택하셔서 자료형을 선언한다고 머리속에 넣어두세요.

그외,

boolean D = true; //참거짓에 사용되는 자료형
byte E =1;  //1byte 크기의 자료형
long F = 123; //int자료형과 같은데 그릇의 크기가 4byte으로 int형보다 더 크다.
double G =123,23; //float형보다 더 큰 그릇인데 아두이노에서 4byte 크기로 동일하게 나오네요. 

결론, 변수는 값을 담는 그릇이라고 생각하시면 됩니다.

[ 코딩 ]

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

  char A = 'a';
  int B =123;
  float C =123.23;

  Serial.println(A);
  Serial.println(B);
  Serial.println(C);  

}
void loop()
{  
}

결과만 보기 위해서 처음 한번만 수행하는 setup()함수에 코딩했습니다. 각 자료형 별 변수들에 저장된 값들을 시리얼모니터로 출력을 하면 아래와 같습니다.


변수에 값을 저장할 수 있고 그 값을 이제 시리얼모니터에 출력할 수 있게 되었습니다. 여기까지 따라오셨나요.

2. 사칙연산 코딩


프로그램 코딩은 수학과 아주 밀접한 관계가 있습니다. 덧셈을 하나 생각해 볼까요.

예) 임의의 두 수 a, b를 더하는 식을 만드세요.

S = a + b

위 식은 초등학교 기초 수학시간에 배웠을 꺼에요. 이 표현은 코딩에서는 어떻게 표현되냐면 변경없이 그대로 적용됩니다.

S = a + b;

이렇게 세미콜론(;)만 뒤에 붙이고 그대로 코딩하시면 됩니다. 바뀐건 세미콜론(;) 하나 추가된 것 밖에 없죠. 어떻게 보면 코딩은 우리가 처리하고자 하는 명령들을 수학공식과 같은 형식으로 식을 만들고 그 식을 그대로 코딩하는 거라고 생각하시면 쉬울꺼에요.

그러면, 수학 사칙연산 프로그램을 만들어 볼까요.


사칙연산 표현을 그대로 그냥 동일하게 표현 하시면 됩니다. 덧셈, 뺄셈, 곱셈, 나눗셈을 하고 그 값을 저장하는 변수만 선언해주면 됩니다.

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

  int A = 10;
  int B = 2;
  int addAB = 0;
  int subAB = 0;
  int mulAB = 0;
  int divAB = 0;
  
  addAB = A + B;
  subAB = A - B;
  mulAB = A * B;
  divAB = A / B;
  
  Serial.println(addAB);
  Serial.println(subAB);
  Serial.println(mulAB);  
  Serial.println(divAB);  

}

addAB, subAB, mulAB, divAB라는 4개의 저장변수를 선언했고 해당 식을 수행하면 아래과 같은 결과가 시리얼 모니터로 출력됩니다.


10+2 = 12
10-2 = 8
10*2 = 20
10/2 = 5 

여기까지 따라 오셨나요.

3. 삼각형의 넓이 구하는 프로그램을 만들자



  • 공식 : S= 1/2ah

수학시간에 배우셨죠. 삼각형의 넓이 공식을 떠올려 보세요. 위 공식이 프로그램 전부입니다. 이걸 코딩을 하면

S= (float)1/2*a*h;

세미콜론(;)만 붙이고 곱셈부분은 곱셈기호(*)를 붙여 줍니다. 그리고 계산된 값이 실수 형태로 저장될려면 (float)을 붙여줘야 합니다. 그 이유는 정수/정수는 결과가 정수가 되기 때문에 실수형으로 저장하기 위해서는 이 문장을 표현해야 합니다. 그냥 단순한 수학 공식인데 세미콜론(;)을 붙이니깐 프로그램 로직 명령어가 되었네요. 이렇게 수학적인 표현을 하는게 코딩입니다. 이건 순수 수학의 표현이고요. 이런 의미로 일상의 표현 특정한 동작의 표현을 공식으로 만들고 그걸 그대로 코딩하면 프로그램 코딩이 됩니다. 어렵게 생각하실 필요가 없어요.

실제 돌아가는걸 확인해 볼까요. 공식을 보면 필요한 변수가 3개 입니다. 밑변, 높이, 삼각형넓이 변수가 필요합니다.

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

  int a = 10;
  int h = 5;
  float S =0;
    
    //삼각형 넓이 공식
    S = (float) 1/2*a*h;
    
  Serial.print("base : ");
  Serial.println(a);
  Serial.print("height  : ");
  Serial.println(h);
  Serial.println("Area of triangles : ");  
  Serial.println(S);  

}


[ 결과 ]


밑변(a)와 높이(h)의 값만 바꾸면 모든 삼각형의 넓이를 구할 수 있는 프로그램을 완성했습니다. 그렇게 어렵지 않죠. 이렇게 식을 만들고 그 식을 그대로 코딩하면 그게 프로그램이 됩니다. 이 의미만 오늘 기억하시면 됩니다.

(float) 1/2 * a * b

이부분이 약간 햇갈릴 수 있기 때문에 다시 설명합니다. C언어에서는 정수/정수는 정수가 출력됩니다. 즉, 실수값이 나와도 그 값은 정수형으로 나와버린다는 것이죠. 실수값을 얻기 위해서는 다음과 같은 표현으로 식을 만들어야 합니다.

정수/실수 or 실수/정수 or (flaot) 정수/정수

이렇게 세가지 표현 중에서 하나를 선택해서 표현 하시면 됩니다. 입력값이 a, h가 정수임으로 위 나눗셈이 들어간 식에서는 저장변수가 실수변수여서 식 앞에 (float)형으로 선언하게 된 것이죠. 이 표현은 해당 자료형으로 저장하겠되는 의미입니다.

여러분들도 한번 생각 나는 수학공식을 제가 코딩했던 스타일로 표현을 해 보세요. 위에서 사칙연산을 수행한 계산 값을 출력했는데 뭘 계산한지 모르잖아요 보기 좋게 하기 위해서 이번에는 print(), println()함수로 어떤 값들을 계산했고 결과가 뭔지 출력문에 담았습니다. 이런 표현들을 꼭 숙지하시고 이해해 주세요.

이렇게 해서 대충 변수를 사용하는 방식을 알아 봤습니다.

4. 코딩의 과정



  • 입력단계 : 변수를 선언해서 그 값을 직접 입력하거나 아니면 외부로 부터 값을 입력을 받는다.
  • 처리단계 : 입력된 값을 위에서 수행한 사칙연산과 같은 원하는 동작의 계산식을 만든다.
  • 출력단계 : 결과를 외부로 보내거나 특정한 위치에 출력한다.

무조건 이 과정으로 코딩을 한다는 점 꼭 기억해 주세요. 그러면 아두이노를 생각해 볼까요. 예를 든다면 아두이노에서 센서의 값을 읽으면 입력부분이 되고 그 입력된 센서의 값을 특정한 동작을 수행하도록 하는 표현식(계산식)이 처리단계가 됩니다. 그 결과를 실질적으로 보여지는게 출력 단계입니다.

여러분들이 이제 코딩을 하게 되면 "입력 ->처리->출력" 이걸 머리속에 꼭 담고 코딩를 해주세요.

어떤 값을 받을 것인지!
그 값을 받았으면 어떻게 처리할 것인지!
최종적으로 어떻게 보여질 것인지!

이 개념을 머리속에 담고 코딩을 전개해 나가시면 됩니다.

마무리


오늘은 변수의 자료형인 문자형, 정수형, 실수형 표현을 배웠으며 그 변수를 이용하여 수학공식을 프로그램 코딩을 해 보았습니다. 그리고 마지막으로 코딩은 어떤식으로 이루어지는지 그 과정을 간단히 살펴보았습니다.

프로그램 언어를 배우면 젤 먼저 사칙연산을 코딩하게 됩니다. 그리고 더 관심이 생기면 이 원리를 이용해서 공업용 계산기를 만들기도 합니다. 저도 처음에 사칙연산을 배우고 나서 젤 먼저 공업용 계산기를 코딩을 해 봤고 더 나아가 전자 회로로 계산기도 응용해서 표현을 해 봤네요. 뭔가 원리를 배우면 이걸 어디에다 써먹을까 상상의 나래를 잘 펼치거든요. 여러분들도 오늘 사칙연산과 삼각형의 넓이 구하는 식을 코딩으로 배웠습니다.
여러분들은 이걸 토대로 상상의 나래를 펼쳐보세요. 난 이 원리로 뭘 만들어 볼까하고 계속 상상을 하셔야 응용력이 생겨 새로운것을 만들 수 있게 됩니다.

더 내용을 추가 할 부분이 있었지만 너무 많이 설명하고 깊게 들어가면 오히려 역효과가 날 것 같아서 이부분은 이정도로 마무리 하겠습니다.

프로그램 코딩을 너무 어렵게 생각하지 마시고 그냥 수학식을 하나 만든다고 생각하시고 그 식을 그대로 코딩하면 그게 코딩이 되니깐 어렵게 생각 안하셔도 돼요.

댓글()

[아두이노] 아두이노 코딩 입문

IOT/아두이노기초문법|2019. 4. 9. 09:00

[아두이노] 아두이노 코딩 입문



오늘은 간단히 코딩에 대해 포스팅을 하겠습니다. 사실 비전공자분들은 코딩이 약간 외계어처럼 느껴지시는 분들이 있는 것 같아서 원래는 이런 내용을 초창기 포스트에서 소개 했었야 했는데 늦게 포스팅을 하게 되었네요. 아두이노 코딩을 할때 알아야 기초적인 문법만 포스팅을 하도록 하겠습니다. 이전에 포스팅한 내용들이 일부 중복되지만 그래요 한번에 기초적인 문법을 묶어서 설명하는게 나을 것 같아서 몇일간 코딩에 관련해서 포스팅을 하도록 하겠습니다.

1. 코딩의 준비


[ 아두이노 ]

[ 동작 ]


아두이노에 전원이 공급되면 젤 먼저 setup()함수가 한번 수행되고 그다음 loop()함수가 반복 수행됩니다. 간단히 아두이노에 전류가 공급되면 setup()함수를 수행후 loop()함수가 반복 호출된다는 정도만 머리속에 넣어 두세요.

2. "Hello World" 출력하기


[ 메인창 ]



아두이노를 편집창으로 드래그 하고 나면 오른쪽 항목에 Code 클릭을 해주세요.



기본 베이스 블록을 위 그림처럼 휴지통이나 블록이 있는 쪽으로 드래그 하면 블록은 삭제됩니다.

[ 블록 ]



시리얼통신 블록 :



오른쪽 항목에 Code가 있는데 그걸 선택하면 위 그림처럼 세가지 방식을 선택 할 수 있습니다. 여기서 두번째 줄에 있는 Bloocks+Text를 선택하십시오. 그리고 Output 항목에서 아래 print 블록을 오른쪽으로 드래그 해주세요. Output는 파란색 블록에 있습니다. 그러면 아래와 같은 코딩이 같이 오른쪽에 text창에 나타납니다. print 블록은 Serial 블록이여서 Serial 관련 기본 세팅이 코딩으로 보여집니다. 사실 블록으로 간단히 표현하면 코딩을 구지 할 필요 없습니다. 하지만 블록을 사용하시면 표현하실 때 약간 제약을 받기 때문에 제 경우는 블록보다 Text 코딩을 선호 합니다.

블록 하나를 배치했을때 아래 코딩이 자동으로 생성됩니다.

[ 코딩 ]

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

}

void loop()
{
  Serial.println("hello world"); //시리얼모니터로 출력
  delay(10); 
}

실행을 하기 위해서 아두이노 IDE 시뮬레이터 창을 띄워야겠죠.


위 그림을 보시면 Serial Monitor를 누르면 모니터창이 나타납니다.

시뮬레이터 실행을 누르시면


"hello world"가 계속 출력됩니다.

println("내용");

위 명령문으로 내용을 시리얼모니터로 출력하라는 명령입니다. 이제 C문법을 배울때 그 결과를 이 함수를 사용하여 출력할 예정입니다.

3. Text 모드로 변경


현재상태에서 Text모드로 바꾸시면 아래와 같이 블록만 없어지고 Serial 출력코딩은 그대로 남습니다. 그러면 loo()함수안에 있는 명령들을 아래 그림처럼 setup()함수로 옮겨주세요.


그리고 실행을 누르면 다음과 같이 딱 한번만 수행합니다.


setup()함수와 loop()함수의 차이점을 구별하셨나요. loop() "hello World"문장을 계속 출력하지만 setup()함수는 딱한번 출력하는 것을 확인 하실 수 있을거에요.

여기까지해서 기본 세팅은 끝났네요. 아두이노를 이용해서 "hello World"란 문장으로 시리얼모니터에 출력할 수 있게 되었습니다. 이제 코딩을 하면 그결과를 시리얼모니터로 출력할 수 있겠죠. 여기까지 따라 오셨으면 코딩의 절반을 배운 거나 다름 없습니다.

이제는 코딩 문법을 하나씩 기초 위주로 배워보도록 하겠습니다. 사실 C언어를 C컴파일를 사용해서 C공부를 하면 좋지만 아두이노 환경에서 아두이노와 친근감을 가지기 위해서 아두이노 상에서 프로그램 언어 공부를 배워 보도록 하겠습니다.

4. 시리얼모니터 출력 함수


시리얼모니터에 출력하는 함수가 print(), println(), write()가 있습니다. write()함수를 제외한 print(), println()함수만 주로 사용할 예정입니다. 그래서 이 둘의 차이점만 구별해 주세요.

  • print("내용") : 해당 내용을 출력하고 커서의 위치는 출력된 해당 라인에 계속 머물어 있게 됩니다.
  • println("내용") : 해당 내용을 출력하고 커서의 위치는 새로운 라인으로 이동하게 됩니다.

print()함수의 예제



위 그림을 보시면 두개의 print()함수를 사용했습니다. 첫번째 "hello "문장을 출력하고 커서는 현재라인에 머물어 있기 때문에 다음 "world"라는 문장이 이여서 출력됩니다. 그런데 또 print()함수를 사용한다면 계속 현재라인에서 이여서 출력되겠죠. 그래서 마지막 출력문에는 println()함수를 사용해서 출력라인의 끝을 표현해야 합니다.

println()함수의 예제



위 그림을 보시면 두개의 println()함수를 사용했습니다. 첫번째 "hello "문장을 출력하고 커서는 새로운 라인으로 이동한다고 했죠. 그래서 "world"문장이 새로운 라인에 출력됩니다. 여기서 두번째 함수도 println()함수임으로 3번째 새로운 라인으로 커서가 옮겨져 있겠죠.

출력함수 올바름 사용



위 그림처럼 두이상의 여러개 내용을 한 라인에 모두 출력을 해야 할경우는 print()문으로 표현하다가 마지막 내용에서는 println()으로 표현해서 커서를 옮겨주는 코딩을 하셔야 합니다.

참고로, "내용"에서 안에 공백문자도 인식을 하니깐 공백(스페이스바) 효과도 넣어 띄워쓰기를 할 수 있습니다.

이 차이점만 이해하시고 출발하시면 되겠습니다.

추가 주의사항

세미클론(;) 이라는 기호가 있습니다. 명령문의 끝을 나타내는 기호로 편하게 명령어 수행하라 정도로만 이해해 두세요. 명령문에는 무조건 세미클론이 붙습니다. 이게 생략되면 에러가 발생하니깐 꼭 기억해 주세요.

'{' 와 '}' 괄호는 함수에는 함수의 영역을 표시하는 기호입니다. setup()함수가 수행하면 이 괄호가 시작하는데 부터 괄호가 끝나는 데까지의 내용을 기계가 읽고 수행합니다. 간단히 "괄호는 영역이다!" 정도로 이해하시면 되겠습니다.

마무리


오늘은 코딩의 첫 관문인 시리얼모니터에 명령한 결과를 출력해보는 시간으로 채웠습니다. 이정도만 이해하시면 프로그램언어를 절반정도 이해하셨다고 보면 될꺼에요.
처음하시는분들은 어색할 수 있지만 setup(), loop()함수가 있는데 전원이 공급되면 setup()이 젤 먼저 호출되어 수행한 뒤에 loop()함수가 그 다음에 반복해서 호출 수행한다 정도정도만 이해하세요.
그리고, 오늘 소개한 Serial.print(), Serial.println()함수만 이해하시면 프로그램언어 공부 절반을 배운것이니깐 꼭 원리를 기억해 주세요. 출력함수 하나만 이해해도 프로그램언어를 절반 배운거에요.

원래는 내용이 더 있는데 너무 길게 빼면 그렇 것 같아서 여기서 마무리 합니다.



댓글()

[아두이노] LED를 통한 전류의 흐름 이해

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

[아두이노] LED를 통한 전류의 흐름 이해



오늘은 코딩이 없는 간단한 LED 제어를 통해 전류의 흐름을 배우는 시간을 갖도록 하겠습니다. 실험할 회로도는 Tinkercad에서 제공하는 RGB LED 예제를 기반으로 하겠습니다. Tinkercad 예제를 우연히 보다가 공식적인 실험 예제를 발견하고 이 예제로 실험하면 전류의 흐름을 좀 더 쉽게 이해하는 할 수 있을 것 같아 이번 포스팅 주제로 결정을 했네요.

1. RGB LED 스위치



위 사진은 RGB LED를 사용해야 하는데 Blue LED가 없어서 그 위치에 어쩔 수 없이 Yellow LED를 배치했네요. 스위치를 누르면 해당 Color Led에 불이 들어오고 3색 LED에 해당 Color가 출력되는 회로도입니다. 두개 이상을 누르면 두가지 Color가 혼합된 Color로 3색 LED에 불이 들어오게 됩니다. Blue LED가 없어서 Yellow LED에 불이 들어오지만 해당 위치는 Blue이기 때문에 3색 LED에는 Blue가 출력되도록 세팅 했네요.

2. RGB LED


1) Tinkercad의 공식 RGB LED 회로도

출처 : Tinkercad 예제

해당 회로도에서는 9V의 건전지를 사용했더군요. 그러면 LED의 저항은 9V에 맞게 다시 계산되어야 합니다. "V=IR" 공식에서 R의 저항값을 다시 계산기로 계산해야 하는데 귀찮아서 회로도의 저항 속성창을 통해 저항을 확인해보니 480옴이더군요.

위 회로도는 뭘 표현한건지 대충 아니깐 직접 안보고 만들어 보도록 하겠습니다. 혹시 원리를 모르시는 분들을 위해 간단히 설명을 하면 스위치 버턴을 누르면 해당 스위치에 연결된 선을 전류가 흐릅니다. 여기서 Red, Blue, Green Led가 각 스위치마다 연결되어 있습니다. 해당 스위치를 누르면 각 color의 Led에 불이 들어옵니다. 여기까지 이해하셨으면 여기서 스위치에 선이 추가되어 3색 LED에 연결하면 어떻게 될까요. Red Led에 연결된 선이 3색 LED의 Red핀에 연결시키고 Blue Led에 연결된 선은 Blue핀에 연결하고 Green Led에 연결된 선을 Green 핀에 연결시켜 놓으면 해당 스위치를 누르면 개별 LED와 3색 LED에 해당된 color가 불이 들어오겠죠. 3색 LED에 해당 RGB핀이 아래 Red, Blue, Green LED랑 한몸이 되어서 같이 동작하는 회로도입니다.

재밌는것은 가상시뮬에이터에서 할 수 없지만 두개 이상의 스위치를 누르면 색이 3색 LED에 혼합된 Color로 출력됩니다. 즉, Red 스위치랑 Blue 스위치를 누르면 해당 LED불이 들어오고 3색 LED에는 Red+Blue가 혼합된 Color가 출력됩니다. Color를 공부하는 아이들에게 좋은 학습자료가 될 수 있겠죠.

참고로 여기서는 스위치로 표현되었지만 가변저항기를 스위치 자리에 교체하면 가변저항기를 돌릴때마다 Color 값을 조절 할 수 있겠죠. 그러면 더 많은 Color를 만들어내는 장치가 될 수 있습니다.

2) 직접 만들기


  • 준비물 : 9V 건전지, 저항 480옴 4개, Red, Blue, Green 각각 1개, 3색 LED 1개, 스위치 3개
  • 내용 : RGB LED 스위치

스위치를 이용해 RGB LED를 제어했구나 하고 대충 몇초만 보고 쉬운 예제이니깐 그 의미에 맞게 동일하게 만들어 봤네요


썩 마음에 들게 만들지 못했네요.

3. 전류의 흐름


이제는 전류가 어떤식으로 흘러가서 LED에 불이 들어오는지 살펴보도록 하겠습니다.


위 그림처럼 Led에 전류를 공급하면 불이 들어옵니다. 전류는 '+'에서 '-'로 이동 합니다.


그런데 Vcc쪽에 스위치를 달게 되면 초기 상태는 끊어진 상태로 전류가 흐리지 않습니다. 여기서, 스위치를 누르면 스위치 내부에 선이 서로 연결되어서 Vcc(+) 전류가 Led에 공급되면서 Led에 불이 들어오게 됩니다. 우리가 일상에서 흔히 형광등을 켤때 벽에 스위치가 붙어 있잖아요. 그걸 상상하시면 됩니다.


위의 그림처럼 3개의 Led를 연결했을 때 각 스위치 중에 누른 스위치는 전류가 공급되고 해당 Led에 불이 들어 옵니다. 이부분을 잘 기억해 두세요. Vcc(+)와 Gnd(-)의 선이 어떻게 연결되었고 여기서 해당 선에 전류가 흐르게 되면 어느 방향으로 전류가 흘러갈지를 머리속에서 잘 그려주세요.


위 그림에서 빨간선이 전류의 진행 방향입니다. Green 스위치를 누르게 되면 전류의 진행 방향에 따라서 흐르게 되고 Green Led에 불이 들어오게 됩니다.



위 그림을 보시면 3색 LED만 추가 되면은 Green Led와 3색 LED로 두갈래로 전류가 공급되고 Green Color의 불이 들어오게 됩니다. 대충 어떻게 전류가 흘러가는지 아시겠지요.

4. 두개의 스위치를 누른 효과 만들기


이 예제는 한개의 스위치 뿐이 누를 수 없습니다. 가상에서도 두개의 스위치를 누르고 싶은 욕망이 생기더군요. 오늘 이야기 하고 싶은 포스트 내용으로 들어가겠습니다. 이 걸 하기 위한 연습단계였네요. 어떻게 하면 두개의 스위치를 누른 효과를 만들 수 있을까요. 임의의 스위치를 만들어서 2개의 LED에 불이 들어오게 전류를 공급하면 됩니다.


위 그림처럼 새로운 스위치를 만들어서 Blue, Green Led 선에 연결을 했을 경우에 스위치를 누르면 2개의 Color에 불이 들어오고 위 3색 LED에 혼합된 색이 출력됩니다. 정상적으로 동작하는 것처럼 보이지만 전류의 흐름에 문제가 있습니다. 과연 뭘까요. 처음의 3개의 스위치를 눌러보세요. Green 스위치를 누르게 되면 Green, Blue에 불이 들어오게 됩니다.


위 그림에서 빨간원을 잘 보시기 바랍니다. Green 스위치를 누르면 해단 선에 전류가 공급되는데 빨간 원모양은 새로운 스위치에 purple 선으로 전류가 흘러가게 되고 purple에 연결된 Blue Led에도 전류가 공급되는 현상이 발생하게 됩니다. 결론은 Blue, Green은 서로 연결되었다는 의미가 됩니다. 그래서 어느 스위치를 누르 든 2개의 LED에 불이 들어오는 현상이 발생합니다.

이 문제를 어떻게 해결 할까요. 전자부품에는 다이오드라는 게 있습니다. 전류를 특정 방향으로만 흘러가도록 하는 부품인데 역전류 현상을 막는 부품이기도 합니다. 아래 그림에서 보는 것처럼 한쪽으로만 진행되고 마이너스 쪽에서 전류가 들어온다면 +쪽으로 전류가 흐르지 못하도록 차단하는 부품입니다.


이 부품을 연결을 아래와 같이 표현하면 Green 스위치를 누를 경우 새로 만든 스위치로 전류가 흘러가지 않게 다이오드가 차단 합니다.


참 재밌는 부품이지요. Green 스위치를 누른 결과인데 Green 스위치를 누르면 새로 만든 pulple선에 연결된 다이오드에 의해서 전류가 흘러가지 못하게 차단이 됩니다. Blue스위치를 눌러도 마찬가지이고요.

회로도 재구성


  • 준비물 : 9V 건전지, 저항 480옴 4개, Red, Blue, Green 각각 1개, 3색 LED 1개, 스위치 7개, 다이오드 9개
  • 내용 : RGB LED 스위치


세개의 Color가 동시에 눌러 졌을 때 상황을 표현한 스위치를 한개 더 추가했습니다. 그리고 그 결과는 위 그림에서 화살표가 가리키는 스위치를 눌렀을 때의 결과 이미지 입니다. 좀 지져분하게 되었지만 위에서 다이오드 연결한 것처럼 추가로 몇개만 더 만드시면 됩니다. 보기만 지져분할 뿐 동작은 잘 됩니다. 위에 공개 회로도로 링크 걸어놓았으니깐 가셔서 시뮬레이터를 돌려 보세요.

다른 방법으로 제어하는 방법도 있겠지만 순간 떠오르는 방법이고 다이오드를 소개하기 딱 좋을 아이템이라고 생각하여 이렇게 표현 했네요. 전류의 흐름을 잘 이해하셨으면 합니다.

5. 실제로 구현


여기서 끝나면 재미 없어서 한번 실제로 만들어 봤네요. 전원부분은 건전지를 사기가 싫어서 아두이노 5V 전원공급으로 처리했습니다. 그래서 저항은 그냥 220옴으로 수정 되었네요. 참고로 실제 구현에서는 스위치를 동시에 누를 수 있기 때문에 구지 복잡한 다이오드 연결을 하고 새로운 스위치를 만들 필요는 없었습니다.

1) 회로도 구성


  • 준비물 : 저항 220옴 4개, Red, Blue, Green 각각 1개, 3색 LED 1개, 스위치 3개, 아두이노우노, 뻥판
  • 내용 : RGB LED 스위치


위 회로도는 깔금한데 실제 구현은 선때문에 보기 지져분합니다. 실제 모습을 포스트 첫 이미지 사진을 보시면 되겠습니다. 좀 지져분하여 이해를 돕기 위해서 가상 시뮬레이터로 먼저 표현을 했네요. 이것도 위에 공개회로도에 링크를 걸어 놓았으니깐 시뮬레이터를 돌려 보세요.

2) 결과

실제 실험 영상에서는 Blue Led가 없어서 해당 위치에 Yellow Led를 넣었네요. 참고로 Yellow LED이지만 3색 LED에서는 Blue로 정확히 출력됩니다. 감안하시고 보세요.


마무리


쓰다보니깐 간단히 포스팅 할려다가 또 길어졌네요. 짧게 표현하는 능력이 부족해서 글이 좀 길어지는 경향이 있네요. 암튼 이번 실험을 통해서 전류가 어떻게 흘러가는지 이해하는 시간이 되었으면 합니다.

마무리는 깔끔하게 여기서 마칩니다.


댓글()

[아두이노] 사운드센서로 그래픽 이퀄라이저 표현

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

[아두이노] 사운드센서로 그래픽 이퀄라이저 표현



어제 마이크사운드 감지센서를 통해서 센서의 값의 초기값 조정하는 것과 읽는 법을 배웠습니다. 오늘은 마이크사운드 감시센서을 이용하여 소리를 NeoPixel로 출력하는 실험을 해보도록 하겠습니다. "아두이노 이퀄라이저" 키워드로 찾으시면 화려한 표현들을 많이 보실 수 있을거에요. 오늘 포스팅은 그런 화려한 표현이 아닌 간단히 어떻게 소리를 NeoPixel로 표현을 하는지에 대한 원리를 이해하는 시간으로 채우겠습니다. 화려한 그래픽 이퀄라이저를 상상했다면 아마 실망하실지 모르겠군요.

1. 마이크사운드 감지센서와 3색LED




3색 LED에 대한 설명은 아래 링크된 포스트로 가셔서 잠깐 살펴보세요.
[아두이노] 3색 LED 제어



마이크사운드 감지센서는 어제 포스트인 아래 링크로 다시 복습를 해주세요.
[아두이노] 마이크사운드 감지센서 제어(아두이노)

입력은 마이크르사운드 감지센서를 사용하고 출력은 NeoPixel이 없는 관계로 비슷한 3색 LED를 이용하여 실험이 이루어집니다.

2. 회로도 구성


  • 준비물 : 마이크사운드 감지센서 1개, 3색 LED 1개, 저항 220옴 3개, 아두이노우노
  • 내용 : 사운센서랑 3색 LED를 사용할 핀을 원하는 위치에 배치해 보자.

가상회로도 이미지에서 저항은 실수 1k옴으로 그려졌네요. 혼동하시면 안되고 정상적으로 220옴을 실제로 사용하셔야 합니다. 이미지의 저항색깔을 보시고 혼동하시면 안됩니다.


RGB 색상핀은 아날로그 출력을 해야하기 때문에 PWM핀들 중에 9,10,11번 핀을 선택했습니다. 그리고 마이크사운드 감지센서의 값을 읽는 아날로그 핀은 이전시간과 동일한 A0핀을 선택했습니다.

3. 코딩


  • 사용함수 : analogRead(), PinMode(), analogWrite(), map(), randomSeed(), random()
  • 내용 : 마이크사운드 감지센서의 소리의 값을 기준으로 RGB 색상을 만들어 그래픽 이퀄라이저 효과를 표현하자.

[ 기본 소스 ] : 마이크사운드 감지센서를 이용한 소리의 최소값과 최대값 출력

int m_min = 26;
int m_max = 0;

void setup()
{
  Serial.begin(9600);
}
void loop()
{
  int SoundSensor =analogRead(A0);
    if(SoundSensor<m_min) m_min=SoundSensor;
    if(SoundSensor>m_max) m_max=SoundSensor;
    
    Serial.print(m_min);    
    Serial.print("  :  ");
  Serial.println(m_max);    
  delay(50); 
}

이전 시간에 실험한 소스입니다. 이 소스를 기반으로 접근해 보겠습니다.

우선 RGB핀을 사용하기 때문에 RGB핀 변수를 만들어야 겠죠.

const int RedPin = 9;
const int GreenPin = 10;
const int BluePin = 11;

그 다음에는 RGB핀들은 출력모드입니다. 그러면 setup()함수에서 "출력모드로 사용할꺼야!" 하고 선언해야겠죠.

void setup()
{
  Serial.begin(9600);
 
  pinMode(RedPin, OUTPUT); 
  pinMode(GreenPin, OUTPUT); 
  pinMode(BluePin, OUTPUT); 
}

이제 소리를 어떤 기준으로 해서 색을 만들면 좋을지 생각해보세요. 마이크사운드 감지센서의 아날로그 신호 0~1023 값을 아두이노가 읽는다고 했죠. 그러면 0~1023값을 쪼개서 색으로 나타내면 되겠다고 처음에 다들 여기서 부터 출발합니다. 여기서, RGB핀 출력은 PWM핀으로 아날로그 0~255 출력을 낼 수 있습니다. 0(0V)이고 255(5V)입니다. 그러면 마이크사운드 감지센서에서 읽은 0~1023 값을 아날로그 출력 0~255값에 매핑 시켜서 출력시키면 되겠다고 생각 하실꺼에요.

 int SoundSenser =analogRead(A0);
 int SoundColor = map(SoundSenser,0,1023,0,255);

map()함수는 다시 복습을 하면

  • map(입력값,입력최소값,입력최대값,출력최소값,출력최대값) : 입력최소~최대범위에서 입력값이 출력 최소~최대범위에 어느정도 위치인지 그 출력위치값을 반환합니다.

예) map(입력값,0,100,0,10) 이면, 입력값이 10일때 출력값는 1이 됩니다. 입력값이 20일때 출력값은 2가 출력됩니다. 즉, 이말은 입력범위를 출력범위에 맞춰서 출력된다고 생각하시면 됩니다. 일정한 간격 비율에 맞춰서 출력값에 매칭 된다고 생각하면 될듯요. 0~10사이의 값은 1로 매칭되고 11~20사이의 값은 2로 매칭이 되고 이렇게 생각하시면 될 듯 하네요. 입력범위에 대한 입력값의 위치가 출력범위에서 어느정도의 위치가 출력위치인지 그 출력위치의 값을 반환해주는 함수라고 생각하시면 됩니다.

 Serial.println(SoundSenser);
 analogWrite(RedPin,random(SoundColor));
 analogWrite(GreenPin,random(SoundColor));
 analogWrite(BluePin,random(SoundColor));

우선 소리값을 그냥 color 값으로 출력한다면 소리값에 0~255사의 값이 RGB 색의 출력된 값이 되고 출력명령은 analogWrite()함수로 color를 출력하게 됩니다. 이렇게 하면 코딩이 끝났다고 생각하실꺼에요. 한번 돌려보세요 어떤 현상이 발생하는지요. 마이크사운드센서에 소리를 입력하기도 전에 3색 LED를 막 깜박일꺼에요.

그 이유가 뭘까요. 지난시간에 공부하셨으면 쉽게 찾을 수 있을꺼에요. 지난시간에 마이크사운드 감지센서는 초기값으로 일정한 전류가 발생한다고 했죠. 같은 종류라도 센서라도 초기의 센서에 흐르는 전류의 초기값은 제각각 입니다. 제가 사용하는 Sensor는 처음 46이 초기값이였고, 가변저항기를 돌려서 26정도로 맞췄습니다. 여기서 아무런 소리를 입력하기 전 초기 상태에서 이미 소리값이 일정 수치가 읽어지니깐 자연히 그 초기값의 색이 RGB LED에 출력이 되는 것이죠 제 경우 초기값이 26이라면 26에 대한 색이 출력되더군요.

처음 마이크 상태는 0에서 출발해야 하는데 그렇게 안되겠죠. 그럼 그렇게 0에서 출발하도록 만들어줘야 합니다. 바로 map()함수를 수정하시면 됩니다.

 int SoundColor = map(SoundSenser,26,1023,0,255);

입력 최소값을 26으로 잡아주면 간단히 해결됩니다. 그런데 두번째 문제가 발생합니다. 과연 뭘까요. 어제 포스트를 읽어봤다면 찾을 수 있을꺼에요. 소리가 입력되고 다시 입력이 안되면 전기신호를 감소합니다. 중요한 것은 소리가 입력될때는 전기신호가 커졌다가 입력이 안될때는 전기신호가 작아지는데 초기값보다 마이너스(-)로 빠져버리는 현상이 발생한다고 했죠. 그러면 어떻게 될까요. 그 이상한 값에 의해서 색이 출력되어버립니다. 최소값 문제가 발생합니다.

그걸 해결하기 위해서 어제 최소값 구하는 로직을 이용할꺼에요.

if(SoundSensor<26) SoundSensor=26;

만약에 26보다 작은 전기신호가 온다면 26에 수렴되게 만들면 됩니다. 그리고 또 어떤 문제가 발생할까요. 아두이노에서 사용되는 마이크사운드 감지센서를 아주 싸고 질이 떨어집니다. 결론은 소리감지에 좀 문제가 있습니다. 어느정도 큰소리라고 생각했지만 측정되는 수치는 그렇게 높지 않습니다. 거의 마이크를 두둘겨야 비로소 일정 수치까지 올라갑니다. 말하자면 대부분의 소리가 낮은 전기신호값을 가지고 있으면 일부 소리만 큰전기신호값으로 입력으로 들어옵니다. 결론은 거의 동작을 안하는 것처럼 보이고 색상도 아주 낮게 보입니다. 그래픽 이퀄라이저 효과를 뚜렷하게 표현하기 어렵다는 것이죠.

해결책으로는 낮은 값을 기준으로 색의 값을 재배열 하면 됩니다.

if(SoundSensor>300) SoundSensor=300;

이렇게 300이상의 소리는 그냥 300에 수렴하게 만들면 됩니다. 대충 아래 그래프처럼 입력값의 범위를 강제적으로 정하면 됩니다. 가로축는 마이크사운드 감지센서의 측정값이고 세로축은 소리입력허용 수치입니다. 26~300사이의 값으로 소리입력범위가 잡으시면 됩니다.


그러면, map()함수는 어떻게 될까요.

 int SoundColor = map(SoundSenser,26,300,0,255);

이렇게 해서 26~300사이의 값을 입력범위로 해서 0~255의 색상값으로 출력하겠다고 표현하시면 됩니다.
여기서, 어제 배웠던 최소값과 최대값 구한 로직을 기본소스로 우선 보여준 이유가 이 로직으로 이런 2가지의 문제를 해결하기 위해서 입니다.

이렇게하면 소리에 대한 밝기만 표현되기 때문에 그래픽 이퀄라이저라고 보기 어렵습니다. 그래서 밝기와 더불어 다양한 색을 만들어보는 시도를 해보겠습니다. 그 방법으로 random()함수를 사용하겠습니다.

void setup()
{
  randomSeed(analogRead(A1));
}
void loop(){
    random(SoundColor);
}

A0은 마이크사운드 감지센서로 사용되니깐 A1은 랜덤함수 초기값으로 세팅하겠습니다. 여기서 아날로그핀값을 읽어오기만 하는게 난수초기세팅인 이유는 뭘까요. 그 이유는 아두이노는 핀마다 미세한 전류가 자체적으로 흐르고 있습니다. 사용을 안하더라고 핀마다 작게 전류가 흘러서 그 전류는 미세하지만 랜덤한 전류의 양을 가지고 있어서 그 값을 기준으로 난수를 세팅하면 랜덤값을 추출할 수 있습니다.
그리고 random(255)함수면 255이 max값으로 임의의 난수를 만들어 냅니다. 이 값을 RGB 마다 random()함수로 색의 난수값을 만들어내면 소리에 대한 다양한 색을 만들 수 있겠죠.

종합해보면.

const int RedPin = 9;
const int GreenPin = 10;
const int BluePin = 11;

void setup()
{
  Serial.begin(9600);
  randomSeed(analogRead(A1));
  pinMode(RedPin, OUTPUT); 
  pinMode(GreenPin, OUTPUT); 
  pinMode(BluePin, OUTPUT); 
}

void loop()
{
  int SoundSenser=0; 
  int SoundColor=0; 
    
  SoundSenser = analogRead(A0);
  if(SoundSenser<26) SoundSenser=26;
  if(SoundSenser>300) SoundSenser=300;
  
  SoundColor= map(SoundSenser,26,300,0,255);
  
  Serial.println(SoundColor);
  analogWrite(RedPin,random(SoundColor));
  analogWrite(GreenPin,random(SoundColor));
  analogWrite(BluePin,random(SoundColor));
    
  delay(50); 
}

4. 결과



음악으로 실험해야하는데 음악은 저작권 때문에 단지 손으로 마이크사운드 감지센서에 자극을 줘서 출력실험을 했네요. 보면은 터치센서인줄 착각할 수 있는 장면이네요.

참고로 위 소스대로 하시면 그렇게까지 그래픽 이퀄라이저 효과를 얻을 수 없습니다. 결함이 있는 소스입니다. 그 이유가 뭘까요. 바로 random()함수를 단순히 측정한 소리값을 max값으로 넣었기 때문입니다. 이렇게 표현하면은 소리에 따라 다양한 색을 만들어 내기는 합니다. 하지만 300의 소리가 입력되었어도 100이 나올수 있고 150의 소리가 입력되어도 100이 나올 수 있다는 것이죠. 이말은 색상을 일정한 패턴 범위에 맞추지 못했다는 결함적 소스입니다.

그런데 왜 수정을 안하고 여기서 멈추었냐면 이제부터서 여러분들이 수정해 나갈 차례입니다. 기본 베이스는 다 주어졌습니다. 소리의 초기상태를 읽을 수 있고 최소와 최대값을 정할 수 있게 되었고 map()으로 색의 값의 범위를 정할 수 있게 되었습니다. random()함수로 색을 랜덤하게 만들어 낼 수 있게 되었습니다. 여러분들은 이제 소리를 좀 더 디테일적으로 나누는 작업과 그 나누었을 때 색을 랜덤함수로 범위를 정할지 아니면 고정된 색값으로 하고 밝기만 변화를 줄지의 선택은 여러분의 몫입니다.

참고로, 이렇게 코딩을 해도 실제 돌려보면 색이 화려하지 않고 낮은 밝기와 색값으로 출력됩니다. 그것은 바로 마이크사운드 감지센서의 문제입니다. 좀 큰소리를 말해도 실질적으로 측정되는 수치는 그렇게 높지 않습니다. 그렇기 때문에 미세한 1의 변화에도 색의 밝기값을 좀 더 큰값 범위를 기준으로 해서 정해보시는 것을 추천드려요.

5. 가상시뮬레이터에서 느낌만 실험


그냥 실제로만 하면 뭔가 아쉬울 것 같아서 느낌만 살펴서 가상시뮬레이터로 실험해 해보세요. 위에 공개회로도에 링크 걸렸으니깐 돌려만 보세요.

1) 가변저항기와 3색 LED


const int RedPin = 9;
const int GreenPin = 10;
const int BluePin = 11;

void setup()
{
  Serial.begin(9600);
  randomSeed(analogRead(A1));
  pinMode(RedPin, OUTPUT); 
  pinMode(GreenPin, OUTPUT); 
  pinMode(BluePin, OUTPUT); 
}

void loop()
{
  int SoundSenser=0; 
  int SoundColor=0; 
    
  SoundSenser = analogRead(A0);
  if(SoundSenser<26) SoundSenser=26;
  if(SoundSenser>300) SoundSenser=300;
  
  SoundColor= map(SoundSenser,26,300,0,255);
  
  Serial.println(SoundColor);
  analogWrite(RedPin,random(SoundColor));
  analogWrite(GreenPin,random(SoundColor));
  analogWrite(BluePin,random(SoundColor));
    
  delay(50); 
}

2) 가변저항기와 NeoPixel


#include <Adafruit_NeoPixel.h>

const byte neopixelPin = 3; 
Adafruit_NeoPixel neopixel = Adafruit_NeoPixel(1, neopixelPin, NEO_GRB + NEO_KHZ800);
 
void setup()
{
  neopixel.begin();   
  randomSeed(analogRead(A1));
}

void loop()
{
  int SoundSenser=0; 
  int SoundColor=0; 
    
  SoundSenser = analogRead(A0);
  if(SoundSenser<26) SoundSenser=26;
  if(SoundSenser>300) SoundSenser=300;
  
  SoundColor= map(SoundSenser,26,300,0,255);
  neopixel.setPixelColor(0, random(SoundColor), random(SoundColor), random(SoundColor));    
  neopixel.show();
  delay(50);    
  neopixel.clear(); 
}

3) 두가지 실험 결과

위 3색 LED와 NeoPixel을 가변저항기가 마이크사운드 감지센서라고 상상하고 실험한 영상입니다.


마무리


하다보니깐 길어졌네요. 원래는 추가적으로 NeoPixl 바 모양 향태로 음악을 들을때 사운드 그래픽 바 모양을 아실꺼에요. 그것도 추가 설명할려고 했는데 그건 못하게 되었네요. 내일 또 이여서 하면 너무 길게 연장 될 것 같아서 여러분들의 상상력으로 표현을 해보세요.

혹시, 사운드 그래픽 바를로 출력하고자 하고자 한다면 참고해주세요. NeoPixel을 예전 포스팅에 어떻게 표현을 했었죠. 배열 행태로 표현했었습니다. 그 배열을 사운드 그래픽 바의 위치라고 상상하고 소리의 크기에 따라서 배열로 몇번째 배열까지 불이 들어오게 할건지 그 간격만 정하시면 됩니다. 그리고 해당 NeoPixel의 색 값은 random()함수로 표현하시거나 고정값을 하셔도 됩니다. 쉽게 말해서, 소리가 1~10까지 있으면 3이라는 신호값이 발생하면은 NeoPixel를 3번째까지 불이 들어오게 하면 됩니다. 이렇게 소리의 크기 값에 neoPixel의 위치를 정하면 됩니다. 한번 연구를 해보세요.

오늘도 어떻게 표현하면 더 자연스럽고 화려할지를 상상의 나래를 펼쳐 보세요.


댓글()

[아두이노] 마이크사운드 감지센서 제어

IOT/아두이노|2019. 4. 6. 09:00

[아두이노] 마이크사운드 감지센서 제어



오늘은 어제 설명한 Sensor 읽기에서 가상시뮬에이터에서 제공되지 않는 실제 Sensor를 다뤄보도록 하겠습니다. 실험에 사용되는 마이크사운드 감지센서는 D0, A0로 디지털신호와 아날로그신호를 출력하기 때문에 해당 핀에 맞는 함수를 사용하여 읽으시면 됩니다. 실험에서는 아날로그신호를 읽는 방식으로 진행되니깐 잘 참고를 해주세요.

1. 마이크사운드 감지센서



사진이 깔끔하게 나오지 않고 약간 좀 떨려서 찍혔네요. 좀 흐려도 자세히 보시면 대충 구분이 되실거라 믿고 진행하겠습니다. 보시면 파란색 나사이 있을꺼에요. 가변저항기로 전류의 출력을 조절하는 장치입니다. 어느쪽 방향인지 햇갈리는데 여기서 오른쪽으로 올리면 마이크센서의 초기 값이 작아지던가 아무튼 아두이노에 연결해서 Serial 통신으로 그 값을 찍어보시면 돌리는 방향에 따라 값이 커졌다 작아졌다 하니깐 초기값을 정하시면 됩니다.

그리고 오른쪽 핀 연결부분을 보시면 A0, G, +, D0으로 표시되어 있는데 A0은 아날로그 신호로 출력하는 거고, D0은 디지털 신호로 출력하는 핀입니다. +, Gnd은 전원부분으로 아두이노우노에 Vcc, Gnd로 연결하시면 되겠죠. 제가 사용하는 모델은 5V에 연결했네요 부품마도 허용치 Vcc가 다르니깐 구매 부품의 사용설명서를 참조하세요.

2. 마이크사운드 감지센서값 읽기


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

void loop()
{
  int SoundSensor =analogRead(A0);
  Serial.println(SoundSensor);    
  delay(50); 
}

대충 이 코딩으로 현재 사용하시는 마이크사운드 감지센서의 출력값을 아두이노 IDE 시리얼모니터에 출력시켜 초기값을 확인하시면 됩니다.
제 마이크사운드 감지센서의 값은 23~26사이의 아날로그 출력값을 초기값으로 출력하는데 평균 26을 주기적으로 출력하더군요.
아무것도 소리를 입력하지 않는 현재 공간의 소음상태의 신호값입니다. 위에서 설명한 가변저항기의 일자나사모양을 돌리시면 돌리는 방향에 따라서 이 수치가 커지거나 작어지거나 할꺼에요. 자신이 정한 기준에 맞춰서 세팅하시면 됩니다.

3. 회로도 구성


  • 준비물 : 마이크사운드 감지센서 1개, 아두이노우노
  • 내용 : 마이크사운드 감지센서를 아두이노에 연결하자.


마이크사운드 감지센서는 어떤 종류라도 상관 없습니다. 사용되는 핀은 아날로그 신호를 입력받기 때문에 A0핀과 전원부분인 +(Vcc), Gnd 핀을 사용하기 때문에 아날로그 출력핀은 아두이노의 원하는 아날로그핀(A0~A5)을 선택하셔서 연결하시면 되고 전원부분은 맞춰서 연결하시면 됩니다. 마이크사운드 감지센서는 종류에 따라 전원공급 허용치에 맞게 연결하시면 되니깐 그건 부품의 사용설명서를 참고해주세요.

4. 코딩


  • 사용함수 : analogRead()
  • 내용 : 간단히 마이크사운드 감지센서를 통해 소리의 최소와 최대값을 출력해 보자.

마이크사운드 감지센서값 읽기에서 최소값, 최대값 변수를 만들어서 if문 조건문을 통해서 최소값과 최대값을 저장하여 어느정도의 범위의 소리 신호를 센서가 측정할 수 있는지 살펴보도록 하겠습니다.

int m_min = 26;
int m_max = 0;
int SoundSensor =analogRead(A0);
if(SoundSensor<m_min) m_min=SoundSensor;
if(SoundSensor>m_max) m_max=SoundSensor;

첫번째 if문은 SoundSensor값이 초기 26보다 작다면 그 값을 최소값으로 한다.
두번째 if문은 SoundSensor값이 초기 0보다 크다면 그 값을 최대값으로 한다.

간단하게 최소값하고 최대값을 구하는 로직입니다. 왜 초기 최소값을 26으로 했을까요. 그냥 마이크사운드 감지센서로 읽은 값을 Serial 모니터로 출력하면 초기평균값이 나오잖아요 .그 값을 최소로 잡은 것이죠. 그냥 26을 최소값으로 하고 구지 if문으로 최소값을 찾을 이유가 없지 않느냐라고 반문할 수 있지만 실제로 아래 돌려보시면 생각했던 값이 나오지 않고 더 작은 값이 최소값으로 찍히게 됩니다. 그 이유는 결과부분에서 자세히 설명드리겠습니다.

우선은 이런식으로 최소값과 최대값을 구하는 로직을 짰는 걸로 정리해주시기 바랍니다. 그럼 완성된 코딩은 다음과 같겠죠.

int m_min = 26;
int m_max = 0;

void setup()
{
  Serial.begin(9600);
}
void loop()
{
  int SoundSensor =analogRead(A0);
    if(SoundSensor<m_min) m_min=SoundSensor;
    if(SoundSensor>m_max) m_max=SoundSensor;
    
    Serial.print(m_min);    
    Serial.print("  :  ");
  Serial.println(m_max);    
  delay(50); 
}

5. 결과


[ 초기상태 ]




[ 소리입력 후 결과 ]



두장의 사진을 보면 어떤 차이가 있나요. 첫번째 사진은 최소값이 23이고 최대값은 27로 나옵니다. 이건 처음에 마이크사운드 감지센서에 전원이 공급될때 발생하는 전류의 순간 초기 변화의 값이고 평균적으로 26의 값을 초기값으로 찍어 냅니다.

하지만 두번째 사진을 보시면 최소값이 17이고 최대값은 1005로 나옵니다. 마이크사운드 감지센서의 소리가 1005까지 증가한 신호가 측정되었네요. 하지만 이상한점은 최소값이 17로 감소한 지점이 마이크사운드 감지센서에서 발생했습니다.

그 이유가 뭘까요. 바로 소리를 측정하고 전기 신호를 발생하는 순간 측정된 만큼의 전류가 늘어나겠죠. 그리고 소리가 끊어지면 전류의 소비된 만큼이 순간 떨어지게 되고 초기 전류상태에서 아래로 전류값이 떨어지게 되는 것 같습니다. 소리의 측정된 전류가 늘었다 줄어드는 순간 초기 전류상태에서 그 아래로 떨어졌다가 다시 초기상태로 되돌아간다고 생각하면 될 듯 싶네요.

소리가 발생할때마다 전류의 신호의 파형이 증가했다가 떨어질때는 초기값 아래로 일시적으로 전류가 떨어졌다가 다시 올라고 반복된 현상을 보입니다.

이 현상을 잘 기억하셔서 다른 부품을 제어할 때 주의해서 코딩해야 합니다. 초기값이 26이니깐 그 값을 기준으로 해야지 했는데 기준값 아래로 떨어질때는 원하지 않는 값으로 다른 부품을 제어하게 됩니다. 위에서 최소값을 26으로 잡고 다시 if문을 써서 최소값을 구하는 로직을 표현했는지 그 이유를 아시겠지요. 정확히 26이란 값이 최소값이 되지 않기 때문에 그 아래 신호값이 발생할 수 있기 때문에 자신이 사용하는 마이크사운드 감지센서에 대한 정확한 측정 수치를 테스트를 해보셔야 합니다.

마무리


원래는 이 포스팅이 아니였는데 쓰다보니깐 길어져 버렸네요. 이 부품을 가지고 다른 원리를 설명하고자 했는데 의도치 않게 마이크사운드 감지센서 포스트가 되고 말았네요.
그리고 디지털 읽기로 한번 해보세요. 어떤 값이 찍히는지요. 그 값을 Serial 모니터로 출력해보세요. 그리고 이런류의 부품을 사용할때는 보정작업이 필요합니다. 초기값을 어느값으로 할지와 그 값의 범위를 정해서 그 밤위의 값으로 나누는 방법도 생각하시면 다양한 표현을 할 수 있습니다.
초기값을 정하면 그 값을 기준으로 다른 부품의 동작을 제어할 수 있습니다. 그리고 범위값을 나누면 소리의 범위별로 서로 다른 동작을 시킬 수 있습니다.

참고로 가상시뮬에이터에서는 실험 할 수 없습니다. 마이크사운드 감지센서가 존재하지 않으니깐요. 그 대안으로 가변저항기를 이용해주세요. 가변저항기를 돌리면 0~1023의 값을 입력받을 수 있습니다.

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

이 포스트가 예제로 적당할 듯 하네요. 다음 포스팅 내용도 이 예제를 기반으로 설명을 할 예정입니다. 한번 가변저항기로 마이크사운드 감지센서가 이 값은 음역대 신호를 발생한다고 가정하고 읽는 것을 연습해보세요. 그리고 이 아날로그 신호값이 발생하면 3색 LED 제어한 것처럼 난 무엇을 해볼까 상상력을 발휘를 해보세요.

마지막으로 마이크사운드 감지센서를 가지고 여러분들은 뭘 만들고 싶을지 상상의 나래를 펼쳐보세요.

댓글()

[아두이노] Sensor 읽는 법

IOT/아두이노|2019. 4. 5. 09:00

[아두이노] Sensor 읽는 법



오늘은 지금까지 다뤘던 Sensor 들에 대해서 정리하는 시간을 갖도록 하겠습니다. 가상시뮬레이터에서 제공되는 Sensor의 종류들은 극히 일부에 지나지 않습니다. 실제는 더 많은 수십 수백가지이상의 센서들이 존재합니다. 여기서 중요한 것은 종류가 많다고 해서 개별적으로 다르게 접근하는게 아니라 이제 설명하는 기본 세가지 방법으로 Sensor의 값을 읽어 올 수 있습니다. 이 세가지 방법만 알고 있으면 센서 종류만 많지 다루는데 그렇게까지 어려움이 없을 거라 생각합니다.

1. Sensor의 종류



가상시뮬레이터에서는 값을 읽는데 사용하는 부품들입니다. 몇 종류가 되지 않지만 그래도 세가지 방법을 다 실험할 수 있는 부품들로 구성되어 있습니다. 실제로 아두이노키트를 구매하시면 몇십가지의 부품들로 구성되어 판매하지만 사실 종류별로 구분하여 분류하면 종류는 그렇게 많지 않습니다. 개수만 많을뿐이죠. 실제 부품들 사진을 올려야 하는데 제 키트 사진을 찍어서 올리기 힘들고 인터넷 키트 사진을 올리는 것도 문제가 될 것 같아서 그부분은 생략하도록 하겠습니다. 관심있으신 분들은 구글 검색에서 "아두이노센서 종류"라는 키워드로 검색하시면 목록 사진들이 나열된 게시물들을 쉽게 찾을 수 있으니깐 어떤 종류의 센서들이 있는지 개별적으로 살펴보시면 되겠습니다.

2. Sensor의 읽기 구분



Sensor를 읽이 위해서는 크게 세가지 방법으로 구분한다고 했죠. 바로 디지털 읽기, 아날로그 읽기, 시간값 읽기로 나누어 살펴볼 수 있습니다.

1) 디지털 읽기 :

디지털핀에서 센서의 값을 읽는 방법입니다. 기본적으로 디지털핀은 HIGH or LOW의 상태값을 읽을 수 있고 쓸 수 있습니다. 쉽게 말해서, 디지털핀으로 읽을때 HIGH or LOW의 상태값을 읽게 됩니다. Sensor에서 디지털 상태값을 출력하는 종류가 뭐가 있을까요. PIR Sensor(인체감지센서), Tilt Sensor(기울기센서), 스위치버턴 등이 대표적으로 들 수 있겠죠. 이런 종류의 Sensor는 두가지 HIGH or LOW 상태값만 갖게 됩니다.

int val = digitalRead(디지털핀);

val이란 변수에 디지털핀에 연결된 센서의 값을 저장하게 됩니다. 우리는 두가지 상태값 HIGH or LOW의 값을 통해서 아두이노에서 특정 동작을 제어하게 됩니다.

2) 아날로그 읽기 :

아날로그핀에서 센서의 값을 읽는 방법입니다. 기본적으로 아날로그핀은 0~1023사이의 값을 읽게 됩니다. 아날로그 값을 출력하는 종류가 뭐가 있을까요. 위 사진을 보면 대충, Gas Sensor(가스센서), Photoresistor(LDR)(조도센서) 등이 있네요. 이런 종류의 센서는 전류의 값을 출력되는데 아두이노는 0~1023사이의 전류의 세기 값을 읽게 됩니다.

int val = analogRead(아날로그핀) ;

val이란 변수에 아날로그핀에 연결된 센서의 값을 저장하게 됩니다. 우리는 전류의 세기 0~1023의 값을 통해서 특정 동작을 제어하게 됩니다. 참고로 부품에 따라 아날로그 신호와 디지털 신호를 두개 다 내보내는 부품이 있는데 사용목적에 따라서 디지털 신호는 디지털 읽기로 아날로그 신호는 아날로그 읽기 함수를 사용해서 읽으시면 됩니다.

3) 시간값 읽기 :

디지털핀에서 센서의 값을 읽는데 어떤 특정한 상태를 기준으로 해서 그 상태가 유지하는 시간을 추출할 수 있습니다. 대표적으로 초음파 센서를 들 수 있습니다.

int val =pulseIn(디지털핀, HIGH/LOW);

val이란 변수에 디지털 핀에 연결된 센서의 값을 읽어오는데 상태의 값이 HIGH or LOW 중 어떤 상태값이 얼마정도 유지 되었는지 그 시간을 측정하는데 사용됩니다. 가령 pulseIn(디지털핀, HIGH) 라고 하면 디지털핀에 들어오는 HIGH값이 LOW가 될때까지의 시간값을 반환하게 됩니다. 초음파센서에서 초음파를 쏘고 되돌아올때 이때 초음파센서를 통해 HIGH에서 LOW가 될때까지의 시간값을 가지고 거리를 계산 했었죠.

원래는 디지털 읽기와 아날로그 읽기로 두가지로 구분하시면 됩니다. 시간값 읽기는 특수한 경우이고요. 다양한 부품들이 있는데 대부분 디지털 값을 출력하거나 아날로그 값을 출력하는 부품들이고 우리는 digitalRead()함수와 analogRead()함수로 센서의 값을 읽게 됩니다.

추가적으로 통신에서 '1'과 '0'의 신호값으로 읽기도 합니다. 가령 1byte의 값을 전송한다면 '00000000'의 범위의 전기신호를 보내는데 '1'이라는 값을 보낸다고 치면 '00000001'이렇게 2진수로 보낸다면 전기 신호가 'LOW' 7번, 'HIGH' 1번으로 짧게 끈어서 8bit의 신호를 보내겠죠. 통신에서는 읽을때 이 전기신호를 읽어서 다시 복호화하여 1이란 숫자로 저장하게 됩니다. 통신 부분이기 때문에 이 부분은 간단히 전기신호로 읽는 방법정도만 이해하시면 되겠습니다.

SoftwareSerial mySerial(RX,TX);
byte val = mySerial.read();

Serial 통신핀을 통해서 1byte의 신호값을 val에 저장합니다. 센서값을 읽은 기기에서 통신을 통해서 그 값을 아두이노우노에서 읽을때 사용 됩니다. 이부분은 통신 부분이니깐 별도로 알아두시기 바랍니다.

마무리


오늘은 간단히 센서의 값을 읽는법을 정리하는 시간으로 채웠습니다. 어떤 Sensor를 사용하시더라고 기본 골격은 디지털 읽기와 아날로그 읽기 뿐이 없습니다. 별도로 라이브러리리 제공 될 경우 해당 라이브러리 객체에 사용핀을 던져주기만 하면 별도의 코딩은 필요 없겠지만 실제 여러분들이 코딩을 하실 경우는 대표적으로 이 두가지 방법으로 접근이 이루어지기 때문에 두 함수만 이해하시면 사용해보지 않는 센서들일지라도 대부분 사용하실 수 있을 꺼에요.

오늘은 정리하는 시간으로 간단히 포스팅을 했네요.

댓글()

[아두이노] ATtiny 제어

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

[아두이노] ATtiny 제어



오늘은 ATtiny에 대해서 살펴보는록 하겠습니다. 아주 작은 프로그램을 이식할 수 있고 다른 부품을 제어할 수 있어서 소형 아두이노로 생각하시면 아마 편하실꺼에요. 그런데 사용하기 위해서는 프로그램을 이식해야하는데 좀 복잡한 과정을 거쳐야 하기 때문에 사용하시기 번거로울 꺼에요. 프로그램 이식과정을 무시하고 바로 가상시뮬레이터에서 동작을 시킬 수 있기 때문에 한번 사용해 보겠습니다. 사용을 해봐야 어디다 사용할지 상상을 할 수 있기 때문에 상상하기 전에 간단히 제어를 통해 ATtiny를 배워도록 하겠습니다.

1. ATtiny 구조



파워포인트로 대충 그려봤는데 잘 그려졌는지 모르겠네요. 우선 핀을 보시면 총 8개의 핀으로 구성되어 있습니다. 전원 공급핀과 리셋핀을 제외하면 대충 Pin 0,1은 PWM으로 사용되고 Pin 2,3,4은 Analog Input으로 사용되네요.

따로 설명할 필요가 없을 것 같아 이 핀들을 가지고 간단히 LED를 제어하는 실험을 해보도록 하겠습니다.

2. 회로도 구성


  • 준비물 : ATtiny 1개, coin Cell 3V Battery 1개, Red Led 1개, 저항 220옴 1개
  • 내용 : 간단히 Red Led를 깜박이기게 하자.


위 그림에서 ATtiny 칩이 동작할려면 전원을 공급해야겠죠. 작은 건전지를 Vcc, Gnd로 연결해서 전원을 공급하게 됩니다. 그리고 첫번째 Pin 0에 출력핀으로 해서 Red Led를 전류를 공급하도록 배치해 놨습니다. 제일 처음 LED 제어편에서 아두이노를 13번 핀에 연결한 Red Led를 깜박이는 예제가 생각나실 꺼에요.

아래 그림에서는 NeoPixel Ring 24 짜리는 선을 구별할 수 있지만 NeoPixel Ring 12와 NeoPixel Jewel은 우리가 NeoPixel를 지난 시간분터 계속 연결해왔기 때문에 안보여도 대충 어떤식으로 연결되는지 아실거라고 생각되기에 그 부분은 설명에서 제외하겠습니다. 아래 결과물 동영상에서 제작과정이 잘 나와 있으니깐 참고해 주세요. 그거랑 같다고 생각하시면 됩니다.

3. 코딩


  • 사용함수 : pinMode(), digitalWrite(), delay()
  • 내용 : "STEEM CODINGMAN" 글자를 만들어 출력하자.
  • 참고소스 :

함수

  • pinMode(사용핀, 입/출력모드) : 해당 사용핀을 어떤 모드로 사용할지 결정.
  • digitalWrite(사용핀, HIGH/LOW) : 해당 사용핀을 디지털 출력으로 HIGH or LOW 인지 결정.
  • delay(시간값) : 시간값만큼 대기한다.

[기본 소스]

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

void loop()
{
  digitalWrite(0, HIGH);
  delay(1000); // 1초(1000) 대기
  digitalWrite(0, LOW);
  delay(1000); // 1초(1000) 대기
}

Pin 0을 출력모드로 설정 합니다. 1초 동안 HIGH(5V)를 공급 한 뒤에 1초동안 LOW(0V)상태가 됩니다. 이렇게 loop()함수는 계속 반복하게 됩니다. 그럼 1초 단위로 깜박이는 로직이 됩니다. 이미 LED 제어편에서 설명한 내용이니깐 간단히 로직에 대해서만 이야기 했네요.

4. 결과



위 그림은 간단히 Red Led가 깜박이는 장면입니다. 코딩하는 것도 아두이노랑 차이가 없고 핀번호에 대해서 구분하여 사용하시면 사용하는데 어려움이 없겠죠. 하지만 문제는 프로그램을 ATtiny 칩에 이식하는 과정입니다. 사용은 쉽고 코딩도 쉬운데 프로그램을 이식하는게 어렵습니다.

5. 아두이노에서 ATtiny로 연결



위 출처로 가시면 자세히 설명 나와 있습니다. 저도 이글을 통해서 ATtiny에 프로그램을 이식시키구나 하고 대충 의미를 이해했네요. 구글검색하시면 국내 게시물도 다양하게 공개되어 있으니깐 어느걸 보셔도 상관없습니다. 따로 제가 아는척 설명드리기는 뭐해서 링크만 걸어 놓겠습니다.


대충 가상시뮬레이터에서 그림만 그린다면 이렇게 되네요. 그리고 나서 위 참고자료에 따라 순서대로 아두이노 IDE에서 설정만 해주시면 된다고 하네요. 실제 ATtiny 칩이 없어서 실험은 해보지 못했네요. 그냥 여러분들도 가상시뮬레이터에서 실험하기 대문에 동작 제어만 한번 코딩해보고 ATtiny 칩에 응용 방법만 머리속에서 설계하시면 됩니다.

6. 추가로 찾아보셔야 할 내용



필독 내용도 꼭 읽어주시기 바랍니다. 어떻게 아두이노에서 다른 칩에 프로그램을 이식시킬 수 있는지 아두이노공식페이지에 잘 나와 있습니다.

그리고 데이터시트 경우는 구글검색 키워드 "attiny85 datasheet"로 하시면 저 게시물이 나옵니다. 해당 데이터시트를 링크를 안걸어 놓은 이유는 다운로드 PDF 파일이기 때문입니다. 오해를 살 수 있는 부분이라서 링크를 걸어놓지 않겠습니다. 다른 데이터시트를 보셔도 됩니다. 내용은 비전공자분들은 어려울 수 있습니다. 제가 소개한 데이터시트의 p59 페이지의 표만 참고하시면 됩니다. 각 핀에 대한 설명이 자세히 나와 있습니다. 그걸 참고하시고 위에서 간단히 핀 설명을 설명을 PWM, Analog Input이라고만 했는데 우선은 이정도만 이해하셔도 충분합니다. 보다 자세히 알고 싶으면 데이터시트를 꼭 참고해 주세요.

마무리


간단히 ATtiny 칩을 제어해 보았습니다. 코딩은 따로 할 것은 없고 아두이노 상에서 코딩한 것 처럼 그대로 코딩하시면 됩니다. 어떤 핀들이 있는지만 잘 이해하시면 됩니다. 명령을 내릴 수 있는 핀은 어떤 핀인지만 구별하시면 어려움은 없을 듯 하네요. 좀 어려운 부분은ATtiny에 프로그램을 이식시키는 과정이 좀 복잡하다는 점이죠.
저는 코딩을 좋아하고 코딩을 위주로 하기 때문에 전자회로쪽은 좀 약한 편입니다. 얇은 지식으로 2편을 나눠서 제가 설명하는 것보다 위에 나온 링크한 자료들을 토대로 공부하시는게 더 좋을 것 같아 포스팅을 늘리지 않겠습니다.

실제로는 다른칩에 프로그램을 이식하기 위해서는 ArduinoISP 튜토리얼을 참고하셔서 그 과정대로 세팅하고 실제 코딩해놓은 프로그램을 이식시키면 됩니다. 가상시뮬레이터에서는 프로그램을 이식시키는 과정이 필요 없기 때문에 뭘 만들지만 여러분들이 상상력을 발휘하시면 됩니다. 지금까지 배워온 여러가지 부품들을 ATtiny와 연결해서 회로도를 설계를 해보시고 동작시켜서 ATtiny의 활용도를 상상해 보세요.

마지막으로 작은 ATtiny 칩을 어디에다 쓸지 상상의 나래를 펼쳐보세요. 아마 소형으로 구현할 수 있는 기기들을 상상하시겠지요.

댓글()

[아두이노] NeoPixel 증흥적 패턴 놀이

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

[아두이노] NeoPixel 증흥적 패턴 놀이 



오늘은 NeoPixel를 가지고 for문만을 이용해서 즉흥적으로 깜박이는 실험을 해 보겠습니다. 지난 시간에는 패턴을 만들고 그 만들어진 패턴을 변수에 저장하고 그것을 다시 불러와서 출력하는 과정이 좀 복잡하고 어렵게 느껴졌을 거라 생각되네요. 재밌는 NeoPixel를 너무 어렵게 나간것 같아서 원래 예정에 없던 추가 포스트를 작성하게 되었네요. for문 하나를 가지고 여러가지 패턴으로 움직이게 하여 NeoPixel를 가지고 놀아 보도록 합시다.


오늘 제작 할 NeoPixel의 모습입니다.

1. 회로도 구성


  • 준비물 : NeoPixel Ring 24 1개 NeoPixel Ring 12 1개, NeoPixel Jewel 1개, 아두이노우노
  • 내용 : 사용 할 NeoPixel를 핀에 맞게 간단히 연결하시오

아래 그림에서는 NeoPixel Ring 24 짜리는 선을 구별할 수 있지만 NeoPixel Ring 12와 NeoPixel Jewel은 우리가 NeoPixel를 지난 시간분터 계속 연결해왔기 때문에 안보여도 대충 어떤식으로 연결되는지 아실거라고 생각되기에 그 부분은 설명에서 제외하겠습니다. 아래 결과물 동영상에서 제작과정이 잘 나와 있으니깐 참고해 주세요.


선연결은 그리 어렵지 않을꺼에요 Vcc은 Vcc로 Gnd은 Gnd로 각각 서로 연결하시면 됩니다. 그리고 아두이노에서 출력하는 값은 3번 핀으로 Orange 선이 Neopixel의 입력핀으로 연결되고 NeoPixel의 출력핀은 다른 NeoPixel의 입력핀과 연결된다는 점만 구별해 주세요.

2. 코딩


  • 사용함수 : Adafruit_NeoPixel(), neopixel.begin(), neopixel.setPixelColor(), neopixel.show(), neopixel.clear()
  • 내용 : 증흥적 다양한 릴레이 동작을 구현해 보자.(랜덤함수로 색을 다양하게 표현)

함수

  • Adafruit_NeoPixel(NeoPixel수, NeoPixelPin, NEO_GRB + NEO_KHZ800) : 생성자함수로 NeoPixel 클래스 객체를 만들때 사용합니다. 몇개의 NeoPixel를 사용하고 어느 핀을 사용할지와 Neopixel 타입을 설정을 하는 함수입니다. 우선 가상시뮬에이터는 이 값을 기본으로 사용하세요.
  • neopixel.begin() : 라이브러릴 사용하면 꼭 객체 시작을 알리는 함수가 있죠. 이것도 마찬가지입니다. 사용하겠다고 선언.
  • neopixel.setPixelColor(위치, R, G, B) : 색을 나타냅니다. 위와 같은 Neopixel 타입을 설정했을때 RGB의 위치는 이와 같이 결정됩니다. 참고로 타입이 바뀌면 색상 위치도 바뀌니깐 햇갈리지 마세요. 쉽게말해서, 색을 세팅하는 함수입니다.
  • neopixel.show() : 색이 세팅한 값을 실제로 보여주라는 함수입니다. Orange선을 통해서 해당 위치에 색이 켜지겠지요.
  • neopixel.clear() : 지금까지 켜진 NeoPixel를 초기화하는 함수입니다. 켜진 NeoPixel를 다 꺼지겠지요.

[기본 소스]

#include <Adafruit_NeoPixel.h>

const byte neopixelPin = 3; 
Adafruit_NeoPixel neopixel = Adafruit_NeoPixel(43, neopixelPin, NEO_GRB + NEO_KHZ800);

void setup() {
  neopixel.begin();  
}

void loop() {  
  for(int i=0;i<43;i++){
    neopixel.setPixelColor(i, 255, 0, 0);    
    neopixel.show();
    delay(100);    
  } 
  neopixel.clear(); 
}

순서대로 NeoPixel에 불이 들어오는지 첨에 이 소스로 돌려주세요.

랜덤 함수로 NeoPixel의 색을 결정하기 위해서 두개의 함수를 더 사용합니다.

randomSeed(analogRead(A0))
random(255)

setup()함수에다가 randomSeed()함수로 A0핀을 난수를 만들 핀으로 사용하겠다고 선언해주시고요.
실제로 RGB는 각각 0~255사이의 값으로 출력되기 때문에 random(255)로 0~255사이의 난수 값을 얻게 됩니다.

[전체 소스]

#include <Adafruit_NeoPixel.h>
const byte neopixelPin = 3; 
Adafruit_NeoPixel neopixel = Adafruit_NeoPixel(43, neopixelPin, NEO_GRB + NEO_KHZ800);

void setup() {
  neopixel.begin();  
  randomSeed(analogRead(A0));
}
void loop() { 
  
  //순차적으로 릴레이
  for(int i=0;i<43;i++){ //1씩 증가하니깐 0~42까지 해당 위치에 NeoPixel의 색을 결정
    neopixel.setPixelColor(i, random(255), random(255), random(255));    
    neopixel.show();
    delay(50);    
  } 
  neopixel.clear(); 
  
  //홀수층 릴레이
  for(int i=0;i<43;i+=2){  //0부터 2씩 증가하니깐 홀수 위치에 색을 설정
    neopixel.setPixelColor(i, 0,255,0);
    neopixel.show();
    delay(50);    
  }  
  //neopixel.clear(); 
  
  //짝수층 릴레이
  for(int i=1;i<43;i+=2){ //1부터 2씩 증가니깐 짝수 위치가 되겠죠.
    neopixel.setPixelColor(i, 0,0,255);
    neopixel.show();
    delay(50);    
  }  
  neopixel.clear(); 
 
  //홀수 위치는 밖에서부터 짝수 위치는 안쪽부터 두가지 패턴을 한번에 세팅
  for(int i=0;i<43;i+=2){
    neopixel.setPixelColor(i, 0,255,0);
    neopixel.setPixelColor(42-i-1, 0,0,255);
    neopixel.show();
    delay(50);    
  }  
  neopixel.clear(); 
  
  //짝수 홀수 교대로 깜박이기 (위의 홀수와 짝수를 릴레이 하는걸 홀수전체 세팅, 짝수 전체세팅으로 설정
  for(int k=0;k<5;k++){ //교대로 반복 5회
    for(int i=0;i<43;i+=2){
        neopixel.setPixelColor(i, random(255),random(255),random(255));  
    }
    neopixel.show();
    delay(50);    
    neopixel.clear(); 
  
    for(int i=1;i<43;i+=2){
        neopixel.setPixelColor(i, random(255),random(255),random(255));
    }
    neopixel.show();
    delay(50);    
    neopixel.clear(); 
  }
}

위 소스만 보면 코딩이 엄청 길지만 기본소스에 원리를 그대로 적용해서 어떻게 출력할지만 표현 했을뿐 자세히 보시면 코딩이 반복되는 코딩으로 for문의 규칙을 잘 살펴보시면 별차이가 없다는 것을 느끼 실 꺼에요.

여기서, 코딩을 이해하실때 neopixel.show()함수와 neopixel.clear()함수의 의미를 의해 잘 생각 하시고 어느 위치에 있느냐에 따라서 결과가 어떻게 변하는지 구별 하실 수 있게 되면은 자기가 원하는 형태로 다양한 패턴을 만들어 낼 수 있을 거라 생각됩니다.

3. 결과


결과만 보여드릴까도 했는데 제작과정을 다 담았네요. 참고로 짝수 릴레이, 홀수 릴레이에서 동영상에서 실수로 오타가 났네요. '0,2,4,,6,8,10...' 순으로 가니깐 짝수인것처럼 한글로 짝수 릴레이라고 했는데요. 실제로는요 0이 첫번째 NeoPixel이니깐 홀수층 릴레이가 됩니다. 그리고 '1,3,5,7,9...'순으로 가니깐 한글로 홀수 릴레이라고 했는데요 이건 반대로 배열 1번은 2번째 위치입니다. 그러니 정확한 표현은 짝수층이 되겠죠. 아무튼, 동영상에서는 오타가 난거고 숫자가 짝수니깐 짝수층이고 홀수니깐 홀수층이라고 생각하시면 안됩니다. 정확히 짚고 넘어갑니다.

프로그램에서는 배열에서 a[0]은 1번째 위치고 a[1]은 2번째 위치입니다. 순서로 a[0]은 홀수 위치가 되고 a[1]은 짝수 위치가 됩니다. 이부분을 한글 오타를 정정합니다.

동영상을 급하게 대충 표현한거라 여러분들은 더 멋진 패턴으로 깜박이게 한번 해보세요.


마무리


NeoPixel은 다양한 형태로 출력할 수 있기 때문에 재밌는 부품입니다. RGB LED를 쉽게 여러개을 한번에 연결하여 제어할 수 있는 부품이라고 생각하시면 아마 될 듯 싶네요.
실제로 구매하셔서 만들어 보시는 것도 재미있을 듯 싶네요.


댓글()

[아두이노] NeoPixel로 글자패턴 만들기

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

[아두이노] NeoPixel로 글자패턴 만들기 


오늘의 주제는 NeoPixel를 이용해서 지난 시간에 배운 3x3x3 CUBE LE와 8x8 Dot Matrix에서 사용한 코딩기법을 복습하는 시간을 가져보도록 하겠습니다. 기본 출력 로직을 회로도에 맞춰서 만들어 놓으면 나머지 패턴 글자만 만드는 작업만 좀 고생 되겠지만 이 후 코딩은 글자 패턴를 만드는 작업뿐이 없으니깐 아마 편하게 코딩 할 수 있을꺼에요. 암튼 좀 어려울 수 있는 내용이지만 코딩을 처음 어떻게 시작해서 어떻게 진화한 코딩으로 바뀌는지 느끼는 시간이 되었으면 합니다. 코딩은 처음부터 정해진 코딩으로 뚝닥 완성되는게 아니라 출발은 아래 글처럼 하나의 글자를 증흥적으로 코딩해보고 다른 방식들을 찾아보면서 최종적으로 자신이 원하는 형태의 로직 형태를 찾아서 그 결과 로직을 토대로 다양한 글자들을 만들어 아래와 같은 결과물을 얻게되는데 이 과정을 잘 살펴 보셨으면 합니다. 완성된 코딩은 그렇게 까지 의미는 없습니다. 자신이 출발은 어디서 부터이고 그 출발에서 어떻게 변화 해가는지가 중요합니다. 아래의 코딩과정을 길게 나열한 것은 그 의미를 전달하기 위해서 입니다. 이 글을 쓰는 저자가 완성된 로직을 만들기 위해서 처음에 여기서부터 출발했고 어떤 과정을 거쳐서 여기까지 왔구나 정도만 이해하시면 됩니다.

코딩한 결과가 중요한 것이 아니라 코딩하는 과정이 무척 중요합니다.

1. NeoPixel 회로도 배치 고민


처음에는 위와 같은 순서대로 회로도를 연결했습니다. 문제는 위치에 대한 공간인지가 좀 불편하실 수 있으며 나중에 2차배열로 위치값을 정해야 하는데 순번이 햇갈릴 수 있기 때문에 이경우는 초보분들에게 혼동을 야기 할 것 같아서 포기했습니다.


그래서 옆으로 눞여 봤는데 홀수 행은 배열 형태를 잘 나타나는데 짝수행은 배열의 역순 위치 값으로 표기 되기 때문에 이 또한 혼동을 야기 할 것 같아서 포기했습니다.

최종적으로 선 연결을 복잡하게 한 대신에 배열 형태를 맞춰서 디자인 했습니다. 그러면 어떻게 했는지 회로도 구성에서 살펴보도록 하겠습니다.

2. 회로도 구성


  • 준비물 : NeoPixel 35개, 아두이노우노
  • 내용 : 사용 할 NeoPixel를 간단히 연결해 보자.


회로도의 경우는 자신의 원하는 형태로 연결하시면 됩니다. 단, 연결하실 때는 어떤식으로 코딩할지에 대해서 고려하시고 연결하셔야 해요. 연결하고 나서 그 연결된 형태를 고려해서 코딩을 해도 되지만 반대로 코딩 할 로직을 어느정도 틀이 잡혀 있으면 그 틀에 맞게 회로도를 배치하는 것도 좋습니다. 제가 코딩을 소개하는 방향에서는 2차배열을 사용하기 때문에 최대한 위치에 대한 순서를 맞춰서 회로도의 선을 연결했네요.

3. 코딩 과정


  • 사용함수 : Adafruit_NeoPixel(), neopixel.begin(), neopixel.setPixelColor(), neopixel.show(), neopixel.clear()
  • 내용 : "STEEM CODINGMAN" 글자를 만들어 출력하자.
  • 참고소스 :

함수

  • Adafruit_NeoPixel(NeoPixel수, NeoPixelPin, NEO_GRB + NEO_KHZ800) : 생성자함수로 NeoPixel 클래스 객체를 만들때 사용합니다. 몇개의 NeoPixel를 사용하고 어느 핀을 사용할지와 Neopixel 타입을 설정을 하는 함수입니다. 우선 가상시뮬에이터는 이 값을 기본으로 사용하세요.
  • neopixel.begin() : 라이브러릴 사용하면 꼭 객체 시작을 알리는 함수가 있죠. 이것도 마찬가지입니다. 사용하겠다고 선언.
  • neopixel.setPixelColor(위치, R, G, B) : 색을 나타냅니다. 위와 같은 Neopixel 타입을 설정했을때 RGB의 위치는 이와 같이 결정됩니다. 참고로 타입이 바뀌면 색상 위치도 바뀌니깐 햇갈리지 마세요. 쉽게말해서, 색을 세팅하는 함수입니다.
  • neopixel.show() : 색이 세팅한 값을 실제로 보여주라는 함수입니다. Orange선을 통해서 해당 위치에 색이 켜지겠지요.
  • neopixel.clear() : 지금까지 켜진 NeoPixel를 초기화하는 함수입니다. 켜진 NeoPixel를 다 꺼지겠지요.

[기본 소스]

#include <Adafruit_NeoPixel.h>

const byte neopixelPin = 3; 
Adafruit_NeoPixel neopixel = Adafruit_NeoPixel(35, neopixelPin, NEO_GRB + NEO_KHZ800);

void setup() {
  neopixel.begin();  
}

void loop() {  
  for(int i=0;i<35;i++){
    neopixel.setPixelColor(i, 255, 0, 0);    
    neopixel.show();
    delay(100);    
  } 
  neopixel.clear(); 
  neopixel.show();
  delay(100);   
}

순서대로 NeoPixel에 불이 들어오는지 테스트를 하였습니다.

2) 하나의 'S' 글자패턴 만들기


위 표에서 보는 것 처럼 2차 배열이 있으면 'S'라는 글자를 만들면 해당 위치에 가운데 표에서 보는 것처럼 색이 칠해지겠죠. 그 위치값을 가지고 글자패턴을 만든다면 아래와 같이 표현이 됩니다.

const byte p[7][5]= {
        {0,1,2,3,0},
        {5,0,0,0,9},
        {10,0,0,0,0},
        {0,16,17,18,0},
        {0,0,0,0,24},
        {25,0,0,0,29},
        {0,31,32,33,0}};

즉, 배열에다가 위치값을 아예 저장하는 방식입니다. 출력을 해볼까요.

   for(int i=0;i<7;i++){
      for(int j=0;j<5;j++){
          if(p[i][j]!=0)neopixel.setPixelColor(p[i][j], 255, 0, 0);    
      }     
    }
    neopixel.show();
    delay(1000);

위 코딩으로 2차원 배열로 행7과 열 5로 순차적으로 0이 아닌 위치에 neopixel.setPixelColor()함수로 색을 세팅합니다. 2차 for문이 다 돌고나면 'S'라는 글자의 위치에는 색이 다 세팅되어 있겠죠. 그리고 나서 neopixel.show()함수로 실제 NeoPixel로 출력하게 됩니다. 그러면 'S'라는 글자를 볼 수 있습니다.

#include <Adafruit_NeoPixel.h>

const byte neopixelPin = 3; 
Adafruit_NeoPixel neopixel = Adafruit_NeoPixel(35, neopixelPin, NEO_GRB + NEO_KHZ800);
const byte p[7][5]= {
        {0,1,2,3,0},
        {5,0,0,0,9},
        {10,0,0,0,0},
        {0,16,17,18,0},
        {0,0,0,0,24},
        {25,0,0,0,29},
        {0,31,32,33,0}};
void setup() {  
   neopixel.begin();   
}       
void loop(){        
    for(int i=0;i<7;i++){
      for(int j=0;j<5;j++){
          if(p[i][j]!=0)neopixel.setPixelColor(p[i][j], 255, 0, 0);    
      }     
    }
    neopixel.show();
    delay(1000);
    neopixel.clear();
    neopixel.show();
    delay(100);  
}       

2) 글자패턴 다른식으로 접근

사실 위 코딩으로 's' 글자를 만들때 위치값을 해도 되지만 '0'과 '1'로 표현을 해보도록 하겠습니다. 글자가 들어가는 위치를 '1'로 그렇지 않는 곳은 '0'으로 표현 하겠습니다.

const byte p[7][5]= 
        {{0,1,1,1,0},
        {1,0,0,0,1},
        {1,0,0,0,0},
        {0,1,1,1,0},
        {0,0,0,0,1},
        {1,0,0,0,1},
        {0,1,1,1,0}};

그러면 처음 코딩한 곳에서 어디를 수정해야 할까요. 바로 for문안에 문장이겠죠.

   byte y=0;
   for(int i=0;i<7;i++){
      for(int j=0;j<5;j++){
          if(p[i][j]!=0)neopixel.setPixelColor(y+j, 255, 0, 0);   
      }
            y+=5; // 행위치값을 5씩 증가,
    }

그냥 i+y하면 안됩니다. 그 이유는 i가 0일때는 j에 더하면 '0,1,2,3,4'가 나오지만 i가 1일때는 '1,2,3,4,5'가 나오게 됩니다. 원래는 '5,6,7,8,9'이렇게 나와야 하는데 말이죠. 이렇게 나오게 하기 위해서 y라는 변수를 행 위치변수로 하나 만들어서 행의 위치를 나타내는 변수가 필요합니다. 행인 i가의 for문이 증가할때마다 행위치변수인 y은 5씩 증가하게 표현함으로 2차 배열의 위치를 정확히 지정할 수 있게 됩니다.

첫번째 코딩한 것에서 위 표현을 변경할 부분에 삽입하셔서 바꾸시면 됩니다. 변수선언과 for문안에 로직과 y변수 선언하시면 됩니다.

3) '0'과 '1'의 표현이면 '0B00000000'로 표현

'0'과 '1'이 나왔으면 어떤 표현이 떠오르지 않나요. 바로 byte형으로 하나의 숫자 값으로 '0B00000000'로 표현이 떠오르셨다면 지난 내용을 제대로 공부하셨던 분일꺼에요, 이 표현을 통해 열을 표현한 5개의 배열공간을 하나의 숫자로 표현이 가능해 집니다.

01110 + 000 => 0B01110000

뒤에다 '000' 붙였는지만 앞에다 붙이셔도 됩니다. 실험은 뒤에다 붙여서 실험했는데 이 표현은 제 마음이니깐요 이게 꼭 해야하는 건 아니니깐 앞이든 뒤든 상관이 없고 나중에 for문을 표현할 때 앞이냐 뒤냐에 따라서 표현이 좀 달라지기는 하지만 그렇게 큰 의미는 없는 표현입니다.

const byte p[7]= {
0B01110000,
0B10001000,
0B10000000,
0B01110000,
0B00001000,
0B10001000,
0B01110000 }

이렇게 표현되는데 아두이노라이브러리에 bit를 읽는 함수를 기억하실지 모르겠네요. bitRead(x,n)함수가 있습니다. X라는 숫자에서 n번째 위치의 bit값을 가져오는 함수입니다.

위의 패턴배열변수에서

0B01110000

이값을 가져올려면

const byte p=0B01110000;
for(int j=7;j>2;j--){
     bitRead(p, j);
}

이렇게 표현해야합니다. 읽는 위치는 역순이니깐요. 오른쪽끝이 0번째가 됩니다. 그런데 왼쪽부터 순서대로 하나식 가져올려면 7번 위치의 자리에 값부터 순서대로 읽어와야겠죠. 총 5개니깐 j는 2보다 커야하고요. 순서대로 가져오니깐 'j--'로 감소연산자로 1씩 감소시켜야 겠죠. 이렇게 표현해야 왼쪽부터 순서대로 1bit씩 가져오게 됩니다.

로직은 이러헥 되겠죠.

    byte x=0; //열위치
   byte y=0;//행위치
   for(int i=0;i<7;i++){
      for(int j=7;j>2;j--){
          if(bitRead(p[i,j)]!=0)neopixel.setPixelColor(y+j, 255, 0, 0);   
                x+=1;
      }
            x=0;
            y+=5; // 행위치값을 5씩 증가,
    }

여기서 열의 위치값을 j로 할 수 없습니다. j가 7부터 시작하기 때문이지요. 그렇기 때문에 따로 x변수로 열도 위치변수를 만들어 줘야 합니다. j가 반복수행 할 때 x를 1씩 증가하게 하고 j가 5번 반복이 끝나면 x를 초기화 해야합니다. 두번째 행의 위치를 처음부터 다시 찾아야 하니깐요.

변수 선언과 이 로직을 처음 코딩한 소스에서 삽입하고 변경하시면 됩니다. 따로 전체소스는 안올리겠습니다.

4) 'S' 글자 16진수화

0B01110000 = 0x70

const byte p[7] ={0x70,0x88,0x80,0x70,0x08,0x88,0x70};

이렇게 한줄로 대폭 줄일 수 있습니다. 단, 힘든 16진수 계산이 필요하지만요. 따로 16진수로 출력되는 프로그램을 만드셔도 됩니다. 해당 2진수 값이 저장된 배열을 for문을 이용해서 출력을 16진수로 바꾸시면 됩니다. 참고로 10진수로 변경하셔도 됩니다.

5) 'STEEM CODING MAN' 글자패턴을 만들기


글자 한개를 만드는 것도 힘들데 총 14자의 글자를 만든다고 생각하니깐 앞이 깜깜하시죠. 이제 글자를 쉽게 만드는 꼼수를 찾아냈는데 알려드리도록 하겠습니다.



위 블로그에 올리신 분께서 젤 하단에 이런 프로그램을 링크 걸어 놓았네요. 글자 패턴을 만들기 힘드신분들을 위한 배려인 듯 합니다. 저도 이런거 프로그램을 만든분 없는지 구글 검색을 통해서 찾아보다가 우연히 발견했네요. 그리고, 쉽게 글자를 만들었네요.


7행의 패턴 글자이기 때문에 마지막 8행의 16진수 값은 필요 없으니깐 지우시면 됩니다. 이렇게 글자를 만들면 다음과 같은 패턴 배열변수가 완성되었네요.

이런식으로 글자들을 14자를 완성하면 이렇게 간단히 표현됩니다.

const byte p[14][7]={ //글자 패턴이 14개임
  {0x70,0x88,0x80,0x70,0x08,0x88,0x70}, //S
    {0xF8,0x20,0x20,0x20,0x20,0x20,0x20}, //T
    {0xF8,0x80,0x80,0xF0,0x80,0x80,0xF8}, //E
    {0xF8,0x80,0x80,0xF0,0x80,0x80,0xF8}, //E
    {0x88,0xD8,0xA8,0x88,0x88,0x88,0x88}, //M
    {0x70,0x88,0x80,0x80,0x80,0x88,0x70}, //C
    {0x70,0x88,0x88,0x88,0x88,0x88,0x70}, //0
    {0xF0,0x88,0x88,0x88,0x88,0x88,0xF0}, //D
    {0x70,0x20,0x20,0x20,0x20,0x20,0x70}, //I
    {0x88,0x88,0xC8,0xA8,0x98,0x88,0x88}, //N
    {0x70,0x88,0x80,0xB8,0x88,0x88,0x70}, //G
    {0x88,0xD8,0xA8,0x88,0x88,0x88,0x88}, //M
    {0x70,0x88,0x88,0xF8,0x88,0x88,0x88}, //A
    {0x88,0xD8,0xA8,0x88,0x88,0x88,0x88} //M
    };

이 글자가 14개의 패턴 글자가 나오니깐 기존 소스에서 14번 for문을 한번 더 돌려야 겠죠.

for(int k=0;k<14;k++){

        기존 2차for문 로직;
        y=0; // 하나의 패턴 글자가 끝나니깐 y행위치 변수값을 초기화 해야겠죠.
}

최종적으로 코딩을 하면

#include <Adafruit_NeoPixel.h>

const byte neopixelPin = 3; 
Adafruit_NeoPixel neopixel = Adafruit_NeoPixel(35, neopixelPin, NEO_GRB + NEO_KHZ800);


const byte p[14][7]={ //글자 패턴이 14개임
    {0x70,0x88,0x80,0x70,0x08,0x88,0x70}, //S
    {0xF8,0x20,0x20,0x20,0x20,0x20,0x20}, //T
    {0xF8,0x80,0x80,0xF0,0x80,0x80,0xF8}, //E
    {0xF8,0x80,0x80,0xF0,0x80,0x80,0xF8}, //E
    {0x88,0xD8,0xA8,0x88,0x88,0x88,0x88}, //M
    {0x70,0x88,0x80,0x80,0x80,0x88,0x70}, //C
    {0x70,0x88,0x88,0x88,0x88,0x88,0x70}, //0
    {0xF0,0x88,0x88,0x88,0x88,0x88,0xF0}, //D
    {0x70,0x20,0x20,0x20,0x20,0x20,0x70}, //I
    {0x88,0x88,0xC8,0xA8,0x98,0x88,0x88}, //N
    {0x70,0x88,0x80,0xB8,0x88,0x88,0x70}, //G
    {0x88,0xD8,0xA8,0x88,0x88,0x88,0x88}, //M
    {0x70,0x88,0x88,0xF8,0x88,0x88,0x88}, //A
    {0x88,0xD8,0xA8,0x88,0x88,0x88,0x88} //M
    };

void setup() {
  neopixel.begin();  
}

void loop() {
  byte x=0;
  byte y=0;
  for(int k=0;k<14;k++){ //글자 패턴의 숫자만큼 반복
    for(int i=0;i<7;i++){
        for(int j=7;j>2;j--){
            if(bitRead(p[k][i],j)!=0) neopixel.setPixelColor(y+x, 0, 255, 0);    
            x+=1;
        }
        x=0;//열 초기화
        y+=5;//열이 5칸이니 행이 증가할때마다 5가 더해져야함
    }
    y=0; //행 초기화
    neopixel.show();
    delay(100);   
    neopixel.clear(); 
    neopixel.show();
    delay(100);
  }
}

이렇게 완성이 되었습니다. 코드를 이해 못하셔도 좋습니다. 제가 처음에 어떻게 시작을 했고 어떤 과정을 통해서 여기까지 왔는지의 과정만 이해하시면 됩니다. 어떤 코딩을 할 때 처음부터 완벽한 코딩은 없습니다. 하나씩 차근 차근 원리를 코딩하고 그것을 끊임없이 다른 방법은 없는지 찾으면서 코딩을 하는게 중요합니다.

그 의미를 잘 이해해 주셨으면 합니다.

4. 결과


원래는 'STEEM CODINGMAN'이라는 14자를 출력해야 하는데 동영상 녹화를 논스톱으로 하다보니깐 'O'자를 실수로 빼먹었네요. 13자만 출력되었네요. 어쩐지 글자가 다 출력되고 다시 loop()함수가가 시작하기 전에 딜레이 시간이 생겨서 가상시뮬레이터 상에서 발생하는 렉인 줄 알았는데 13자 출력하고 반복 패턴글자 1글자 분량의 동작을 더 수행하다 보니 결과는 없고 1글자 분량의 동작은 수행만큼의 딜레이 현상처럼 보였네요. 수정할려다가 그러면 영상을 편집해야 하기 때문에 그냥 패턴글자를 'STEEM CDINGMAN'로 출력하는걸로 끝내겠습니다.

참고로, 공개된 회로도 링크 주소로 가셔서 결과를 실제 돌려보시면 정상적으로 'STEEM CODINGMAN'이란 글자가 출력되도록 수정했으니깐 참고하세요.


만드는 과정이 좀 길었네요. 다 자르고 뒤에 결과만 편집할려다가 그냥 올렸습니다. 젤 마지막의 글자 패턴 결과만 보시거나 아니면 실제로 공개된 회로도 링크 주소로 가셔서 직접 돌려보셔도 됩니다.

마무리


NeoPixel이 재밌다고 했는데 갑자기 코딩수업이 되어서 어렵게 느껴졌을 듯 싶네요. 간단한 단순 패턴을 만들어서 화려하게 꾸미고 싶었는데 글자가 너무 땡겨서 글자 출력으로 하고 말았네요. 사실 특정한 문자로 출력하는 것은 좀 코딩이 복잡하고 불편합니다. 단순하게 홀짝 출력이나 릴레이 색상출력이나 큰틀에서의 한두가지 패턴을 색상과 덧붙여서 출력하는게 더 재미 있고 화려한데 말이죠.
이부분은 이 포스팅을 읽으시는 분들의 몫으로 남겨 두겠습니다. 혹시 땡겨서 밤에 만들어 내일 올릴 수 도 있겠지만 오늘밤 땡기냐 안땡기냐로 기분에 맡겨야 겠습니다.
갑자기 코딩이 좀 어렵게 됐는데 이것 말고 간단히 색상 별 한두가지 패턴으로 지그재그로 꾸며 보세요. 그리고 위치를 달리해서 어떤 독특한 모양을 만들어 보세요.
아니면 이 출력하는 원리를 잘 생각해보셔서 어느 부품하고 연결하면 좋을지 상상의 나래를 한번 펼쳐보세요.


댓글()

[아두이노] NeoPixel 제어

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

[아두이노] NeoPixel 제어 


오늘의 주제는 NeoPixel로 재밌는 LED 제어에 대해서 살펴보도록 하겠습니다. NeoPoxel를 제어하기 위해서 Adafruit_NeoPixel 라이브러리를 이용하는데 별로 어렵지 않게 LED 색을 만들어 내기 때문에 재미 있는 시간이 될거라 생각됩니다. 사용되는 함수는 몇개 안되지만 그래도 상상력을 얼마나 발휘하느냐에 따라서 멋진 작품들을 만들 수 있는 부품임으로 관심을 많이 가져주세요.

1. NeoPixel


NeoPixel은 여러 종류가 있습니다. 긴 띠, 한개짜리, 링형 막대형 등 다양한 부품들이 있습니다. 가상시뮬레이터에서는 아래 그림처럼 한개짜리와 원형과 여러종류의 링을 제공하고 있네요. 다루는 것은 다 동일하니깐 간단히 다뤄보도록 하겠습니다.


NeoPixel의 핀 구조는 Vcc, Gnd 핀이 각각 두개씩 있으며 Vin과 Vout 핀으로 나눠져 있습니다. Vcc, Gnd은 NeoPixel의 전원을 담당하겠죠. Vin은 해당 NeoPixel의 들어오는 입력값이고 Vout은 해당 NeoPixel에 들어왔던 입력값 중 일부를 다음 NeoPixel로 보내는 출력핀이 됩니다. 아래 그림의 Orange 선을 보시면 됩니다. Orange 선이 신호값이 들어오고 다음 NeoPixel로 보내는 흐름선으로 생각하시면 됩니다.


예를들어, 순차적으로 1초 단위로 1,2,3 NeoPixel이 켜진다고 가정해 봅시다. 신호 값은 1,2,3번에 불이 켜지라고 명령을 내리게 됩니다. 이때 데이터값이 Orange선으로 따라서 해당 위치에 불이 들어오게 합니다. 고로, Orange선은 명령값을 전달하는 통로로 생각하시면 됩니다.


다시 종합하면, 3번까지 NeoPixe에 불이 들어오라고 명령을 내리면 그 신호 값이 1번에 불이 들어오고 2번의 Neopixel에 신호를 보내고 2번에 불이들어오고 다시 Orange선을 통해서 3번 NeoPixel에 신호값이 전달되어 3번에 불이 들어오게 됩니다. NeoPixel간의 연결은 Vout과 Vin을 연결한 통로로 신호가 전달되니깐 이 점만 잘 기억해 주세요.

2. 회로도 구성


  • 준비물 : NeoPixel Ring 12 1개, NeoPixel 6개, 아두이노우노
  • 내용 : 사용 할 NeoPixel를 간단히 연결해 보자.

대충 두종류의 NeoPixel를 Vcc, Gnd 명칭을 잘 보고 연결하시면 됩니다. 그리고 Vin, Vout은 3번핀에 연결했네요. 제 블로그에 올렸던 회로도에서 약간만 수정했네요.


주의할것은 1개짜리 NeoPixel을 연결할때 두번째 라인은 회전시켜서 배치한 거라 Vout, Vin을 잘 체크하시고 연결하셔야 합니다. 그냥 드래그해서 배치한 형태에서 두번째 라인을 Vout에서 Vout로 연결하는 실수를 하시면 안됩니다.

3. 라이브러리 추가


참조 : [아두이노] LCD16x2 I2C(LiquidCrystal_I2C) 제어
라이브러리 출처 : https://github.com/adafruit/Adafruit_NeoPixel


NeoPixel 라이브러리는 여러 종류가 있습니다. 실제로 실험하실 분은 위 링크된 참조 LCD16x2 I2C 포스트 내용중에 라이브러리 추가하는 방법이 잘 나와 있으니깐 보시고 라이브러리를 추가하시면 됩니다.

그런데 가상시뮬레이터로 하시는 분들은

#include <Adafruit_NeoPixel.h>

이 문구만 있으면 됩니다.

라이브러리 올려주신 분의 github 주소입니다. 거기 가셔서 Adafruit_NeoPixel.h, Adafruit_NeoPixel.h.cpp 파일을 꼭 보시기 바랍니다.

거기 보시면 아래와 같은 코딩들이 있습니다. 타입 설정하는데 어느정도 보셔야 합니다. 실제로 구현 하실때 왜 불이 안들어오지 의도치 않게 결과가 나오는 이유가 타입 설정 때문에 그렇습니다. 하나로 고정되어 있는게 아니라 부품에 따라서 그 타입에 맞게 설정해야지 정상적으로 동작합니다.

 Constructor: number of LEDs, pin number, LED type
 
 LED type :
 NEO_KHZ800  800 KHz datastream
 EO_KHZ400  400 KHz datastream
 
 NEO_RGB  ((0 << 6) | (0 << 4) | (1 << 2) | (2))
 NEO_RBG  ((0 << 6) | (0 << 4) | (2 << 2) | (1))
 NEO_GRB  ((1 << 6) | (1 << 4) | (0 << 2) | (2))
 NEO_GBR  ((2 << 6) | (2 << 4) | (0 << 2) | (1))
 NEO_BRG  ((1 << 6) | (1 << 4) | (2 << 2) | (0))
 NEO_BGR  ((2 << 6) | (2 << 4) | (1 << 2) | (0))
 NEO_RGBW
 ...
 NEO_WRGB 
 ...
 

다른 함수들도 꼭 보시고 대충 어떤 느낌으로 흘러가는지만 살펴보세요. 나중에 색을 세팅하는 함수에서 위에 나와있는 RGB라는 글자들이 보이시죠. 위치를 나타냅니다. 색을 세팅하는 함수는 같지만 해당 위치의 인자값은 달라지게 됩니다. RGB 인자를 순서대로 넣었는데 처음 세팅을 BGR로 해버렸다면 코딩하는 사람은 RGB라고 생각하고 색 값을 넣었지만 색 세팅함수에서는 BGR로 인식해버릴 수 있으니깐 잘 살펴보셔야 해요. 그리고 함수명들만 헤더 파일에 어떤게 있는지만 한번 살펴봐 주세요.

4. 코딩


  • 사용함수 : Adafruit_NeoPixel(), neopixel.begin(), neopixel.setPixelColor(), neopixel.show(), neopixel.clear()
  • 내용 : 간단히 순차적으로 NeoPixel에 불이 들어오게 하자.
  • 참고소스 : [아두이노] 3x3x3 CUBE LED 제어 III

함수

  • Adafruit_NeoPixel(NeoPixel수, NeoPixelPin, NEO_GRB + NEO_KHZ800) : 생성자함수로 NeoPixel 클래스 객체를 만들때 사용합니다. 몇개의 NeoPixel를 사용하고 어느 핀을 사용할지와 Neopixel 타입을 설정을 하는 함수입니다. 우선 가상시뮬에이터는 이 값을 기본으로 사용하세요.
  • neopixel.begin() : 라이브러릴 사용하면 꼭 객체 시작을 알리는 함수가 있죠. 이것도 마찬가지입니다. 사용하겠다고 선언.
  • neopixel.setPixelColor(위치, R, G, B) : 색을 나타냅니다. 위와 같은 Neopixel 타입을 설정했을때 RGB의 위치는 이와 같이 결정됩니다. 참고로 타입이 바뀌면 색상 위치도 바뀌니깐 햇갈리지 마세요. 쉽게말해서, 색을 세팅하는 함수입니다.
  • neopixel.show() : 색이 세팅한 값을 실제로 보여주라는 함수입니다. Orange선을 통해서 해당 위치에 색이 켜지겠지요.
  • neopixel.clear() : 지금까지 켜진 NeoPixel를 초기화하는 함수입니다. 켜진 NeoPixel를 다 꺼지겠지요.
    참고로 clear()함수로 명령을 내렷다고 해서 NeoPixel에 들어온 불이 꺼지지는 않습니다. 내부적으로 세팅한 setPixelColor()함수의 값만 초기화 될 뿐이죠. 내부적으로 초기화 된 값에서 show()함수를 실행 시켜야 초기화된 상태로 NeoPixel이 꺼지게 됩니다. ( "왜! 안꺼져! 이런 실수를 안하셨으면 해요!")

설계

NeoPixel 라이브러리를 사용하니깐 사용할 객체를 선언해야 합니다. 한개짜리 6개와 12개짜리 링 한개로 총 18개의 NeoPixel를 제어하니깐 아래와 같이 선언하시면 되겠습니다.

const byte neopixelPin = 3;
Adafruit_NeoPixel neopixel = Adafruit_NeoPixel(18, neopixelPin, NEO_GRB + NEO_KHZ800);

순차적으로 NeoPixel로 불이 들어와야 하니깐 18개NeoPixel 기준으로 for문 한개를 사용하여 18번 반복하면 되겠죠.

for(int i=0;i<18;i++){
   NeoPixel i에 불이 들어오게하라;
}

이 로직으로 대충 돌아가야 겠죠. NeoPixel 함수는 불이 들어올려면 색을 세팅하고 그 세팅값을 NeoPixel로 보내야 합니다.

setPixelColor()함수로 색을 정하고, show()함수로 출력하면 됩니다.

  for(int i=0;i<24;i++){
    neopixel.setPixelColor(i, 255, 0, 0);    
    neopixel.show();
    delay(100);    
  } 

대충 이렇게 코딩 됩니다. i번째 위치 NeoPixel에 RGB에서 R(255)로 Red색으로 세팅하고 show()함수로 해당 위치에 NeoPixel에 불이 들어오게 됩니다. 그렇게 어렵지 않죠. NeoPixel 라이브러리로 간단히 해당 위치에 원하는 색으로 불이 들어오게 하는 함수가 이 두 함수입니다. 어떻게 로직을 짜냐에 따라서 재밌는 패턴이 만들어 지고 화려하게 불이 들어오게 할 수 도도 있게 됩니다.

딜레이는 빠르게 보기 위해서 0.1초로 했네요. 가상시뮬레이터에는 지연렉이 좀 있기 때문에 좀 빠르게 보기 위한 값이니깐 실험할 때는 원하는 시간 간격으로 돌려보세요.

그리고, 시작은 begin()함수를 사용하고 초기화는 clear()함수를 사용합니다. 꺼먹지 마세요. 그리고 clear()함수 명령을 내렸는데 왜 NeoPixel이 안꺼지지 하고 혼동하시는 분이 있는데요. 무조건 Neopixel에 명령을 보내는 것은 show()함수 입니다. 내부적으로 clear()함수로 초기화 되었어도 출력된 NeoPixel은 초기화 되지 않습니다. show()함수로 같이 쓰시면 외부의 NeoPixel까지 초기화 된다는 점을 꼭 기억해주세요.

전체적으로 코딩을 하면,

#include <Adafruit_NeoPixel.h>

const byte neopixelPin = 3; 
Adafruit_NeoPixel neopixel = Adafruit_NeoPixel(18, neopixelPin, NEO_GRB + NEO_KHZ800);

void setup() {
  neopixel.begin();  
}

void loop() {  
  for(int i=0;i<18;i++){
    neopixel.setPixelColor(i, 255, 0, 0);    
    neopixel.show();
    delay(100);    
  } 
  neopixel.clear(); 
  neopixel.show();
  delay(100);    
}

5. 결과




오늘은 회로도 만드는 것이 간단하니깐 전과정을 기록해 봤네요. 그리고 결과는 Red 색 하나만 순차적으로 불이 들어오게 하면 좀 그러니깐 R->G->B순으로 불이 들어오게 가상시뮬레이터에서 돌려봤네요. 어떤 결과가 나오는지 동영상을 꼭 확인 해보세요. 아니면 공개 회로도에 링크된 곳에 가셔서 가상시뮬레이터를 직접 돌려보세요.


마무리


진짜 오늘 배운 부품 소재는 재맸는 소재입니다. 아마도 한번은 보셨을지 모르겠네요. 클럽에 네온싸인 같은 것이나 할로윈 축제때 어떤 사람을 보면 몸에서 야광 LED가 깜박이는 것들을 보셨을꺼에요. 유튜브를 검색을 하시면 NeoPixel로 모니터를 만들어서 동영상을 감상하시는 분도 있고 연주가들은 악기에 붙여서 휘황찬란하게 표현하는 분도 있고 찾아보시면 스케일들이 남다른 분들의 영상물들을 많이 보실 수 있을 꺼에요. 아마도 실제로 구매해서 만들고 싶은 충동이 느껴지실 거라고 생각됩니다. 그런데 개당 가격이 좀 비싼편이라서 약간 구매해서 실험하기는 애매한 점도 있습니다. 우리에게는 가싱시뮬레이터가 있고 그걸 통해서 대리 만족을 느끼면 됩니다.

오늘은 간단한 동작으로만 채웠습니다. 그 이유는 여러분들의 상상력을 발휘할 시간을 주기 위해서 입니다. 다양한 표현을 시도해 보세요. 여러분들은 NeoPixel로 난 무엇을 만들어 볼까? 무엇을 만들 수 있을까? 계속 자신에게 질문을 던져주세요. 그리고 순차적으로 출력되는 저 for문을 가지고도 다양한 표현을 할 수 있습니다. setPixelColor()함수와 show()함수의 의미와 동작원리를 곰곰히 잘 생각해보시면 for문 한개로도 꽤 다양한 패턴을 만드실 수 있으니깐 꼭 동작 원리를 이해해 주세요.


댓글()