VirtualWire Explained

Is there someone out there who can explain how the Virtual Wire commands work? I have reviewed many posts and EVERY SINGLE ONE OF THEM is the result of not understanding how the character arrays and the unsigned 8 bit integers and coding of information works. I have also reviewed all the YouTube tutorials and found no help there either. At the very least, someone could point out some useful links as I've searched everything in this forum and found NOTHING helpful. If someone is going to invent a library to make things easier, they should at least explain it. For example, what is that uint8_t * about? (Especially the *). And what does &buffer do? Can someone provide examples of sending real data (from sensors) along with limitations on number of bytes? THANK YOU!

I can’t fully explain, but here’s the transmit part of the code in loop I have running in a remote control:

    // go read the keypad
  char key = keypad.getKey();                 // reading the keypad
  if(key)                                     // same as if(key != NO_KEY)- did something change?
  {
    msg[0]=key;                               // load the array with the key character
    // msg[1]=NULL;                           // Rx side seems to work without this

    digitalWrite(ledPin, true);               // Flash a light to show transmitting

    vw_send((uint8_t *)msg, strlen(msg));     // send the character out

//    Serial.println(key);                // for debugging only

    vw_wait_tx();                             // Wait until the whole message is gone

msg[0] can be 27 bytes (37?), that is clearly explained at the virtualwire download site - a function of how much data can be sent, with synchronization bytes and Manchester encoding/decoding at the 16 MHz clock speed.

Here’s my receive code from loop:

// look for wireless input 

uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;

if (vw_get_message(buf, &buflen)) // Non-blocking
{
  int i;
  digitalWrite(ledPin, LOW); // Turn on LED to show working a message

  // Debug statements, no longer needed:
  // Message with a good checksum received, dump it.
  //Serial.println("Got: ");  // Show on PC for debugging

  //    for (i = 0; i < buflen; i++)
  //    {
  //Serial.print(byte(buf[i]));
  //    }
  //Serial.println(""); // spaces it out for the monitor

  switch ( buf[0] ) 
  {    // switch on the first byte in the array for now

// 16 case statements follow, one for each button press on the remote
}

Ok then.

"uint8_t * " means "unsigned 8 bit int ", * means it’s a pointer. In this case it is type casting a char array to an unsigned 8 bit int pointer.

A simple transmitter code, that transmits data from an accelerometer to a receiving Arduino.

#include <VirtualWire.h>

char Array[20]; // create an array large enough to hold the string of data
int X,Y,Z; // Accelerometer variables

void setup()
{
  Serial.begin(9600);	  // Debugging only
  Serial.println("Sending"); // Debugging only

  // Initialise the IO and ISR
  //vw_set_ptt_inverted(true); // Required for DR3100   ** NOT NEEDED UNLESS USING DR3100 MODULE **
  vw_setup(2000);	 // Bits per sec   **Baud Rate** Max is 4000, but you may lose data
  vw_set_tx_pin(33); //RF sending pin 
  
  pinMode(37, OUTPUT);
  pinMode(35, OUTPUT);
  pinMode(53, OUTPUT);
  
  digitalWrite(37, LOW); // RF ground
  digitalWrite(35,HIGH); // RF Vcc
  digitalWrite(53,HIGH); // accelormeter Vcc

  pinMode(13, INPUT); //accel Z
  pinMode(14, INPUT); //accel Y
  pinMode(15, INPUT); //accel X
}

void loop()
{ 
  X = analogRead(15) / 4; // X raw data to 0 - 1023 ** Divided by 4 to give range of 0 - 255**
  Y = analogRead(14) / 4; // Y raw data to 0 - 1023 ------------------------------------------
  Z = analogRead(13) / 4; // Z raw data to 0 - 1023 ------------------------------------------
  
  sprintf(Array, "%d,%d,%d ",X,Y,Z);  // sprintf("storage location array" , "How the data is grouped and stringed together", "the data variables to be stringed and sent")
//Example data: "205,10,46 "

  vw_send((uint8_t*)Array, strlen(Array)); 
  // strlen counts the number of characters in the array, 
  //and sets how many times "vw_send" needs to go through the array to send everything in it.
  vw_wait_tx(); // wait until all data is sent 
}

Now the receiving end.

#include <VirtualWire.h>

void setup()
{
  Serial.begin(9600);	// Debugging only
  Serial.println("Receiving");
  pinMode(13,OUTPUT); // Arduino onboard LED, pin 13
  
  // Initialise the IO and ISR
  //vw_set_ptt_inverted(true); // Required for DR3100
  vw_setup(2000);      // Bits per sec **Must match transmitter baud rate**
  vw_set_rx_pin(8);    // data pin, pin 8 on arduino
  vw_rx_start();       // Start the receiver PLL running
}

void loop()
{
  uint8_t buf[VW_MAX_MESSAGE_LEN];  // The max message length is 30 chars, but after the NULL terminator and two other bytes ( not sure which) the actual max length is 27 char.
  uint8_t buflen = VW_MAX_MESSAGE_LEN;

  if (vw_get_message(buf, &buflen)) // Non-blocking
  {
    //Data received: "205,10,46 "
    digitalWrite(13, HIGH); // Indicate data is being received
    
    int temp1 = atoi(strtok(buf, ",")); // reads the buf array until it finds a comma "," then stores the data before the comma in temp1
    // temp1 = 205   ** Notice no comma, that because strtok reads everything before the comma
    int temp2 = atoi(trtok(NULL,",")); // NULL tells strtok to pick up where it found the last condition IE the comma.
    //temp2 = 10
    int temp3 = atoi(strtok(NULL," "));// Now strtok is looking for a blank space indicated by " ", and like the previous two, it will store the last bit of data in temp3
    // temp3 = 46
    Serial.print(temp1); // X axis
    Serial.print(", ");
    Serial.print(temp2); // Y axis
    Serial.print(", ");
    Serial.print(temp3); // Z axis
    Serial.println();
  }
  else digitalWrite(13, LOW); // No data received
}

Darn, Crossroads beat me to it.

#include <VirtualWire.h>

int CS_ObjTemp;        // variables set in the GetTemperature() function
int CS_AmbTemp;
char buf[30];                 // the buffer to hold the message
byte packetnum = 0;  // a packet number for diagnostic purposes

void setup() { 
  vw_setup(1000);    // set up VirtualWire, 1000 bps
}

void loop() {
  GetTemperature();     // Sets two variables

//  the following line writes the string to be sent. It will look like
//  P10 S -10 A 17
  sprintf(buf,"P%d S %d A %d :\n" ,packetnum, CS_ObjTemp, CS_AmbTemp);
  send(buf);                  // calls the send function with buf (buf is a pointer to the string above)
  packetnum++;          // increment packet number for next packet.
  delay(5000);            // wait 5 seconds... lather, rinse, repeat
}

void send (char *message){  // accepts the char pointer, which is locally called message
    vw_send((uint8_t *)message, strlen(message));  //   sends the message 
    vw_wait_tx();     // waits for the transmission to finish
}

&buffer is the address of buffer. In my case, I didn’t need to use the &, because buf is already the address of the char array I am sending.

HI HazardsMind !

Your example is very ilustrative.

I tried tocompile the receiver code and I got the following compile error :

sketch_nov02c.ino: In function ‘void loop()’:
sketch_nov02c:26: error: invalid conversion from ‘uint8_t*’ to ‘char*’
sketch_nov02c:26: error: initializing argument 1 of ‘char* strtok(char*, const char*)’
sketch_nov02c:26: error: invalid conversion from ‘char*’ to ‘int’
sketch_nov02c:28: error: invalid conversion from ‘char*’ to ‘int’
sketch_nov02c:30: error: invalid conversion from ‘char*’ to ‘int’

line: 26 int temp1 = strtok(buf, “,”); // reads the buf array until it finds a comma “,” then stores the data before the comma in temp1

could you give some help on this ?

int temp1 = strtok( (char*) buf, ",");
Try that.

int temp1 = strtok( (char*) buf, ",");
Try that.

strtok() returns a char *. Storing a pointer to char in an int is a bad idea.

Your right, atoi should be in there too.
int Temp1= atoi(strtok((char*)buf, ","));

Why look in the forums or ytube when you have the playground?

Mark