Momentary switch with latching code

Hello,

I've been doing simple things with the arduino but I'm having a few problems some code for a momentary switch and I'm not sure how to "latch" the code so it doesn't continue switching a relay when the switch is held.

Here is what I'm trying to achieve:

When the momentary switch is pressed, I need the LED to light (uno led on pin 13) and the relay to switch. When pressed again the LED should turn off and the relay switch back. I'm using a dual latching relay that has a current pulse requirement of around 20mA @5V. WIth the code I posted below the relay is switching via a short pulse on a high and low pin and the led is lighting. The problem is that the LED and relay continue to change status when the switch is held. I need it to stop switching and retain the status if the switch is held by accident. Right now it will flip a few times on one short push. It's also slightly erratic, sometimes it doesn't register the switch. Also, I'm using an external pull up resistor, not the uno's internal pull up.

Thanks for any assistance!

/* 
 Alternating LED and relay switching
 */

#include <Bounce.h>

const int inputPin = 2;      // momentary switch
const int ledPin =  13;      // the number of the LED pin
const int relayPin1 =  12;   // relay +
const int relayPin2 = 11;    // relay -

int ledState = LOW;           // the current state of the output pin
int lastbuttonState = LOW;   // the previous reading from switch

Bounce bouncer = Bounce(inputPin,75);   //setting up debounce for the push button

void setup() 
{
  pinMode(inputPin, INPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(relayPin1, OUTPUT);
  pinMode(relayPin2, OUTPUT);
}

void loop() {

  bouncer.update ( );    // Update the debouncer for the push button

  int value = bouncer.read();     // Get the update value

  int reading = value == HIGH;

  if (lastbuttonState == LOW && reading == HIGH) 
  {
    digitalWrite (ledPin, HIGH);
    digitalWrite (relayPin2, LOW);
    digitalWrite (relayPin1, HIGH);
    delay (100);
    digitalWrite (relayPin1, LOW);
  }
bouncer.update ( );    // Update the debouncer for the push button

int val = bouncer.read();     // Get the update value

  int read = val == HIGH;
  
 if (lastbuttonState == LOW && read == HIGH) 
  {
    digitalWrite (ledPin, LOW);
    digitalWrite (relayPin1, LOW);
    digitalWrite (relayPin2, HIGH);
    delay (100);
    digitalWrite (relayPin1, LOW);
  }
}

I Haven't read the full code but the following pops out:

  • The following line is bit strange: * int reading = value == HIGH;*
  • in the second block i see two times in a row : digitalWrite (relayPin1, LOW);
  • When is 'lastbuttonState' made high in the code

Thanks, it should have been digitalWrite(relayPin2, LOW) but it's still acting the same.

The switch sometimes switches the led and relay and sometimes it does not. I don't know if it's the way I have the debounce code/library written or not. But if I hold the switch it cycles the relay and LED. I need it to "latch"

Without int reading = value == HIGH; the code does not work

Here is the updated code

/* 
 Alternating LED's
 */

#include <Bounce.h>

const int inputPin = 2;    // momentary switch
const int ledPin =  13;      // the number of the LED pin
const int relayPin1 =  12;
const int relayPin2 = 11;

int ledState = LOW;           // the current state of the output pin
int lastbuttonState = LOW;   // the previous reading from first push button pin

Bounce bouncer = Bounce(inputPin,75);   //setting up debounce for the first push button

void setup() 
{
  pinMode(inputPin, INPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(relayPin1, OUTPUT);
  pinMode(relayPin2, OUTPUT);
}

void loop() {

  bouncer.update ( );    // Update the debouncer for the push button

  int value = bouncer.read();     // Get the update value

  int reading = value == HIGH;

  if (lastbuttonState == LOW && reading == HIGH) 
  {
    digitalWrite (ledPin, HIGH);
    digitalWrite (relayPin2, LOW);
    digitalWrite (relayPin1, HIGH);
    delay (500);
    digitalWrite (relayPin1, LOW);
  }
bouncer.update ( );    // Update the debouncer for the push button

int val = bouncer.read();     // Get the update value

  int read = val == HIGH;
  
 if (lastbuttonState == LOW && read == HIGH) 
  {
    digitalWrite (ledPin, LOW);
    digitalWrite (relayPin1, LOW);
    digitalWrite (relayPin2, HIGH);
    delay (500);
    digitalWrite (relayPin2, LOW);
  }
}

See if you can follow the following, it has a statemachine (switch-case) that 'walks' through the stages of how the system should behave.
Its a common way to code these types of things

State/Case 0: the system is OFF and in rest, we are waiting for someone to push a button.
If someone pushes button we switch on Relay and led and go to the next state
State/case 1: here we wait untill the button is released
if button is released we go to the next state.
State/case 2: here the system is ON and we are in rest, we are waiting for someone to push button

...etc....

/*  Alternating LED's  */
#include <Bounce.h>

const int inputPin = 2;    // momentary switch
const int ledPin =  13;      // the number of the LED pin
const int relayPin1 =  12;
const int relayPin2 = 11;

byte mode = 0;

Bounce bouncer = Bounce(inputPin,75);   //settup debounce for first push button

void setup() 
{ pinMode(inputPin, INPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(relayPin1, OUTPUT);
  pinMode(relayPin2, OUTPUT);
}

void loop() {
  bouncer.update ( );    // Update the debouncer for the push button
  switch( mode )
  {
    case 0://------------------------ I'm off and in restmode
      if ( bouncer.read() == HIGH )
      { // switch relay ON
        // switch LED ON
        mode = 1;
      }
      break;
    case 1://------------------------ I'm in ON mode, w8 4 keyrelease
      if ( bouncer.read() == LOW )
        mode = 2;
      break;
    case 2://------------------------ I'm ON and in restmode
      if ( bouncer.read() == HIGH )
      { // switch relay OFF
        // switch LED OFF
        mode = 3;
      }
      break;
    case 3://------------------------ I'm in OFF mode, w8 4 keyrelease
      if ( bouncer.read() == LOW )
        mode = 0;
      break;
  }//switch


}//loop

Code is untested and the case gives you the framework, still need to fill in the Relay ON/OFF and LED On/OFF

Thanks so much for the help. I'll plug in the missing pieces and try it out!

:slight_smile:

Got it, works perfect. Thank you for steering me in the correct direction. I looked into switch cases much deeper and it certainly helped fill in some of the gaps of my newbie knowledge.

Thanks again for your help.

no prob's glad to help.

Nice work astro. Karma bump.

Hey There,

I am a newbie to arduino and am trying to accomplish the same problem. This is an awesome case statement code, but is not working as anticipated. I am using the same 5V relay with 20mA switching current.

Could you post the updated code used? I know it has been a year since this thread was active but if you still have it saved I would greatly appreciate it.

Thanks!

@cterjesen, can you describe what you are trying to do?

If you just want to press a button and have a relay stay on for a specified time something like this should work (not tested)

unsigned long relayDuration = 5000;  // number of millisecs - adust to suit
unsigned long relayStartMillis = 0;
byte switchVal = HIGH;
boolean relayOn = false;
byte switchPin = 8;
byte relayPin = 9;

void setup() {
   pinMode(switchPin, INPUT_PULLUP);  // pin will be HIGH when switch is open
   pinMode(relayPin, OUTPUT);
   digitalWrite(relayPin, LOW); // assume LOW = off
}

void loop() {
   readPin();
   operateRelay();
}

void readPin() {
  switchVal = digitalRead(switchPin);
}

void operateRelay() {
   if (relayOn == false) {
      if (switchVal == HIGH) {
          relayStartMillis = millis();
          digitalWrite(relayPin, HIGH);
          relayON = true;
      }
   }
  else {   // this happens if relayON == true
      if (millis() - relayStartMills >= relayDuration) {     // time has expired
           digitalWrite(relayPin, LOW);
           relayON = false;
       }
   }
}

...R

Hey Robin2,

Thanks for the quick reply!

Here is my situation: I am using a single coil DPDT latching relay to switch between 2 audio signals. I would like to control the relay with a momentary switch that sends a quick pulse to the relay.

The ultimate goal is to program an ATtiny85 to switch the relay. I understand that I need a transistor network to increase current to switch the relay because like the Arduino Uno, the ATtiny85 has a max current output of only 20mA. The relay needs around 30mA to switch. I have been trying it with a 2n3904 transistor and have been having luck switching the relay but not being able to switch it back. Here is the data sheet for the AL-5WN-K relay that I am using:

http://www.fujitsu.com/downloads/MICRO/fcai/relays/a.pdf

This page has helped me clarify how to operate a single coil relay with an Arduino but a quick glance at the schematic shows that current will only flow in one direction.

I greatly appreciate your help Robin2!

cterjesen:
a quick glance at the schematic shows that current will only flow in one direction.

Why would you want it to flow in 2 directions?

It sounds like you don't have a problem with code (so maybe I have been wasting my time) and that your problem is with the transistor connection. That's not my specialty.

It probably would have made more sense if you had started your own Thread with a title that reflects your own problem. You could still do that. Just include a link to this for continuity.

...R

The relay is a single coil DPDT latching relay. If the current flows in 1 direction, the relay switches. Visa versa.

The code you provided almost worked but I cannot figure out how to tweak. My digital in on pin 8 (the switch) and my relay pins are on pin 2 and 3. Here is what I need to happen:

Switch is press (pin 8 reads a signal)

Pin 2 == High
Pin 3 == Low

this only needs to be a short pulse then

Pin 2 == Low
Pin 3 == Low

Until the button is pressed again THEN

Pin 2 == LOW
Pin 3 == HIGH

again, this only needs to be a small pulse.

I am very new to arduino but I understand this is what has to happen. Could you help me write this out?

I am a little concerned by your requirement to change the state of two pins to drive one relay. I hope you are not expecting the Arduino pins to provide the full current for the relay coil. Can you draw a wiring diagram for your project and post a photo of the drawing?

As to the code (assuming you do need to control 2 pins) ...

Where my code in the function operateRelay() has digitalWrite(relayPin, HIGH); you could just add another line so it looks like

digitalWrite(relayPin, HIGH);
digitalWrite(relayPin2, LOW);

...R

fishlim123:
hi, may i ask you some question? Arduino R3 got code for timer???if got can you show me??thanks~~

As this is a new question, please start your own Thread - you will get help much more easily that way.

...R

Edit to add - it looks like someone deleted something I replied to.

Problems with holding a momentary switch for an extended time is the debounce period could time out, the debouncer may not work on both rising and falling conditions, the switch may not be tactile or spring type and rely on finger pressure only and the input signal may be weak or noisy.

Had a bit of time, so I merged some code I've done previously with some of the code from here.
This is untested with relay ... an output buffer or relay driver push-pull circuit is required to handle the relay coil's current.

The user can press the button for any length of time (even using a jumper wire as a switch by touching to ground will not give false readings). The print monitor will show relay status.

/*-----------------------------------------------
 One Momentary Switch Toggles Latching Relay
 Print monitor shows relay contact status.
 Unique debounce/filter/register prevents false
 operation and does not use timeouts for reading.
 ------------------------------------------------*/

// constants
const byte inputPin = 2;         // momentary switch
const byte ledPin = 13;          // LED pin
const byte relayPin1 =  12;      // relay coil +
const byte relayPin2 = 11;       // relay coil -
const byte impulsePeriod  = 10;  // relay coil impulse period in milliseconds

// variables
byte inputState; // bit register for storing 8 previous input readings
boolean inputRead = HIGH;
boolean inputReadPrevious = HIGH;
boolean relayState = HIGH;
unsigned long microsStart = 20000;

void setup() {
  Serial.begin(9600);
  Serial.println ("RELAY STATUS");
  pinMode(inputPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
  pinMode(relayPin1, OUTPUT);
  pinMode(relayPin2, OUTPUT);
  inputState = 0xFF;
}

void loop() {
  inputReadPrevious = inputRead;
  inputFilter();
  if (inputRead == LOW && inputReadPrevious == HIGH)
  {
    if (relayState == HIGH) {
      digitalWrite (ledPin, HIGH);
      digitalWrite (relayPin2, LOW);
      digitalWrite (relayPin1, HIGH);
      delay (impulsePeriod);
      digitalWrite (relayPin1, LOW);
      Serial.println ("Relay Reset");
    }
    else if (relayState == LOW) {
      digitalWrite (ledPin, LOW);
      digitalWrite (relayPin1, LOW);
      digitalWrite (relayPin2, HIGH);
      delay (impulsePeriod);
      digitalWrite (relayPin2, LOW);
      Serial.println ("Relay Set");
    }
    relayState = !relayState; // toggle
  }
}

void inputFilter(void) {
  if (micros() - microsStart >= 10000) // minimum 10ms interval between bounces
  {
    inputState = (inputState << 1) | digitalRead(inputPin); // shift and read
    if ((inputState & B11111) == B01111) // if rising and high for 3 stable reads
    {
      inputRead = HIGH;
    }
    if ((inputState & B11111) == B10000) // if falling and low for 3 stable reads
    {
      inputRead = LOW;
    }
    microsStart = micros();
  }
}