[아두이노] [강좌] 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
이 글을 페이스북으로 퍼가기 이 글을 트위터로 퍼가기 이 글을 카카오스토리로 퍼가기 이 글을 밴드로 퍼가기

임베디드 보드

번호 제목 글쓴이 날짜 조회수
118 아두이노 ESP32 Analog Inputs (ADC) +4 icon 양재동메이커 02-12 16,137
117 아두이노 TIP : Serial의 Port가 Open 시점 확인 icon 양재동메이커 01-21 12,990
116 아두이노 ESP32 Boot Mode icon 양재동메이커 12-28 12,835
115 아두이노 아두이노 에러 리스트(Arduino Error list) icon 양재동메이커 11-24 17,818
114 아두이노 ESP32 main.cpp +1 icon 양재동메이커 11-19 13,181
113 아두이노 ESP32 EEPROM 와 IR Remote icon 양재동메이커 08-06 13,074
112 아두이노 Learn ESP32 icon 양재동메이커 06-25 12,655
111 라즈베리 파이 라즈베리 파이 (Raspberry Pi) 기초 icon 양재동메이커 06-19 14,150
110 라즈베리 파이 (동영상 강의) 라즈베리 파이 강좌 Link icon 양재동메이커 06-17 13,248
109 STM32 / MBED [MED] Switch debouncing icon HellMaker 12-30 15,226
108 기타 [타이젠] 아두이노의 16x2 LCD Display라이브러리 LiquidCrystal_I2C의 타이젠 포팅 icon 양재동메이커 09-15 14,803
107 기타 [타이젠] GPIO의 디지탈 출력과 입력 인터럽트의 C++ Class 제작 icon 양재동메이커 09-12 14,280
106 마이크로비트 서보 모터 icon HellMaker 09-03 14,098
105 마이크로비트 아날로그 온도센서 (마이크로 비트 센서 활용) icon HellMaker 09-01 14,605
104 마이크로비트 터치센서 (마이크로 비트 센서 활용) icon HellMaker 09-01 13,719
103 마이크로비트 디지털 홀 센서 (마이크로 비트 센서 활용) icon HellMaker 08-29 12,900
102 마이크로비트 리니어 홀 센서 (마이크로 비트 센서 활용) icon HellMaker 08-29 12,455
101 마이크로비트 불꽃 감지 센서 (마이크로 비트 센서 활용) icon HellMaker 08-26 12,794
100 마이크로비트 로터리 엔코더 (마이크로 비트 센서 활용) icon HellMaker 08-25 12,899
99 마이크로비트 2컬러 LED(3mm) (센서 활용) icon HellMaker 08-22 12,901