Go Down

Topic: Sending variable over Virtual Wire (Read 11696 times) previous topic - next topic

acidblue

Sending text over an RF link using Virtual Wire is easy , but what if
I want to send a int or float or any other variable.

Say I want to send a temp reading from a sensor to another arduino via a RF link.
Unfortunately something simple like this doesn't work.

Code: [Select]
tempC = analogRead(tempPin); // read value from sensor
 tempC = (5 * tempC * 100) / 1024; //convert voltage to Celcius
 tempF = (tempC * 9) / 5 + 32;    // convert Celcius to Fahrenheit
 Serial.print(tempF);Serial.println(" F");    // print to serial monitor
void loop()
{
   float *msg = (tempC);       // this is your message to send

  vw_send((uint8_t *)msg, strlen(msg));
  vw_wait_tx();                            // Wait for message to finish
  delay(200);


This gives "can't convert float to float"
So how do you send a variable using Virtual Wire??

PaulS

Quote
This gives "can't convert float to float"
So how do you send a variable using Virtual Wire??

I don't think that that is the correct error message that you got.

The key to how to send a variable using Virtual Wire is in the function call itself:
Code: [Select]
vw_send((uint8_t *)msg, strlen(msg));

The strlen function expects a string as an argument. A string is a NULL terminated array of chars.

Code: [Select]
char msg[24];
sprintf(msg, "%f", tempC);
vw_send((uint8_t *)msg, strlen(msg));


Unfortunately, sprintf on the Arduino doesn't support the %f format specifier. So, you need to approach the problem slightly differently. Separate the value to be sent into its integral and fractional parts:

Code: [Select]
int tempC1 = (int)tempC;
int tempC2 = (int)(tempC - tempC1) * 100; // For two decimal points
char msg[24];
sprintf(msg, "%i.%i", tempC1,tempC2);
vw_send((uint8_t *)msg, strlen(msg));

acidblue

Thanks PaulS, that works.
I never would have figured that out myself.

However one more thing, the resulting tempC on the receiver prints
out as xx.0 it seems to truncate the 2 decimal points to just one and
it's always .0 never the actual tempC, which would be xx.xx,(20.59).
I guess the value of tempC2 will always be 0, due to "
Code: [Select]
tempC2 = (int)(tempC - tempC1) * 100

I can live with it, it's not a big deal, but for extra 'wow' factor I would like to have print out the actual temp, xx.xx.
Is this possible?

PaulS

You might need an extra set of parentheses in there (or two), and to change 100 to 100.0, but, yes, tempC2 can be made to equal 59 when tempC is 20.59.

acidblue

Thanks, I'll see if I can work that out.

Next task is to print to an LCD.
Somehow I don't think this will work:
Code: [Select]
lcd.print(buf[i])

Can I pass the serial buffer to a variable?
Code: [Select]
int x = (buf[i])
lcd.print(x)

Then pass the variable to lcd.print

PaulS

Quote
Somehow I don't think this will work:

It will, but it will only print the one value in buf, whatever it is.

You could, if buf is a NULL-terminated array of chars, use:
Code: [Select]
lcd.print(buf);
to print the whole string in one step.

Quote
Can I pass the serial buffer to a variable?

Maybe. Maybe not. Depends on whether the variables are the same type. We don't know what type buf is.

acidblue

I tried lcd.print(buf), but I got this error:
error "call of overloaded 'print(uint8_t[30])' is ambiguous"

Here is my code;
Code: [Select]
#include <VirtualWire.h>  //
#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 8, 9, 10, 11, 12); //set digital pins

#undef int
#undef abs
#undef double
#undef float
#undef round
void setup()
{
    Serial.begin(9600);
    lcd.begin(16, 2); //set colums and rows of LCD  

// Initialise the IO and ISR
   vw_set_ptt_inverted(true);    // Required for RX Link Module
   vw_setup(1200);              // Bits per sec
   vw_set_rx_pin(3);           // We will be receiving on pin 3 () ie the RX pin from the module connects to this pin.
   vw_rx_start();             // Start the receiver
}

void loop()
{
   
   uint8_t buf[VW_MAX_MESSAGE_LEN];
   uint8_t buflen = VW_MAX_MESSAGE_LEN;

   if (vw_get_message(buf, &buflen)) // check to see if anything has been received
   {
   int i;
    // Message with a good checksum received.
       
   for (i = 0; i < buflen; i++)
   {
       Serial.print(buf[i]);  // the received data is stored in buffer
       }
   Serial.println("");
   
   lcd.clear(); //clear screen
   lcd.setCursor (0, 0); //set cursor to top row
   lcd.print(buf);
   
    }
}

PaulS

Try:
Code: [Select]
lcd.print((char)buf);
or
Code: [Select]
lcd.print((char *)buf);

acidblue

Code: [Select]
lcd.print((char *)buf);

That works fine  [smiley=grin.gif]
The other one gave a "loss of precision" error.
Thanks, you the man!

javilolo

Hi.
I'm triying send a float value also. I see the next code:
int tempC1 = (int)temperatura;
int tempC2 = (int)((temperatura - tempC1) * 100); // For two decimal points
char msg[24];
sprintf(msg, "%i.%i", tempC1,tempC2);
vw_send((uint8_t *)msg, strlen(msg));
vw_wait_tx(); // Wait until the whole message is gone

Why do you use 24 in the msg declaration?

I'm trying other values and it works fine ...

  2 * int = 8 bytes (8 char)
        "." = 1 byte (1 char)
-------------------------------
                            9 char

PaulS

The maximum value that can be stored in an int is +32767. The minimum is -32768. The minimum value takes 6 characters to represent. 6 * 2 is 12, plus one for the . and one for the NULL makes 14. So, the msg array could be as small as 14 characters and still hold everything that sprintf could possibly write into it. In reality, it could be much smaller, since the Arduino can't function at temperature near -10,000 degrees on any scale.

But, it's better to have an array that is too large than one that is too small.

Go Up