Switching a relay on & off using a momentary push button

Complete beginner here, trying to learn...

I am trying to use a normally closed push button to change the state of a relay each time the button is pushed and released. I'm trying to do this by taking the 'contacts closing' event (on pin 2) to switch power on or off to pin 12. I started with the basic 'Button' sketch and modified it. Here's what I presently have:

// Constants:
const int SwitchPin = 2; // the pin that the switch is attached to
const int RelayPin = 12; // the pin that the relay is attached to

// Variables:
int SwitchState = 0; // current state of the switch
int PreviousSwitchState = 0; // previous state of the switch
int RelayState = 0; // current state of relay pin

void setup() {
// initialize switch pin (2) as an input:
pinMode(SwitchPin, INPUT);
// initialize relay pin (12) as an output:
pinMode(RelayPin, OUTPUT);
// initialize serial communication:
Serial.begin(9600);
}

//Look for switch Off to On event
void loop() {
// read the switch pin (2):
SwitchState = digitalRead(SwitchPin);
// read the relay pin (12):
RelayState = digitalRead(RelayPin);

// compare the SwitchState to its previous state
if (SwitchState != PreviousSwitchState) {

// if the state has changed, check change direction
if (SwitchState == HIGH){
// if the current state is HIGH then the switch
// went from off to on, ie the NC push button was released:

if (SwitchState == LOW)
RelayState = HIGH;

else
RelayState = LOW;}

}
}

The sketch compiles and uploads without problem. I tested my Arduino (a Mega 2560), using Blink, it works fine.

I wired a breadboard as per the attached file (hope this is readable). On opening and then closing the contacts, I expected to see the voltage on pin 12 change from 0 to 5V, or vice versa. Nothing happens - it's always zero.

I tried changing the output to pin 13, hoping to see the on board LED light and then extinguish - this didn't happen either. The problem seems to lie with the code.

Would someone be kind enough to help me out here?

Many thanks,

Ian

Add after this line in setup:

  // initialize switch pin (2) as an input:
  pinMode(SwitchPin, INPUT);
digitalWrite (SwitchPin, HIGH); // enable internal pullup resistor - open switch will now go high

Why is the relay connected to analog pin 12? Analog pins are input only. You can't perform a digitalRead on an analog pin.

You also forgot to put digitalWrite(RelayPin, RelayState); anywhere. Since you never write to it, it stays LOW.

PaulS:
Why is the relay connected to analog pin 12? Analog pins are input only. You can't perform a digitalRead on an analog pin.

Yes, since you are wiring to Analog Input 2 and 12 you need to say that:

// Constants:
const int  SwitchPin = A2;        // the pin that the switch is attached to
const int  RelayPin = A12;        // the pin that the relay is attached to

I'm pretty sure A2 can be used as an digital input/output. Not so sure about A12 since A6 and A7 CANNOT be used for digital I/O on those processors that have 8 analog input pins (surface mount 168/328 processors).

Instead of changing the code to match the wiring it might be easier (and make more sense) to change the wiring to match the code. Move the wires from A2 and A12 to 2 and 12.

Aren't the analog pins something like D54 & up?
So he can read them, they just need to be referenced correctly.

PreviousSwitchState is never updated.

CrossRoads:
Aren't the analog pins something like D54 & up?
So he can read them, they just need to be referenced correctly.

http://arduino.cc/en/Hacking/PinMapping2560

But of course they are. In the MEGA2560, pin A0 is the same as 54, A1==55, etc.

I don't have any use for analog pins so I use them as regular digital I/O pins.

And you can either say:

digitalWrite(A0,HIGH);
or
digitalRead(A0);
digitalWrite(A0,HIGH);

or

digitalWrite(54,HIGH);
or
digitalRead(54);
digitalWrite(54,HIGH);

it doesn't matter. I prefer the latter for using in for loops.

All, many thanks for the help so far; with it, I now have an (almost) working system. The code is now as follows:

// Constants:
const int SwitchPin = 32; // the pin that the switch is attached to
const int RelayPin = 42; // the pin that the relay is attached to

// Variables:
int SwitchState = 0; // current state of the switch
int PreviousSwitchState = 0; // previous state of the switch
int RelayState = 0; // current state of relay pin

void setup() {
// initialise switch pin (32) as an input:
pinMode(SwitchPin, INPUT);

// enable internal pullup resistor - open switch will now go high
//digitalWrite (SwitchPin, HIGH);

// initialise relay pin (42) as an output:
pinMode(RelayPin, OUTPUT);

// initialize serial communication:
Serial.begin(9600);
}

//Look for switch Off to On event
void loop() {

// read the switch pin (32):
SwitchState = digitalRead(SwitchPin);

// read the relay pin (42):
RelayState = digitalRead(RelayPin);

// compare the SwitchState to its previous state
if (SwitchState != PreviousSwitchState) {

// if the state has changed, check change direction
if (SwitchState == HIGH){

// if the current state is HIGH then the switch went from off to on
// instigate a relay state change:

if (RelayState == LOW)
digitalWrite(RelayPin, HIGH);
else
digitalWrite(RelayPin, LOW);}

}
}

I put the line in to enable the pull up resistor, the code didn't work - it only worked when I removed it.

As can be seen, I'm now using digital pins 32 & 42. I changed the physical switch to a normally open push button. On loading the sketch, the LED is off, as I'd expect. I press the button, and the LED comes on. I press the switch again, and - sometimes it goes off, sometimes not - it seems intermittent. I tried just shorting the wires (suspecting a bad switch), same problem. It occasionally works on the first "off" press, sometimes the tenth or so - no apparent pattern.

Worse, it sometimes switches all by itself...

This has me baffled! Common sense tells me to suspect the switch not making contact, yet - after re-uploading the code, the first press to switch the LED on always works.

Could it be a floating pin, still to do with the internal pull up resistor?

Thanks,

Ian

Again...

Arrch:
PreviousSwitchState is never updated.

I presume you are trying to detect the signal edge, yes?

You possible also need contact bounce sorted to make sure you have a nice clean signal to work from.
Search for either hardware or software de-bounce, depending on your choice

Yes, I'm trying to detect a signal edge (or maybe more accurately, a change of switch state from a short open state to closed). I also think that debouncing is the answer - I'm reading up on it right now.

Let me explain what I'm really trying to do.It's a home automation project to control simple on/off room lighting.

The wife isn't at all keen on push buttons, and I'll be fitting conventional switches (normal single pole changeover switches, SPDT) throughout the house to start with. I'd like to reuse these. I'll be running CAT5E cable from every light switch box back to the central hub, for use as signal cabling. What I'm thinking of doing when I automate is to first disconnect the mains power from the light switches, and then reuse the same switches to send a 12V signal back to the Arduino-based control system (there'll be no mains anywhere near the switch from then on). My idea is to connect the 2 switched contacts L1 and L2 of the switch together, such that the switch is on in either position. Run 2 signal cables back to the Arduino, one from the switch's common, the other from the shorted together L1 & L2. Use this to give a constant 5 volt signal to a digital pin, which it will do almost all of the time.

The only time that it won't will be when someone operates the switch, and as they're break before make switches, there should be a very brief interruption of the signal. Use this to trigger an "if off then turn on, or if on then turn off" event to control the power relay. It means that there'll no longer be a relationship between a switch's position (up for on, down for off etc), but this is already the case with dual switch upstairs / downstairs switching - so it shouldn't be a problem.

I don't actually know how long the switch will be in the open position for as it's being switched - I'm guessing in the order of 100ms or so, and I can see that there'll be lots of contact bounce (these are off the shelf DIY store switches, not lab quality ones with unobtanium contacts). But I think all I have to do is capture one 'contacts close' event for the code to work. If debouncing is necessary, then I'd rather do it with software, as any hardware solution would need to be repeated for 30 or more switches.

It means that I get to reuse the old switches, and whichever position they're in, an external source can still be used to switch lights on or off (ie. instigating a mood lighting preset routine) by injecting a short 'off' pulse. It also makes 'upstairs / downstairs' switching easy - just wire the signal cables in series, and any switch being operated will send a break & make signal. No limit to how many switches can be daisy chained in this way - try that with conventional home wiring!

Thanks,

Ian

My experience with standard wall switches and low voltage signals is that you will likely have a few failed switches. Sometimes the work, sometimes they don't.
They are usual copper contacts, often burnt or oxidised, hence don't make for a nice reliable contact at low voltage and mA level.
If you can run a diode, at a minimum ,through the contact, it may be better (20mA) or a load resistor.

No good upsetting the boss :slight_smile:

Kim

Kim,

Good point on the quality of the switches. I'm planning to use a reasonably good make (Crabtree), and I could probably withstand a few failures as they're easy enough to change out - no need to isolate mains power, as there won't be any. Sounds like using a small pre-installation test rig's a good idea, catch the baddies.

Could you elaborate on the diode and load resistor - how do these get wired in, what do they do?

Thanks,

Ian

When turning on an input are you switching to Vcc or Gnd ?