Turn relay on with switch and off with different switch

Hi
My Coke machine control board died after a lightning strike.
I'm programming 6 relays to engage 6 motors to dispense sodas. I'm looking for ideas to program the controls.

I need the relay to engage when a button is pressed and disengage when a different switch is engaged. I also want to make sure that only one relay can be engaged at a time.

Thanks,

That sounds reasonably straight forward. The Thread planning and implementing a program may give you some ideas about getting your project underway.

Your program will need to keep track of the state of your machine - for example which motor is working. It will then be easy to use any collection of switches to change to a different state and to prevent inappropriate changes.

...R

You can achieve that with two SPDT switchs. No processing required.

Thanks for the redirect Robin2, that looks like a good place to get started. I'm new to the programming side of this.

KenF, The coke machine is a little more complicated then that. The push button to dispense a can activates a motor that has 4 different and adjustable stops to properly dispenses a can.

I can do this with no programming and several relays, including a self holding relay. I drew this up, but had not got around to building it. I thought it would be fun to use the Arduino.

madodds:
I can do this with no programming and several relays, including a self holding relay. I drew this up, but had not got around to building it. I thought it would be fun to use the Arduino.

That's as good a reason as any :slight_smile:

I have a code that works. My only problem is if someone presses and holds the button it will keep dispensing sodas until they let go. I want the button to only dispense 1 soda at a time.

I have looked at the code that counts the number of buttons pushed, but was wondering if there was something easier.

Is there an easy solution?

Look at the entry for button 1, the other buttons are the same.

Thanks

/*
Relay control for Coke machine
When Button_1 is pushed it will engage relay_1
Relay_1 will stay engaged a minimum of 1000 mSec (to make sure motor turns enough to disengage Motor position switch)
Relay_1 will stay engaged until Motor_1 Position switch is closed
There is a total of 6 buttons
Code will only allow one relay to be engaged at a time.
Motor position switch is closed when can is dispensed, and open when motor is turning.
Motor runs at 115VAC and 2.5 Amps
*/

#define RELAY_ON 0
#define RELAY_OFF 1

// Relay Digital output pin numbers
#define Relay_1 1
#define Relay_2 2
#define Relay_3 3
#define Relay_4 4
#define Relay_5 5
#define Relay_6 6

// Button ( Digital input pin numbers
#define Button_1 7
#define Button_2 8
#define Button_3 9
#define Button_4 10
#define Button_5 11
#define Button_6 12

#define Motor_1 A0
#define Motor_2 A1
#define Motor_3 A2
#define Motor_4 A3
#define Motor_5 A4
#define Motor_6 A5

void setup() /****** SETUP: RUNS ONCE ******/
{
//-------( Initialize Pins so relays are inactive at reset)----
digitalWrite(Relay_1, RELAY_OFF);
digitalWrite(Relay_2, RELAY_OFF);
digitalWrite(Relay_3, RELAY_OFF);
digitalWrite(Relay_4, RELAY_OFF);
digitalWrite(Relay_5, RELAY_OFF);
digitalWrite(Relay_6, RELAY_OFF);

//---(set pins as outputs )----
pinMode(Relay_1, OUTPUT);
pinMode(Relay_2, OUTPUT);
pinMode(Relay_3, OUTPUT);
pinMode(Relay_4, OUTPUT);
pinMode(Relay_5, OUTPUT);
pinMode(Relay_6, OUTPUT);

//---(set pins as Inputs with pull up resistor)----
pinMode(Button_1, INPUT_PULLUP);
pinMode(Button_2, INPUT_PULLUP);
pinMode(Button_3, INPUT_PULLUP);
pinMode(Button_4, INPUT_PULLUP);
pinMode(Button_5, INPUT_PULLUP);
pinMode(Button_6, INPUT_PULLUP);

pinMode(Motor_1, INPUT_PULLUP);
pinMode(Motor_2, INPUT_PULLUP);
pinMode(Motor_3, INPUT_PULLUP);
pinMode(Motor_4, INPUT_PULLUP);
pinMode(Motor_5, INPUT_PULLUP);
pinMode(Motor_6, INPUT_PULLUP);

delay(4000); //Check that all relays are inactive at Reset

}//--(end setup )---

void loop() /****** LOOP: RUNS CONSTANTLY ******/
{
int buttonVal_1 = digitalRead(7);
int buttonVal_2 = digitalRead(8);
int buttonVal_3 = digitalRead(9);
int buttonVal_4 = digitalRead(10);
int buttonVal_5 = digitalRead(11);
int buttonVal_6 = digitalRead(12);

int motorVal_1 = digitalRead(A0);
int motorVal_2 = digitalRead(A1);
int motorVal_3 = digitalRead(A2);
int motorVal_4 = digitalRead(A3);
int motorVal_5 = digitalRead(A4);
int motorVal_6 = digitalRead(A5);

//--- (Button 1) ---
if (buttonVal_1 == LOW) // Button 1 pushed
{digitalWrite(Relay_1, RELAY_ON); // Relay engaged
delay(1000); // let motor turn enough to disengage motor switch
while(digitalRead(Motor_1) == HIGH) // As long as motor switch is disengaged keep relay engaged
digitalWrite(Relay_1, RELAY_ON);}
else {
digitalWrite(Relay_1, RELAY_OFF);} // turn relay off

//--- (Button 2) ---
if (buttonVal_2 == LOW)
{digitalWrite(Relay_2, RELAY_ON);
delay(1000);
while(digitalRead(Motor_2) == HIGH)
digitalWrite(Relay_2, RELAY_ON);}
else {
digitalWrite(Relay_2, RELAY_OFF);}

//--- (Button 3) ---
if (buttonVal_3 == LOW)
{digitalWrite(Relay_3, RELAY_ON);
delay(1000);
while(digitalRead(Motor_3) == HIGH)
digitalWrite(Relay_3, RELAY_ON);}
else {
digitalWrite(Relay_3, RELAY_OFF);}

//--- (Button 4) ---
if (buttonVal_4 == LOW)
{digitalWrite(Relay_4, RELAY_ON);
delay(1000);
while(digitalRead(Motor_4) == HIGH)
digitalWrite(Relay_4, RELAY_ON);}
else {
digitalWrite(Relay_4, RELAY_OFF);}

//--- (Button 5) ---
if (buttonVal_5 == LOW)
{digitalWrite(Relay_5, RELAY_ON);
delay(1000);
while(digitalRead(Motor_5) == HIGH)
digitalWrite(Relay_5, RELAY_ON);}
else {
digitalWrite(Relay_5, RELAY_OFF);}

//--- (Button 6) ---
if (buttonVal_6 == LOW)
{digitalWrite(Relay_6, RELAY_ON);
delay(1000);
while(digitalRead(Motor_6) == HIGH)
digitalWrite(Relay_6, RELAY_ON);}
else {
digitalWrite(Relay_6, RELAY_OFF);}

}//--(end main loop )---

madodds:
I need the relay to engage when a button is pressed and disengage when a different switch is engaged. I also want to make sure that only one relay can be engaged at a time.

Thanks,

Start stop buttons, a relay with interlocks.

Never amazes me how everyone needs to control simple operations with a microcontroller.

My goodness you're making hard work of this. Why don't you introduce some arrays into that code.

As a suggestion, you could dispense a drink ONLY once a button has been pressed and then released.

You could also simplify your code by splitting off the dispensing operation as a separate function.

Obviously I don't have your hardware (and don't totally understand the logic of your motor control). But here's an idea of what your code could look like.

/*
Relay control for Coke machine
When Button_1 is pushed it will engage relay_1
Relay_1 will stay engaged a minimum of 1000 mSec (to make sure motor turns enough to disengage Motor position switch)
Relay_1 will stay engaged until Motor_1 Position switch is closed
There is a total of 6 buttons
Code will only allow one relay to be engaged at a time.
Motor position switch is closed when can is dispensed, and open when motor is turning.
Motor runs at 115VAC and 2.5 Amps
*/


#define RELAY_ON 0
#define RELAY_OFF 1

const byte RELAY[6]={1,2,3,4,5,6};
const byte BUTTON[6]={7,8,9,10,11,12};
const byte MOTOR[6]= {A0,A1,A2,A3,A4,A5};

//used to store previous states of buttons
bool buttonPrev[6];


void setup()   /****** SETUP: RUNS ONCE ******/
{
//-------( Initialize Pins so relays are inactive at reset)----

for (int n=0;n<6;n++)
  {
   digitalWrite(RELAY[n], RELAY_OFF);
   pinMode(RELAY[n], OUTPUT);
   pinMode(BUTTON[n], INPUT_PULLUP);
   pinMode(MOTOR[n], INPUT_PULLUP);
   buttonPrev[n]=HIGH;
  }
 delay(4000); //Check that all relays are inactive at Reset

}//--(end setup )---

void loop()   /****** LOOP: RUNS CONSTANTLY ******/
{
int buttonVal;

//loop through all buttons
for (int n=0; n<6; n++)
  {
  buttonVal = digitalRead(BUTTON[n]);
  if (buttonVal ==LOW) 
    delay(50);//debounce button
  //if a button has just been released
  if( (buttonVal==HIGH) && (buttonPrev[n]==LOW) )
    dispense (n);
  buttonPrev[n]=buttonVal;
  }  

}//--(end main loop )---

void dispense (byte itemNo)
{
digitalWrite(RELAY[itemNo], RELAY_ON);      // Relay engaged
delay(1000);                                // let motor turn enough to disengage motor switch
while(digitalRead(MOTOR[itemNo]) == HIGH);  //wait for motor

digitalWrite(RELAY[itemNo], RELAY_OFF);     // turn relay off 
}

"Never amazes me how everyone needs to control simple operations with a microcontroller."

Thanks for the support!
Yes, I can do this without a microcontroller. What is so bad about spending $9 on a relay board and $20 on an Arduino and having some fun. I have enjoyed running through this simple code.
I'm learning and just asking for some advice. I was not looking for someone to piss all over everything.
so again thanks for the support!

Never fails to amaze me that the posts I put the most effort into, get totally ignored. That's life.

Never fails to amaze me that the posts I put the most effort into, get totally ignored. That's life.

Sorry for not replying, but your post is a little more complicated and I'm still trying to figure it out. I can tell that you put time into it, so I’m trying my best to understand it.

Still new to a lot of this.

Thanks. :slight_smile:

KenF

Your code works great! It is also very simple. It is so different from my approach. I have not done the research to understand all aspects of it yet.

thanks again!

madodds:
thanks again!

OK No worries :slight_smile:

I suggest that you don't use pins 0 & 1 as they are used by the USB input to upload your programs. If either is connected to a relay, you may not be able to upload your sketch.

Henry_Best:
I suggest that you don't use pins 0 & 1 as they are used by the USB input to upload your programs. If either is connected to a relay, you may not be able to upload your sketch.

This is a valid point.

You're not currently using pin 13 and this is useable. I wouldn't put a relay on pin 13 though as it gets blipped on boot up. You could move one of your buttons onto pin 13. This would free up a pin that could be used for that relay (that's currently on pin 1).

While you are at it, madodds, read point 7 in this set of instructions and go back and correct where you posted your code.

KenF:
As a suggestion, you could dispense a drink ONLY once a button has been pressed and then released.

The problem with that is when I used to operate some vending machines, I've seen that it's far too common for or people to press and hold the button until they hear that the machine is actually doing something, or even until the soda actually drops out of the machine. Waiting until release will frustrate these people. (There are also those who try to push the button so hard it seems like they want to push it out the back of the machine!)

The key is to not use a "while pressed" metaphor as in the original code. Instead, add some button debounce logic, similar to your version of the code, and act on the stabilized idle-to-active button transition. This triggers the dispense logic, which should not have to worry about the button state. That button will not be considered again until the debounce logic has determined that it was released and stable again. At that point the debounce logic starts to look for a new active transition.

Basically, the debounce logic looks for stable button activations, and when found it sends an event to a dispensing state machine to trigger a new dispense cycle.

ShapeShifter:
The key is to not use a "while pressed" metaphor as in the original code. Instead, add some button debounce logic, similar to your version of the code, and act on the stabilized idle-to-active button transition. This triggers the dispense logic, which should not have to worry about the button state. That button will not be considered again until the debounce logic has determined that it was released and stable again. At that point the debounce logic starts to look for a new active transition.

Basis of my example code:

// Blink without "delay()" - multi!

const int led1Pin =  13;    // LED pin number
const int led2Pin =  10;
const int led3Pin =  11;
const int button1 =  4;
int led1State = LOW;        // initialise the LED
int led2State = LOW;
int led3State = LOW;
char bstate1 = 0;
unsigned long count1 = 0;   // will store last time LED was updated
unsigned long count2 = 0;
unsigned long count3 = 0;
unsigned long bcount1 = 0; // button debounce timer.  Replicate as necessary.

// Have we completed the specified interval since last confirmed event?
// "marker" chooses which counter to check 
boolean timeout(unsigned long *marker, unsigned long interval) {
  if (millis() - *marker >= interval) { 
    *marker += interval;    // move on ready for next interval
    return true;       
  } 
  else return false;
}

// Deal with a button read; true if button pressed and debounced is a new event
// Uses reading of button input, debounce store, state store and debounce interval.
boolean butndown(char button, unsigned long *marker, char *butnstate, unsigned long interval) {
  switch (*butnstate) {               // Odd states if was pressed, >= 2 if debounce in progress
  case 0: // Button up so far, 
    if (button == HIGH) return false; // Nothing happening!
    else { 
      *butnstate = 2;                 // record that is now pressed
      *marker = millis();             // note when was pressed
      return false;                   // and move on
    }

  case 1: // Button down so far, 
    if (button == LOW) return false; // Nothing happening!
    else { 
      *butnstate = 3;                 // record that is now released
      *marker = millis();             // note when was released
      return false;                   // and move on
    }

  case 2: // Button was up, now down.
    if (button == HIGH) {
      *butnstate = 0;                 // no, not debounced; revert the state
      return false;                   // False alarm!
    }
    else { 
      if (millis() - *marker >= interval) {
        *butnstate = 1;               // jackpot!  update the state
        return true;                  // because we have the desired event!
      }
      else 
        return false;                 // not done yet; just move on
    }

  case 3: // Button was down, now up.
    if (button == LOW) {
      *butnstate = 1;                 // no, not debounced; revert the state
      return false;                   // False alarm!
    }
    else { 
      if (millis() - *marker >= interval) {
        *butnstate = 0;               // Debounced; update the state
        return false;                 // but it is not the event we want
      }
      else 
        return false;                 // not done yet; just move on
    }
  default:                            // Error; recover anyway
    {  
      *butnstate = 0;
      return false;                   // Definitely false!
    }
  }
}

void setup() {
  pinMode(led1Pin, OUTPUT);      
  pinMode(led2Pin, OUTPUT);      
  pinMode(led3Pin, OUTPUT);      
  pinMode(button1, INPUT);      
  digitalWrite(button1,HIGH);        // internal pullup all versions
}

void loop() {
  // Toggle LED if button debounced
  if (butndown(digitalRead(button1), &bcount1, &bstate1, 10UL )) {
    if (led1State == LOW) {
      led1State = HIGH;
    }
    else {
      led1State = LOW; 
    } 
    digitalWrite(led1Pin, led1State);
  } 

  // Act if the latter time (ms) has now passed on this particular counter,
  if (timeout(&count2, 300UL )) {
    if (led2State == LOW) {
      led2State = HIGH;
    }
    else {
      led2State = LOW; 
    } 
    digitalWrite(led2Pin, led2State);
  } 

  if (timeout(&count3, 77UL )) {
    if (led3State == LOW) {
      led3State = HIGH;
    }
    else {
      led3State = LOW; 
    } 
    digitalWrite(led3Pin, led3State);
  } 
}

Lots of valid points, lets address them one at a time.

Henry_Best
I suggest that you don't use pins 0 & 1 as they are used by the USB input to upload your programs. If either is connected to a relay, you may not be able to upload your sketch.

KenF
This is a valid point.
You're not currently using pin 13 and this is useable. I wouldn't put a relay on pin 13 though as it gets blipped on boot up. You could move one of your buttons onto pin 13. This would free up a pin that could be used for that relay (that's currently on pin 1).

I initially put a relay on pin 13 and it blipped a lot on startup, so I rearranged my pin locations. I should be able to move a button to 13, but I’m able to upload the sketch and everything is working. Once the sketch is uploaded no more communication is happening, so do I need to change it?

Paul__B
While you are at it, madodds, read point 7 in this set of instructions and go back and correct where you posted your code.

Thanks for information, proper forum edict is always a good thing.

ShapeShifter
The problem with that is when I used to operate some vending machines, I've seen that it's far too common for or people to press and hold the button until they hear that the machine is actually doing something, or even until the soda actually drops out of the machine. Waiting until release will frustrate these people. (There are also those who try to push the button so hard it seems like they want to push it out the back of the machine!)

The key is to not use a "while pressed" metaphor as in the original code. Instead, add some button debounce logic, similar to your version of the code, and act on the stabilized idle-to-active button transition. This triggers the dispense logic, which should not have to worry about the button state. That button will not be considered again until the debounce logic has determined that it was released and stable again. At that point the debounce logic starts to look for a new active transition.

Basically, the debounce logic looks for stable button activations, and when found it sends an event to a dispensing state machine to trigger a new dispense cycle.

I agree with your assessment of people and vending machines. I would prefer the coke machine to immediately dispense a can once the button is pushed.

The good news is, this is in my personnel work shop and the people using it are friends (when working on club members jeeps), and the neighbor kids when I work on their bicycles (the kids love the “free” sodas). I will be present 90% of the time.

I like the code KenF provided. I have not had a chance to review Paul__B’s code yet.
My plan is to install the board (get the machine working again), then add some more programming later. I would like to add a temperature display. In its current state, it will try to dispense soda even when it is empty. I would like the display to say “Sold Out”, when empty. These are not required, but could be fun to add.

Paul__B
Thanks for uploading the code. I have not had a chance to go through it yet, but I will.

Thanks again to everyone for the help and advice.

Here's a plan, rather than have the drink dispensing as soon as the button is pressed, you could, at this point just cause a beep to sound. That should be sufficient feedback to the user that their button press has been noted. Then as they release, the drink gets dispensed.