Need delay after digitalRead to make variables work

I went through a lot of trouble trying to get this code to work. The program moves a motorized arm which has a limit switch to stop it in it's deployed position and a limit swith to stop it in it's retracted position. There are two momentary buttons "deploy" and "retract". I press deploy once and the sequence starts. The arm extends then stops. The problem is that the section of code that sets deploying=true; gets executed after the arm stops in its' deployed position. There is no way possible for that code to execute unless the deploy button is pressed. Watching the variables with a bunch of serial.print statements I could see that deployPressed (and armDown) remained true even though pin 6 was high. (internal pullups) The arm takes 20 seconds to deploy so it isn't a bounce issue. I eventually fixed it by creating a delay(20) right after I read the pins. Now the variables deployPressed and armDown reflect the proper values. Why is this delay necessary? I makes me nervous that I may need one somewhere else and not know it.

boolean armDown=false;
boolean armUp=false;

boolean deployPressed=false;
boolean retractPressed=false;
boolean deploying=false;
boolean retracting=false;

void setup() {                
  //switches
  pinMode(9, INPUT);  // arm down
  digitalWrite(9, HIGH);
  pinMode(7, INPUT);  // arm up
  digitalWrite(7, HIGH);
  pinMode(6, INPUT);  // deploy
  digitalWrite(6, HIGH);
  pinMode(5, INPUT);  // retract
  digitalWrite(5, HIGH);
 
  //motors
  pinMode(8,OUTPUT); // arm motor
  digitalWrite(8, HIGH);  
}

void armMotorOn() {
   digitalWrite(8,false);
}

void armMotorOff() {
   digitalWrite(8,true);
}

void loop() {
  armDown=!digitalRead(9);
  armUp=!digitalRead(7);
  deployPressed=!digitalRead(6);
  retractPressed=!digitalRead(5);

  delay(20);  // This delay makes the variables reflect the correct value.
   
  if (deployPressed && !deploying && armDown && !retracting) {
    deploying=true;
  }
 
  if (retractPressed && !deploying && armUp && !retracting) {
    retracting=true;
  }
 
  if (!armUp && deploying) {
    armMotorOn();  //arm motor on
  }
 
  if (armUp && deploying) { //fully deployed - end deploy sequence
    armMotorOff();  //arm motor off
    deploying=false;
  }
 
  if (!armDown && retracting){
    armMotorOn();
  }
 
  if (armDown && retracting){
    armMotorOff();
    retracting=false;
  }
}
  delay(20);  // This delay makes the variables reflect the correct value.

I'm sorry, but I simply can't believe the above is true.

While a delay may make your program work, it's not because a delay is needed to set the variables.

Could you post the complete code and any info about external libraries used?

Brad (KF7FER)

I've stared at this code for 10 minutes and I'm still confused. Can't you rewrite with less "if" tests?

For example, instead of:

 if (!armDown && retracting){
    armMotorOn();
  }

  if (armDown && retracting){
    armMotorOff();
    retracting=false;
  }
if (retracting)
  {
  if (armDown)
    {
    armMotorOff();
    retracting=false;
    }
  else
    armMotorOn();
  }  // end of retracting

My gut feeling is it is switch bounce. Who cares how long it takes the arm to retract? You are back at the start of loop a millisecond later. I suggest that if either switch changes state, then wait 10 or 20 milliseconds. That's your debounce.

You're looking at the whole program.

We care how long it takes for the arm to retract because in 20 seconds any bounce would surely be settled. Look at the code...

if (deployPressed && !deploying && armDown && !retracting) {
    deploying=true;
}

Once you've started the arm moving by pressing deployPressed... you step back and watch it happen. deployPressed and armDown will never get touched again by either the device or a human. Yet somehow deployPressed and armDown are still true 20 seconds later even though the pins are false. I caught this because I put a serial.print statement right after reading the pins for debugging and it started working correctly. So I switched in a delay and it worked too. I can't stress enough that there should be no bounce 20 seconds later from both switches.

The problem is that what you are describing is the bouncing of the buttons. The fact that a delay() settles out the input values highly suggests bouncing.

Because of all your if-and conditions, if the button pressed bounces a little or the button indicators for your arm bounces a little, your status variables might be "corrupted."

Try adding a cap to the buttons. If a cap across the buttons solves the problem (without a delay()) then you know its bouncing.

I really don't understand how a switch could be bouncing 20 seconds after it is pressed.

Has something as simple as the following been tried?

void setup(void)
{  pinMode(9, INPUT);                  // arm down
   digitalWrite(9, HIGH);
   pinMode(7, INPUT);                  // arm up
   digitalWrite(7, HIGH);
   pinMode(6, INPUT);                  // deploy
   digitalWrite(6, HIGH);
   pinMode(5, INPUT);                  // retract
   digitalWrite(5, HIGH);
   pinMode(8,OUTPUT);                   // arm motor
   digitalWrite(8, HIGH);  
}

void loop(void)
{  while (digitalRead(6)) ;            /* Wait for deploy button              */
   digitalWrite(8,LOW);                /* Arm motor on                        */
   while (digitalRead(7)) ;            /* Wait for extended limit switch      */
   digitalWrite(8,HIGH);               /* Arm motor off                       */
   while (digitalRead(5)) ;            /* Wait for retract button             */
   digitalWrite(8,LOW);                /* Arm motor on                        */
   while (digitalRead(9)) ;            /* Wait for retracted limit switch     */
   digitalWrite(8,HIGH);               /* Arm motor off                       */
}

The deploy and extend buttons are momentary contact.

freakdaddy:
I really don't understand how a switch could be bouncing 20 seconds after it is pressed.

If you're referring to the delay(20), that is 20 milliseconds, not 20 seconds.

The deploy and extend buttons are momentary contact.

That's what the code I posted is depending on (Don't hold 'em down - just press and release).

PeterH:

freakdaddy:
I really don't understand how a switch could be bouncing 20 seconds after it is pressed.

If you're referring to the delay(20), that is 20 milliseconds, not 20 seconds.

No incorrect. The arm takes 20 SECONDS to deploy after deployPressed is pressed. There could be no switch bounce after 20 SECONDS.

My mistake. However this program will be expanded to do more. First a door needs to open, arm extend, then turn on a light. Then the process needs to reverse. Light off, arm retract, door close. I would have to see if that would all fit in the way you did it. This part was only the first step.

You may have a different set of rules - but my rule #1 to to first verify that I have working hardware, and my rule #2 is to verify that it works the way I think it works. :grin:

I'm not trying to write your application - I'm just trying to help you with those verifications. My tiny test loop doesn't depend on debounce or any of the fine touches you'll probably want to include later - it just exercises the buttons, motor, and limit switches in the most simple and idiot-proof way I could imagine (what I shoot for in my own projects).

I agree that you shouldn't need a delay.

I think I have followed your rules. My hardware works. It works the way I think it should. I do think there is an arduino bug here however. Is there an issue reporting system in place for arduino?

I honestly don't know, but if you're certain it isn't you the first board listed on the forum index page is listed as being for Arduino problems. Give it a try.

freakdaddy:
[...]I do think there is an arduino bug here however.

Ok. What I'd do first is try to describe the bug. Then I'd try to write a test sketch that would show the problem.
Sometimes the simple act of trying to explain what you expect from your code and what you get instead makes you understand where the problem (and the solution) lies.
(hint: 99% of times it's not in the platform).

freakdaddy:
Is there an issue reporting system in place for arduino?

I think you're right into it :slight_smile:

mromani:

freakdaddy:
[...]I do think there is an arduino bug here however.

Ok. What I'd do first is try to describe the bug. Then I'd try to write a test sketch that would show the problem.
Sometimes the simple act of trying to explain what you expect from your code and what you get instead makes you understand where the problem (and the solution) lies.
(hint: 99% of times it's not in the platform).

freakdaddy:
Is there an issue reporting system in place for arduino?

I think you're right into it :slight_smile:

If I read the problem description correctly, this really does sound like a =hardware= problem. Not with switch bounce, but possibly with something happening when the motor is operating and/or stopped. Liberal application of capacitors across =all= switches, as well as a beefier cap across the power supply, might help.

For a test, I'd suggest disconnecting the motor, then pressing the various buttons by hand. And I'd still add the caps. Starving children in China need us to buy more capacitors ...

freakdaddy:
Yet somehow deployPressed and armDown are still true 20 seconds later even though the pins are false.

 armDown=!digitalRead(9);

armUp=!digitalRead(7);
  deployPressed=!digitalRead(6);
  retractPressed=!digitalRead(5);

You mean "even though the pins are true" I hope, since you are doing "not" what the pins read.

Pins are not true or false, they are HIGH or LOW. Let's get the terminology straight.

Can you describe the hardware a bit more? Which end is the armUp button? Before you start submitting bug reports about the Arduino, better get straight what is happening. If you swapped the armUp and armDown tests (ie. the switches are mis-wired) this might account for some of what you see.

I recall another thread not that long ago where I suggested a wiring error. "Absolutely not!" the poster declared. "Photo?" I replied. About 4 or 5 pages in (I'm not kidding) there was an "oops, I made a wiring mistake".

{Had to edit... Sorry I posted before I was done typing!!!!]

I will certainly run more tests before submitting a bug. What bothers me is this... I inserted all kinds of serial.print statements to see what was happening. I even put one in the main loops to watch it the whole time to see if I could see bounces. Here is what happened...
(pseudo code)

SerialA.print(!digitalRead(6), deploying,!digitalRead(9), retracting)
if (deployPressed && !deploying && armDown && !retracting) {
    SerialB.print(deployPressed, deploying, armDown, retracting)
    deploying=true;
}
  1. System idle
    1.5. SerialA.print is repeating 0 0 1 0
  2. Press deployPressed button.
    2.5 SerialA.print shows 1 0 1 0
  3. serialB.print shows 1 0 1 0
  4. now because deploying=false the code above will never execute again for the time being. It takes around 20 seconds to fully extend the arm.
    4.5 SerialA.print is repeating 0 1 0 0 <- You would think that deployPressed and armDown would be false as well
  5. arm is done deploying and code elsewhere sets deploying=false.
  6. SerialA.print shows 0 0 0 0
  7. code above executes again because deploying is now false AND deployPressed and armDown are STILL TRUE. Remember that deployPressed and armDown were last touched 20 seconds ago.
    7 serialB.print shows 1 0 1 0 <- should not be