0

I am working on a code, which is running a function once a second:

switch (gearbox1) {
  case 1:
    //manually close
    Serial.println("Closing1");
    digitalWrite(gear1OpenPin, OFF);
    t.setTimer(1000, Close1, 1);

    break;

  case 2:
    //manually open
    Serial.println("Opening1");
    digitalWrite(gear1ClosePin, OFF);
    t.setTimer(1000, Open1, 1);

    break;

This part is working fine. But then i want at case 10: call function autoClose() which would work in 10 second cycles.

Struggle is, as my first function is called once a second, it is starting function autoClose() once a second as well. How can I overcome this please?

At the moment I have current, non working code:

  case 10:
    //automatic close
    Serial.println("A Close1"); 
    digitalWrite(gear1ClosePin, OFF);
    digitalWrite(gear1OpenPin, OFF);

    t.enable(autoClose);
    autoClose();
    break;

Edit: Added minimal possible code. I want autoOpen() and autoClose() to loop in 10 sec. intervals.

#include <SimpleTimer.h>
SimpleTimer t;
int gearbox1;

#define gear1OpenPin 44
#define gear1ClosePin 46

int OFF = HIGH;  // states for relays
int ON = LOW;

byte gear1Open = 0;
byte gear1Close = 0;

void setup() {

  t.setInterval(1000, Control1);
  int autoOpen = t.setInterval(10000, autoOpen);
  int autoClose = t.setInterval(10000, autoClose);
}

void loop() {

  t.run();
}

void Control1() {
  //*****************************************
  switch (gearbox1) {
    case 1:
      //manually close
      Serial.println("Closing");
      digitalWrite(gear1OpenPin, OFF);
      t.setTimer(1000, Close1, 1);

      break;

    case 2:
      //manually open
      //   Serial.println("Opening");
      digitalWrite(gear1ClosePin, OFF);
      t.setTimer(1000, Open1, 1);

      break;

    case 5:
      //stop
      Serial.println("Stopping");
      digitalWrite(gear1ClosePin, OFF);
      digitalWrite(gear1OpenPin, OFF);


      break;

    case 10:
      //automatic close

      digitalWrite(gear1ClosePin, OFF);
      digitalWrite(gear1OpenPin, OFF);
      if (t.isEnabled(autoClose)) {
        autoClose();
      } else {
        t.restartTimer(autoClose) ; t.enable(autoClose);
        autoClose();
      }
      break;

    case 20:
      //automatic open

      digitalWrite(gear1ClosePin, OFF);
      digitalWrite(gear1OpenPin, OFF);
      t.restartTimer(autoOpen); t.enable(autoOpen);
      autoOpen();
      break;
 }
}

void Open1() {
  digitalWrite(gear1OpenPin, ON);
}
//**********************************************
void Close1() {
  digitalWrite(gear1ClosePin, ON);
}
//**********************************************
void autoOpen() {

  if (gear1Open == ON) {
    gear1Open = OFF;
  } else {
    gear1Open = ON;
  }
  digitalWrite(gear1OpenPin, gear1Open);
}
//**********************************************
void autoClose() {
  if (gear1Close == ON) {
    gear1Close = OFF;
  } else {
    gear1Close = ON;
  }
  digitalWrite(gear1ClosePin, gear1Close);
}
2
  • 1
    You don't show Auto() function being called at all, yet you state it is starting once per second. Show all your code, or at least a complete working example that demonstrates the problem. Feb 7, 2018 at 15:53
  • Sorry, function is autoClose. And t.enable is part of SimpleTimer library.
    – zarsss
    Feb 7, 2018 at 15:56

1 Answer 1

0

Create a new variable to hold the state of whether or not you are in autoClose mode:

uint8_t inAutoClose=0;

Then, add a line in your switch statement to set that flag when you enter that state, but not call the function if you were already in that state:

case 10:
  //automatic close
  Serial.println("A Close1"); 
  digitalWrite(gear1ClosePin, OFF);
  digitalWrite(gear1OpenPin, OFF);
  if (!inAutoClose) {
    inAutoClose = 1;
    t.enable(autoClose);
    autoClose();
  }
  break;

Add a line in your other switch branches to clear that flag:

case 1:
  //manually close
  inAutoClose = 0;
  [...]

If you want autoClose() to be called every 10 seconds repeatedly as the "idle" state, then you need to clear inAutoClose (set it to zero) at the end of every 10 second period. How and where you do that depends on other factors you haven't shown, like what autoClose() does, or what the timer you enable does.

Side note: avoid naming your timer name (autoClose) and your function name autoClose() the same! Does your code compile that way? It ought to throw an error.

ANSWER 2 (based on comments)

Your auto-close state is described as

Turns on for 10 seconds, after that off for 10 seconds.

This can be accomplished with a similar structure to what you have now, with a few changes. (These are my suggestions, but by no means the best or worst way.)

Edit your open and close functions:

void Open1() {
  digitalWrite(gear1OpenPin, ON);
  if (isAutoOpen) {
    t.setTimeout(10000UL, Close1); // Sets a timer to call closer in 10s
   }
}

void close1() {
  digitalWrite(gearClosePin, ON);
  if (isAutoOpen) {
    t.setTimeout(10000UL, Open1); // Sets a timer to call opener in 10s
  }
}

When you call either Open1() or Close1(), if your auto-open flag is set, then 10s later, the opposite function is called, and this keeps chaining together, every 10s.

Whenever it's time to stop this, you clear the isAutoOpen flag and disable the timers. You may wish to keep track of the timer ID that is created with the setTimeout() function, so you can disable it at any time to avoid the system going through the cycle one more time after you clear the flag.

7
  • Thank you a lot. One step closer. >If you want autoClose() to be called every 10 seconds repeatedly as the "idle" state, then you need to clear inAutoClose (set it to zero) at the end of every 10 second period. This is little bit difficult, as all i do in that loop, changing states from HIGH to LOW.
    – zarsss
    Feb 7, 2018 at 18:53
  • Take a look at the setTimeout() function of SimpleTimer -- it's like the setInterval(), but is a one-shot. You can set a timeout at just under 10s and have it call a function that un-sets inAutoClose. As in t.setTimeout(9900UL, endAutoClose); where endAutoClose() is a function that just sets inAutoClose=0; You would call this setTimeout() function just before enabling the timer. Feb 7, 2018 at 19:03
  • I tried that in separate simple sketch. The output was unpredictable .
    – zarsss
    Feb 7, 2018 at 19:24
  • In your updated example code, your switch statement switches on gearbox1, but you don't show how that value gets set to the various states. Could you update it again so that you show code that demonstrates your problem? Feb 7, 2018 at 19:29
  • gearbox1 is value read from Nextion screen gearbox1=myNextion.getComponentValue("G1"); What i am trying to achieve is, when case 10 (witch is checked once a second) run a 10 second loop turning output on and off. And the same with case 20, but different output. Tried different ways, one result is outputs changing in 1 second intervals or output blinks short on 10 second intervals. I don`t know how to post a code in comments, sorry.
    – zarsss
    Feb 7, 2018 at 19:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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