고급 예제

다양한 도구들을 가지고 마음껏 응용해보세요.

433MHZ RF 라디오 송수신기-아두이노 통신하기

2014-09-29 11:51:59

개요

433MHZ RF 라디오 송수신기 모듈은 일반적으로 무선 원격 제어에 사용됩니다.
두 아두이노를 연결하는 등 무선통신용으로 사용할 경우 xbee 보다 사용이 쉽고 쉴드가 따로 필요하지 않기 때문에 간편합니다.
송수신 거리도 최대 500m까지 가능하다고 하네요.
다양한 라이브러리까지 많이 있어 스케치 작성도 용이합니다.
 

  • 송신기
  • 수신기



출처 : www.ebay.com / electronics.stackexchange.com

원격 제어기, 차량용및 가정용 경보기, 자동도어, 브레이크 경보 시스템등 응용이 가능하겠죠?
예를 들어 키패드를 연결해서 번호가 맞으면 송신기로 신호를 보내 수신기와 연결된 문이 열리게 할 수도 있습니다.

출처 : www.onemillionvideos.de


본문에서는 두 개의 보드를 433MHZ RF 라디오 송수신기 모듈을 이용해 통신해보겠습니다.
송신기 쪽에서 버튼으로 수신기 쪽 LED의 ON/OFF를 조절하도록 하겠습니다. 
 

미리보기 동영상

 

 

부품목록

 

 

 

NO 부품명 수량 상세설명
1 아두이노 우노 2 두 개의 보드 사이 통신이므로 보드가 두개 필요합니다.
2 브레드 보드 2 브레드 보드는 하나로 사용하실 수도 있습니다.
3 433MHZ RF 라디오 송신기 1 FS1000A 모듈을 사용했습니다.
4 433MHZ RF 라디오 수신기 1 xy-mk-5v 모듈을 사용했습니다.
5 LED 1  
6 330 ohm 저항 1  
7 점퍼 케이블 10  
8 푸시 버튼 1  
9 10K ohm 저항 1  

 

부품명 아두이노 우노  브레드 보드 LED 330 ohm 저항 점퍼 케이블
사진 X2 X2 X2 X2 X2

 

 

부품명 433MHZ RF 라디오 송신기 433MHZ RF 라디오 수신기 10K ohm 저항 푸시 버튼
사진 x1 x1

 

하드웨어 Making

회로도

 

  • 송신기

 

 

 

  • 수신기

 

 

 

 

브레드 보드 레이아웃

 

  • 송신기

 

 

 

  • 수신기
 

소프트웨어 Coding

아래의 스케치를 아두이노에 업로드 하세요.
 

  • 송신기 스케치
/* 
 송신기 쪽 스케치
 본 스케치는 여러 커뮤니티를 참고하여 kocoafab에서 작성했습니다.
 누구나 무료로 사용하실 수 있습니다.      
*/

#include <VirtualWire.h>       //본 스케치는 VirtualWire 라이브러리를 사용합니다.
#include <Bounce2.h>             //바운싱 현상을 방지하기 위해 이 라이브러리를 사용합니다.
 
 int buttonPin = 2;            //버튼과 연결된 2번 핀

 boolean oneTimeFlag = false;        
 
 Bounce bouncer = Bounce();    
 
  void setup() {
    pinMode(buttonPin, INPUT);
    digitalWrite(buttonPin, HIGH);
    bouncer.attach( buttonPin );
    bouncer.interval(5);
    
    vw_setup(2000);             //라이브러리 사용하기 위한 세팅 및 초기화
    vw_set_tx_pin(4);           //송신 핀 설정
    Serial.begin(9600);
  }
 
  void loop() {
   if ( bouncer.update() && bouncer.read() == LOW) {      //버튼이 눌리면
      if( oneTimeFlag == false) {                         //꺼진 상태라면
        Serial.println("on");
        sendMessage("1", "1");                            //명령 1 전송(on)
        oneTimeFlag = true;

      } else {                                            //켜저 있는 상태였다면
        Serial.println("off");                 
        sendMessage("1", "2");                            //명령 2전송(off)
        oneTimeFlag = false;

      }         
   }
 }
 
 //메세지 송신 함수
  void sendMessage(char* pinCode, char *data) {
     if (strlen(data) > 0) {           //data(command)가 있다면

      int msgSize = (strlen(data) + strlen(pinCode) + 1);  //송신 메세지의 전체 길이를 구하고
      char packetData[msgSize];                            //구한 길이를 바탕으로 메세지 저장할 문자배열변수 선언
      strcat(packetData, pinCode);                         //문자열 합치는 함수를 이용해 전송할 메세지 만듬
      strcat(packetData, ".");
      strcat(packetData, data);
 
      vw_send((uint8_t *)packetData, msgSize);             //메세지 전송
      vw_wait_tx();                                        //메세지 전송 완료시 까지 기다림

    }  
  }

 

  • 수신기 스케치

 

 

/* 
 수신기 쪽 스케치
 본 스케치는 여러 커뮤니티를 참고하여 kocoafab에서 작성했습니다.
 누구나 무료로 사용하실 수 있습니다.        
*/
 #include <VirtualWire.h>
 #include <string.h>
 
  byte message[VW_MAX_MESSAGE_LEN];          //받은 메세지 저장할 임시변수 선언           
  byte messageLength = VW_MAX_MESSAGE_LEN; 
 
 int ledPin = 10;
 
  void setup() {
    vw_setup(2000);
    vw_set_rx_pin(2);            //수신 핀 설정
    vw_rx_start();               //수신 시작
    pinMode(ledPin, OUTPUT);
  }
 
  void loop() {
    if (vw_get_message(message, &messageLength)) {       //메세지 읽어옴
       int command = processResponse((char*)message, 1); //메세지에서 command만 분리
       if (command) {
         switch (command) {
          case 1:                         //명령어가 1이면
            digitalWrite(ledPin, HIGH);   //LED ON
            break;
          case 2:                         //명령어가 2이면
            digitalWrite(ledPin, LOW);    //LED OFF
            break;
        }
       }  
    }
  }
 
 //메세지에서 command만 분리하는 함수
  int processResponse(char* message, int pinCode) {
      char *p = message;
      char *buf;
      int o = 0;
      int pin;
      int command;
 
      while ((buf = strtok_r(p, ".", &p)) != NULL)  {  //메세지 분리 후 buf에 저장
         if (o == 0) {                                 //o가 0이면
           pin = atoi(buf);                            //핀 코드 부분 정수로 변환
         } else {
           command = atoi(buf);                        //명령어 정수로 변환
         }
         o++;
      }
 
      if (pinCode == pin && command > 0) {             //명령어만 반환      
          return command;
      } else {
         return 0; 
      }
  }

 

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

1. 하드웨어 설명


보드는 두 개가 필요하지만 브레드 보드의 경우 하나를 반반 나눠서 사용하셔도 됩니다.
일정 거리 사이의 두 개의 보드를 통신 하는 경우 아닐 경우 하나의 보드를 사용하실 수 도 있습니다.

 

2. 소프트웨어 설명

 

#include <VirtualWire.h>       //본 스케치는 VirtualWire 라이브러리를 사용합니다.
#include <Bounce2.h>             //바운싱 현상을 방지하기 위해 이 라이브러리를 사용합니다.

본 스케치는 송신기 쪽 보드에 연결된 푸시 버튼을 누를  때마다 수신기 쪽 보드에 연결된 LED를 ON/OFF 시킬 수 있습니다.
VirtualWire을 사용하고 있습니다. 다음 링크를 클릭하시면 다운로드 하실 수 있습니다.
Bounce2라이브러리는 다음 링크를 클릭하시면 다운로드 하실 수 있습니다.
기존의 Bounce라이브러리가 있으시다면 지우시고 2를 다시 설치해주세요.
외부라이브러리 사용법을 모르시는 분들은 다음 링크를 참고하세요.
 


 
  Bounce bouncer = Bounce();    
 
  void setup() {
    pinMode(buttonPin, INPUT);
    digitalWrite(buttonPin, HIGH);
    bouncer.attach( buttonPin );
    bouncer.interval(5);

 


bounce2라이브러리를 왜 사용해야 하는 지 설명하겠습니다.
사실 버튼을 누른다고 했을 경우 한 번 눌렀지만 실제 버튼 내부에서는 접촉이 여러번 발생하게 됩니다.
특히 본문 처럼 버튼을 누를 때마다 상태를 변경하려고 할 때 접촉된 횟수의 홀짝의 여부에 따라
버튼이 의도와 반대로 동작하는 경우가 있습니다. 이런 현상을 바운싱이라고 합니다.

그럼 안정적으로 버튼이 동작하게 하려면 디바운싱을 해줘야 합니다.
다행히도 이런 디바운싱을 해주는 라이브러리가 바로 bounce2라이브러리 입니다.

먼저 INPUT으로 사용할 버튼을 설정하고 내부 풀업저항을 올려준뒤
위와 같이 bounce객체의 attach, interval함수를 사용합니다.
디바운싱 시간을 5밀리초로 설정한다는 뜻입니다.

 

 

vw_setup(2000);             //라이브러리 사용하기 위한 세팅 및 초기화
vw_set_tx_pin(4);


VirtualWire을 이용하여 송신기를 사용하실 경우 setup함수에서 위와 같은 함수를 사용하셔야합니다.
Serial.begin과 같이 vw_setup을 통해 초기화를 합니다.
pinMode함수 대신 vw_set_tx_up을 사용하여 송신 핀을 설정합니다.

 

 

 

 

 void loop() {
   if ( bouncer.update() && bouncer.read() == LOW) {      //버튼이 눌리면
      if( oneTimeFlag == false) {                         //꺼진 상태라면
        Serial.println("on");
        sendMessage("1", "1");                            //명령 1 전송(on)
        oneTimeFlag = true;

      } else {                                            //켜저 있는 상태였다면
        Serial.println("off");                 
        sendMessage("1", "2");                            //명령 2전송(off)
        oneTimeFlag = false;

      }         
   }
 }

 

 


이제부터는 직접 디지털 값을 읽어서 버튼의 상태를 알아내지 않습니다.
bouncer 객체를 사용하여 키에서 어떤 일이 일어나는 지를 확인합니다.
update함수는 bouncer 객체에 변화가 있으면 1을 리턴 합니다.
즉 변화가 있고 LOW상태이면 버튼이 눌린 것입니다.
 

그 다음 변수를 하나 더 사용하여 버튼 누르기 전 상태를 구분합니다.
false 였을 경우 켜짐 메세지를 전송하고
true 였을 경우 off인 2번 메세지를 전송합니다.
 

//메세지 송신 함수
  void sendMessage(char* pinCode, char *data) {
     if (strlen(data) > 0) {           //data(command)가 있다면

      int msgSize = (strlen(data) + strlen(pinCode) + 1);  //송신 메세지의 전체 길이를 구하고
      char packetData[msgSize];                            //구한 길이를 바탕으로 메세지 저장할 문자배열변수 선언
      strcat(packetData, pinCode);                         //문자열 합치는 함수를 이용해 전송할 메세지 만듬
      strcat(packetData, ".");
      strcat(packetData, data);
 
      vw_send((uint8_t *)packetData, msgSize);             //메세지 전송
      vw_wait_tx();                                        //메세지 전송 완료시 까지 기다림

    }  
  }


pinCode는 수신쪽에서 메세지를 정확하게 받았는 지 확인하기 위한 변수 입니다. 
원하는 숫자를 넣으시면 됩니다.
strlen함수는 문자열의 길이를 확인하는 함수입니다. 
즉 strlen(data) > 0이면 data가 있다는 뜻이 됩니다.

strcat은 두 문자열을 병합해주는 함수입니다. 
최종적으로 vw_send(메세지, 길이)를 통해 메세지를 전송합니다.
다음으로 vw_wait_tx()를 사용하여 전송 완료시 까지 기다립니다.

 

 

vw_setup(2000);
vw_set_rx_pin(2);            //수신 핀 설정
vw_rx_start();               //수신 시작


수신 스케치 또한 라이브러리 사용을 위해서 위와 같이 세팅을 해야 합니다.
tx가 아닌 rx입니다.

 

 

 

 

if (vw_get_message(message, &messageLength)) {       //메세지 읽어옴


vw_get_message(메세지, 길이)를 통해 쉽게 메세지를 읽어 올 수 있습니다.

 

 

 

 

//메세지에서 command만 분리하는 함수
  int processResponse(char* message, int pinCode) {
      char *p = message;
      char *buf;
      int o = 0;
      int pin;
      int command;
 
      while ((buf = strtok_r(p, ".", &p)) != NULL)  {  //메세지 분리 후 buf에 저장
         if (o == 0) {                                 //o가 0이면
           pin = atoi(buf);                            //핀 코드 부분 정수로 변환
         } else {
           command = atoi(buf);                        //명령어 정수로 변환
         }
         o++;
      }
 
      if (pinCode == pin && command > 0) {             //명령어만 반환      
          return command;
      } else {
         return 0; 
      }
  }


읽어온 메세지는 int형태가 아니고 pinCode . command가 하나로 되어있습니다.
저희는 command를 따로 분류한 후 정수로 변환하고 pinCode를 통해 메세지가 정확히 왔는 지 확인해야 합니다.
strtok_r은 주어진 토큰(.)을 기준으로 값을 분리해줍니다.
atoi는 문자를 정수로 변환 해줍니다.

 

 

 

 

if (command) {
         switch (command) {
          case 1:                         //명령어가 1이면
            digitalWrite(ledPin, HIGH);   //LED ON
            break;
          case 2:                         //명령어가 2이면
            digitalWrite(ledPin, LOW);    //LED OFF
            break;
        }
  }  


사실 수신 스케치에서 여러분이 가장 많이 수정하게 될 부분은 이 부분입니다.
넘겨온 명령어를 확인한 후 각 명령어 마다 원하는 작동을 할 수 있도록 작성하시면 됩니다.
본문에서는 1번을 넘겨 받은 경우 LED를 ON하고 2번을 넘겨 받은 경우 LED를 OFF 합니다.

 

 

 

 

kocoafabeditor

항상 진취적이고, 새로운 것을 추구하는 코코아팹 에디터입니다!

433MHZ RF 라디오 송수신기, 아두이노