Pages: [1]   Go Down
Author Topic: debouncing a switch during 'while' loop  (Read 966 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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.


* IMG_0375.jpg (2219.46 KB, 2448x3264 - viewed 9 times.)
« Last Edit: July 26, 2012, 06:18:25 am by mdb024 » Logged

California
Offline Offline
Faraday Member
**
Karma: 82
Posts: 3123
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
Logged

Norfolk UK
Offline Offline
Edison Member
*
Karma: 52
Posts: 2214
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
  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
Logged

Handle every stressful situation like a dog. If you can't eat it or hump it. Piss on it and walk away.

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 551
Posts: 46266
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
  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.
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Could be worse:

Code:
delay (10000);
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
delay (100000);
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:

  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.
Logged

California
Offline Offline
Faraday Member
**
Karma: 82
Posts: 3123
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 6
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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?
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 551
Posts: 46266
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Did I integrate this correctly?
No. The while statement needs some conditional statement in the parentheses, not all the stuff you put there.
Logged

Copenhagen, Denmark
Offline Offline
Edison Member
*
Karma: 26
Posts: 1148
Have you testrun your INO file today?
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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?
Logged

Pages: [1]   Go Up
Jump to: