1

Desired program:

I have 3 momentary push buttons and a 4-channel relay board with my Arduino Uno. The relays are connected to 2 sinks, a shower, and a pump. Each push button should turn the pump and its respective fixture on for 10 seconds. I used a time buffer to debounce the push buttons.

Problem:

The time in which the function stays on is inconsistent. Sometimes 10 seconds, sometimes 3 seconds. Additionally all the relays turn off at the same time even if they were started at different times. they should all be individually timed and the pump should stay on as long as any of the three other relays are on.

Wiring Diagram:

enter image description here

Code:

//initialize and declare variables
// Pins 10,11,12,13 will be connected to their respected relays
const int pump = 13;
const int relay2 = 12;
const int relay3 = 11;
const int relay4 = 10;

//initialize pins 2,3,4 to be connected to the momentary push buttons
const int buttonPin1 = 2; 
const int buttonPin2 = 3; 
const int buttonPin3 = 4;

//these variables track the state of the buttons, low if not pressed, high if pressed
int buttonState1 = LOW; 
int buttonState2 = LOW;
int buttonState3 = LOW;

//Initialize pin states for valve check
int relay2State;
int relay3State;
int relay4State;

long lastDebounceTime = 0; // the last time the output pin was toggled
long debounceDelay = 100; // the debounce time; increase if the output flickers
unsigned long previousMillis = 0;
unsigned long previousMillis2 = 0;
unsigned long previousMillis3 = 0;
unsigned long runTime = 10000;

void setup() {
  //set pins connected to the relays as outputs.
  pinMode(pump, OUTPUT);
  pinMode(relay2, OUTPUT);
  pinMode(relay3, OUTPUT);
  pinMode(relay4, OUTPUT);

  //set push buttons as inputs
  pinMode(buttonPin1, INPUT);
  pinMode(buttonPin2, INPUT);
  pinMode(buttonPin3, INPUT);

  //initialize the starting state of the relay pins
  digitalWrite(pump, HIGH);
  digitalWrite(relay2, HIGH);
  digitalWrite(relay3, HIGH);
  digitalWrite(relay4, HIGH);
} // close void setup

void loop() {
  unsigned long currentMillis = millis();
  unsigned long currentMillis2 = millis();
  unsigned long currentMillis3 = millis();
  //sample the state of the buttons
  buttonState1 = digitalRead(buttonPin1);
  buttonState2 = digitalRead(buttonPin2);
  buttonState3 = digitalRead(buttonPin3);
  //check to see if any valves are open
  relay2State = digitalRead(relay2);
  relay3State = digitalRead(relay3);
  relay4State = digitalRead(relay4);
  //filter out any noise by setting a time buffer
  if ((millis() - lastDebounceTime) > debounceDelay) {
    //sample the state of the buttons
    buttonState1 = digitalRead(buttonPin1);
    buttonState2 = digitalRead(buttonPin2);
    buttonState3 = digitalRead(buttonPin3);
    //check to see if any valves are open
    relay2State = digitalRead(relay2);
    relay3State = digitalRead(relay3);
    relay4State = digitalRead(relay4);
  }

  // if button1 has been pressed, let's toggle the pump and relay2 from off
  //to on for 10 seconds
  if (buttonState1 == HIGH) {
    digitalWrite(relay2, LOW); // turn relay2
    lastDebounceTime = millis(); // set the current time
  }
  if (currentMillis - previousMillis > runTime) {
    digitalWrite(relay2, HIGH); // turn relay2
    previousMillis = currentMillis;
  }
  //if button2 has been pressed, lets toggle the pump and relay3 from off
  //to on for 10 seconds
  if (buttonState2 == HIGH) {
    digitalWrite(relay3, LOW); // turn relay3 on
  }
  if (currentMillis2 - previousMillis2 > runTime) {
    previousMillis2 = currentMillis2;
    digitalWrite(relay3, HIGH); // turn relay3 off
  }
  // if button3 has been pressed, lets toggle the pump and relay4 from off to
  //on for 10 seconds
  if (buttonState3 == HIGH) {
    digitalWrite(relay4, LOW); // turn relay4 on
    lastDebounceTime = millis(); // set the current time
  }
  if (currentMillis3 - previousMillis3 > runTime) {
    previousMillis3 = currentMillis3;
    digitalWrite(relay4, HIGH); // turn relay4 off
  }
  // if any valve is open, turn the pump on
  if(relay2State == LOW || relay3State == LOW || relay4State == LOW) {
    digitalWrite(pump, LOW);
  } else {
    digitalWrite(pump, HIGH);
  }
} // close void loop

Any help would be greatly appreciated. I think I'm stuck in the time buffer for the debounce and my time checks aren't updating right.

3

In a program like this it rapidly becomes quite confusing with the variable names all being so similar. Because of this, this is a good candidate for creating a class to do the job for you. This is because you have sets of functionality and variables that are duplicated to do the same job with different settings (IO pins).

It would be a trivial matter to create a class that turns on an output for a specified amount of time:

class TimedOutput {
    private:
        uint8_t _pin;
        uint32_t _started;
        uint32_t _runtime;
        bool _running;

    public:
        TimedOutput(uint8_t pin, uint32_t runtime) {
            _pin = pin;
            _runtime = runtime;
            _started = 0;
            _running = false;
        }


        void begin() {
            pinMode(_pin, OUTPUT);
            digitalWrite(_pin, LOW);
        }

        void start() {
            digitalWrite(_pin, HIGH);
            _running = true;
            _started = millis();
        }

        void run() {
            if (!_running) return;
            if (millis() - _started >= _runtime) {
                digitalWrite(_pin, LOW);
                _running = false;
            }
        }
};

// Create the object
TimedOutput shower(10, 10000); // Output on pin 10 for 10 seconds
TimedOutput sink(11, 3000);    // Output on pin 11 for 3 seconds

void setup() {
    // Configure the pin
    shower.begin();
    sink.begin();
    pinMode(2, INPUT_PULLUP); // Button
    pinMode(3, INPUT_PULLUP); // Button
}

void loop() {
    // Start it if the button is pressed:
    if (digitalRead(2) == LOW) {
        shower.start();
    }

    if (digitalRead(3) == LOW) {
        sink.start();
    }

    // Do the checking for if it needs to stop:
    shower.run();
    sink.run();
}
  • is there no need to debounce the button in this case? – Nathan H. Aug 30 '17 at 18:04
  • No, not really. Once the output is on its on regardless of what the button does. – Majenko Aug 30 '17 at 18:11
  • the relays start out energized. What would i need to change to have them start deenergized? this would be my last question as this code has helped a ton! – Nathan H. Aug 30 '17 at 18:46
  • Swap the highs and lows in the digitalWrites in the class. – Majenko Aug 30 '17 at 18:47
  • @NathanH. I see your buttons are pull down. You should change INPUT_PULLUP to INPUT and check if the input is HIGH not LOW. – Majenko Aug 30 '17 at 20:32
0

Take a modular approach to it.

For example, break the functionality intwo two pieces.

Readbutton1() returns 1 if and only if button 1 has been pressed and it passed debouncing. There are tons of ways to do that.

Energizerelay1() is called to energize relay number 1 for 10 seconds. Again, there are tons of ways to do that.

Then you can integrate them all together in your loop.

Fairly easy. The key to any programming is to break down a task into individual modules and then reintegrate those modules together to perform the desired the task.

Coding those individual modules is often simple.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.