Go Down

Topic: debouncing a switch during 'while' loop (Read 1 time) previous topic - next topic

mdb024

Jul 26, 2012, 05:22 am Last Edit: Jul 26, 2012, 01:18 pm by mdb024 Reason: 1
I'm trying to create a project that involves a motor being turned on, and then turning off once it completes a single rotation, as indicated by the switch. Its easier to describe using the attached picture.

In the picture, the switch starts open because the level is in the indent of the wheel. Once the motor turns on, it depresses the switch and the switch remains pressed until the wheel completes the turn, at which point it reaches the indent again and the switch is released. At this point I would like the motor to turn off.

The switch is connected through a pull-down resistor such that when the switch is open, it is pulled to ground, but when it is closed, the switch pulls +5V. The switch is connected to a pin which I have named "motorSwitch" in the code below.

I'm trying to use the 'while' function, but I've had very inconsistent results. Sometimes it works as intended. Other times, the motor turns on and very quickly turns off. I've troubleshooted by removing the switch and manually providing +5V to the pin. When I do this carefully, the motor turns on, then I apply +5V and the motor stays on until I release the +5V, at which point it turns off. However, if I do not create good contact, the motor turns off. Based on this operation, I believe that the cause of my problem is that the switch is bouncy.

I understand the concept of debouncing a switch (take the reading about 10 ms apart and if they are the same, consider that the switch has settled), but cannot integrate this idea in the while function. The code that I am using is below:

Code: [Select]
digitalWrite(motorPin, HIGH);   //power to motor circuit
 while(digitalRead(motorSwitch) == LOW) {;} //while the switch is not pressed, take no action
 delay(100);     //once the switch has been pressed, wait 0.1 seconds                                                            
 while(digitalRead(motorSwitch) == HIGH)  {;}  //take the reading again, while the switch is still high, take no action
 digitalWrite(motorPin, LOW); //once the switch is released, turn the motor off


I think that the switch is bouncing in each of the 'while' functions, when it is reading the motorSwitch pin. Once it bounces from low, it kicks out of the while loop and continues the rest of the code, but it shouldn't.

I apologize if this is an easy question, but I am new to Arduino and programming as a whole. If you have any help on how to implement the above, that would be great. Thanks so much for your help.

Arrch

You need to implement the debounce code inside the while loop. Your while condition should be checking a "state" variable while inside the loop you are taking the "reading" and only setting "state" when you've held the same "reading" for the same debounce time. Psuedocode:

Code: [Select]
While state is LOW
  set reading variable
  if reading is not last reading
    reset debounce timer

  if it's been longer than debounce time
   set state to HIGH

  set last reading to current reading

Nick Gammon


The switch is connected through a pull-up resistor such that when the switch is open, it is pulled to ground, but when it is closed, the switch pulls +5V.


Don't understand that. A pull-up resistor normally pulls up to +5V. What is wired to what?
http://www.gammon.com.au/electronics

Riva

I'm with Nick here, you say the switch is connected with a pullup resistor so the arduino pin it's connected to should read HIGH if the switch contacts are open and LOW when they are closed.
Your sample code looks like it should work apart from the motorSwitch logic being reversed.
Code: [Select]
  digitalWrite(motorPin, HIGH);                 //power to motor circuit
  while(digitalRead(motorSwitch) == HIGH) {}    //while the switch is not pressed, take no action
  delay(100);                                   //once the switch has been pressed, wait 0.1 seconds for debounce                                                           
  while(digitalRead(motorSwitch) == LOW)  {}    //take the reading again, while the switch is still high, take no action
  digitalWrite(motorPin, LOW);                  //once the switch is released, turn the motor off
http://forum.arduino.cc/index.php?action=unread;boards=5,67,10,11,66,12,15,17,21,22,23,24,25,29;ALL

PaulS

Code: [Select]
  delay(100);     //once the switch has been pressed, wait 0.1 seconds for debounce
That would be a lllooonnnggg time for a switch to bounce.

Nick Gammon

http://www.gammon.com.au/electronics

Nick Gammon

http://www.gammon.com.au/electronics

mdb024

Oops. Got confused with my terminology up there. Its a pull-down resistor. When it is open, the pin reads low. When it is closed, the pin reads high. (I modified the original post)

Quote
Code: [Select]


  delay(100);     //once the switch has been pressed, wait 0.1 seconds for debounce


That would be a lllooonnnggg time for a switch to bounce.


The 0.1 second delay isn't for purposes of debouncing the switch. The delay is in there just to be safe that the wheel has turned far enough to be securely pressing the switch down. It takes about 0.6 seconds to make one revolution, so I added that delay since I had the extra time.

Quote
You need to implement the debounce code inside the while loop. Your while condition should be checking a "state" variable while inside the loop you are taking the "reading" and only setting "state" when you've held the same "reading" for the same debounce time.


Okay. From looking at your logic, I think I understand, but don't know how to translate that into code (I'm very new at this). If anyone could help out, that'd be great.

Arrch


Okay. From looking at your logic, I think I understand, but don't know how to translate that into code (I'm very new at this). If anyone could help out, that'd be great.


Look at the debounce example.

mdb024

Okay, well I tried to integrate the code from the debounce example into my code, as shown below. I only need the code to be debounced upon the switch being pressed. Once the switch is released, it doesn't matter if it bounces, because the motor will have turned off already, and I am not reading any other inputs off of this switch.

Code: [Select]

int motorSwitch = 2;     // the number of the pushbutton pin
int motorPin =  XX;      // the number of the LED pin
int buttonPressed;             // the current reading from the input pin
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
 pinMode(motorSwitch, INPUT);
 pinMode(motorPin, OUTPUT);}

void loop() {

 while(digitalRead(motorSwitch) == LOW) {:}       //until the switch is pressed, don't do anything.  
int reading = digitalRead(motorSwitch);               //should read LOW    
while(
 (if (reading != lastButtonState) {                                   // If the switch changed, due to noise or pressing:
      lastDebounceTime = millis();}                                    // reset the debouncing timer
 if ((millis() - lastDebounceTime) > debounceDelay) {      // whatever the reading is at, it's been there for longer  // than the debounce  
                                                                              //delay, so take it as the actual current state and set to "ButtonPressed"                                                            
   ButtonPressed = reading;                                                
  ) == ButtonPressed {;}                                     //if the switch is debounced, create the variable "ButtonPressed". As the "while" loop
                                                                          //outputs "ButtonPressed," do nothing
 );
digitalWrite(motorPin, LOW)                                     //once the switch is released, turn the motor off.


Did I integrate this correctly?

PaulS

Quote
Did I integrate this correctly?

No. The while statement needs some conditional statement in the parentheses, not all the stuff you put there.

Msquare

I'm with PaulS.

But I actually think your first attempt was better. It should be sufficient for the scenario you describe.

The debounce, even when implemented correctly, would not help. I think something else is causing the switch sensing to change. For example that you power the motor directly from the Arduino, or it is insufficently decoupled (capacitors) - the Arduino resets, and your program starts from the beginning, or just plain malfunctions.

Nick Gammon


I understand the concept of debouncing a switch (take the reading about 10 ms apart and if they are the same, consider that the switch has settled), but cannot integrate this idea in the while function.


The simplest method of debouncing, considering you are already using a delay, is to only use the delay.

eg.

Code: [Select]
if (reading == HIGH)
{
delay (10);  // debounce for 10 mS

// do other stuff

}


Who cares what the switch reading is after the debounce time? The fact is that the switch was pressed, right?
http://www.gammon.com.au/electronics

Go Up