Prevent spurious triggering by noise?

My first project circuit as an Arduino novice is triggered by a low-going pulse (5V to 0V) and then sends a sequence of servo arm movements. Here is the IF that achieves that at the start of the void loop.

 void loop()
{
  if (digitalRead(triggerPin) == LOW)
  {

But although it works successfully in an electrically quiet environment, when installed in its intended location it suffers from unwanted triggering by very brief noise spikes. I will also try some RC filtering experiments, but I’d prefer to do it within the program. Any practical advice on doing that would be appreciated please. I expect that what’s needed is some way of ensuring that the IF tests for the trigger staying low for a time that’s relatively long, say 20 ms, compared to the noise?

Terry, UK

Look into how switch debounce is done using millis().

Also check out the State Change Detection example (File->examples->02.Digital->StateChangeDetection) since you want to do things WHEN the trigger goes low, not IF the trigger is low.

How is triggerPin handled in setup()?

pinMode (triggerPin, INPUT);
or
pinMode (triggerPin, INPUT_PULLUP);

The 2nd way will actively pull the pin high when it is not low, preventing or helping to prevent spurious low readings.

What pullup / pull down resistors do you have on the trigger pin? What is doing the triggering and how far is it from the digital input?

groundFungus:
Look into how switch debounce is done using millis().

Thanks, that looks promising, although a bit complex.

blh64:
Also check out the State Change Detection example (File->examples->02.Digital->StateChangeDetection) since you want to do things WHEN the trigger goes low, not IF the trigger is low.

I will follow up your suggestion, thanks. But I’m not clear about the distinction you draw. As the loop gets run only WHEN a low voltage is FIRST detected, no matter how briefly, there seems no practical difference?

CrossRoads:
How is triggerPin handled in setup()?

pinMode (triggerPin, INPUT);
or
pinMode (triggerPin, INPUT_PULLUP);

The 2nd way will actively pull the pin high when it is not low, preventing or helping to prevent spurious low readings.

I’m using INPUT_PULLUP on that pin, but it doesn’t prevent unwanted triggering.

AJLElectronics:
What pullup / pull down resistors do you have on the trigger pin? What is doing the triggering and how far is it from the digital input?

I’m using the built in pull-up.

The supply lines are fairly long but there are several sources of noise in this shed workshop, including fluorescent lights, an old PC, the servo itself when the circuit is triggered, etc.

Terrypin:
I will follow up your suggestion, thanks. But I’m not clear about the distinction you draw. As the loop gets run only WHEN a low voltage is FIRST detected, no matter how briefly, there seems no practical difference?

No, loop() loops continuously. So when the pin goes low it completes whatever comes after the if, then returns to the top of loop() and if the pin is STILL low it does it all over again...and again...and again. That's often an important distinction.

Steve

Note the time a trigger occurs. After 5ms, check to see if it is still low, 5mS, check it again. 3 good lows and, and run the trigger event.
Something like this, may need some tweaking

if (digitalRead (triggerPin == low) && (triggerTimerStarted) == 0)) {
triggerTime = millis(); // capture the start time of a pulse
triggerTimerStarted = 1; // flag to show time is running
numberOfCycles = 1; // count number of 5mS attempts
}
// read the pin after 5, 10, 15ms have passed
if ( (millis() >= (triggerTime +(5*numberOfCycles)) && (triggerTimerStarted == 1) && (digitalRead (triggerPin) == low) ){
   numberOfCycles = numberOfCycles +1;
   if  (numberOfCycles == 3){
   numberOfCycles = 0;
   triggerTimerStarted = 0;
   // run trigger pulse code
   }
}   // wait 5mS for the next read

if (millis() >= (triggerTime +16)) && ( triggerTimerStarted ==1) && (digitalRead (triggerPin) == high) ){
// pin was not low for 16mS, call it a spike and restart scanning
triggerTimerStarted = 0;
numberOfCycles = 0;
}

You could also try a stronger external pullup, 10K, 5K.
Whatever brings the signal low then needs to sink (5V/10000) = 0.5mA,
or 1mA with 5K, etc. Do the math. That should get rid of a lot of noise.
If it is just a mechanical switch, you can go a lot lower and let the switch sink more current.
500 ohm for 10mA, 50 ohm for 100mA. The Ardiuno won't care it just has 1uA going in and out of the pin, independent of what goes thru the resistor and driver.

If not a switch, check the driver output of whatever drives the signal.

Hi,
Do you need to detect a LOW or a HIGH to LOW?

void loop()
{
  if (digitalRead(triggerPin) == LOW)
  {

Does not detect a transition.
Please can you post a complete copy of your code and a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

How long are your leads and do you have bypassing on them?

Thanks.. Tom... :slight_smile:

But although it works successfully in an electrically quiet environment, when installed in its intended location it suffers from unwanted triggering by very brief noise spikes.

The supply lines are fairly long but there are several sources of noise in this shed workshop, including fluorescent lights, an old PC, the servo itself when the circuit is triggered, etc.

If with a stronger signal there's still false triggering, it could be partially due to interference on the ground line. Due to the long length and pathway of the signal wires, I think the best solution would be to use an opto-isolator.

slipstick:
No, loop() loops continuously. So when the pin goes low it completes whatever comes after the if, then returns to the top of loop() and if the pin is STILL low it does it all over again...and again...and again. That's often an important distinction.

Steve

Thanks Steve, but I understand that, and it’s the basis of how my circuit works. (Detect any occurrence of a low voltage on that pin, do about 30 seconds of various servo movements, then wait for another detection.) My puzzlement was about the distinction between IF and WHEN in this context.

Terry

CrossRoads:
Note the time a trigger occurs. After 5ms, check to see if it is still low, 5mS, check it again. 3 good lows and, and run the trigger event.
Something like this, may need some tweaking

if (digitalRead (triggerPin == low) && (triggerTimerStarted) == 0)) {

triggerTime = millis(); // capture the start time of a pulse
triggerTimerStarted = 1; // flag to show time is running
numberOfCycles = 1; // count number of 5mS attempts
}
// read the pin after 5, 10, 15ms have passed
if ( (millis() >= (triggerTime +(5*numberOfCycles)) && (triggerTimerStarted == 1) && (digitalRead (triggerPin) == low) ){
  numberOfCycles = numberOfCycles +1;
  if  (numberOfCycles == 3){
  numberOfCycles = 0;
  triggerTimerStarted = 0;
  // run trigger pulse code
  }
}  // wait 5mS for the next read

if (millis() >= (triggerTime +16)) && ( triggerTimerStarted ==1) && (digitalRead (triggerPin) == high) ){
// pin was not low for 16mS, call it a spike and restart scanning
triggerTimerStarted = 0;
numberOfCycles = 0;
}

That looks great, thanks a bunch. Will try it as soon as I get back to my PC.

Also pay good attention to your shielding. Shielded cables help alot.

I had to instal an ardino powered device very close to a high power AC transformer , it as used to check hmidity , temperature and also had a light sensor inside the space where the transformer was housed.

Although programming workarounds did help, my best bet was going for shielding, nice grounded cables and i also ended up having to make a Faraday shield for the uno itself.

CrossRoads:
You could also try a stronger external pullup, 10K, 5K.
Whatever brings the signal low then needs to sink (5V/10000) = 0.5mA,
or 1mA with 5K, etc. Do the math. That should get rid of a lot of noise.
If it is just a mechanical switch, you can go a lot lower and let the switch sink more current.
500 ohm for 10mA, 50 ohm for 100mA. The Ardiuno won't care it just has 1uA going in and out of the pin, independent of what goes thru the resistor and driver.

If not a switch, check the driver output of whatever drives the signal.

Thanks, that too is really helpful. I’d read that the built in pull-up was typically about 35k and had been thinking along the lines you suggest but reluctant to try it until I just read your reassurance, particularly about the pin’s high impedance. I’ll try a parallel 1k as my first step and simulate noise with a few toggles of the shed lights.

TomGeorge:
Hi,
Do you need to detect a LOW or a HIGH to LOW?

void loop()

{
  if (digitalRead(triggerPin) == LOW)
  {



Does not detect a transition.
Please can you post a complete copy of your code and a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

How long are your leads and do you have bypassing on them?

Thanks.. Tom... :)

From my opening post: “triggered by a low-going pulse (5V to 0V)”.

alexs_tech:
Also pay good attention to your shielding. Shielded cables help alot.

I had to instal an ardino powered device very close to a high power AC transformer , it as used to check hmidity , temperature and also had a light sensor inside the space where the transformer was housed.

Although programming workarounds did help, my best bet was going for shielding, nice grounded cables and i also ended up having to make a Faraday shield for the uno itself.

Thanks, but hope I can fix it without such relatively serious measures.