Taillieu.Info

More Than a Hobby..

VirtualWire

Sending Messages Using Low-Cost Wireless Modules

Problem

You want to transmit data between two Arduino boards using simple, low-cost wireless modules.

Solution

This recipe uses simple transmit and receive modules such as the SparkFun 315 MHz: WRL-10535 and WRL-10533, or the 434 MHz: WRL-10534 and WRL-10532.

Wire the transmitter as shown in Figure 14-1 and the receiver as in Figure 14-2. Some modules have the power line labeled VDD instead of Vcc.

Simple wireless transmitter using VirtualWireFigure 14-1 Simple wireless transmitter using VirtualWireSimple wireless receiver using VirtualWireFigure 14-2 Simple wireless receiver using VirtualWire

The transmit sketch sends a simple text message to the receive sketch, which echoes the text to the Serial Monitor. The transmit and receive sketches use the VirtualWire library written by Mike McCauley to provide the interface to the wireless hardware. The library can be downloaded fromhttp://www.open.com.au/mikem/arduino/VirtualWire-1.5.zip:

/*
  SimpleSend
  This sketch transmits a short text message using the VirtualWire library
  connect the Transmitter data pin to Arduino pin 12
*/

#include <VirtualWire.h>

void setup()
{
    // Initialize the IO and ISR
    vw_setup(2000);           // Bits per sec
}

void loop()
{
    send("hello");
    delay(1000);
}

void send (char *message)
{
  vw_send((uint8_t *)message, strlen(message));
  vw_wait_tx(); // Wait until the whole message is gone
}

The receive sketch also uses the VirtualWire library:

/*
  SimpleReceive
  This sketch  displays text strings received using VirtualWire
  Connect the Receiver data pin to Arduino pin 11
*/
#include <VirtualWire.h>

byte message[VW_MAX_MESSAGE_LEN];    // a buffer to hold the incoming messages
byte msgLength = VW_MAX_MESSAGE_LEN; // the size of the message


void setup()
{
    Serial.begin(9600);
    Serial.println("Ready");

    // Initialize the IO and ISR
    vw_setup(2000);             // Bits per sec
    vw_rx_start();              // Start the receiver
}

void loop()
{
    if (vw_get_message(message, &msgLength)) // Non-blocking
    {
        Serial.print("Got: ");
    for (int i = 0; i < msgLength; i++)
    {
        Serial.write(message[i]);
    }
    Serial.println();
    }
}

Discussion

The VirtualWire library defaults to pin 12 for transmit and pin 11 for receive, but see the documentation link at the end of this recipe if you want to use different pins. Setup initializes the library. The loop code simply calls a send function that calls the library vw_send and waits for the message to be transmitted.

The receive side initializes the library receive logic and then waits in loop for the message.vw_get_message will return true if a message is available, and if so, each character in the message is printed to the Serial Monitor.

The VirtualWire library handles the assembly of multiple bytes into packets, so sending binary data consists of passing the address of the data and the number of bytes to send.

The sending sketch that follows is similar to the transmit sketch in this recipe’s Solution, but it fills the message buffer with binary values from reading the analog input ports using analogRead. The size of the buffer is the number of integers to be sent multiplied by the number of bytes in an integer (the six analog integer values take 12 bytes because each int is two bytes):

/*
  SendBinary
  Sends digital and analog pin values as binary data using VirtualWire library
  See SendBinary in Chapter 4
*/

#include <VirtualWire.h>

const int numberOfAnalogPins = 6; // how many analog pins to read

int data[numberOfAnalogPins];  // the data buffer

const int dataBytes = numberOfAnalogPins * sizeof(int); // the number of bytes
                                                        // in the data buffer

void setup()
{
    // Initialize the IO and ISR
    vw_setup(2000);           // Bits per sec
}

void loop()
{
  int values = 0;
  for(int i=0; i <= numberOfAnalogPins; i++)
  {
    // read the analog ports
    data[i] = analogRead(i); // store the values into the data buffer
  }
  send((byte*)data, dataBytes);
  delay(1000); //send every second
}


void send (byte *data, int nbrOfBytes)
{
  vw_send(data, nbrOfBytes);
  vw_wait_tx(); // Wait until the whole message is gone
}

Note

The sizeof operator is used to determine the number of bytes in an int.

The receive side waits for messages, checks that they are the expected length, and converts the buffer back into the six integer values for display on the Serial Monitor:

/*
 SendBinary
 Sends digital and analog pin values as binary data using VirtualWire library
 See SendBinary in Chapter 4
 */

#include <VirtualWire.h>

const int numberOfAnalogPins = 6; // how many analog integer values to receive
int data[numberOfAnalogPins];  // the data buffer

// the number of bytes in the data buffer
const int dataBytes = numberOfAnalogPins * sizeof(int); 

byte msgLength = dataBytes;


void setup()
{
  Serial.begin(9600);
  Serial.println("Ready");

  // Initialize the IO and ISR
  vw_set_ptt_inverted(true); // Required for DR3100
  vw_setup(2000);            // Bits per sec

  vw_rx_start();              // Start the receiver
}

void loop()
{
  if (vw_get_message((byte*)data, &msgLength)) // Non-blocking
  {
    Serial.println("Got: ");
    if(msgLength == dataBytes)
    {
      for (int i = 0; i <  numberOfAnalogPins; i++)
      {
        Serial.print("pin ");
        Serial.print(i);
        Serial.print("=");
        Serial.println(data[i]);
      }
    }
    else
    {
       Serial.print("unexpected msg length of ");
       Serial.println(msgLength);
    }
    Serial.println();
  }
}

The Serial Monitor will display the analog values on the sending Arduino:

Got:
pin 0=1023
pin 1=100
pin 2=227
pin 3=303
pin 4=331
pin 5=358

Bear in mind that the maximum buffer size for VirtualWire is 30 bytes long (the constantVW_MAX_MESSAGE_LEN is defined in the library header file).

Wireless range can be up to 100 meters or so depending on supply voltage and antenna and is reduced if there are obstacles between the transmitter and the receiver.

Also note that the messages are not guaranteed to be delivered, and if you get out of range or there is excessive radio interference some messages could get lost. If you need a guaranteed wireless delivery mechanism, the ZigBee API used in recipes that follow is a better choice, but these inexpensive modules work well for tasks such as displaying the status of Arduino sensors—each message contains the current sensor value to display and any lost messages get replaced by messages that follow.

See Also