Need help - a way to pause or reset the operation performed

Hi everyone!
I am new to this forum and new to Arduino in general. I Am working on my Senior Design project in University of Connecticut. We are building a machine that will be performing tests on a military parachute release mechanism.

The program I am working on has to perform two tasks at the moment. it controls the repeated motion of a servo and displays number of cycles on the LCD. I don’t know what exacly is the best way to do this.

Here are my problems:

  1. what is the best way to display a number of cycles or loop iterations performed. what I have done is just count every two seconds because that’s how long my loop takes.

  2. how can I include a pause button. Basically it will be a momentary push button that when pressed the loop should pause. I am still learning about this. I think that I should use the button library and detect a state change of the button. Then how do i pause the loop? Do I put the main look inside a “if”

The problem right now is that when I press the button I have to hold it down all the time. Another problem is that the cycle counter does not stop counting just stop displaying.

Please understand that I am really a beginner that is trying to learn. Thanks for help.
Here is my Code:

/*
Wojtek Pajor
Capewell Test sketch
October 22, 2013
*/


// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

// include servo library code:
#include <Servo.h>
Servo servoMain; // Define our Servo


// initiate the STOP button button pin
const int stopbutton = 8; 

void setup()
{
  
    //setup LCD to display a message in the upper row
    lcd.begin(16, 2);          // set up the LCD's number of columns and rows: 
    // Print a message to the LCD.
    lcd.print("Capewell TESTING");  // This message will always be displayed in the top row
    
    
    //Setup STOP Button as input
    pinMode (stopbutton, INPUT);
  
     //Setup Servo motor
    servoMain.attach(9);      // servo on digital pin 10
    
}

void loop()
{
 while (digitalRead(stopbutton) == LOW) {      //attempt to create a STOP button.  Should pause the loop from running
    testing(); 
  }
}
void testing() {               // If the button is not pressed then this loop will run
     
  servoMain.write(120);      // Turn Servo Left to 120 degrees
   delay(1000);              // Wait 2 second
   servoMain.write(155);     // Turn Servo Left to 155 degrees
   delay(1000);              // Wait 2 second
   
   
   lcd.setCursor(10, 1);      //Set the cursor to second row column 11
   lcd.print("cycles");       // display  "cycles" in the second row
   

  if(digitalRead(stopbutton) == LOW){
  lcd.setCursor(0, 1);                   // set the cursor to column 0, line 1
  lcd.print(millis()/2000);              // start counting up every 2 seconds  This does not stop when the button is pressed, not sure why
  }
}

Best way to display the number of cycles?
Count them, and display the count.

First, let me ask you to please, put your code in code tags. You can do this by pasting your code in, highlighting it, and clicking on the # icon above the editor.

For counting cycles, jut declare a counter, and increment it right after the end of the cycle.

int cyclecount;

I'll leave it to you to decide when in the code to count it.

For a 'pause' button, make a digital pin INPUT, wire a switch to that pin, and when it's pressed, debounce it, and loop until it becomes unpressed, then pressed again.

For this, you'll need while loops (to implement the pause), and the millis() fiunction (to debounce the button)

Ok from now on I will know how to insert code. Sorry about that. Below is the code.

/*
Wojtek Pajor
Capewell Test sketch
October 22, 2013
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

// include servo library code:
#include <Servo.h>
Servo servoMain; // Define our Servo

// initiate the STOP button button pin
const int stopbutton = 8; 

void setup()
{
  
    //setup LCD to display a message in the upper row
    lcd.begin(16, 2);          // set up the LCD's number of columns and rows: 
    // Print a message to the LCD.
    lcd.print("Capewell TESTING");  // This message will always be displayed in the top row
    
    
    //Setup STOP Button as input
    pinMode (stopbutton, INPUT);
  
     //Setup Servo motor
    servoMain.attach(9);      // servo on digital pin 10
    
}

void loop()
{
 while (digitalRead(stopbutton) == LOW) {      //attempt to create a STOP button.  Should pause the loop from running
    testing(); 
  }
}
void testing() {               // If the button is not pressed then this loop will run
     
  servoMain.write(120);      // Turn Servo Left to 120 degrees
   delay(1000);              // Wait 2 second
   servoMain.write(155);     // Turn Servo Left to 155 degrees
   delay(1000);              // Wait 2 second
   
   
   lcd.setCursor(10, 1);      //Set the cursor to second row column 11
   lcd.print("cycles");       // display  "cycles" in the second row
   

  if(digitalRead(stopbutton) == LOW){
  lcd.setCursor(0, 1);                   // set the cursor to column 0, line 1
  lcd.print(millis()/2000);              // start counting up every 2 seconds  This does not stop when the button is pressed, not sure why
  }
}

lar3ry thank you for help. So far I fixed the cycle counter. it works great now. But I am having trouble understanding how to use the debounce. I have a while loop in my code that is similar to what you said but I am not using debounce maybe that’s the problem. My program stops only when I press and hold the button.

/*
Wojtek Pajor
Capewell Test sketch
October 22, 2013
*/


// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

// include servo library code:
#include <Servo.h>
Servo servoMain; // Define our Servo


// initiate the STOP button button pin
const int stopbutton = 8; 

int count=0;

void setup()
{
  
    //setup LCD to display a message in the upper row
    lcd.begin(16, 2);          // set up the LCD's number of columns and rows: 
    // Print a message to the LCD.
    lcd.print("Capewell TESTING");  // This message will always be displayed in the top row
    
    
    //Setup STOP Button as input
    pinMode (stopbutton, INPUT);
  
     //Setup Servo motor
    servoMain.attach(9);      // servo on digital pin 10
    
}

void loop()
{
 while (digitalRead(stopbutton) == LOW) {      //attempt to create a STOP button.  Should pause the loop from running
    testing(); 
    //count++;
  }
}
void testing() {             // If the button is not pressed then this loop will run
     
  servoMain.write(120);      // Turn Servo Left to 120 degrees
   delay(1000);              // Wait 2 second
   servoMain.write(155);     // Turn Servo Left to 155 degrees
   delay(1000);              // Wait 2 second
   
   
   lcd.setCursor(10, 1);      // Set the cursor to second row column 11
   lcd.print("cycles");       // display  "cycles" in the second row
   
   count++;                   // the cycle counter is incrementing by one every time the loop runs

   lcd.setCursor(0, 1);       // set the cursor to column 0, line 1
   lcd.print(count);          // start counting up every 2 seconds  This does not stop when the button is pressed, not sure why
  
}

One approach to having the button start and stop the loop is to use a latching button instead of a momentary one. This puts all the "logic" into the mechanics of the button, instead of your code. Just read the button state, and either perform, or don't perform the task as required.

If you are locked into the momentary button, then you need to study the "edge detection" example that came with your Arduino IDE. Basically, you need to store the button's current state, then detect when the button's current state changes. If the button goes from un-pressed to pressed, then back to un-pressed again, that will pause the loop. When that same thing happens again, that re-starts the loop. Within that logic, you can also implement debounce.

The debounce example is the best way of implementing debounce, but you can also implement debounce with a simple delay, such as:

boolean buttonPressed = false;

if (digitalRead(buttonPin) == LOW) // detect button pressed
{
  delay(50); // rudimentary debounce
  if (digitalRead(buttonPin) == LOW) // is button still pressed?
    buttonPressed = true;
}
else // button is not pressed
{
  delay(50); // rudimentary debounce
  if (digitalRead(buttonPin) == HIGH) // is button still not pressed?
    buttonPressed = false;
}

if (!buttonPressed) 
{
  // do some stuff here that only runs when the button is not-pressed
}

This debounce causes your code to run slower, which can matter in some real-time applications, but in other applications it doesn't matter at all. The advantage of the debounce example's approach is that your code continues to run while the debounce process is occurring. Also, bear in mind that this code does not implement edge detection.

Implementing edge detection in a case like this is pretty easy, because you don't really need to worry about button presses, just button releases. You can assume that the code is running fast enough that you will never mis-interpret a press-release-press-release as one button press instead of two. Humans just don't push buttons that fast. So...

boolean lastButtonState;
boolean codeIsPaused = false;
const byte pinNumber = 11;

void setup()
{
  pinMode(pinNumber, INPUT_PULLUP);
  lastButtonState = digitalRead(pinNumber);
}

void loop()
{
  boolean currentButtonState = digitalRead(pinNumber);

  if (lastButtonState == LOW && currentButtonState == HIGH) // button was pressed and has now been released
    codeIsPaused = !codeIsPaused; // toggle paused state

  if (!codeIsPaused)
  {
    // do work here
  }
}

This code example doesn't implement any debounce, however, which leaves it susceptible to false readings. For example, after a button press, there may be several release/press events, which may leave you with false pause/unpause readings.

Thank you Joshua. I am testing this right now. I can’t get the button to stop the code from running yet. Here is my test code implementing your advised code. I am checking how my button is wired up right now. This test code just displays a counter on the LCD and if should stop when button is pressed.

// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
 
boolean lastButtonState;
boolean codeIsPaused = false;
const byte pinNumber = 8;

int count=0;

void setup()
{
    pinMode(pinNumber, INPUT_PULLUP);
    lastButtonState = digitalRead(pinNumber);
}

void loop()
{
 boolean currentButtonState = digitalRead(pinNumber);

  if (lastButtonState == LOW && currentButtonState == HIGH) // button was pressed and has now been released
    codeIsPaused = !codeIsPaused; // toggle paused state

  if (!codeIsPaused)
  {
    // do work here 
   lcd.setCursor(10, 1);      // Set the cursor to second row column 11
   lcd.print("cycles");       // display  "cycles" in the second row
   
   count++;                   // the cycle counter is incrementing by one every time the loop runs

   lcd.setCursor(0, 1);       // set the cursor to column 0, line 1
   lcd.print(count);          // start counting up every 2 seconds  This does not stop when the button is pressed, not sure why
   delay(1000);
  }
}

Is it ok If my button is in LOW state when it is unpressed?

wojtek86:
Is it ok If my button is in LOW state when it is unpressed?

Your button can be either HIGH or LOW when unpressed depending on how it is wired but do not let it float at an undefined voltage. Using INPUT_PULLUP removes the need to use external resistors in your circuit.

wojtek86:
Is it ok If my button is in LOW state when it is unpressed?

If you are using pinMode(INPUT_PULLUP), then your button should be in a HIGH state when it is unpressed. If it's not, something is amiss in your wiring.

wojtek86:
Thank you Joshua. I am testing this right now. I can’t get the button to stop the code from running yet. Here is my test code implementing your advised code. I am checking how my button is wired up right now. This test code just displays a counter on the LCD and if should stop when button is pressed.

A useful way of debugging code is to add Serial.print() statements to allow you to follow the code’s logic. It’s entirely possible that my code example contains an unforseen error, since I didn’t really test it before posting it. On the other hand, if your switch is reading LOW when it’s un-pressed, then this could be a wiring mistake.

Here’s an example of how to add the Serial.print() statements to code.

#define DEBUG // comment out this line to ignore debug output commands

// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
 
boolean lastButtonState;
boolean codeIsPaused = false;
const byte pinNumber = 8;

int count=0;

void setup()
{
    pinMode(pinNumber, INPUT_PULLUP);
    lastButtonState = digitalRead(pinNumber);

#ifdef DEBUG
  Serial.begin(9600);
}

void loop()
{
 boolean currentButtonState = digitalRead(pinNumber);

#ifdef DEBUG
  Serial.print("lastButtonState =\t");
  Serial.print(lastButtonState);
  Serial.print("\tcurrentButtonState =\t");
  Serial.print(currentButtonState);
#endif

  if (lastButtonState == LOW && currentButtonState == HIGH) // button was pressed and has now been released
    codeIsPaused = !codeIsPaused; // toggle paused state

 #ifdef DEBUG
  Serial.print("\tcodeIsPaused =\t");
  Serial.print(codeIsPaused);
#endif

  if (!codeIsPaused)
  {
    // do work here 
   lcd.setCursor(10, 1);      // Set the cursor to second row column 11
   lcd.print("cycles");       // display  "cycles" in the second row
   
   count++;                   // the cycle counter is incrementing by one every time the loop runs

   lcd.setCursor(0, 1);       // set the cursor to column 0, line 1
   lcd.print(count);          // start counting up every 2 seconds  This does not stop when the button is pressed, not sure why
   delay(1000);
  }

#ifdef DEBUG
  Serial.println(); // go to newline for next loop() of debug output
#endif
}

[/quote]

It's better if you use the F() macro for constant strings when writing serial debug code - it will help you not introduce unexpected out of RAM errors.

I have performed the DEBUG and here are the results:
lastButtonState is always 1
currentButtonState is 1 and when I press the button it is = 0
codeIsPaused always stays as 0

So how should my code pause when I press the button. Does it pause when codeIsPaused is = 1? That doesn’t seem to be working.

#define DEBUG // comment out this line to ignore debug output commands

// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
 
boolean lastButtonState;
boolean codeIsPaused = false;
const byte pinNumber = 6;

int count=0;

void setup()
{
    pinMode(pinNumber, INPUT_PULLUP);
    lastButtonState = digitalRead(pinNumber);

#ifdef DEBUG
  Serial.begin(9600);
 #endif
}

void loop()
{
 boolean currentButtonState = digitalRead(pinNumber);

#ifdef DEBUG
  Serial.print("lastButtonState =\t");
  Serial.print(lastButtonState);
  Serial.print("\tcurrentButtonState =\t");
  Serial.print(currentButtonState);
#endif

  if (lastButtonState == LOW && currentButtonState == HIGH) // button was pressed and has now been released
    codeIsPaused = !codeIsPaused; // toggle paused state

 #ifdef DEBUG
  Serial.print("\tcodeIsPaused =\t");
  Serial.print(codeIsPaused);
#endif

  if (!codeIsPaused)
  {
    // do work here 
   lcd.setCursor(10, 1);      // Set the cursor to second row column 11
   lcd.print("cycles");       // display  "cycles" in the second row
   
   count++;                   // the cycle counter is incrementing by one every time the loop runs

   lcd.setCursor(0, 1);       // set the cursor to column 0, line 1
   lcd.print(count);          // start counting up every 2 seconds  This does not stop when the button is pressed, not sure why
   delay(1000);
  }

#ifdef DEBUG
  Serial.println(); // go to newline for next loop() of debug output
#endif
}

You are not updating lastButtonState in the loop() function so it is no wonder that its value does not change. Have a careful look at the StateChangeDetection example in the IDE and note the following

  // save the current state as the last state, 
  //for next time through the loop
  lastButtonState = buttonState;

You have declared lastButtonState as boolean. Note how it is declared in the example. Whilst a boolean variable has a value of true or false and these equate to 1 and 0 it is probably better not to mix the data types as it can make the code more difficult to read and understand.

wojtek86:
I have performed the DEBUG and here are the results:
lastButtonState is always 1
currentButtonState is 1 and when I press the button it is = 0

So you know that the code is correctly detecting the button press (currentButtonState). You know that your button is wired up correctly also. This is kind of the way I try to think about debugging: what do I know to be working correctly? What do I know to be working incorrectly? Then try to figure out why. In this case, lastButtonState is not working correctly...