Go Down

Topic: Repeated calls to digitalRead() (Read 164 times) previous topic - next topic

couldabin

I am having some difficulty reading input from a contact switch. The workaround I am using involves some delay, and I'm wondering if the board really needs this.

I am using an Arduino Uno. The input pin is connected to the common terminal on a double-pole contact switch; the NO terminal on the switch goes to ground, the NC goes to 5V. I want to take action when the switch closes but wait for it to be released.

In setup(), I call pinMode(MyPin,INPUT_PULLUP).

In the loop, I poll for MyPin to go HIGH, and then wait until the contact switch opens before proceeding. So:

if(digitalRead(MyPin)==HIGH)
   {
   while(digitalRead(MyPin)==HIGH);
   // continue with the action
   }

What happens is that when the switch is closed, the program goes to the while() statement, but doesn't go any further. It stops there as if MyPin never goes LOW.

The workaround that appears to work:

if(digitalRead(MyPin)==HIGH)
   {
   while(1)
      {
      if(digitalRead(MyPin)==LOW)
          break;
      delay(25);
      }
   // continue with the program
   }

Is the first method actually incorrect? Are there better workarounds? Thanks for your input.

Blackfin

You may be seeing switch bounce. The micro is reading that pin on a timescale of microseconds and every mechanical switch is going to have some mechanical action where the contact is made and broken a number of times over a short period of time. Look up debounce strategies.
 

couldabin

Blackfin, I had not thought of that. What I'm puzzled by is why it doesn't proceed once the contact is released. I can see how bounce might make COM go low prematurely but would that prevent it from correctly responding when the switch is released?

Blackfin

Pls forgive me, I misread your OP. Will mull further...

larryd

#4
Today at 02:58 am Last Edit: Today at 03:08 am by larryd
Please, show complete sketches.
Use CTRL T to format your code.
Attach your sketch between code tags
[code]Paste your sketch here[/code]

You might get some benefit from reading this discussion.

http://www.gammon.com.au/forum/?id=11955   

Also, this code demonstrates Mr. Gammon's switch manager library.
It makes short work of switch handling.
Code: [Select]
/*SwitchManager skeleton
 
 
 This sketch is to introduce new people to the SwitchManager library written by Nick Gammon
 
 The library handles switch de-bouncing and provides timing and state change information in your sketch.
 The SwitchManager.h file should be placed in your libraries folder, i.e.
 C:\Users\YourName\Documents\Arduino\libraries\SwitchManager\SwitchManager.h
 You can download the library at:
 http://gammon.com.au/Arduino/SwitchManager.zip    Thank you Nick!
 
 In this example we have 2 normally open (N.O.) switches connected to the Arduino - increment and decrement.
 The increment switch will also be used as a "Reset" switch if pressed for more than two seconds.
 The two switches are connected between GND (0 volts) and an Arduino input pin.
 The library enables pull-up resistors for your switch inputs.
 Pushing a switch makes its pin LOW. Releasing a switch makes its pin HIGH.
 
 The SwitchManager library provides 10ms de-bounce for switches.
 i.e. enum { debounceTime = 10, noSwitch = -1 };
 If you need more time, edit the SwitchManager.h file
 i.e. enum { debounceTime = 50, noSwitch = -1 }; //here it is changed to 50ms
 */

#include <SwitchManager.h>             
//object instantiations
SwitchManager myIncSwitch;
SwitchManager myDecSwitch;

unsigned long currentMillis;
unsigned long heartBeatMillis;
unsigned long heartFlashRate  = 500UL; // time the led will change state       
unsigned long incShortPress   = 500UL; // 1/2 second
unsigned long incLongPress    = 2000UL;// 2 seconds
unsigned long decShortPress   = 500UL; // 1/2 second

const byte heartBeatLED       = 13;
const byte incSwitch          = 4; //increment switch is on Arduino pin 4
const byte decSwitch          = 5; //decrement switch is on Arduino pin 5

int myCounter;

//======================================================================

void setup()
{
  Serial.begin(9600);

  //gives a visual indication if the sketch is blocking
  pinMode(heartBeatLED, OUTPUT); 

  myIncSwitch.begin (incSwitch, handleSwitchPresses);
  myDecSwitch.begin (decSwitch, handleSwitchPresses);
  //the handleSwitchPresses() function is called when a switch changes state

} //                   E N D  O F  s e t u p ( )

//======================================================================

void loop()
{
  //leave this line of code at the top of loop()
  currentMillis = millis();

  //***************************
  //some code to see if the sketch is blocking
  if (CheckTime(heartBeatMillis, heartFlashRate, true))
  {
    //toggle the heartBeatLED
    digitalWrite(heartBeatLED,!digitalRead(heartBeatLED));
  }

  //***************************
  //check to see what's happening with the switches
  //"Do not use delay()s" in your sketch as it will make switch changes unresponsive
  //Use BlinkWithoutDelay (BWD) techniques instead.
  myIncSwitch.check (); 
  myDecSwitch.check ();

  //***************************
  //put other non-blocking stuff here


} //                      E N D  O F  l o o p ( )


//======================================================================
//                          F U N C T I O N S
//======================================================================


//                        C h e c k T i m e ( )
//**********************************************************************
//Delay time expired function
//parameters:
//lastMillis = time we started
//wait = delay in ms
//restart = do we start again 

boolean CheckTime(unsigned long  & lastMillis, unsigned long wait, boolean restart)
{
  //has time expired for this task?
  if (currentMillis - lastMillis >= wait)
  {
    //should this start again?
    if(restart)
    {
      //yes, get ready for the next iteration
      lastMillis = millis(); 
    }
    return true;
  }
  return false;

} //                 E N D   o f   C h e c k T i m e ( )


//                h a n d l e S w i t c h P r e s s e s ( )
//**********************************************************************

void handleSwitchPresses(const byte newState, const unsigned long interval, const byte whichPin)
{
  //  You get here "ONLY" if there has been a change in a switches state.

  //When a switch has changed state, SwitchManager passes this function 3 arguments:
  //"newState" this will be HIGH or LOW. This is the state the switch is in now.
  //"interval" the number of milliseconds the switch stayed in the previous state
  //"whichPin" is the switch pin that we are examining 

  switch (whichPin)
  {
    //***************************
    //are we dealing with this switch?
  case incSwitch:

    //has this switch gone from LOW to HIGH (gone from pressed to not pressed)
    //this happens with normally open switches wired as mentioned at the top of this sketch
    if (newState == HIGH)
    {
      //The incSwitch was just released
      //was this a short press followed by a switch release
      if(interval <= incShortPress)
      {
        Serial.print("My counter value is = ");
        myCounter++;
        if(myCounter > 1000)
        {
          //limit the counter to a maximum of 1000
          myCounter = 1000;
        }
        Serial.println(myCounter);
      }

      //was this a long press followed by a switch release
      else if(interval >= incLongPress)
        //we could also have an upper limit
        //if incLongMillis was 2000UL; we could then have a window between 2-3 seconds
        //else if(interval >= incLongMillis && interval <= incLongMillis + 1000UL)
      {
        //this could be used to change states in a StateMachine
        //in this example however, we will just reset myCounter
        myCounter = 0;
        Serial.print("My counter value is = ");
        Serial.println(myCounter);
      }

    }

    //if the switch is a normally closed (N.C.) and opens on a press this section would be used
    //the switch must have gone from HIGH to LOW
    else
    {
      Serial.println("The incSwitch was just pushed");
    }

    break; //End of case incSwitch

    //***************************
    //are we dealing with this switch?
  case decSwitch:

    //has this switch gone from LOW to HIGH (gone from pressed to not pressed)
    //this happens with normally open switches wired as mentioned at the top of this sketch
    if (newState == HIGH)
    {
      //The decSwitch was just released
      //was this a short press followed by a switch release
      if(interval <= decShortPress)
      {
        Serial.print("My counter value is = ");
        myCounter--;
        if(myCounter < 0)
        {
          //don't go below zero
          myCounter = 0;
        }
        Serial.println(myCounter);
      }

    }

    //if the switch is a normally closed (N.C.) and opens on a press this section would be used
    //the switch must have gone from HIGH to LOW
    else
    {
      Serial.println("The decSwitch switch was just pushed");
    }

    break; //End of case decSwitch

    //***************************
    //Put default stuff here
    //default:
    //break; //END of default

  } //End switch (whichPin)

} //      E n d   o f   h a n d l e S w i t c h P r e s s e s ( )


//======================================================================
//                      E N D  O F  C O D E
//======================================================================
     


FYI


There is also an example in the IDE that shows how to respond to switch changes rather than switch levels.

"and then wait until the contact switch opens before proceeding"
Waiting for a slow mechanical thing to occur in your sketch makes that sketch lock up and unresponsive.
Don't wait, when the switch goes from HIGH to LOW do your stuff.




No technical PMs.
The last thing you did is where you should start looking.

jremington

#5
Today at 03:07 am Last Edit: Today at 03:10 am by jremington
Quote
The input pin is connected to the common terminal on a double-pole contact switch; the NO terminal on the switch goes to ground,the NC goes to 5V. I want to take action when the switch closes but wait for it to be released.
Your logic is backwards. Switch closure shows up as a LOW on the pin.

You must use INPUT_PULLUP with that setup, or the switch state will be undefined during a transition. I see no reason to connect NC to 5V.

couldabin

Larryd, thanks for the link and info. I'm very curious about one thing you said: "Waiting for a slow mechanical thing to occur in your sketch makes that sketch lock up and unresponsive."

Does constant polling cause the sketch to lock up?

jremington

Quote
Does constant polling cause the sketch to lock up?
No.

larryd

As mentioned, polling does not result in lock up.

However, this does:
while(digitalRead(MyPin)==HIGH);


The following code 'looks for a change in state' on a switch, not a level.
If there was a change, we check to see if it went HIGH, if not, it must have gone LOW.

Code: [Select]
  //******************************************
  //check if this switch has changed state
  switchPosition = digitalRead(ToggleSwitch);

  if (switchPosition != lastToggleSwitchState)
  {
    //update to the new switch state
    lastToggleSwitchState = switchPosition;

    //This switch position has changed, let's do some stuff

    //"HIGH condition code"          <-----<<<<<
    //Switch went from LOW to HIGH
    if (switchPosition == HIGH)
    {
      //Do some HIGH stuff here
    }

    //"LOW condition code"           <-----<<<<<
    //Switch went from HIGH to LOW
    else
    {
      digitalWrite(testLED, !digitalRead(testLED));  //toggle the testLED
    }   



No technical PMs.
The last thing you did is where you should start looking.

couldabin

Larryd, thanks for the response. What I'm not clear on is why execution would not proceed as soon as the switch went LOW. If the switch is LOW when the statement is executed, won't the sketch move on to the next statement immediately? If the switch is HIGH when the statement is first executed, won't the sketch move on as soon as the switch goes LOW? Am I right in assuming that if the program stops on the statement

while(digitalRead(MyPin)==HIGH);

it is only because digitalRead(MyPin) is in fact returning HIGH, regardless of the true state?

jremington

#10
Today at 05:56 pm Last Edit: Today at 05:57 pm by jremington
Quote
it is only because digitalRead(MyPin) is in fact returning HIGH, regardless of the true state?
No, but do keep flailing around. You will get there some day.

RayLivingston

Why not just do a simple test so you can SEE what is going on:

Code: [Select]

void loop()
{
if(digitalRead(MyPin)==HIGH)
    Serial.println("HIGH");
else
    Serial.println("Low");
}
delay(100); // slow down prints


Regards,
Ray L.

Go Up