Using an interrupt in a noisy environment

I have a tone coming in to the arduino on pin 2 (Int 0). I am measuring the frequency and then converting that to a command. The tones are pre-shaped to 5V square waves and are not analog.

These tones are coming in from a radio receiver and are being sent from a remote control. So the commands could come in at any time and there is going to be long periods with no command coming in. So moving my routine to an interrupt is desired if possible.

However, this being the output of a radio receiver, I have to deal with noise, which means the interrupt is almost constantly being triggered.

And of course, being a tone with a continuous frequency while the remote button is being pressed, I am also going to trigger on every rising edge (which means thousands of times a second.) And what I really want is just to know what button was pressed and then act on that command in my loop (if valid).

So given the above, is using an interrupt in this scenario even feasible at all?

The application is a robot. And for example, four of the tones will control the steering of the robot. So I also need to know if the button is being held down to continue to drive in a direction. When there is no command from the remote, I want the robot to be doing robot things on its own.

I am thinking that a polling method might be more appropriate? Just wanted to get some thoughts.

I can post the code that I want to put in an interrupt if it will help, but I think the question is maybe generic enough?

1 Like

Which poor Arduino board are you pushing to the limit ?

Do you know the VirtualWire / RadioHead library.
They have a "ASK" mode that does just that. Noise is received in a interrupt, and inside the interrupt the distance between the pulses is measured. Those libraries are very good in finding real data in the noise.
The fuzzillogic does the same and might be easier to understand.

The drawback is that when a Arduino Uno is used, the whole Arduino is occupied. Other libraries that intensively use interrupts or disable the interrupts can no longer be used.

A transceiver that does the protocol in hardware makes everything a lot easier. Is that possible.

Can you provide more information ? Which receiver is it ? Why is there so much noise ? What generates the transmitter signal ?

Yup. And the math for the polling rate is fairly simple.

This is the code to determine the command. The tones are 200HZ apart. So I am just dividing the frequency by 200 using integers, so that it gives me a number like 7,8,9,10, etc....

long highTime = pulseIn(2, HIGH, 700);
long lowTime = pulseIn(2, LOW, 700);

long period = highTime + lowTime;

long freq = 1000000/period; //1 second divided by period

int command = int(freq/200);

Very basic, but it is working well.

The Goertzel algorithm - Wikipedia will very likely be more appropriate for what you are trying to do.

I am currently using an Arduino Uno, but am not married to that. The overall application will be simple enough that I think the Arduino would do the job. If I poll, it certainly can.

I am not familiar with those libraries and will check them out, thanks!

I was wanting to modify the hardware as little as possible. This is a TOMY Omnibot. What I am trying to do right now is just replace the dumb CPU in the robot with an Arduino and retain all of the original functions. It is a 2Mhz 4-bit microcontroller. And all it really does is detect tones and set outputs based on the tones.

Just replacing with bluetooth would make everything easier. But the goal is to use the original remote and retain the original functions. This way the toy appears and works just like the original, but we can expand with sensors and other outputs to give it a little bit of intelligence on its own. I am definitely doing this "the hard way" at first, more of as an exercise.

The receiver is a 49Mhz radio, since this was a toy from the 80s.

I don't know if such a project is all that interesting to people here, but I could post all of the details in a project thread if people were interested.

I figured. Polling wouldn't be terrible, I suppose.

Since you are dealing with square waves, the odd harmonics will be VERY strong. Are you sure the "noise" is not harmonics of the fundamental tone?

Some clarification...

The tones are single frequency tones. 1400-4600 hertz. The code that I have, no matter how overly simple it appears is detecting the commands perfectly if that is all that I am doing. I can just reject any numbers that are not in the range of the commands. When the remote is on, I have not improperly decoded noise as a command yet because the pulsewidths of the noise are not wide enough.

So, basically, I am not getting noise that looks like commands. I am getting noise that triggers an interrupt.

All I am doing is dividing the frequency to get a number.

The tones are (in hertz):

If I divide by 200, I get 7,8,9,10,11,12,13,14, and 23

If it isn't any of those numbers, it is invalid and can be ignored.

I am probably not really understanding FFT at all. That gets recommended to me a lot. I can see that it would help to pull a signal out of noise. But I am not understanding how that would prevent an interrupt from being triggered. And if I am polling, I don't really need to worry about the noise much because I can just reject any command that isn't valid. I think?

I just wanted to clarify that I am not currently trying to solve the issue of detecting the tones out of noise. My issue was that even the slightest spike in noise will trigger an interrupt. The noise is only a problem if I want to use an interrupt.

Ok, Are the tones mutually exclusive? Meaning two buttons cannot be pressed at the same time? That seems to be the case.
Are the tones synchronized, so that the square wave of one tone cannot begin immediately at the end of the previous tone, resulting in an incorrect timing?

I am sure there is a level of that. But the noise will trigger an interrupt even (and even moreso) if the remote is off. When the remote is turned out, the noise is a bit quieter.

The hardware is just shaping the signal with just an integrator. It isn't doing any filtering it seems. But the interrupt is very fast and is voltage based, so even a tiny super fast spike will trigger it. My code can't even see it. But the interrupt can. So, if an interrupt were possible, it would be like debouncing a switch in software (if that switch made some noise even when not pressed), I guess. But even then, I am still triggering almost constantly and will lose a few microseconds every time.

Based on the replies so far, I am becoming convinced that I am going to need to go with polling and that an interrupt is just not feasible.

Only one button can be pressed at a time.

A button press will produce a dozen or so miliseconds of pulses. Holding the button down will just keep the same tone going until released. I am not 100% what happens if you pressed another button while holding but, I am sure it would just ignore the second press based on what I know of the hardware. I guess one tone would never be immediately after another because it would take time to move your fingers from one button to another.

No you are not!.
In your interrupt code, read the pin causing the interrupt and see if it is still high. If not, then you have a noise pulse.
If still high, read again and see if still high, if not, noise.
Do again.
Depending on the shape of the noise, you may need only one read or several to eliminate noise and still discover a tone square wave. Experiment!
Good luck,

Hmm.... good idea, actually! I could maybe expand on that by just testing my first pulseIn(2,HIGH,700); line and then rejecting if it is not long enough to be a valid command.

Or you may have to get creative and code your own interrupt process!

Maybe this DTMF page could give you some ideas.

With that frequency range, I would use the FreqCount library and see if noise can be distinguished from a frequency.

Something I had not considered is that it looks like the pulseIn function that I am using is using the interrupts on that pin to do its work, so I cannot turn off the interrupt while running my interrupt code. :cry: And if I can't turn off the interrupt, then noise interrupts my interrupt and the whole thing goes off the rails.

So polling, it is.

I started with that actually. It worked great for getting the right frequency. It runs in the background continuously so does the polling for me. I will try that approach again.

I was using a terrible method previously to convert to a command that wasn't working well with the freqcount library, but the new method should work with it.

I haven't looked at the pulse length code, but suspect it is doing pretty much as I suggested. Writing the code to do your own is not difficult.