프로젝트

나도 메이커! 메이커스 여러분들의 작품/프로젝트를 공유하는 공간입니다.

시리얼통신-Mood Lamp 제작

2018-12-27 11:50:05

개요

 

컴퓨터와 아두이노간의 시리얼통신을 사용하여 스케치의 시리얼모니터에 색상과 밝기 값을 입력하면 
색상에 해당하는 LED가 그 값에 맞게 밝아지는 Mood Lamp를 만들어 보자.


단순한 LED 시스템이지만 응용해서 여러 개를 만들어 효과를 낸다면 방안에 은은한 촛불이 켜진 효과를 낼 수 있다.





시리얼 통신이란 간단하게 설명하면 통신채널이나 케이블을 통해 디지털화된 바이트단위의 데이터를 직렬방식으로 전송하는 통신기술을 말한다.

LED조명시스템을 시리얼통신으로 제어하는방법이 아닌 다른 방법으로 응용할수 있다면
위와같은 LED조명기구를 원거리통신기술인 이더넷통신이나 

근거리 통신기술인 블루투스를 통해 제어할 수 있는 시스템을 응용하여 구축할 수 있다.




 

 

 

미리보기 동영상

 

 

 

 

 

부품 목록

 

NO  부 품 명 수  량 상 세 설 명
1 아두이노  1개 오렌지 보드
2 Red, Green, Yellow
LED 
각1개  
3 150Ω 저항 3개  
4 케이블 7개 점퍼 케이블

 

부품명 아두이노  Red, Green, Yellow
LED 
150Ω 저항 케이블
부품사진

 

 

 

하드웨어 making

 

회로도

 


 

 

 

 

브레드보드 레이아웃



항상 LED를 연결할때에는 전류의 세기가 강하기 때문에 저항을 함께 사용하여 연결해 주어야 한다.
LED의 +는 아두이노UNO의 입출력핀의 번호에 맞게 연결하면 되고 -부분은 GND부분에 브레드보드를 이용하여 연결하면 된다.

 

 

 

소프트웨어 coding

 

/*
 제목		: 시리얼 통신으로 제어하는 mood lamp
 내용		: 시리얼 통신을 이용해 PC에서 아두이노로 데이터를 보내고, 데이터에 따라 LED를 제어해 봅시다.
 */

// 입력받을 데이터값을 저장할 버퍼를 생성합니다.
char buffer[18];  
int red, green, blue;

// RED LED를 디지털 11번 핀에 연결합니다. 
int RedPin = 11;
// GREEN LED를 디지털 10번 핀에 연결합니다.
int GreenPin = 10;
// YELLOW LED를 디지털 9번 핀에 연결합니다.
int YellowPin = 9;

// 실행시 가장 먼저 호출되는 함수이며, 최초 1회만 실행됩니다.
void setup() {
	// 시리얼 통신 속도를 9600bps로 설정합니다.
	Serial.begin(9600); 
	// 현재 시리얼포트에 있는 데이터값을 삭제합니다.
	Serial.flush();     
	// 11번 핀을 출력 핀으로 설정합니다.
	pinMode(RedPin, OUTPUT);
	// 10번 핀을 출력 핀으로 설정합니다. 
	pinMode(GreenPin, OUTPUT);
	// 9번 핀을 출력 핀으로 설정합니다.
	pinMode(YellowPin, OUTPUT);
}

// setup() 함수가 호출된 이후, loop() 함수가 호출되며,
// 블록 안의 코드를 무한히 반복 실행합니다.
void loop() {
	// 시리얼 포트내에 입력받은데이터값이 존재할 경우
	if(Serial.available() > 0) {  
		// index을 0으로 설정합니다.
		int index = 0;
		// 0.1초동안 대기합니다.
		delay(100);
		// 시리얼 통신을 통해 입력받은 데이터를 numChar에 저장합니다.
    	int numChar = Serial.available();
		// 입력받은 데이터의 크기가 15바이트 이상일 경우
		if (numChar > 15) {         
			// numahr를 15로 고정합니다.
			numChar = 15;             
		}
    	while (numChar--) {  
    		// 입력받은 데이터를 버퍼에 저장합니다.
			buffer[index++] = Serial.read();
		}
		// 함수를 호출합니다.
		splitString(buffer);
	}   
}

void splitString(char* data) {
	// 시리얼 모니터 창에 Data entered:를 출력합니다. 
 	Serial.print("Data entered: ");
 	// 시리얼 모니터 창에 입력 받은 데이터를 출력합니다.
 	Serial.println(data);
 	char* parameter;
 	// 입력받은 문자를 ""안의 " ,"이 문자를 기준으로 잘라냅니다.
	parameter = strtok(data, " ,"); 
	// 잘라낸 값이 0이 아닐경우에는 그값으로 다시 " ,"을 기준으로 잘라냅니다.
	while(parameter != NULL) { 
		// parameter의 값에 따라 LED를 제어합니다. 
		setLED(parameter);
		parameter = strtok (NULL, " ,");
	}
  
	// 데이터 버퍼의 값을 비운다
	for(int x = 0; x < 16; x++) {
    buffer[x] = '\0';
	}
	// 현재 시리얼포트에 있는 데이터값을 삭제합니다.
	Serial.flush();
}

void setLED(char* data) {
	// 잘라낸 데이터의 첫글자가 r이나 R일 경우
	if((data[0] == 'r') || (data[0] == 'R')) { 
		// 뒤에오는 값을 10진수의 int형으로 변환합니다.
		int Ans = strtol(data+1, NULL, 10); 
		// int형 값을 최소0 최대255로 제한합니다.
		Ans = constrain(Ans, 0, 255);  
		// Ans 값의 크기만큼의 밝기로 LED를 점등합니다.
		analogWrite(RedPin, Ans);  
		// 시리얼 모니터 창에 Red is set to:를 출력합니다. 
		Serial.print("Red is set to: ");
		// 시리얼 모니터 창에 Ans 값을 출력합니다.
		Serial.println(Ans);
	}
	
	// 잘라낸 데이터의 첫글자가 g나 G일 경우
    if((data[0] == 'g') || (data[0] == 'G')) { 
    	// 뒤에오는 값을 10진수의 int형으로 변환합니다.
  		int Ans = strtol(data+1, NULL, 10);  
 		// int형 값을 최소0 최대255로 제한합니다.
 		Ans = constrain(Ans, 0, 255);
 		// Ans 값의 크기만큼의 밝기로 LED를 점등합니다.
 		analogWrite(GreenPin, Ans);
 		// 시리얼 모니터 창에 Green is set to:를 출력합니다. 
 		Serial.print("Green is set to: ");
		// 시리얼 모니터 창에 Ans 값을 출력합니다.
		Serial.println(Ans);
	}
	
	// 잘라낸 데이터의 첫글자가 y나  Y일 경우
    if((data[0] == 'y') || (data[0] == 'Y')) { 
		// 뒤에오는 값을 10진수의 int형으로 변환합니다.
		int Ans = strtol(data+1, NULL, 10);  
		// int형 값을 최소0 최대255로 제한합니다.
		Ans = constrain(Ans, 0, 255);  
		// Ans 값의 크기만큼의 밝기로 LED를 점등합니다.
		analogWrite(YellowPin, Ans); 
		// 시리얼 모니터 창에 Yellow is set to:를 출력합니다.
		Serial.print("Yellow is set to: ");
		// 시리얼 모니터 창에 Ans 값을 출력합니다.
 		Serial.println(Ans);
	}
}

 

 

 

소프트웨어 & 하드웨어 설명


Serial Controlled Mood Lamp는 시리얼통신을 통해 값을 입력받아 그 값에 맞는 밝기로 LED를 점화시키는 시스템이다.

SetLED함수안에 보면 아래 함수가 존재하는데 간단하게 설명하면

첫 번째 인자값을 두 번째 인자값과 세 번째 인자값으로 제한하는 함수이다.
여기에서는 두 번째 인자값과 세 번째 인자값을 각각 0과 255를 줌으로
밝기의 값을 최소 0부터 최대 255까지 설정하였고 각 밝기 조절은

 

    // int형 값을 최소0 최대255로 제한합니다.
    Ans = constrain(Ans, 0, 255);  
 
1 constrain(x, a, b) 첫번째 인자값을 두번째 인자값과 세번째 인자값의 사이값으로 제한(값의 범위를 지정)



다음과 같이 r200 or R200을 입력하면 RedLED의 밝기가 200이 된다.
r200, g40, y60(RedLED의 밝기를 200으로 GreenLED의 밝기를 40으로 YellowLED의 밝기를 60으로 조절)이런 식으로도 명령 입력이 가능하다.
"," comma를 사용하여 최소1개 부터 3개까지의 LED를 한번에 밝기 조절이 가능하고
0일 경우에는 LED off, 255일 경우에는 LED Full On인 상태가 된다.
이렇게 써서 밝기를 조절할 수 있다.

 





시리얼 통신은 

// 실행시 가장 먼저 호출되는 함수이며, 최초 1회만 실행됩니다.
void setup() {
  // 시리얼 통신 속도를 9600bps로 설정합니다.
  Serial.begin(9600); 
  // 현재 시리얼포트에 있는 데이터값을 삭제합니다.
  Serial.flush();     
  // 11번 핀을 출력 핀으로 설정합니다.
  pinMode(RedPin, OUTPUT);
  // 10번 핀을 출력 핀으로 설정합니다. 
  pinMode(GreenPin, OUTPUT);
  // 9번 핀을 출력 핀으로 설정합니다.
  pinMode(YellowPin, OUTPUT);
}

부터 시작된다. 

Serial.begin(9600) 선언을 통해 시리얼통신의 속도를 9600bps로 설정하고 Serial.flush()선언을 통해
시리얼포트내에 혹시 존재할 수도 있는 다른 값들을 다 삭제시키며 시리얼포트를 초기화 시킨다.

loop()안에 있는 Serial.available()은 시리얼포트내에 있는 값의 크기를 반환하는데 이 값이 0보다 클 경우에는 시리얼 포트안에 입력받은 값이 존재한다는 경우이므로 이때는 if문의 조건을 충족하기 때문에 if문 안으로 들어와서 그 값을 처리하는 명령문을 실행하게 된다.
if문 안에 있는 Serial.available()은 입력받은 값의 크기를 반환하는데 여기서는 15바이트를 최대의 데이터 크기로 지정하였다. 15보다 클 경우에는 15바이트만을 버퍼에 저장하게 된다. 

 

// 시리얼 포트내에 입력받은데이터값이 존재할 경우
  if(Serial.available() > 0) {  
    // index을 0으로 설정합니다.
    int index = 0;
    // 0.1초동안 대기합니다.
    delay(100);
    // 시리얼 통신을 통해 입력받은 데이터를 numChar에 저장합니다.
      int numChar = Serial.available();
    // 입력받은 데이터의 크기가 15바이트 이상일 경우
    if (numChar > 15) {         
      // numahr를 15로 고정합니다.
      numChar = 15;             
    }
      while (numChar--) {  
        // 입력받은 데이터를 버퍼에 저장합니다.
      buffer[index++] = Serial.read();
    }



splitString은 입력받은 문자를 특정한 문자를 기준으로 나누는 함수로
함수내에서는 ","를 기준으로 문자를 자르게 된다.
예를들어 
splitString("영희, 철수, 영수")이렇게 문자를 받았을때 문자를

1. 영희
2. 철수
3. 영수

이렇게 구분하게 된다.

splitString()안에서 문자를 특정한 문자를 기준으로 자르는 역할을 하는 함수는 strtok()인데 
이 함수는 매개변수값을 두개 받는데 앞에 받는 값은 문자열을 받게 되고 뒤에 받는 값은 자를 기준이 되는 문자값이다.

예를들어
char data[20] = "HI nice to meet you";
 strtok(data," ");
이런식으로 작성했다면 문자열을 빈공간을 기준으로 나누게 되므로 문자는

HI
nice
to
meet
you 

이렇게 나뉘게 된다

r200, g50이 버퍼에 저장되어 있을 경우 이 문자는 r200과 g50으로 나뉘게 되고
r40, g50, y140이 저장되어 있을 경우에는 r40 따로 g50 따로 y140 따로 나뉘게 된다.

문자를 comma를 기준으로 잘라서 더 이상 잘라지지 않을 경우에는 for문을 통해 버퍼안에 있는 값을 라인피드값으로 저장하여 버퍼를 초기화한다.

 

void splitString(char* data) {
  // 시리얼 모니터 창에 Data entered:를 출력합니다. 
  Serial.print("Data entered: ");
  // 시리얼 모니터 창에 입력 받은 데이터를 출력합니다.
  Serial.println(data);
  char* parameter;
  // 입력받은 문자를 ""안의 " ,"이 문자를 기준으로 잘라냅니다.
  parameter = strtok(data, " ,"); 
  // 잘라낸 값이 0이 아닐경우에는 그값으로 다시 " ,"을 기준으로 잘라냅니다.
  while(parameter != NULL) { 
    // parameter의 값에 따라 LED를 제어합니다. 
    setLED(parameter);
    parameter = strtok (NULL, " ,");
  }
  
  // 데이터 버퍼의 값을 비운다
  for(int x = 0; x < 16; x++) {
    buffer[x] = '\0';
  }
  // 현재 시리얼포트에 있는 데이터값을 삭제합니다.
  Serial.flush();
}




setLED함수는 값의 크기에 맞게 LED를 발광시키는 함수로 입력된 데이터에 맞게 조건문을 처리한다.

r200이 입력된 데이터일 경우
buffer에는
buffer[0] = 'r' , buffer[1] = '2' , buffer[2] = '0' , buffer[3] = '0'
이렇게 데이터가 존재하게 된다.
buffer[0]에는 'r'문자가 존재하기 때문에 RedLED를 발광시키는 조건문을 만족시키게 된다.

strtol함수는 char형 변수를 int형으로 변환시키는 함수로 시리얼통신을 할 때에는 데이터를 char형식으로만 받게 된다.
하지만 밝기 값을 제어할 때는 int형의 숫자이므로 char형을 int로 바꿔야하기때문에 strtol함수를 써서 바꾸게 된다.


int형으로 바꾼다음에는 constrain함수를 통해 값을 최소 0 최대 255로 제한하고 값에 맞는 밝기로 LED를 발광시키게 된다.

void setLED(char* data) {
  // 잘라낸 데이터의 첫글자가 r이나 R일 경우
  if((data[0] == 'r') || (data[0] == 'R')) { 
    // 뒤에오는 값을 10진수의 int형으로 변환합니다.
    int Ans = strtol(data+1, NULL, 10); 
    // int형 값을 최소0 최대255로 제한합니다.
    Ans = constrain(Ans, 0, 255);  
    // Ans 값의 크기만큼의 밝기로 LED를 점등합니다.
    analogWrite(RedPin, Ans);  
    // 시리얼 모니터 창에 Red is set to:를 출력합니다. 
    Serial.print("Red is set to: ");
    // 시리얼 모니터 창에 Ans 값을 출력합니다.
    Serial.println(Ans);
  }
  
  // 잘라낸 데이터의 첫글자가 g나 G일 경우
    if((data[0] == 'g') || (data[0] == 'G')) { 
      // 뒤에오는 값을 10진수의 int형으로 변환합니다.
      int Ans = strtol(data+1, NULL, 10);  
    // int형 값을 최소0 최대255로 제한합니다.
    Ans = constrain(Ans, 0, 255);
    // Ans 값의 크기만큼의 밝기로 LED를 점등합니다.
    analogWrite(GreenPin, Ans);
    // 시리얼 모니터 창에 Green is set to:를 출력합니다. 
    Serial.print("Green is set to: ");
    // 시리얼 모니터 창에 Ans 값을 출력합니다.
    Serial.println(Ans);
  }
  
  // 잘라낸 데이터의 첫글자가 y나  Y일 경우
    if((data[0] == 'y') || (data[0] == 'Y')) { 
    // 뒤에오는 값을 10진수의 int형으로 변환합니다.
    int Ans = strtol(data+1, NULL, 10);  
    // int형 값을 최소0 최대255로 제한합니다.
    Ans = constrain(Ans, 0, 255);  
    // Ans 값의 크기만큼의 밝기로 LED를 점등합니다.
    analogWrite(YellowPin, Ans); 
    // 시리얼 모니터 창에 Yellow is set to:를 출력합니다.
    Serial.print("Yellow is set to: ");
    // 시리얼 모니터 창에 Ans 값을 출력합니다.
    Serial.println(Ans);
  }
}

 

 

 

kocoafab

시리얼통신, LED, 아두이노, 오렌지보드