merging button sketches and DS3231 sketches controlling same "LED"

Hello,

I'm trying to write a sketch for an aquarium controller. I basically have most of it running but I'm having a real hard time combining the individual sketches "I" wrote (I mostly plagiarized existing sketches).

The basic concept for the full sketch would be :

  • equipment A controlled by the RTC for on / off period. let's say on from 12.00pm to 8.00pm
  • while the equipment A in On, i would like to have 2 buttons options
    i) button "cleaning" that turn off equipment A when pushed and turn it back on when pushed again.
    ii) button "feeding" that turn off equipment A when pushed and turn it back on after a given time.

I would have more than 1 equipment obviously but I'm keeping things simple for now. Since I can't make it work for one thing!

Hardware used for the RTC is DS3231 and an arduino uno R3 special edition. I have a LEd connected to pin 9 represneting the equipement.

The issue I'm having is merging the two separate sketches.

My "time" sketch (I apologize for my unconventional coding syntax). (skimmer is the equipment name I used.)

#include <DS3231.h>
// Init the DS3231 using the hardware interface
DS3231  rtc(SDA, SCL);
// Init a Time-data structure
Time  t;

// declaring my pin equipment
const int skimmer = 9;    // skimmer is on pin 9

void setup()
{ // Setup Serial connection
  Serial.begin(115200);
  // declaring the equiment:
  pinMode(skimmer, OUTPUT);
  // Initialize the rtc object
  rtc.begin();

  // The following lines can be uncommented to set the date and time
  //rtc.setDOW(WEDNESDAY);     // Set Day-of-Week to SUNDAY
  //rtc.setTime(12, 0, 0);     // Set the time to 12:00:00 (24hr format)
  //rtc.setDate(1, 1, 2014);   // Set the date to January 1st, 2014
}


// setting lights on / off period ( my skimmer is on the same time period)
// declare start time       // declare off time
int lightOnHour = 12;       int lightOffHour = 20;
int lightOnMin = 29;         int lightOffMin = 59;

void lightP () { // managing light on and off, skimmer is on the same timer.
  // converting time to xxxx number ie 1508, this is done to ease time comparison
  // current time conversion
  int tHourNow = t.hour;
  int tMinNow = t.min;
  int tNow = tHourNow * 100 + tMinNow;
  // light on/off time conversion
  int tOn = lightOnHour * 100 + lightOnMin;
  int tOff = lightOffHour * 100 + lightOffMin;

  if ( ((tNow >= tOn) && (tNow < tOff)) ) { // defining the time period when the lights are on
    digitalWrite (skimmer, HIGH);
  }
  else {
    digitalWrite (skimmer, LOW);  // otherwise the lights are off
  }      
}


// function that print time in serial monitor.
void printingTime() {
  // printing time on serial monitor
  Serial.print(t.hour, DEC);
  Serial.print(":");
  Serial.print(t.min, DEC);
  Serial.print(":");
  Serial.print(t.sec, DEC);
  Serial.println(" ");
}

void loop() {
  // Get data from the DS3231 , real time clock
  t = rtc.getTime();
  // calling the printing time function
  printingTime();
  // running the different function
  lightP();
}

And this the the code for the 2 push buttons. The behavior isn't exactly what I would have expected but it works close enough. ( sorry again for my coding syntax.)

// declaring my pin equipement
const int skimmer = 9;    // skimmer is on pin 9
const byte feedingButton = 4; // our button pin
const int cleaningButton = 2; // cleaning button connected to pin 2

void setup()
{
  // Setup Serial connection
  Serial.begin(115200);

  // declaring the equiment:
  pinMode(skimmer, OUTPUT);
  pinMode(feedingButton, INPUT); // push button declared as input
  pinMode(cleaningButton, INPUT); // push button declared as input

  // having the skimmer HIGH, this is used to check program without the clock running
  digitalWrite( skimmer, HIGH);
}

//start of the feeding function
// declaring the feeding button variable
unsigned long feedingPushedMillis;  // when button was released
unsigned long feedingStartedAt;  // when feeding started
unsigned long feedingDelay = 5000; // how long is the feeding ( filter , skimmer powered off)
unsigned long feedingOffDelay = 50; // debouncing time
bool feedingReady = false; // flag for when button is let go
bool feedingState = false; // for feeding state on or not.

// end of the feeding variables
void feedingP () {
  unsigned long currentMillis = millis();
  // check the button
  if (digitalRead(feedingButton) == HIGH) {
    // update the time when button was pushed
    feedingPushedMillis = currentMillis;
    feedingReady = true; // allow to go through the next if loop when the button is released.
  }

  // make sure this code isn't checked until after button has been let go
  if (feedingReady) {
    //this is typical millis code here:
    if ((currentMillis - feedingPushedMillis) >= feedingOffDelay) {
      // okay, enough time has passed since the button was let go.
      digitalWrite(skimmer, LOW);
      // setup our next if loop
      feedingState = true;
      // save when the equipement was turned off
      feedingStartedAt = currentMillis;
      // wait for next button press, exit this if loop
      feedingReady = false;
    }
  }
  // see if we are watching for the time to turn off LED
  if (feedingState) {
    // okay, led on, check for now long
    if ((currentMillis - feedingStartedAt) >= feedingDelay) {
      feedingState = false;
      digitalWrite(skimmer, HIGH);
    }
  }
}

// declaring the cleaning button variable
int cleaningState ; // for cleaning state true or false
int cleaningButtonState ; //  read the state of the button
int lastCleaningButtonState = LOW; // last reading from input pin
unsigned long lastCleaningTime = 0;
unsigned long cleaningDelay = 50;

void cleaningP () {
  // read the state of the switch into a local variable
  int cleaningReading = digitalRead(cleaningButton);
  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH),  and you've waited
  // long enough since the last press to ignore any noise:
  // If the button state changed, due to noise or pressing:
  if (cleaningReading != lastCleaningButtonState) {
    lastCleaningTime = millis();      // reset the debouncing timer
  }
  if ((millis() - lastCleaningTime) > cleaningDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    if (cleaningReading != cleaningButtonState) {     // if the button state has changed:
      cleaningButtonState = cleaningReading;
      if (cleaningButtonState == HIGH) {  // only change equipment on off if the new button state is HIGH
        cleaningState = !cleaningState;
        // set the equipement
        digitalWrite(skimmer, cleaningState);
      }
    }
  }
  // save the reading.  Next time through the loop,
  // it'll be the lastCleaningButtonState:
  lastCleaningButtonState = cleaningReading;
}


void loop() {
  // running the different function
  feedingP();
  cleaningP();
}

When moving the button function ( with variables) to the time function, the button are render inactive. I also declare the push button in the void setup(). pushing the button does not turn off the LED. Looking around it seems that I should be using some sort of "state machine" but I have no clue where to start. is state machine the right way to go? A little guidance would be appreciated. The above sketches took me 1 months to"figure" out. Complete newbie here ....

Hopefully I didn't bored you guys to deaf and might get some pointers...

Thanks.

I suspect that what's happening (although you didn't post the combined code) is that although you might be checking the buttons in feedingP() and cleaningP(), and switching the skimmer on, when lightP() runs it turns them straight off again based on the time of day.

You could try a boolean flag, called say buttonOverride, and set it true in feedingP() and cleaningP() when either turns the skimmer on. Then use that flag's state to control if lightP() should turn the skimmer off, with the flag being set in feedingP() or cleaningP() taking priority. Remember to set it back to false when feedingP() and cleaningP() have done what they do.

(Very off the top of my head, YMMV.)

:o
Well I guess I just needed to start a thread to make it "work"!!
Thanks to manor_royal for the pointer. I always tried to create 2 separates Boolean statement for each button status, never though of using one for both ...

I still have some conflicts on my buttons(if i push one buttoncleaning and then the buttonfeeding , i'm getting some strange behavior...).... but that's enough success for one day :slight_smile:

Here is the complete code that work ok as long as I don't mix the button push...

/*  this is a program that contain 2 push buttons
     - one button create a feeding session of xxx minutes where selected equipment are turn off
     - one button is used to turn off selected equipement and when pushed again will turn
       the equipement back on.

     This is using a DS3231 for the time contol.
*/
#include <DS3231.h>
// Init the DS3231 using the hardware interface
DS3231  rtc(SDA, SCL);
// Init a Time-data structure
Time  t;

// declaring my pin equipement
const int skimmer = 9;           // skimmer is on pin 9
const byte feedingButton = 4;    // our button pin
const int cleaningButton = 2;    // cleaning button connected to pin 2
boolean buttonOverride = false;  // this command is true if either the feeding or the cleaning function are running
// when the value is false, the light function run by default
void setup()
{
  // Setup Serial connection
  Serial.begin(115200);

  // declaring the equiment:
  pinMode(skimmer, OUTPUT);
  pinMode(feedingButton, INPUT); // push button declared as input
  pinMode(cleaningButton, INPUT); // push button declared as input

  // Initialize the rtc object
  rtc.begin();

  // The following lines can be uncommented to set the date and time
  //rtc.setDOW(WEDNESDAY);     // Set Day-of-Week to SUNDAY
  //rtc.setTime(12, 0, 0);     // Set the time to 12:00:00 (24hr format)
  //rtc.setDate(1, 1, 2014);   // Set the date to January 1st, 2014
}
/*  **************************************************************************************  */
/*  **************************************************************************************  */
// setting lights on / off period ( my skimmer is on the same time period)
// declare start time       // declare off time
int lightOnHour = 12;       int lightOffHour = 22;
int lightOnMin = 29;         int lightOffMin = 59;

void lightP () { // managing light on and off, skimmer is on the same timer.
  // converting time to xxxx number ie 1508, this is done to ease time comparison
  // current time conversion
  int tHourNow = t.hour;
  int tMinNow = t.min;
  int tNow = tHourNow * 100 + tMinNow;
  // light on/off time conversion
  int tOn = lightOnHour * 100 + lightOnMin;
  int tOff = lightOffHour * 100 + lightOffMin;

  if ( ((tNow >= tOn) && (tNow < tOff)) ) { // defining the time period when the lights are on
    digitalWrite (skimmer, HIGH);
  }
  else {
    digitalWrite (skimmer, LOW);  // otherwise the lights are off
  }
}
/*  **************************************************************************************  */
/*  **************************************************************************************  */
//start of the feeding function
// declaring the feeding button variable
unsigned long feedingPushedMillis;  // when button was released
unsigned long feedingStartedAt;  // when feeding started
unsigned long feedingDelay = 5000; // how long is the feeding ( filter , skimmer powered off)
unsigned long feedingOffDelay = 50; // debouncing time
bool feedingReady = false; // flag for when button is let go
bool feedingState = false; // for feeding state on or not.

// end of the feeding variables
void feedingP () {
  unsigned long currentMillis = millis();
  // check the button
  if (digitalRead(feedingButton) == HIGH) {
    // update the time when button was pushed
    feedingPushedMillis = currentMillis;
    feedingReady = true; // allow to go through the next if loop when the button is released.
  }

  // make sure this code isn't checked until after button has been let go
  if (feedingReady) {
    //this is typical millis code here:
    if ((currentMillis - feedingPushedMillis) >= feedingOffDelay) {
      // okay, enough time has passed since the button was let go.
      digitalWrite(skimmer, LOW);
      // setup our next if loop
      feedingState = true;
      // save when the equipement was turned off
      feedingStartedAt = currentMillis;
      // wait for next button press, exit this if loop
      feedingReady = false;
      buttonOverride = !buttonOverride; // set the button override to true to disable lightP
    }
  }
  // see if we are watching for the time to turn off LED
  if (feedingState) {
    // okay, led on, check for now long
    if ((currentMillis - feedingStartedAt) >= feedingDelay) {
      feedingState = false;
      digitalWrite(skimmer, HIGH);
      buttonOverride = !buttonOverride; // set the button override to fasle to enable lightP
    }
  }
}

/*  **************************************************************************************  */
/*  **************************************************************************************  */
// declaring the cleaning button variable
int cleaningState ; // for cleaning state true or false
int cleaningButtonState ; //  read the state of the button
int lastCleaningButtonState = LOW; // last reading from input pin
unsigned long lastCleaningTime = 0;
unsigned long cleaningDelay = 50;

void cleaningP () {
  // read the state of the switch into a local variable
  int cleaningReading = digitalRead(cleaningButton);
  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH),  and you've waited
  // long enough since the last press to ignore any noise:
  // If the button state changed, due to noise or pressing:
  if (cleaningReading != lastCleaningButtonState) {
    lastCleaningTime = millis();      // reset the debouncing timer
  }
  if ((millis() - lastCleaningTime) > cleaningDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    if (cleaningReading != cleaningButtonState) {     // if the button state has changed:
      cleaningButtonState = cleaningReading;
      if (cleaningButtonState == HIGH) {  // only change equipement on off if the new button state is HIGH
        cleaningState = !cleaningState;
        // set the equipement
        digitalWrite(skimmer, cleaningState);
        buttonOverride = ! buttonOverride; // set the button override to true and then back
        // to false to disable/enable lightP
      }
    }
  }
  // save the reading.  Next time through the loop,
  // it'll be the lastCleaningButtonState:
  lastCleaningButtonState = cleaningReading;
}

void loop() {
  // running the different function
  feedingP();
  cleaningP();
  if (buttonOverride != true) {
    lightP();
  }
}