Making 433 Mhz communication reliable

Hi,

I have written some code that works for transmitting data with wireless on 433 Mhz modules. The problem is it only works around 50 to 75 percent of the time and sometime has large gaps before it updates. I am hoping to get some clues as to how to hook up the system better and maybe upgrade the code.

The transmitter works fairly well, though I am sure it could be better. Basically you enter a byte of data, an integer between 0 and 255 in the sendData() function. In the second tab of the transmitter the number is converted to an array of true or false. This array is used to send the data.

/*James 9/22/2014
new attempt to send data instead of pulse widths over
single channel transmitter receiver module*/

//pins
int dataLine = 7;

//global vars
byte data; //0-255
boolean signal[8];
byte conversion[8] = {128,64,32,16,8,4,2,1};
int signalTime = 1000;// in Micro s

void setup()
{
  pinMode(dataLine, OUTPUT); 
  //Serial.begin(9600);
}

void loop()
{
  //convertData(125);
  //sendData(255);
  for(int i=0;i<10;i++)
  {
   sendData(250);
   delay(100);
  }
  for(int i=0;i<10;i++)
  {
   sendData(15);
   delay(100);
  }
  for(int i=0;i<10;i++)
  {
   sendData(55);
   delay(100);
  }
  for(int i=0;i<10;i++)
  {
   sendData(0);
   delay(100);
  }
  for(int i=0;i<10;i++)
  {
   sendData(150);
   delay(100);
  }
  
  
}

To catch the receiver a pulse of signalTime = 1ms is sent. This is followed by a 1ms low signal followed by the data. (This is the second tab for the transmitter)

void convertData(byte sending)
{
  int holder;
  /*1,2,4,8,16,32,64,128*/
  
  //8th bit
  /*if(sending / 128 > 0)//anything less than 128 should come out as zero
  {
    signal[7] = true;
    holder = sending - 128;
  }
  else
  {
     signal[7] = false;
     holder = sending;
  }
  *///...
  holder = sending;
  //Serial.println(holder);
  for(int i = 0; i<8;i++)
   {//Serial.println(i);
      if( holder - conversion[i] >= 0)
      {  
         signal[i] = true;
         holder = holder - conversion[i]; 
      }
      else
      {
         signal[i] = false; 
      }
   }
  
}//how could I have done this with less code?function or for loop

void sendData (byte sending)
{
   convertData(sending);
  
   digitalWrite(dataLine, HIGH);
   delayMicroseconds(signalTime);
   
   digitalWrite(dataLine, LOW);
   delayMicroseconds(signalTime);
   
   for ( int i=0; i< 8; i++)
   {
     if(signal[i] == true)
     {
       digitalWrite(dataLine, HIGH);
       delayMicroseconds(signalTime); 
     }
     else
     {
       digitalWrite(dataLine, LOW);
       delayMicroseconds(signalTime); 
     }
   }
   digitalWrite(dataLine, LOW);
}

The receiver works in a similar way but opposite. It puts the data into an array then converts it to an number between 0 and 255.

/*basic data reciever for one byte data
James 
9/23/2014*/

//pins
int dataIn = 2;//busa d1

//global variables
byte data;
byte conversion[8] = {128,64,32,16,8,4,2,1};
boolean signal[8];
int signalTime = 1000;//us

void setup()
{
  pinMode(dataIn, INPUT);
  
  Serial.begin(9600);
}

void loop()
{
  receiveData();
  data = convertData();
  Serial.print("got ");
  Serial.println(data);
  delay(10);
}

The second tab for the receiver that has the functions.

void receiveData()
{
  /*for (int i = 0; i<8; i++)//reset array
  {
     signal[i] = false; 
  }*/
  
  long length = pulseIn(dataIn, HIGH, 1000000);
  Serial.print("length = ");
  Serial.println(length);
  
  delayMicroseconds( signalTime/2);
  int check = digitalRead(dataIn);
  Serial.println(check);
  delayMicroseconds(signalTime);
    
  if(length > signalTime - 100 && check == LOW/*&& length < signalTime + 100*/)
  {
     
     
     for(int i = 0; i < 8; i++)
     {
       
        //Serial.print("dataIn ");
        //Serial.println(digitalRead(dataIn));
        if (digitalRead(dataIn) == HIGH)
        {
          signal[i] = true; 
        }
        else
        {
          signal[i] = false;
        }
        //Serial.print("signal ");
        //Serial.println(signal[i]);
        
        delayMicroseconds(signalTime);
     }   
  }
}

byte convertData()
{
   byte dataToReturn = 0;
   
/*for(int i = 7; i >= 0 ; i-- )
   {
     byte added = 1;
     if(signal[i] == true)
      {        
      
        for(;i > 0; i--)
        {
           dataToReturn =  2 * added + dataToReturn; 
           added = 2* added;
        }
      }
   }*/ 
   /*if(signal[0] == true)
   dataToReturn = dataToReturn +1;*/
   for(int i = 0; i<8; i++)
   {
       if(signal[i] == true)
       {
          dataToReturn = dataToReturn + conversion[i];
       }
   }
  return dataToReturn; 
}

As far as hardware goes I have found that if I use a capacitor between signal and ground I get better results. However I do not know what size of capacitor to use and am guessing as far as that goes. I plan to use this cod to control a Remote control car.

Look at using RadioHead (formerly VirtualWire) for those 433 Mhz modules.
You will get better reliability.
http://www.airspayce.com/mikem/arduino/RadioHead/

Thank you. I have looked into radio head and will look into it again. Though now I have this code written I think it would be cool to get it working. Any help with getting this code working would be appreciated.

At a minimum you need a Manchester Coder Manchester code - Wikipedia
to remove the DC component from the data you are trying to send, and a Manchester decoder at the receiver.
You need a flag sequence comprising 1 - 0 transitions repeated many times 10 - 20 is a good compromise sent before the data to condition the receivers data slicer and allow the receiver time to adjust its AGC loop to the required value to suit the incoming signal strength from your transmitter.
Those 433 Mhz modules are totally dumb in that they dont understand serial data, and the reciever has no squelch so that the receiver continuously generates digital garbage, which is fed into your Arduino.
Its far easier to use Virtual wire.

Thank you! Took me a bit but I think I understand what you are saying. The manchester coder makes it so there are a good amount of zeros and ones which allows the data to get through with less noise. I noticed when I tried to send zero there was a lot of noise on the receiver. The flag sequence allows for a transmitter to send to different receivers or different variables. It also makes sure there is good data coming after. again thanks

To make it reliable, you should write the same code as RadioHead (previous VirtualWire):

  • Use training pulses at the start, to make the hardware of the receiver happy and to detect the start in software.
  • Use manchester coding.
  • Allow extra noise pulses in the data :o !
  • Add a checksum to detect bad data.
    ... and more that the RadioHead/VirtualWire can do.

The RadioHead/VirtualWire is an outstanding piece of programming. You can never achieve that kind of reliability. Trust me on that.

I believe radiohead is good programming. However it is not easily understood and does not seem to me to be very user friendly. It is too complicated. Perhaps if I had more examples of the code for ask receiver/transmitters I could use it easier. I do learn more writing my own code and I am not trying to compete. I am working on an RC car that needs fairly reliable data that updates quickly. I do not know how to use radiohead for that so I am learning to write my own wireless transmitter/receiver code.

What do you mean by reliable data?
Do you mean low latency?
Those 433 Mhz modules with whatever protocol you like will only guarantee that what you transmit
might be received as it was transmitted.
They dont guarantee that everything sent will be received, as the link is one way.
To do that you need a bi directional radio link where every transmission is acknowledged by the receiver.
Something line an Xbee or NRF24l01 would be more suitable.

.

Yes, those transceivers are so much better.
But the VirtualWire/RadioHead has many things as I wrote in reply #5. When a (ASK) 433MHz transmitter is almost out of range, other libraries fail, but with the VirtualWire it is still possible to transfer data. It is really an amazing piece of software.

They dont guarantee that everything sent will be received, as the link is one way.
To do that you need a bi directional radio link where every transmission is acknowledged by the receiver.

I can only agree to that.
But are you sure that modules, or whatever you are using, are working well. I have used about 20 the modules in couple of projects and they are still working well. I used datarate about the middle of the datarate range. (2400bauds.) I used no special coders. Serial input to analog input of the transmitter. I also transmitted the same data 3 times. Then it was easy to notice errors. Higher datarates and shorter pulses mean higher noise and worse reception.

Only receiver antenna was an official antenna but it was probably a FM antenna, and I didn't tune it.