Problem with virtualwire buffer

I have a problem with my virtualwire connection (unidirectional 433mhz).

I want the receiver to behave like this

Turn on → activate receiver (listening for messages) → receive a message and compare it to the command it should receive → if it’s this command then perform a certain action → go back to listening modus

This works fine basically. but after it received the message it makes the comparsion,resets one byte in the received message as it should so it doesn’t get stuck in an infinite loop. After that there is a waiting period since i am sending the command 10 times to make sure it gets to the receiver.
But no matter how long this waiting period is 5seconds… 20 seconds… there is always another time that the command gets executed.

It seems that there is always still one in the buffer.

char msg[9] = "";  //Speicher für die eingehende Nachricht
void loop()
{
    uint8_t buf[VW_MAX_MESSAGE_LEN];
    uint8_t buflen = VW_MAX_MESSAGE_LEN;
    if (vw_get_message(buf, &buflen)) // Non-blocking
    {         
        int i;  // Zähler für den Array pointer
        digitalWrite(led_pin, HIGH); // Empfange Nachricht [LED AN]	
	for (i = 0; i < buflen; i++)
	{
            msg[i] = buf[i];
	}
        Serial.print(" MSG lautet:   ");
        Serial.println(msg);
    }
     else if (strcmp(msg, "klingel#") == 0)
        {
          Serial.println("Nachricht erfolgreich angekommen");
          msg[1] = '0';
          delay(8000);
        }
}

The VirtualWire uses perhaps a timer and interrupts. I think that while you are waiting, messages are still being received.

You can receive them all, and perhaps use millis() for a timestamp. When the same message is received within a certain time, it is considered the same.

Or use an unique identifier (like a 16-bits counter), add that to the message. Receive the message, execute the command and remember the unique identifier. When the next message arrives, and it has the same unique identifier, you can ignore it.

	for (i = 0; i < buflen; i++)
	{
            msg[i] = buf[i];
	}

Useless! Quit copying the data!

    if (vw_get_message(buf, &buflen)) // Non-blocking
    {
       // Make and print a useless copy of buf
    }
     else if (strcmp(msg, "klingel#") == 0)

If there was something received, make a useless copy, but do nothing else.
If there was not anything new received, deal with the message that came last time.
Why? Deal with the message WHEN IT ARRIVES!

I understand what you are saying but i don't know the solution :/

I tried to deal with the message when it arrives but i can't use the strcmp command since it would be uint_8 compared to char.

Should i calculate the uint_8 value of my char array "klingel#" and then compare this to "buf" ?

but i don't know the solution :/

I’ve told you some of it. I expect you to research some of it.

Select this code:

	for (i = 0; i < buflen; i++)
	{
            msg[i] = buf[i];
	}

Delete it!

    if (vw_get_message(buf, &buflen)) // Non-blocking
    {
        if (strcmp((char *)buf, "klingel#") == 0)
        {
            // Do something
        }
    }

Compare what you received. If you received anything.

For some reason it still doesn’t work. I was not sure if there was a problem with the Receiver so added some Serial.println commands at some points to see where the program gets stuck

void loop()
{
    uint8_t buf[VW_MAX_MESSAGE_LEN];
    uint8_t buflen = VW_MAX_MESSAGE_LEN;
    if (vw_get_message(buf, &buflen)) // Non-blocking
    {
      Serial.println("Receiving a Message");  
      Serial.println((char*)buf);
      
      if (strcmp((char *)buf, "klingel#") == 0)
        {
            Serial.println("Nachricht erhalten");
        }
    }
}

The Serial outputs looks like this evertime i send a message.

Receiving a Message
klingel#¨
Receiving a Message
klingel#¨
Receiving a Message
klingel#¨
Receiving a Message
klingel#¨

I copied the message “klingel#¨” into the strcmp command to see if it will work then, but it still has the same issue. I also tried adding \0 to it at the end. After i did that it still got stuck in the exact same way but Serial.println((char*)buf)M spat out “klingel#” and not “klingel#¨” anymore.

I have not modified my transmitter in any way. It still works when i use my old code where it sends the message two times.

I also tried adding \0 to it at the end.

You need to post the code you are actually using.

Don't just print the buffer. Print delimiters before and after the buffer, so to can see everything in the buffer without making assumptions.

Serial.print(buf contains: [");
Serial.print((char *)buf);
Serial.println("]");
void loop()
{
    uint8_t buf[VW_MAX_MESSAGE_LEN];
    uint8_t buflen = VW_MAX_MESSAGE_LEN;
    if (vw_get_message(buf, &buflen)) // Non-blocking
    {
      Serial.print("buf contains: [");
      Serial.print((char *)buf);
      Serial.println("]");
      
      if (strcmp((char *)buf, "klingel#") == 0)
        {
            Serial.println("Nachricht erhalten");
        }
    }
}

Is the current code.

      if (strcmp((char *)buf, "klingel#\0") == 0)

Is what i meant when i said " i tried addin \0 to it at the end"

Currently it always returns this when it gets the message

buf contains: [klingel#¨]

Make a test sketch for the transmitter and receiver and show us the [u]full[/u] sketch for both.

    if (vw_get_message(buf, &buflen)) // Non-blocking
    {
      Serial.print("buf contains: [");
      Serial.print((char *)buf);
      Serial.println("]");
      
      if (strcmp((char *)buf, "klingel#") == 0)

The array returned by vw_get_message is NOT a string. That's why it tells you the number of bytes in the array it fills. If it could be a string, it is up to you to make it one.

buf[buflen] = '\0'; // This is where to add the NULL;

Is what i meant when i said " i tried addin \0 to it at the end"

Which is why you needed to post the code. You are adding a NULL after a NULL terminated string. Pointless - two stops don't mean any more than one. You are not adding the NULL to the data retrieved from the radio, which you need to do.

PaulS, to transmit a string, I would transmit strlen() + 1 to include the zero-terminator. That makes it easier. But we have to know the full RX and TX sketch. At the moment we are all stirring in troubled water.

Apicalis, the VirtualWire is almost never used with a string. Can you use a byte (with a number) as a command ?

Now that you made me think about it, it would of course be no problem to just send numbers. Since this is just a code that gets send everytime the transmitter has power supply until the power fades away.

// Sender

#include <VirtualWire.h>
int LED = 13;
int TRANSMIT = 11;




void setup()
{
  pinMode(LED, OUTPUT);  // LED
  vw_set_tx_pin(TRANSMIT); // Senderanschluss
  vw_setup(500); // Datenrate
}

byte msg[] = { 0,2,2,4,1,8,2,0 };

void loop()
{
    digitalWrite(LED, HIGH);
    vw_send((uint8_t *)msg, 8);
    vw_wait_tx();
    digitalWrite(LED, LOW);
}

The current receiver sketch is this one, i reduced the one before to just the virtual wire elements to isolate the problem.

#include <VirtualWire.h>

const int led_pin = 13;
const int receive_pin = 7;

void setup()
{
    pinMode(led_pin, OUTPUT);
    Serial.begin(9600);	// Debugging only
    vw_set_rx_pin(receive_pin);
    vw_setup(500); // Bits per sec
    vw_rx_start();       // Start the receiver PLL running
}


void loop()
{
    uint8_t buf[VW_MAX_MESSAGE_LEN];
    uint8_t buflen = VW_MAX_MESSAGE_LEN;
    
    if (vw_get_message(buf, &buflen)) // Non-blocking
    {
      Serial.print("buf contains: [");
      Serial.print((unsigned int)buf);
      Serial.println("]");
    }
}

Currently it spits this out

buf contains: [2214]
buf contains: [2214]
buf contains: [2214]

The IDE says i am not allowed to cast buf into byte " error: cast from ‘uint8_t*’ to ‘byte’ loses precision"

      Serial.print("buf contains: [");
      Serial.print((unsigned int)buf);

The address of buf, that you are printing, and the data in the array are completely separate things.

The IDE says i am not allowed to cast buf into byte " error: cast from 'uint8_t*' to 'byte' loses precision"

An address is a pointer. You are casting the uint8_t pointer to an unsigned int.

Apicalis, you receive a buffer with the numbers that you transmitted, but you don’t print the contents of the buffer, as PaulS wrote. You also better add a delay in the transmitter. The rest is okay.

This is what you transmit: byte msg = { 0,2,2,4,1,8,2,0 };
This is what you receive: vw_get_message(buf, &buflen)
Both should be the same data.

// print received bytes
Serial.print(F("Received: ");
for (int i=0; i<buflen; i++) 
{
  Serial.print(buf[i]); // print contents of buffer
}
Serial.println();

Please add a “delay(500);” at the end of the “loop()” in the transmitter.

For the bitrate, you have 500. But with those cheap modules, 2000 works just as well.
With 500, you can only transmit a few bytes per second, since the VirtualWire has some overhead.

Probably you already solved or quit the project, but anyway I will send a solution that worked fine to me

char msg[9] = "";  //Speicher für die eingehende Nachricht
void loop()
{
    uint8_t buf[VW_MAX_MESSAGE_LEN];
    uint8_t buflen = VW_MAX_MESSAGE_LEN;
    if (vw_get_message(buf, &buflen)) // Non-blocking
    {         
      vw_rx_stop();
        int i;  // Zähler für den Array pointer
        digitalWrite(led_pin, HIGH); // Empfange Nachricht [LED AN] 
    for (i = 0; i < buflen; i++)
    {
            msg[i] = buf[i];
    }
        Serial.print(" MSG lautet:   ");
        Serial.println(msg);
    }
     else if (strcmp(msg, "klingel#") == 0)
        {
          Serial.println("Nachricht erfolgreich angekommen");
          msg[1] = '0';
          delay(2000);
          vw_rx_start();
        }
}

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.