[Solved... sort of] How to send one simple number with VirtualWire?

Yep, that is it - wondering how to send wirelessly a number from one arduino to another... Nothing fancy, not a negative, not a fraction, just a number between 1 and 99 and receive a number on the other end, preferably as an integer...

There is an example sketch with 4 buttons on transmitter side and 4 LEDs on receiver, and it work just fine. It is so reliable in fact that after two nights of trying to send an integer I feel like assigning letter codes to numbers on transmitter side and making 99 switch / case statements for receiver :slight_smile:

There must be a better way?..

The code below is a 4 buttons/LEDs example, posting my attempts to produce something similar for integers would be a waste of space:

Transmitter:

//
// example 13.2tx - http://tronixstuff.com/tutorials > Chapter 13
// 
// basic tx sketch - based on code by Mike McCauley 2010 http://www.open.com.au/mikem/arduino
//
// don't forget the 10k resistor between digital pin 0 and GND for independent operation

// Need these lines below ///////////////////
#include <VirtualWire.h> 
#undef int
#undef abs
#undef double
#undef float
#undef round
////////////////////////////////////////////

void setup()
{
  // Initialise the IO and ISR
  vw_set_ptt_inverted(true);      // Required for RF Link module
  vw_setup(2400);                 // Bits per sec
  vw_set_tx_pin(1);               // pin 1 is the TX pin on our Arduino Duemilanove
  pinMode(8, INPUT);      // for each of the four buttons 
  pinMode(9, INPUT);
  pinMode(10, INPUT);
  pinMode(11, INPUT);
  delay(2000); // give the radio module time to get going
}

const char *l1 = "a"; // a~h will represent the states of the four buttons, 1~4 high or low
const char *h1 = "b"; // the less data to send wirelessly the better
const char *l2 = "c"; 
const char *h2 = "d";      
const char *l3 = "e";      
const char *h3 = "f";      
const char *l4 = "g";
const char *h4 = "h";

void loop()
{
  if (digitalRead(8)==LOW)
  {
    vw_send((uint8_t *)l1, strlen(l1));   // send the data out to the world
    vw_wait_tx();     // Wait for sending of message to finish.  
    delay(20);
  } 
  else if (digitalRead(8)==HIGH)
  {
    vw_send((uint8_t *)h1, strlen(h1));   // send the data out to the world
    vw_wait_tx();                           // Wait for sending of message to finish.  
  }
  delay(20);
  if (digitalRead(9)==LOW)
  {
    vw_send((uint8_t *)l2, strlen(l2));   // send the data out to the world
    vw_wait_tx();                           // Wait for sending of message to finish.  
    delay(20);
  } 
  else if (digitalRead(9)==HIGH)
  {
    vw_send((uint8_t *)h2, strlen(h2));   // send the data out to the world
    vw_wait_tx();                           // Wait for sending of message to finish.  
  }
  delay(20);
  if (digitalRead(10)==LOW)
  {
    vw_send((uint8_t *)l3, strlen(l3));   // send the data out to the world
    vw_wait_tx();                           // Wait for sending of message to finish.  
    delay(20);
  } 
  else if (digitalRead(10)==HIGH)
  {
    vw_send((uint8_t *)h3, strlen(h3));   // send the data out to the world
    vw_wait_tx();                           // Wait for sending of message to finish.  
  }
  delay(20);
  if (digitalRead(11)==LOW)
  {
    vw_send((uint8_t *)l4, strlen(l4));   // send the data out to the world
    vw_wait_tx();                           // Wait for sending of message to finish. 
    delay(20); 
  } 
  else if (digitalRead(11)==HIGH)
  {
    vw_send((uint8_t *)h4, strlen(h4));   // send the data out to the world
    vw_wait_tx();                           // Wait for sending of message to finish.  
    delay(20);
  }
}

And the receiver:

//
// exercise 13.2rx - http://tronixstuff.com/tutorials > Chapter 13
// 
// receive and decode data from tx unit, display in serial monitor
//
//  based on code by Mike McCauley 2010 http://www.open.com.au/mikem/arduino
//

// Need these lines below ///////////////////
#include <VirtualWire.h>  
#undef int
#undef abs
#undef double
#undef float
#undef round
uint8_t buf[VW_MAX_MESSAGE_LEN]; // this is an array of unsigned integers 8-bits long. In other words, bytes between 0 and 65535
uint8_t buflen = VW_MAX_MESSAGE_LEN;

////////////////////////////////////////////
void setup()
{
  // wake up the wireless receiver

  vw_set_ptt_inverted(true);    // need this line
  vw_setup(2400);               // sets speed of data reception. 
  vw_set_rx_pin(0);             // this is the RX pin number - 0 on a Duemilanove
  vw_rx_start();                // start the receiver!
  Serial.begin(9600);

}


void loop()
{
  // check to see if there is received data in the buffer, and that it came through correctly.
  // if the message didn't come through completely, it will be ignored
  if (vw_get_message(buf, &buflen)) 
  {

    switch(buf[0])
    {
    case 'a':
      Serial.println("Button 1 low");
      break;
    case 'b': 
      Serial.println("Button 1 high");
      break;
    case 'c': 
      Serial.println("Button 2 low");
      break;
    case 'd': 
      Serial.println("Button 2 high");
      break;
    case 'e':
      Serial.println("Button 3 low");
      break;
    case 'f': 
      Serial.println("Button 3 high");
      break;
    case 'g':
      Serial.println("Button 4 low");
      break;
    case 'h':
      Serial.println("Button 4 high");
    }
  }
}

You should post one of your tries so maybe we can find where your misunderstanding is. To sent numbers from 1 to 99 put them in a byte variable and send them exactly like in the example you posted. For int variables (16 bit) you gotta break them into 2 bytes. But if you only want 0 - 99 you can fit that in an 8bit byte.

There's nothing special about the fact that this example sends characters. After all, to the CPU those characters are just numbers.

You do need to make sure when you send the number that you are sending the number and not the ascii representation of that number. Here's why it would be good to post your code, one could see if that was indeed your problem.

Thank you, Delta_G for fast reply!

On the transmitter side characters are created as pointers to chars, which then get converted to pointers to integers: uint8_t vw_send(uint8_t*, uint8_t)...

On receiver side things are short and to the point, but on transmitter side there is a bit of a mess - I've modified Hennig Karlsens drawing example for a TFT LCD - added a slider on the screen that generate numbers 1 to 99... Should I post the whole thing (260 lines) or only part that is to do with sending the message?

Anyway, here goes nothing - receiver code:

#include <VirtualWire.h>  
#include <LiquidCrystal.h>

LiquidCrystal lcd(19, 18, 17, 16, 15, 10);

int red = 13;
int pValue;
char Position [2];
int i;

////////////////////////////////////////////
void setup()
{
  pinMode(red, OUTPUT);   

  // wake up the wireless receiver
  vw_set_ptt_inverted(true);    
  vw_setup(1000);                     // sets speed of data reception. 
  vw_set_rx_pin(0);                   // this is the RX pin number - 0 on a Duemilanove
  vw_rx_start();                      // start the receiver!

  lcd.begin(20, 4);                   // Test LCD - connected one for debugging
  lcd.setCursor(0, 0);
  lcd.print("hello, world 1!");
  lcd.setCursor(0, 1);
  lcd.print("hello, world 2!");
  lcd.setCursor(0, 2);
  lcd.print("hello, world 3!");
  lcd.setCursor(0, 3);
  lcd.print("hello, world 4!");

  digitalWrite(red, HIGH);             //Debugging LED, no longer used in the code below but still connected
  delay(500);
  digitalWrite(red, LOW);
  lcd.clear();
}

void loop()
{
  //  lcd.setCursor(0, 0);
  uint8_t buf[VW_MAX_MESSAGE_LEN];
  uint8_t buflen = VW_MAX_MESSAGE_LEN;


// Here I've tried to get insight here what is it I'm actually receiving
  if (vw_get_message(buf, &buflen))           
  {

    lcd.clear();

    int sizeOfPosition = sizeof(tValue);

    lcd.setCursor(0, 2);
    lcd.print(sizeOfPosition);

    int sizeOfBuf = sizeof(buf);

    lcd.setCursor(3, 2);
    lcd.print(sizeOfBuf);

    lcd.setCursor(7, 2);
    lcd.print(buf[0]);

    lcd.setCursor(10, 2);
    lcd.print(buf[1]);

    lcd.setCursor(13, 2);
    lcd.print(buf[2]);

    lcd.setCursor(17, 2);
    lcd.print(buflen);
    
  //  int i;
    
    for ( i = 0; i <= buflen; i ++)
    {
    Position[i] = buf[i];
    }
    tValue = atoi (Position);
    
    
        lcd.setCursor(0, 3);
    lcd.print(tValue, DEC);
    
  }

I see you're calling atoi on what you received. Can you show the transmitter code too? Is it transmitting the number in ascii or just the number?

Yes, its just a number from an integer - not an ascii character.

#include <UTFT.h>
#include <UTouch.h>
#include <VirtualWire.h> 

extern uint8_t BigFont[];

//const char *redoff = "a";    
//const char *redon = "b";
int sliderPosition = 0;
char hLevel [4];
//char hLevel;

UTFT myGLCD(SSD1289,15,14,13,12);
UTouch      myTouch(11,10,2,1,0);

int color = 0;
word colorlist[] = {
  VGA_WHITE, VGA_BLACK, VGA_RED, VGA_BLUE, VGA_GREEN, VGA_FUCHSIA, VGA_YELLOW, VGA_AQUA};
int  bsize = 4;

void drawColorMarkerAndBrushSize(int col)
{
  myGLCD.setColor(VGA_BLACK);
  myGLCD.fillRect(25, 0, 31, 239);
  myGLCD.fillRect(320-31, 184, 320-1, 206);   //color indication circle background refresh
  myGLCD.setColor(VGA_WHITE);
  myGLCD.drawPixel(25, (col*30)+15);
  for (int i=1; i<7; i++)
    myGLCD.drawLine(25+i, ((col*30)+15)-i, 25+i, ((col*30)+15)+i);

  if (color==1)
    myGLCD.setColor(VGA_WHITE);
  else
    myGLCD.setColor(colorlist[col]);
  if (bsize==1)
    myGLCD.drawPixel(320-15, 192);
  else
    myGLCD.fillCircle(320-15, 192, bsize);

  myGLCD.setColor(colorlist[col]);
}

void whiteRect ()
{
  myGLCD.fillRect(288,96,320-1,142);
  myGLCD.print("H", 320-24, 109);
}

void slider ()
{
  myGLCD.drawLine(256,0,256,240-1);
  myGLCD.setColor(VGA_BLACK);
  myGLCD.fillRect(257,0,287,240-1);

  myGLCD.setColor(VGA_FUCHSIA);
  myGLCD.fillRect(270,20,274,220);
  myGLCD.setColor(colorlist[color]);
}
void sliderBar ()
{
  myGLCD.fillRect(266,sliderPosition,278,5+sliderPosition);
}
void sliderBarStatic ()
{
  myGLCD.fillRect(266,20,278,25);
}

void setup()
{
  myGLCD.InitLCD();
  myGLCD.clrScr();
  myGLCD.setFont(BigFont);

  myTouch.InitTouch();
  myTouch.setPrecision(PREC_HI);

  myGLCD.setColor(VGA_WHITE);
  myGLCD.drawLine(32,0,32,240-1);
  myGLCD.drawLine(288,0,288,240-1); //right vertical line
  myGLCD.print("C", 320-24, 8);
  myGLCD.print("L", 320-24, 24);
  myGLCD.print("E", 320-24, 40);
  myGLCD.print("A", 320-24, 56);
  myGLCD.print("R", 320-24, 72);
  myGLCD.print("+", 320-24, 151);
  myGLCD.print("-", 320-24, 215);
  //x = 320,   y = 240;
  whiteRect();
  slider();
  sliderBarStatic();

  myGLCD.drawLine(320-32,175,320-1,175);
  myGLCD.drawLine(320-32,207,320-1,207);
  myGLCD.drawLine(320-32,239,320-1,239);
  for (int i=0; i<8; i++)
  {
    myGLCD.setColor(colorlist[i]);
    myGLCD.fillRect(0, (i*30), 24, (((i+1)*30)-1));
  }
  drawColorMarkerAndBrushSize(color);

  // Initialise the IO and ISR

  /*
  int XSize = 240;
   char buf [4];
   sprintf (buf, "%03i", XSize);
   myGLCD.print(buf, 90, 10);*/
}

void loop()
{

  myGLCD.printNumI(millis()/1000/60, 35, 2);

  long x, y;

  while (myTouch.dataAvailable() == true)
  {
    myTouch.read();
    x = myTouch.getX();
    y = myTouch.getY();
    //       myGLCD.printNumI(x, 70, 30);
    //       myGLCD.printNumI(y, 120, 30);

    if ((x!=-1) and (y!=-1))
    {
      if (x>(31+bsize) and (x<320-(65+bsize)))  //main brush
      {
        if (bsize==1)
          myGLCD.drawPixel(x, y);
        else
          myGLCD.fillCircle(x, y, bsize);
      }
      else
      {
        if ((x>256) and (x<288) and (y>19) and (y<220)) //slider
        {
          sliderPosition = myTouch.getY();
          myGLCD.printNumI(sliderPosition, 35, 30);
          slider();
          sliderBar();
          
          sliderPosition = sliderPosition/2;

          sprintf (hLevel, "%i", sliderPosition);
       //      hLevel = chartostring(sliderPosition);
          myGLCD.print(hLevel, 35, 50);

        }

        if (x<(30+bsize))    //set color
        {
          if (y<240)
          {
            color = y / 30;
            drawColorMarkerAndBrushSize(color);
            while (myTouch.dataAvailable()) {
            };
            delay(50);
          }
        }
        else
        {
          if ((y<96) and (x>288))    //clear
          {
            myGLCD.setColor(VGA_BLACK);
            myGLCD.fillRect(33, 0, 320-65, 240-1);
            myGLCD.setColor(colorlist[color]);
          }
          if ((y>143) and (y<175) and (x>288))   // increase brush size
          {
            if (bsize<7)
            {
              bsize++;
              drawColorMarkerAndBrushSize(color);
              while (myTouch.dataAvailable()) {
              };
              delay(50);
            }
          }
          if ((y>175) and (y<207) and (x>288))
          {
            bsize=4;
            drawColorMarkerAndBrushSize(color);
            while (myTouch.dataAvailable()) {
            };
            delay(50);
          }
          if ((y>207) and (y<239) and (x>288))
          {
            if (bsize>1)
            {
              bsize--;
              drawColorMarkerAndBrushSize(color);
              while (myTouch.dataAvailable()) {
              };
              delay(50);
            }
          }
          if ((y>96) and (y<142) and (x>288))  // slider position sent
          {
            myGLCD.setColor(VGA_RED);

            while (myTouch.dataAvailable()) {

              vw_set_ptt_inverted(true);      
              vw_setup(1000);                 // Bits per sec
              vw_set_tx_pin(9);   

              delay (10);
              
              int Position=3;                            //integer sent by VirtualWire
              vw_send((uint8_t *)Position, sizeof(Position));
              vw_wait_tx();
              delay (100);
              
              whiteRect();
            }

            delay (100);

            myGLCD.setColor(VGA_WHITE);
            whiteRect();
            myGLCD.setColor(colorlist[color]);
            myTouch.InitTouch();

 
          }
        }
      }
    }
  }
}

Part of the code with number (number three in this attempt) that is being send:

int Position=3;
vw_send((uint8_t *)Position, sizeof(Position));
vw_wait_tx();
delay (100);

So its just an integer, nothing fancy.. I my late attempts I've typed it myself and then uploaded the code to uC.

On debugging screen on "the other side" (receiver side) number three came out as:

int sizeOfPosition = sizeof(tValue); => 2
int sizeOfBuf = sizeof(buf); => 80
lcd.print(buf[0]); => 1
lcd.print(buf[1]); => 54
lcd.print(buf[2]); => 0
lcd.print(buflen); => 2
tValue = atoi (Position); => 0

These numbers does not seem to correspond to anything.

Hence at this point I'm inclined to start over from scratch. This is why I'm asking a general question of how to transfer a number, rather how to get this code to work :slight_smile:

Removed from transmitters code everything but the RF guts:

#include <VirtualWire.h> 
void setup()
{
}

void loop(){

  delay (10000);

  vw_set_ptt_inverted(true);      
  vw_setup(1000);                 // Bits per sec
  vw_set_tx_pin(9);   

  delay (10);

  int Position=1;
  vw_send((uint8_t *)Position, sizeof(Position));
  vw_wait_tx();
  delay (100);

  vw_send((uint8_t *)Position, sizeof(Position));
  vw_wait_tx();
  delay (100);

  vw_send((uint8_t *)Position, sizeof(Position));
  vw_wait_tx();
  delay (100);

  vw_send((uint8_t *)Position, sizeof(Position));
  vw_wait_tx();
  delay (100);

  vw_send((uint8_t *)Position, sizeof(Position));
  vw_wait_tx();
  delay (100);
}

With Position value of 3 numbers on debugging screen remained the same.

Changed the Position value to 2, got same result "on the other side" - slightly different numbers, equally meaningless.
Similar result with other digits.

  int Position=1;
  vw_send((uint8_t *)Position, sizeof(Position));

Do you really need an int to hold the value 1? Wouldn't a uint8_t (a byte) be big enough?

On the receiver, the size of buf is pretty useless. It is the number of elements in the array, which is a constant. Printing that value is pretty much pointless.

I don't see where tValue is declared, but printing the size of a variable seems pointless.

The value in buflen is the only thing you are printing that is important. It prints as 2 because you sent two bytes, because an int is two bytes.

The values in buf[0] and buf[1] are important, too. But, now you need to take those two bytes and make an int out of them

Far simpler, of course, is to send the byte sized value as a byte, and receive it as a byte.

If that isn't an option, then send the int as an int, and receive it as an int:

int valToSend = 3;
  vw_send((uint8_t *)valToSend, sizeof(valToSend));

and

  int valGotten;
  uint8_t buflen = 2;;

  if (vw_get_message((uint8_t *)&valGotten, &buflen))           
  {

Thank you Paul for taking time to respond!

Do you really need an int to hold the value 1? Wouldn't a uint8_t (a byte) be big enough?

You are absolutely right! For values from 1 to 99 a uint8_t will be better, than an uint16_t.

tValue was just something to hold values from buf, and then convert them in to an integer with atoi...
I've printed sizes of variables in an attempt to see what is coming in... Made no difference, you right, printing them was pointless.

Have tried several data types, but have not managed to get it right. Either not using pointers right, or hardware is damaged. Checked output of radio module with oscilloscope, something is coming through. That however does not rule out damaged hardware version.

Eventually gave up on these wireless modules and VirtualWire.

Success came with nRF24L01+ modules and library by ManiacBug.
Here are codes for transmitter and receiver for sending numbers 0 to 255. This range allow not only for temperature to be sent but even for setting position of a servo.

Transmitter:

#include <SPI.h>
#include "RF24.h"
int msg[1];
RF24 radio(1,3); 

const uint64_t pipe = 0xE8E8F0F0E1LL;


int potpin = 0;
int val;

void setup(){
  radio.begin();
  radio.openWritingPipe(pipe);
}

void loop (){
  val = x;  // x is any number from 0 to 255
  msg[0]=val;
  radio.write(msg,1);
  // delay(20);
}

Receiver:

#include <SPI.h>
#include "RF24.h"
#include "printf.h"

RF24 radio(8,3); 

int msg[1];
const uint64_t pipe = 0xE8E8F0F0E1LL;
int potVal;  // value sent to DAC
word outputValue = 0;  // a word is a 16-bit number
byte data = 0;         // a byte is an 8-bit number

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

  radio.begin();
  radio.openReadingPipe(1, pipe);
  radio.startListening();
  printf_begin();
  
  // Good way to check if wireless module is functional
  // Requires print.h file and #include "printf.h" statement
  //This is a debugging feature only, does not required
  //for transmission
  radio.printDetails();     
  
}

void loop(){

  if (radio.available()){
    //    bool done;
    radio.read(msg,1);
    Serial.print("Receved: ");
    Serial.println(msg[0]);

  }
}

Many thanks everyone!