[아두이노] [강좌] 46. 블루투스 통신 (5) - 프로토콜 만들기 (2)

드디어 블루투스 통신의 마지막 강좌. 


지난 강좌에 이어 프로토콜을 만들어 데이터를 주고받는 실습을 해보자. 지난 강좌에서는 스마트 폰에서 데이터를 보내고, 아두이노에서 받은 데이터를 분석하여 LED를 켜고 끄거나, 모터를 돌리고 멈추는 실습을 진행했었다. 


 

그리고 데이터의 길이를 유동적으로 사용하고, 연속해서 들어오지 않을 경우를 방지하기 위해 '시작 문자'와 '종료 문자'를 사용한 프로토콜에 대해서도 알아봤었다. 



다시 한 번 말하지만, 프로토콜은 사용하는 사람 마음대로 정하면 된다. 단, 보내는 쪽과 받는 쪽에서 같게 적용되어야 하고.



지난 강좌에서 예고한대로, 이번 강좌에서는 스마트 폰에서 모터의 속도를 제어하는 실습과, 아두이노에서 스마트 폰으로 값을 전달하는 실습을 진행할 예정이다. 




우선 모터 속도 제어 실습.


LED를 켜고 끄는 기능에 모터 기능까지 추가해보자. '시작 문자'는 이전 예제와 마찬가지로 '#'을 사용할거고,N'종료 문자'는 '@'를 사용할거다. 



참고로, 아스키 코드 중에는 코드 번호 0x02가 "STX"라는 시작 문자로 지정되어 있다. 0x03은 "ETX",N'종료 문자'. 하지만 "STX"나 "ETX" 문자를 사용하지 않고 '#'과 '@' 같은 문자를 사용하는 이유는, 스마트 폰에서 "STX"나 "ETX"를 입력할 수 있는 방법이 없기 때문;; 




우선 데이터 형식과 커맨드를 만들자. 


LED와 모터를 제어할 것이고, LED는 On/Off 기능을, 모터는 속도 제어 기능을 제어할 것이다. LED On/Off 기능을 "ON", "OFF"로 하면 나중에 LED On인지, 모터 On인지 헷갈릴 수 있으니까 "ON", "OFF" 앞에 "LED"라고 붙여주자. 그리고 "LED"와 "ON/OFF" 사이를 ',(콤마)'로 구분.


모터 역시 앞에 "MOTOR"라고 붙인 후 뒤에 0~255까지의 속도 값을 문자로 줄 것이다. "MOTOR"와 속도 값은 역시 ','로 구분.


표로 보면 이해가 빠를 것이다.



* 데이터 형식 : '#(시작 문자)' + 커맨드 + ',(콤마,구분자)' + 데이터 + '@(종료 문자)'

커맨드 (문자)

데이터 (문자) 

동작 

예시 

LED

 OFF

LED Off 

#LED,OFF@

 ON

LED On 

#LED,ON@ 

MOTOR

속도 값 (0~255)

모터 속도 조절 

#MOTOR,200@ 



'예시' 부분을 보면 쉽게 이해할 수 있을 것이다. 



제어할 센서나 모듈을 나타내는 ',' 앞 부분을 '커맨드', 제어 동작을 나타내는 부분을 '데이터'라고 칭하도록 하겠다. 


즉, 이 프로토콜은 다음과 같이 정의할 수 있다.



 #커맨드,데이터@



소스로 구현해보자.



ProtocolTest03.ino


int ledPin = 13;

int dcPin1 = 7;

int dcPin2 = 8;


String rxData = "";

boolean bStart = false;

int dataCnt = 0;


void setup() {

  // put your setup code here, to run once:

  pinMode(ledPin, OUTPUT);

  pinMode(dcPin1, OUTPUT);

  pinMode(dcPin2, OUTPUT);

  digitalWrite(dcPin2, LOW);

  

  Serial1.begin(115200);

}


void loop() {

  // put your main code here, to run repeatedly:

  if(Serial1.available()) {

    char data = Serial1.read();

    

    if(bStart) {

      if(data == N'@') {

        parseData(rxData);

        bStart = false;

        rxData = "";

      } else {

        rxData += data;

      }

    } else {

      if(data == N'#') bStart = true;

    }

  }

}


void parseData(String rxStr) {

  String cmd = rxStr.substring(0, rxStr.indexOf(','));

  String data = rxStr.substring(rxStr.indexOf(',')+1);

  

  if(cmd == "LED") {

    if(data == "ON") digitalWrite(ledPin, HIGH);

    else if(data == "OFF") digitalWrite(ledPin, LOW);

  } else if(cmd == "MOTOR") {

    analogWrite(dcPin1, data.toInt());

  }

}


 


parseData() 함수 부분 외의 다른 코드는 이전 강좌의 예제와 동일하므로 설명은 생략한다.


parseData() 함수에서는 매개 변수로 받은 String 타입의 데이터를 String.substring() 함수와 String.indexOf() 함수를 이용하여 커맨드와 데이터를 분리 또는 추출한다. 그리고 분리된 커맨드와 데이터를 각각 검사하여 해당하는 기능을 수행한다. 


String.substring() 함수와 String.indexOf() 함수에 대한 설명은 String 관련 강좌를 참조.



업로드 한 후 실행해보자.





입력 중간에 공백 문자가 들어가지 않도록 유의. (',' 다음에 자꾸 공백 문자가 자동 입력됨. ㅜㅜ)



아무튼 모터 속도가 전송한 데이터에 따라 달라지는 것을 확인할 수 있다. 


이 예제에 모터를 하나 더 추가하고, 방향을 제어하는 프로토콜을 추가한다면 스마트 폰으로 제어하는 RC 카를 만들 수 있다. 우와!!

brown_and_cony-35 




마지막으로, 아두이노에서 스마트 폰으로 데이터를 전달하는 실습을 해보자. 


무슨 데이터를 보낼까? 조도 센서를 이용해서 밝기 값을 보내볼까? 좋다. 3초에 한 번씩 조도 값을 읽어 보내는 기능을 만들어보자. 


참고로, 보내는 건 아주 쉽다. 그냥 시리얼로 보내면 됨. +_+



 ProtocolTest04.ino

 

 int lightPin = A0;

 unsigned long preMillis = 0;


 void setup() {

    Serial1.begin(115200);

 }


 void loop() {

   unsigned long curMillis = millis();


   if(curMillis - preMillis > 3000) {

     preMillis = curMillis;

     Serial1.print(analogRead(A0));

   }

 }





끝. 너무 쉽죠??


소스를 업로드한 후 확인해보자. 



 


brown_and_cony-76 



뭔가 좀 끊기는 듯 하지만 값이 가긴 간다. 



지금은 채팅 앱으로 테스트 중이라 그냥 데이터가 오는 것만 확인하면 되지만, 만일 앱을 직접 만들어 값을 사용하는 경우에는 위 영상처럼 데이터가 끊어져 들어오면 처리하기 어려울 것이다. 


이럴 경우에 뭐가 필요하다??


프.로.토.콜.



위에서 실습한 모터 예제의 프로토콜을 여기에도 적용해보자. 



 

 #커맨드,데이터@



 

* 데이터 형식 : '#(시작 문자)' + 커맨드 + ',(콤마,구분자)' + 데이터 + '@(종료 문자)'

커맨드 (문자)

데이터 (문자) 

예시 

LIGHT

밝기 값 (0~1023)

#LIGHT,123@ 



아두이노의 소스는 단 한 줄만 변경하면 된다. 



 

   if(curMillis - preMillis > 3000) {

     preMillis = curMillis;

     Serial1.print("#LIGHT,");

     Serial1.print(analogRead(A0));

     Serial1.print("@");

   }


 



어익후, 두 줄이네. 



별 거 아니다. 여기에 "TEMP"나, "HUM" 같은 커맨드를 추가한 후 온도 값이나 습도 값을 보낼 수도 있다. 그러면 데이터를 받는 앱 쪽에서 그 데이터를 가지고 처리하면 된다. 처리하는 방법은, 시작 문자와 종료 문자를 구분하는 아두이노 소스와 동일한 방식을 사용하면 됨. 물론 사용되는 함수 이름이나 방식은 조금 다르겠지만. 



자, 이 것으로 블루투스 강좌는 마치도록 하겠다. 블루투스를 이용하는 프로젝트가 많기 때문에 데이터를 보내거나 받아서 처리하는 법까지 함께 설명하느라 강좌가 길어졌다. 힘든 여정이었..ㅜㅜ



그럼 다음 강좌에서 또 만나요. 안녕!

0
0
이 글을 페이스북으로 퍼가기 이 글을 트위터로 퍼가기 이 글을 카카오스토리로 퍼가기 이 글을 밴드로 퍼가기

임베디드 보드

번호 제목 글쓴이 날짜 조회수
72 아두이노 ESP32 Analog Inputs (ADC) +4 icon 양재동메이커 02-12 18,556
71 아두이노 TIP : Serial의 Port가 Open 시점 확인 icon 양재동메이커 01-21 15,054
70 아두이노 ESP32 Boot Mode icon 양재동메이커 12-28 15,145
69 아두이노 아두이노 에러 리스트(Arduino Error list) icon 양재동메이커 11-24 20,342
68 아두이노 ESP32 main.cpp +1 icon 양재동메이커 11-19 15,294
67 아두이노 ESP32 EEPROM 와 IR Remote icon 양재동메이커 08-06 15,216
66 아두이노 Learn ESP32 icon 양재동메이커 06-25 15,013
65 아두이노 C 언어 비교문에서 == 사용 방법 icon 양재동메이커 04-12 15,160
64 아두이노 [아두이노 실습] 푸쉬버튼 long press, short press 판단하기 icon 양재동메이커 03-27 16,426
63 아두이노 [아두이노 실습] Push button 스위치로 FND 카운트 증가/감소 icon 양재동메이커 03-27 20,654
62 아두이노 Blynk를 사용해 아두이노에서 IoT 맛보기 icon 양재동메이커 03-27 17,336
61 아두이노 아두이노에서 u8glib로 0.96" OLED 사용하기 icon 양재동메이커 03-27 17,123
60 아두이노 아두이노에서 여러개의 스위치를 1개의 analog input핀으로 검사하기 icon 양재동메이커 03-27 16,024
59 아두이노 아두이노에서 RTOS 사용하기 (FreeRTOS in Arduino) icon 양재동메이커 03-27 19,181
58 아두이노 아두이노에서의 delay() 함수 icon 양재동메이커 03-27 14,772
57 아두이노 아두이노의 pinMode()에서 INPUT과 INPUT_PULLUP의 차이 icon 양재동메이커 03-27 17,232
56 아두이노 아두이노등의 임베디드 시스템의 변수 값 오버플로우 문제 icon 양재동메이커 03-27 13,818
55 아두이노 아두이노에서 외부 라이브러리 설치하기 (Install library in arduino) icon 양재동메이커 03-27 15,576
54 아두이노 WS2812 color LED 사용하기 icon 양재동메이커 03-27 14,719
53 아두이노 WS2812와 APA102의 차이 비교 (Comparison between WS2812 and APA102) icon 양재동메이커 03-27 17,113