433mhz *RECEIVER* arduino - How to deal with interferance?

Hi

I want to use one of those cheap 433mhz transmitter/receivers as a remote control for an arduino (actually, I'll be using a Tiny, but I'm developing on perfboarduino that behaves like an Uno).

THE ARDUINO IS BEING CONTROLLED - NOT THE OTHER WAY AROUND. I know there are a billion projects about using your arduino to drive the transmitter; that's not what I'm doing.

I'm just completely lost on how to write the code for the receiver. The receiver is producing a constant gibberish signal from interferance, and even in a faraday cage, the receiver switches between 1 and 0. My understanding of the automatic adaptive gain is that it will adjust gain appropriately... but this means that what I'm listening to is going to be:

GibberishgibberishgibbeSIGNALgibberishgibberishgibberish.

I've stared at this, and I just have no idea where to even get started on writing something that can pick the signal out of the gibberish. It's not that I can write something but it doesn't work - I CANT EVEN DO THAT. I have just no idea - none at all - how to pick the signal out of the gibberish. (honestly, this feels really wierd emotionally - I cannot remember another time when I've looked at a programming or hardware task and had NO IDEA AT ALL how to even get started).

I've done some simple arduino programming before, and I've done a lot of programming in other languages - and, I don't know what critical insight i'm missing, but I just have no clue how to do this.

I've seen a few examples of things that receive 433mhz on arduino, but they are all directed towards reading out the pattern in order to design code that works, and so they start from a known point, and don't have to do the parts that I'm clueless on.

Maybe the problem is that there's no way to get a feel for this without accounting for the interferance, since the receiver will generate shit on it's own, even in a faraday cage, so I can't start from something simple, because the hardest part needs to be done before anything can be done. Like, I wanted to start out with something that just turned a light on when it received something. But of course, THAT isn't going to work, because when there's no signal, the signal keeps switching from high to low.

Does anyone have an example of an Arduino sketch that does something when receiving a code from 433mhz receiver? I figure if I saw how it was being done, I'd have no trouble adapting it to my goal, but I'm clearly missing some critical bit of knowledge.

I am also designing the transmitter (this side is trivial) - the transmissions will be sent by a different MCU (an Espruino), so I can design the code however I want; this was recommended:

If you're making your own signal format, it seems a good form is:
A ~4ms '1' signal - which is easy to detect and which gives the receiver time to adjust
A series of pulses - PWM is easiest, maybe 0.7ms for a 0, and 1.3ms for a 1, with a gap of ~0.5ms

Please help - I'm desperate here.

Thanks

433mhz RECEIVER arduino - How to deal with interferance?

You get what you pay for.

I'm just completely lost on how to write the code for the receiver. The receiver is producing a constant gibberish signal from interferance, and even in a faraday cage, the receiver switches between 1 and 0.

Of all the people in the world, only one can see your code. You'll need to ask that person for help, unless you are willing to share.

I would always post code if I had any. The problem is, I do not have any code yet - that's why I'm asking for help.

As i said above, I am just completely lost as to where to even start here.

Once I have a way to start reading bits and recognizing when it starts, I won't need help anymore. But I can't get to that point. I've spent many hours looking at this, but I just get nowhere.

Once I get that stepping stone, I know I'll be able to extend it and do everything I want to with it. But I have no idea how to take the output of one of those receivers, and get data out of it, and tell that apart from the rest of the crap on the line.

This is such unfamiliar territory for me - the bit about having no idea where to start. Usually I can at least get my code to a point where I've got most of it down, but I'm stuck on one part. Here, I'm stuck at the starting line, with no code and no idea what to write.

The receiver is producing a constant gibberish signal from interferance, and even in a faraday cage, the receiver switches between 1 and 0.

That is the way those cheap receivers work. All useful receiver codes overcome this by applying certain rules to a potentially valid signal, and failing all those signals that don't meet the tests.

The VirtualWire library is open source and reasonably well explained. Some study of that will reveal all the inner workings. Or, you could just use it.

The receiver is producing a constant gibberish signal from interferance, and even in a faraday cage, the receiver switches between 1 and 0.

Not all by itself, it isn't.

The problem is, I do not have any code yet

Either this statement or the previous one is false.

Sorry, I meant I had no code that was directed towards actually extracting data.

The code that I had tried for my simple test was something like this (from memory - it was really trivial)

void loop {
if (digitalRead(rxpin)==1)
{
digitalWrite(ledpin,1);
} else {
digitalWrite(ledpin,0);
}

I was expecting that I could just do that, and the light would be off, and go on when i turned the transmitter on, and go off when I turned it off; if it did that, I'd be well one my way. But that's not what it does; the LED flickers even with no transmitter around. I'd put in a serial.println statement to record the state of the rx pin, and that was consistent with what I saw in the LED. I even tried it in a faraday cage - the whole thing was put in a cardboard box covered in several layers of foil, and it still did that. I was about ready to declare the receiver defective. But it was then explained to me that this is expected behavior on those transmitters, and you have to pick out the code from the noise.

The receiver is producing a constant gibberish signal from interferance, and even in a faraday cage, the receiver switches between 1 and 0.
Not all by itself, it isn't.

Yes, Paul, the cheap receivers do output a constant stream of 1s and 0s, even in a Faraday cage. But it is not due to interference, rather due to internal noise. Take a look with a scope some time.

Edit: or use Audacity. Here is a sample trace from Decoding RF Link Using A PC Soundcard | Hackaday. The junk on the left is the typical noise output.

The gibberish you are seeing is simply thermal noise converted into a 2 state indication.
Even in a faraday cage , the receiver will still generate the same gibberish as all radio receivers no matter how good they are
have a RF front end which has a noise figure > 0, and is operating above 0 K.

The basic methodology to making these receivers work is to send data to them in a form thats easy to pick out from the noise.
A sequence of 1 - 0 - 1 - 0 transitions at the start, usually around 20 + will do , followed by a pattern thats differant , such as
1 -0 - 0-1 , then whatever data you want to send.
Using a Manchester Coder at the sending end will improve your chances of receiving anything.
But as others have mentioned, you get what you pay for.
These receivers are extremely simple.
Have a good read about Virtualwire and how it works , and look at the sourcecode.

There is a specific library that can use those modules ( and others) it used to be called virtualwire but it seems to have changed to:

http://www.airspayce.com/mikem/arduino/RadioHead/

Those modules detect ASK modulation, which stands for amplitude shift keying. Also they are not crap, but the constant stream of 0-1 makes them less than desirable for a microprocessor. In fact it is likely the best one transistor receiver that can be made.

That is one reason why the supperregenerative receiver is still used today.

Note I have not used the library.

VirtualWire is still around VirtualWire: VirtualWire library for Arduino and other boards but is no longer being supported. Some people prefer the newer (and more complex) RadioHead library, as it offers a number of additional and useful features.

For simple applications like remote temperature sensors, VirtualWire is very easy to use and works well.

PaulS:

The receiver is producing a constant gibberish signal from interferance, and even in a faraday cage, the receiver switches between 1 and 0.

Not all by itself, it isn't.

Actually, yes, it is.

It's actually a self-contained random number generator called a "superregenerative" receiver. It uses a "quench" oscillator (function - usually the entire receiver stage is a single transistor) to continuously ramp up the positive feedback gain until oscillation occurs, at which point it shuts off and allows the gain to ramp up again in a sawtooth fashion. In the absence of a signal, the receiver amplifies its own internal noise.

Interesting consequence - this is why your car lock remote works at a considerable range out in the open, but frequently requires you to be directly alongside the car in a car park, as interference is occurring from the radiation from all the other superregenerative receivers in the other cars.

In order to make sense of the signal, it is necessary that valid information is bounded by distinctive "flag" patterns. Until a valid flag is received, the software simply ignores the noise. Even then, "packets" require checksums to prove their validity.

silverxxx:
Those modules detect ASK modulation, which stands for amplitude shift keying.

Actually, some of them are OOK (On-Off-Keying), but you interface with them the same was as ASK.

I had a breakthrough and came up with this.

Of course, it doesn't work, at all. I try to send it my bitstream (just 1 byte, with 4ms on pulse first). It will report starting to receive, but never catches any bits. Does anyone have any suggestions?

#define rxpin 19

int RBright=0;
int GBright=0;
int BBright=0;
int WBright=0;
int lastPinState;
unsigned long lastPinHighTime;
unsigned long lastPinLowTime;;
unsigned long lastTempHighTime=0;
unsigned long lastTempLowTime=0;
unsigned long rxdata;
int lastTempPinState;
int bitsrx;
int rxing;
int MyState;

void setup() {
        lastPinState=0;
        lastPinLowTime=0;
        lastPinHighTime=0;
        rxdata=0;
        bitsrx=0;
        rxing=0;
        MyState=2;
	Serial.begin(9600);
}

void loop() {
	onListenST();
 // }
}

void onListenST() {
	int pinState=digitalRead(rxpin);
	if (pinState==lastTempPinState) {
		return;
	} else if (pinState==0) {
             lastTempPinState=pinState;
              lastPinState=pinState;
        } else {
          lastTempPinState=pinState;
        }
        if (pinState==0) {
           lastTempLowTime=micros();
        } else {
           lastTempHighTime=micros();
        }
        if (pinState==0) {
          if (lastTempLowTime-lastTempHighTime < 200 && lastTempHighTime >0 && lastTempLowTime>0) {
            lastTempHighTime=0;
            lastTempLowTime=0;
            return;
          }
        }
	if (pinState==0) {
		lastPinLowTime=micros();
                bitsrx=10;
		unsigned long bitlength=lastPinLowTime-lastPinHighTime;
                //Serial.println("bitlength:");
                if (bitlength < 1400 && bitlength > 600) {
                  //Serial.println(bitlength);
                }
		if (bitlength > 4200) {
			//bogus bit
                        // Serial.println(bitlength);
			resetListen();
			return;
		} else if (bitlength >3000) {
                        rxing=1;
                        Serial.println("starting to receive");
                        return;
		} else if (rxing==1) {
                        Serial.print(bitlength);
			if (bitlength > 550 && bitlength < 850) {
				rxdata=rxdata<<1;
				Serial.println("Got a 0");
			} else if (bitlength > 1100 && bitlength < 1500 ) {
				rxdata=(rxdata<<1)+1;
				Serial.println("Got a 1");
			} else {
				Serial.println(bitlength);
				resetListen();
				return;
			}
			bitsrx++;
			if (bitsrx==8) {
				Serial.println("Got 8 bits");
				Serial.println(bitsrx);
				resetListen();
			}
			return;
		}   
	} else {
		lastPinHighTime=micros();
		if ((lastPinHighTime-lastPinLowTime > 600 || lastPinHighTime-lastPinLowTime < 400) && rxing==1) {
		        Serial.println(lastPinHighTime-lastPinLowTime);
			//resetListen();
			return;
		}
	}
}

void resetListen() {
	bitsrx=0;
	rxdata=0;
        rxing=0;
}

I'm sending it from an Espruino, manually calling sendTest():

    var txpin=A1;
    function sendTest() {
    digitalPulse(txpin,1,4); //4ms start
    digitalPulse(txpin,0,0.5); //pause
    digitalPulse(txpin,1,0.7); //send a 0
    digitalPulse(txpin,0,0.5); //pause
    digitalPulse(txpin,1,1.3); //send a 1
    digitalPulse(txpin,0,0.5); //pause
    digitalPulse(txpin,1,0.7); //send a 0
    digitalPulse(txpin,0,0.5); //pause
    digitalPulse(txpin,1,1.3); //send a 1
    digitalPulse(txpin,0,0.5); //pause
    digitalPulse(txpin,1,1.3); //send a 1
    digitalPulse(txpin,0,0.5); //pause
    digitalPulse(txpin,1,1.3); //send a 1
    digitalPulse(txpin,0,0.5); //pause
    digitalPulse(txpin,1,1.3); //send a 1
    digitalPulse(txpin,0,0.5); //pause
    digitalPulse(txpin,1,1.3); //send a 1
    digitalPulse(txpin,0,0.5); //pause
    }

You don't want to send a 4ms solid-ON pulse. You want to send a 50% duty cycle square wave for 4ms. This is to allow the receiver to adjust it's AGC for the following data transmission.

A solid-ON just makes the receiver AGC turn it's sensitivity way down.

Ooooh

Should all the pulses be 50% duty cycle? or just the starting one?

What frequency should I make the pulses at?

And - any thoughts on how I would recognize 4ms long 50% duty cycle square wave?

DrAzzy:
Ooooh

Should all the pulses be 50% duty cycle? or just the starting one?

What frequency should I make the pulses at?

And - any thoughts on how I would recognize 4ms long 50% duty cycle square wave?

Just the starting pulse needs to be modulated.

Frequency should be the same as your bit rate.

You don't need to recognize the square wave on the receiver. Just look for valid bytes and ignore everything else, like noise or the square wave.

In general, the radio protocol should strive for a balance of around 50% on vs off. Long strings of on or off will tend to make the AGC on the receiver vary from the optimum level and lead to receive errors. Purpose built libraries like VirtualWire or RadioHead handle this internally. If you have the sender and receiver under your own software control, why wouldn't you just use one of these libraries?

Because I looked at the virtualwire library, and it seemed horrendously complicated, and I couldn't make one bit of sense of it... and I can't transmit using the virtualwire library because I'm transmitting with a non-Arduino. (it's an Espruino, which runs a version of javascript - it's pretty awesome for some types of projects, espruino.com for more info if interested).

The whole idea is that I'll have command and control on the highly capable web connected Espruino, and use some form of wireless communication for the Espruino to give commands to smaller, cheaper Arduino-like devices (once I have it working on ATMega328P, I'll convert to ATTiny84 or ATTiny85, depending on the application)..

I had tried using the NRF's, but neither me nor some other people on the Espruino forum were ever able to get the two of them talking to eachother (and they're also overkill - I only need to transmit a few bytes - and may be tricky to use with an ATTiny). And actual WiFi is way too complicated.

So that leaves 433mhz comms.

DrAzzy:
javascript

I see.

Well 99% of the complication of VirtualWire is on the receive side. Sending is not too gnarly.

My advise is to define what you want your protocol to be up front.

A lot of simple remotes and temperature sensors use a pulse spacing protocol that is easy to implement and easy to parse. ON pulses are a set width of, say, 500 microseconds. The data is encoded by how the pulses are spaced out, so 500 usec on + 500 usec off is used as an AGC training pulse, 500 usec on + 2000 usec off is a sync pulse, 500 usec on + 750 usec off is a "1" and 500 usec on + 1000 usec off is a "0".

A transmission is something like:

10 AGC training pulse
1 sync pulse
8-48 or so data bits pulses

   *   _           _
   * _| |_________| |_
   *  ^           ^
   *  |           edge_rise_us
   * last_edge_rise_us

  _   _   _   _          _    _     _    _
_| |_| |_| |_| |________| |__| |___| |__| |__

 ^ AGC Train ^  Sync   ^  1  ^  0 ^  1  ^  etc

Receiving logic is not too bad.
(1) You need a function to wait for the edge transitions to measure the pulse length and classify it as one of the 4 types -- or some noise artefact that is non-of-the-above
(2) you need a state machine to interpret the train of pulses and weed out noise artefacts

That post is Very useful.

I'll get to work on the re-worked protocol and new receiver logic.