I am using interrupts to monitor two relays about 300 feet away. I have enabled the internal pull ups and tied the pin to ground through the normally closed contacts on the relay. Interrupt on rising edge. I used millis() to debounce the relay. My problem is that occasionally I get a false trigger. Is this due to the distance of the relay? If so, how do I compensate? The following is my ISR.
I assume you use twisted pair, like cat-5 or cat-6.
If not, you have made a perfect aerial.
If you want fast detection, use a normal open contact.
The closing contact discharges the cable (and cap) faster.
I think a 10-100n to ground and 10k to +5volt will do.
Leo..
Hi,
does the relay have to be that far from the arduino, can you put the relay at the arduino and run the coil wires back to what ever you are connected to?
You may need to increase the voltage to the coil to over come the volt drop due to 600ft of wire.
Worth a try.
Wawa:
I assume you use twisted pair, like cat-5 or cat-6.
If not, you have made a perfect aerial.
If you want fast detection, use a normal open contact.
The closing contact discharges the cable (and cap) faster.
I think a 10-100n to ground and 10k to +5volt will do.
Leo..
It is not a twisted pair...unfortunately I did not choose the cable and I do not have the option to redo it. I have the pull up already and I will try adding the capacitance and switching back to N.O. contacts.
TomGeorge:
Hi,
does the relay have to be that far from the arduino, can you put the relay at the arduino and run the coil wires back to what ever you are connected to?
You may need to increase the voltage to the coil to over come the volt drop due to 600ft of wire.
Worth a try.
Tom.....
I am dealing with an existing installation with restrictions on what I can modify...moving the relays would be great, but it's not an option in this case.
Thank you everyone for your assistance. I will be returning to try these modifications in a couple days and I will report on the results. I will also continue monitoring this thread for any further suggestions. Thanks again.
Regarding the suggested circuit. The components were selected to give 94ms time constant. Reasoning for this is to eliminate contact bounce from the relay (could be 10ms+) and possible 60Hz line pickup (8.3ms full wave or 16.7ms 1/2 wave) or 10-20ms for 50Hz. Do not use the internal pullup as it is too weak and will affect the filter time constant. If faster response is needed, 2.2µF would give approx 44ms time constant on the rising signal. Falling signal time constants are 47ms and 22ms respectively.
Hi,
Fine on the restrictions, can you fit a second relay at the arduino, is speed of response a problem?
Or use an optocoupler at the arduino end, either option will isolate the controller from the long length of wire to the remote input.
TomGeorge:
Hi,
Fine on the restrictions, can you fit a second relay at the arduino, is speed of response a problem?
Or use an optocoupler at the arduino end, either option will isolate the controller from the long length of wire to the remote input.
Tom....
If I can't filter out the noise then I will try isolation. Speed isn't super critical. I'm leaning toward the optocoupler so voltage drop will be less of an issue.
dlloyd:
Regarding the suggested circuit. The components were selected to give 94ms time constant. Reasoning for this is to eliminate contact bounce from the relay (could be 10ms+) and possible 60Hz line pickup (8.3ms full wave or 16.7ms 1/2 wave) or 10-20ms for 50Hz. Do not use the internal pullup as it is too weak and will affect the filter time constant. If faster response is needed, 2.2µF would give approx 44ms time constant on the rising signal. Falling signal time constants are 47ms and 22ms respectively.
Thank you for the graphic and very detailed explanation. I am debouncing for a full 2 seconds in software because the relay will actuate for 1 second and then release and I want to ignore everything except the initial rising/falling edge. I know that with an input as slow as this I could repeatedly poll the pin instead of using interrupts, but when I tried I got the same result(random false triggers). I am looking for noise filter, not necessarily a full debounce circuit.
I probably should have posted my full sketch at the beginning of the thread. Here it is.
#include <EEPROM.h>
const int countUp=11;//increment relay coil output N.O.
const int countDown=10;//decrement relay coil output N.O.
const int powerReset=9;//future use - relay coil output N.C.
const int interrupt0Pin=2;
const int interrupt1Pin=3;
int bounceDuration0=2000;//interrupt0 debounce time
int bounceDuration1=2000;//interrupt1 debounce time
volatile unsigned long lastMillis0=0;//interrupt0 last interrupt time
volatile unsigned long lastMillis1=0;//interrupt1 last interrupt time
volatile unsigned int interruptWaveCount=0;//current wave count, updated in interruptHandler0
unsigned int lastWaveCount=0;//last non-volatile wave count
unsigned int waveCount=0;//stores non-volatile wave count during loops
volatile int interruptResetFlag=0;//reset pressed flag, set to 1 in interruptHandler1
int resetFlag=0;//non-volatile reset flag
int addr=0;//EEPROM address for storing current wave count
byte high=0;//stores high byte of 2 byte value read from memory
byte low=0;//stores low byte of 2 byte value read from memory
unsigned int memValCurrentAddr=0;//used to compare values in different memory addresses
unsigned int memValNextAddr=0;//used to compare values in different memory addresses
//##################################################################
void setup() {
pinMode(4, INPUT);//not used, set as input because ground trace runs across this pin
pinMode(interrupt0Pin, INPUT);
pinMode(interrupt1Pin, INPUT);
digitalWrite(interrupt0Pin,HIGH);
digitalWrite(interrupt1Pin,HIGH);
attachInterrupt(0, interruptHandler0, RISING);//increment input
attachInterrupt(1, interruptHandler1, RISING);//reset input
pinMode(countUp, OUTPUT);
pinMode(countDown, OUTPUT);
pinMode(powerReset, OUTPUT);//future use
digitalWrite(countUp,LOW);//initialize relay to off
digitalWrite(countDown,LOW);//initialize relay to off
digitalWrite(powerReset,LOW);//initialize relay to off
for(int i=0;i<1023;i+=2){//find EEPROM address of last known wave count
high=EEPROM.read(i);
low=EEPROM.read(i+1);
memValCurrentAddr=word(high,low);//current address value
high=EEPROM.read(i+2);
low=EEPROM.read(i+3);
memValNextAddr=word(high,low);//next address value
if(memValCurrentAddr!=memValNextAddr-1){//is next address value == current address value + 1
addr=i;//next address value != current address value + 1, this address contains current wave count
break;//address found, exit for loop
}//if
}//for
high=EEPROM.read(addr);//read high byte of last known wave count
low=EEPROM.read(addr+1);//read low byte of last known wave count
waveCount=word(high,low);//set non-volatile wave count == last known wave count
lastWaveCount=waveCount;
noInterrupts();//no interrupts while working with volatile variable
interruptWaveCount=waveCount;//set volatile wave count == last known wave count
interrupts();
}
//##################################################################
void loop() {
/*Wave count*/
noInterrupts();
waveCount=interruptWaveCount;//set current volatile wave count to non-volatile variable
interrupts();
for(int i=lastWaveCount;i<waveCount;i++){//cycle increment relay and update EEPROM
addr+=2;
if(addr==1024)addr=0;//if last EEPROM address reached, roll over to 0
EEPROM.write(addr,highByte(waveCount));//write high byte of new wave count
EEPROM.write(addr+1,lowByte(waveCount));//write low byte of new wave count
digitalWrite(countUp,HIGH);//turn on increment relay for 1 second
delay(500);
digitalWrite(countUp,LOW);//turn off increment relay
delay(500);//wait in case there were wave counts during reset
}//for
lastWaveCount=waveCount;//set last wave count == current wave count
/*Reset*/
noInterrupts();
resetFlag=interruptResetFlag;//set current reset flag to non-volatile variable
interrupts();
if(resetFlag==1){//if reset input detected, cycles decrement relay == number of increments
for(int i=0;i<waveCount;i++){//cycle decrement relay == current non-volatile wave count
EEPROM.write(addr,0);
EEPROM.write(addr+1,0);
addr-=2;
digitalWrite(countDown,HIGH);
delay(200);
digitalWrite(countDown,LOW);
delay(800);
}//for
noInterrupts();
interruptWaveCount-=waveCount;//waves in reset == current volatile wave count - current non-volatile wave count
interruptResetFlag=0;//set volatile reset flag == 0
interrupts();
resetFlag=0;//set non-volatile reset flag == 0
lastWaveCount=0;//reset last wave count to 0
waveCount=0; //reset non-volatile wave count to 0
addr=0;
}//if
}//loop
//##################################################################
void interruptHandler0(){//increment interrupt handler
if(millis()-lastMillis0>bounceDuration0){// has the debounce time elapsed
interruptWaveCount+=1;//debounce time has elapsed increment volatile wave counter
lastMillis0=millis();//set last interrupt time == current interrupt time
}//if
}//interruptHandler0
void interruptHandler1(){//reset interrupt handler
if(millis()-lastMillis1>bounceDuration1){// has the debounce time elapsed
interruptResetFlag=1;//debounce time has elapsed, set reset flag == 1
lastMillis1=millis();//set last interrupt time == current interrupt time
}//if
}//interruptHandler1
Regarding the circuit, it is 100% a filter that would also eliminate contact bounce and AC pickup. It also dampens noise on the return GND connection.
The problem with generic software debounce, it will sense spontaneous noise, glitches, etc if it occurs before or after the ignore interval. So the first spike that comes along after power up gets sensed, then the software will apply a bounce ignore interval. During this interval, if the spikes keep coming in, they keep interrupting the program flow as the interrupt routine keeps getting called repeatedly. A long debounce interval will not solve this problem. However, a debounce routine that acts as a filter could work, but it will not prevent unwanted interrupts from firing.
Since I have so much time to play with, could I just do a delay and digitalRead inside the ISR to filter out spikes? If the input is still high after the delay then it must be a valid input. Perhaps like this: