How to change the behavior of the button?

Hi all,
as a newbie trying to build my first project, i'm not being able to solve one problem.
The code bellow works well, as a prototype
When manual_open button is pressed, it loops until stop_open == HIGH.
I want to press manual_button anytime and stop he loop (while), and set a flag, which enables that the procedure to be resumed when pressing manual_button again. Which would be the safest way to implement it?
Thx in advance,
PW

#include <EEPROM.h>
#include <LiquidCrystal.h>
#include <AccelStepper.h>
#include <Button.h> 

Button automatic(8, LOW) ; /* digital pin 8 */
Button manual_open(9, LOW); /* digital pin 9 */
Button manual_close(10, LOW); /* digital pin 10 */
const int stop_open = 6; /* digital pin 6 */
const int stop_close = 7; /* digital pin 7 */
const int ldr_pin = 0; /* analog pin 0 */
int ldr_val = 0;
int operation_mode = 'auto'; /* auto, mclose, mopen, wait */
int pause_mode = 0;  /* 0 1 */

int val;
int buttonstate;

const int ledAutomatic =  3;
const int ledOpen =  4;
const int ledClose =  5;

void setup() {
  pinMode(stop_open, INPUT);
  pinMode(stop_close, INPUT); 
  pinMode(13,OUTPUT);
  pinMode(ledAutomatic, OUTPUT);
  pinMode(ledOpen, OUTPUT);
  pinMode(ledClose, OUTPUT);   
  Serial.begin(9600);
}
void loop() {
  ldr_val = analogRead(ldr_pin);
  check_mode();
  switch (operation_mode) {
    case 'auto':
      Automatic_Mode();
      break;
    case 'mclose':
      Manual_Close();
      break;
    case 'mopen':
      Manual_Open();
      break;
    case 'wait':
      break;
  }  
  digitalWrite(ledAutomatic, LOW);
  digitalWrite(ledOpen, LOW);
  digitalWrite(ledClose, LOW);
}
void check_mode() {
  int val = 0;
  automatic.listen();
  manual_open.listen();
  manual_close.listen();
  if (automatic.onChange()) operation_mode = 'auto'; 
  if (manual_open.onChange()) operation_mode = 'mopen';
  if (manual_close.onChange()) operation_mode = 'mclose'; 
}
void Automatic_Mode() {
  if (ldr_val < 600) {
    digitalWrite(13, HIGH);
    /* open blinds */
    Serial.print("Automatic Open\n\r"); }
  else {
    digitalWrite(13, LOW);
    /* close blinds */
  Serial.print("Automatic Close\n\r"); }
  digitalWrite(ledAutomatic, HIGH);
  delay(100);
}
void Manual_Open() {
    while(digitalRead(stop_open) == LOW && operation_mode == 'mopen') {
    Serial.print("manual_open  ");
    Serial.print(pause_mode);
    Serial.print("\r\n");
    digitalWrite(ledOpen, HIGH);
    check_mode();
    }
    digitalWrite(ledOpen, LOW);
    Serial.print("manual_open  ");
    Serial.print(pause_mode);
    Serial.print("\r\n");
    operation_mode = 'stop';
}

void Manual_Close() {
    while(digitalRead(stop_close) == LOW && operation_mode == 'mclose') {
          digitalWrite(ledClose, HIGH);
          check_mode();
    }
    digitalWrite(ledOpen, LOW);
    operation_mode = 'stop';
}
int operation_mode = 'auto'; /* auto, mclose, mopen, wait */

?????????

Which button library are you using ? Your code includes methods that are not in the button library that I have.

int operation_mode = 'auto'; /* auto, mclose, mopen, wait */

I think not. You seem to be trying to put the string "auto" into an integer.

I think not. You seem to be trying to put the string "auto" into an integer.

Not even a string - a multi-character constant.

Thx all for pointing the mistake of declaration. Beside this error, it's working.

Just for my education, which should be the type of operation_mode? A i read, char takes up 1 byte of memory that stores a character value, but i want to declare a full string. Using String did also gave problem when compiling, and int worked.

The button library being used is the GitHub - carlynorama/Arduino-Library-Button: This is a library for adding buttons to Arduino projects. It supports events like OnPress and OnRelease..

But the question was not about the string, but how to implement a pause and a resume pressing the same button (manual_open) to the Manual_Open() routine.

Thx in advance.

but i want to declare a full string. Using String did also gave problem when compiling

A string and a String are not even close to the same things. When you make up your mind which you want to use (strings are better!), let us know.

PaulS:

but i want to declare a full string. Using String did also gave problem when compiling

A string and a String are not even close to the same things. When you make up your mind which you want to use (strings are better!), let us know.

Thx for the answer. Not even close to the same things. As i asked before, could you please educate me in explaining the difference?

But the question was not about the string, but how to implement a pause and a resume pressing the same button (manual_open) to the Manual_Open() routine.

Thx in advance.

AWOL:
Not even a string - a multi-character constant.

That's why I said "seem to be". :wink:

As i asked before, could you please educate me in explaining the difference?

A string is a NULL terminated array of chars.

A String is a class that adds some functionality, some of which doesn't fit well on the Arduino, along with a NULL terminated array of chars.

If you can do without that added functionality, and people have managed for 40 years, because it is part of the string.h library, then you can avoid the problems inherent in the String class.

Thx. Now i have it defined as char and working.
About the primary question, when manual_open button is pressed, it loops until stop_open == HIGH.
I want to press manual_open button anytime and stop he loop (while), and set a flag, which enables that the procedure to be resumed when pressing manual_button again. Which would be the safest way to implement it?
TIA!

#include <EEPROM.h>
#include <LiquidCrystal.h>
#include <AccelStepper.h>
#include <Button.h>

Button automatic(8, LOW);     /* digital pin 8 */
Button manual_open(9, LOW);   /* digital pin 9 */
Button manual_close(10, LOW); /* digital pin 10 */
const int stop_open = 6;     /* digital pin 6 */
const int stop_close = 7;    /* digital pin 7 */
const int ldr_pin = 0;       /* analog pin 0 */
int ldr_val = 0;
char operation_mode = 'A'; /* A = auto, C = mclose, O = mopen, P = wait */
char pause_mode = 'N';               /* no, yes */


const int ledAutomatic =  3;
const int ledOpen =  4;
const int ledClose =  5;

void setup() {
//  pinMode(automatic, INPUT);
//  pinMode(manual_open, INPUT);
//  pinMode(manual_close, INPUT);
  pinMode(stop_open, INPUT);
  pinMode(stop_close, INPUT); 
  pinMode(13,OUTPUT);
  pinMode(ledAutomatic, OUTPUT);
  pinMode(ledOpen, OUTPUT);
  pinMode(ledClose, OUTPUT);   
  Serial.begin(9600);
}
void loop() {
  ldr_val = analogRead(ldr_pin);
  check_mode();
  switch (operation_mode) {
    case 'A':
      Automatic_Mode();
      break;
    case 'C':
      Manual_Close();
      break;
    case 'O':
      Manual_Open();
      break;
  }  
  digitalWrite(ledAutomatic, LOW);
  digitalWrite(ledOpen, LOW);
  digitalWrite(ledClose, LOW);
}
void check_mode() {
  automatic.listen();
  manual_close.listen();
  manual_open.listen();
  if (automatic.onChange()) { Serial.print("Mode set to AUTO\r\n"); operation_mode = 'A'; } 
  if (manual_close.onChange()) { delay (100); Serial.print("Mode set to MCLOSE\r\n"); operation_mode = 'C'; }
  if (manual_open.onChange()) { delay(100); Serial.print("Mode set to MOPEN\r\n"); operation_mode = 'O'; }
}
void Automatic_Mode() {
 Serial.print("automatic routine\r\n");
  if (ldr_val < 600) {
    digitalWrite(13, HIGH);
//     open blinds 
//    Serial.print("Automatic Open Blinds\n\r");
  } 
  else {
    digitalWrite(13, LOW);
// close blinds 
//  Serial.print("Automatic Close Blinds\n\r"); 
  }
  digitalWrite(ledAutomatic, HIGH);
  delay(10); // keep led on, no delay will flicker so fast almost can't be seen
}

void Manual_Close() {
    Serial.print("manual_close routine\r\n");
    while(digitalRead(stop_close) == LOW && operation_mode == 'C') {
      Serial.print("CLOSE\r\n");
      digitalWrite(ledClose, HIGH);
      check_mode();
    }
    digitalWrite(ledOpen, LOW);
    
}

void Manual_Open() {
    Serial.print("\r\nmanual_open routine\r\n");
    while(digitalRead(stop_open) == LOW && operation_mode == 'O') {
    Serial.print("OPEN\r\n"); 
      digitalWrite(ledOpen, HIGH);
      check_mode();
    }
    digitalWrite(ledOpen, LOW);
   
}

I want to press manual_button anytime and stop he loop (while), and set a flag, which enables that the procedure to be resumed when pressing manual_button again.

Permission granted. Proceed.

Clearly, you need to check the results of check_mode() and break out of the while loop when the manual switch is pressed.

Might I also suggest that you have far too many global variables. The check_mode() function, for instance, should return a value, not set a global variable.

PaulS:

I want to press manual_button anytime and stop he loop (while), and set a flag, which enables that the procedure to be resumed when pressing manual_button again.

Permission granted. Proceed.

Clearly, you need to check the results of check_mode() and break out of the while loop when the manual switch is pressed.

Might I also suggest that you have far too many global variables. The check_mode() function, for instance, should return a value, not set a global variable.

Thx for answering. And how would i implement your suggestion? Learning from experts will improve my logic and coding skills.

Learning from experts will improve my logic and coding skills.

Trying something on your own will do far more for your skills than reading what we write.

In the open function, you have a call to check_mode(). Regardless of what that function does, you keep on trucking. Perhaps you shouldn't.

PaulS:

Learning from experts will improve my logic and coding skills.

Trying something on your own will do far more for your skills than reading what we write.

In the open function, you have a call to check_mode(). Regardless of what that function does, you keep on trucking. Perhaps you shouldn't.

Did not get what you mean. Could you please explain?
TIA

Did not get what you mean. Could you please explain?

Suppose that you are manually closing the drapes. Before you get halfway done, I yell stop. Do you keep closing the drapes, and then ask me why you should have stopped? I hope not.

But that is what your code is doing. When you are closing the drapes, a switch is pressed, saying stop! Your check_mode() function detects that, but you do not care. You keep on closing the drapes. Only after the drapes are closed do you pay attention to the fact that check_mode() said stop!

PaulS:

Did not get what you mean. Could you please explain?

Suppose that you are manually closing the drapes. Before you get halfway done, I yell stop. Do you keep closing the drapes, and then ask me why you should have stopped? I hope not.

But that is what your code is doing. When you are closing the drapes, a switch is pressed, saying stop! Your check_mode() function detects that, but you do not care. You keep on closing the drapes. Only after the drapes are closed do you pay attention to the fact that check_mode() said stop!

The hardware (prototype yet):
1 push button enabling automatic mode
1 push button enabling manual close, disabling automatic and open (push starts another push pause another push resume another push pause and so on)
1 push button enabling manual open, disabling automatic and close (push starts another push pause another push resume another push pause and so on)
1 push key as stop open - when drape reaches the end (totally open), no more open - only close (manually or automatic)
1 push key as stop close - when drape reaches the end (totally close), no more close - only open (manually or automatic)
on automatic mode, the value of a LDR is read and opens or closes the drape, stopping by stop open or stop close.
If stop open and stop close are LOW, any action can be done (manually open, manually close or automatic, depending on light condition).

What the code is suppose to do:
at any time during drape movement, the behavior can be changed, i.e. while closing, can be paused and resume closing later or can be opened or change to automatic.
That's why check_mode is called inside the subroutines. May look confuse, but was the best way i got the desired result.
Finally i understood how the button library works, and so, i solved the debounce and the start / stop during manual open and close.
For sure the code can be more elegant, but i'm restarting to program, after 20 years (i was a Cobol and PL/1 programmer), and Arduino with interfaces is a little more critical.

The tested code, doing all this, yet as prototype with all the debug (Serial.print), now it will start the motor interface:

#include <EEPROM.h>
#include <LiquidCrystal.h>
#include <AccelStepper.h>
#include <Button.h>

Button automatic(8, LOW);     /* digital pin 8 */
Button manual_open(9, LOW);   /* digital pin 9 */
Button manual_close(10, LOW); /* digital pin 10 */
int newDebounceDelay = 60;    /* debounce delay for push buttons = 60 ms */
const int stop_open = 6;     /* digital pin 6 */
const int stop_close = 7;    /* digital pin 7 */
const int ldr_pin = 0;       /* analog pin 0 */
int ldr_val = 0;
char operation_mode = 'A'; /* A = auto, C = mclose, O = mopen, P = wait */
char pause_mode = 'N';               /* no, yes */

const int ledAutomatic =  3;
const int ledOpen =  4;
const int ledClose =  5;

void setup() {
  automatic.setDebounceDelay(newDebounceDelay);
  manual_open.setDebounceDelay(newDebounceDelay);
  manual_close.setDebounceDelay(newDebounceDelay);
  pinMode(stop_open, INPUT);
  pinMode(stop_close, INPUT); 
  pinMode(13,OUTPUT);
  pinMode(ledAutomatic, OUTPUT);
  pinMode(ledOpen, OUTPUT);
  pinMode(ledClose, OUTPUT);   
  Serial.begin(9600);
}

void loop() {
  ldr_val = analogRead(ldr_pin);
  check_mode();
  switch (operation_mode) {
    case 'A':
      Automatic_Mode();
      break;
    case 'C':
      Manual_Close();
      break;
    case 'O':
      Manual_Open();
      break; 
    case 'P':
      break;   
  }  
  digitalWrite(ledAutomatic, LOW);
  digitalWrite(ledOpen, LOW);
  digitalWrite(ledClose, LOW);
}

void check_mode() {
  automatic.listen(); manual_close.listen(); manual_open.listen();
  if (automatic.onPress()) {
    Serial.print("Mode set to AUTO\r\n"); 
    operation_mode = 'A'; 
  } 
  if (manual_close.onPress()) {
    if (operation_mode == 'C') {
      Serial.print("operation_mode = C\r\n");
      operation_mode = 'P';
      Serial.print("operation_mode = P - close\r\n");
    } else {
    Serial.print("Mode MCLOSE start/stop\r\n");
    operation_mode = 'C';    
    }
  }
  if (manual_open.onPress()) {
    if (operation_mode == 'O') {
      Serial.print("operation_mode = O\r\n");
      operation_mode = 'P';
      Serial.print("operation_mode = P - open\r\n");
    } else {
    Serial.print("Mode set to MOPEN\r\n"); 
    operation_mode = 'O';
    } 
  }
}
void Automatic_Mode() {
  Serial.print("automatic routine\r\n");
  if (ldr_val < 600) {
    digitalWrite(13, HIGH);
//    open blinds 
//    Serial.print("Automatic Open Blinds\n\r");
  } 
  else {
    digitalWrite(13, LOW);
// close blinds 
// Serial.print("Automatic Close Blinds\n\r"); 
  }
  digitalWrite(ledAutomatic, HIGH);
  delay(10); // keep led on, no delay will flicker so fast almost can't be seen
}

void Manual_Close() {
  while(digitalRead(stop_close) == LOW && operation_mode == 'C') {
    Serial.print("CLOSE\r\n");
    digitalWrite(ledClose, HIGH);
    check_mode();
  }
    digitalWrite(ledClose, LOW);
    Serial.print("CLOSE STOP_OPEN\r\n");    
}

void Manual_Open() {
  while(digitalRead(stop_open) == LOW && operation_mode == 'O') {
    Serial.print("OPEN\r\n"); 
    digitalWrite(ledOpen, HIGH);
    check_mode();
  }
    digitalWrite(ledOpen, LOW);
    Serial.print("OPEN STOP_OPEN\r\n");   
}

Thx for helping.