parallel tasks or array

Hi there,

I am trying to write some code that counts button presses from two buttons.

I need each button to be debounced so that even if a button is pressed and held it still only counts as one press.
my friend mentioned something about parallel tasks or an array but after looking them up I got quite confused...

This is the code I have so far:

This code is written for one sensor at the moment
*/

// constants:
const int  sensorPin1 = 2;    // the pin that sensor1 is attached to


// variables:
int counter1 = 0;   // counter for the number of products passing through
int sensorState1 = 0;         // current state of the sensor
int lastSensorState1 = 0;     // previous state of the sensor

void setup() {
  // initialize the sensor pin as a input:
  pinMode(sensorPin1, INPUT);
  // initialize serial communication:
  Serial.begin(9600);
}


void loop() {
  // read the sensor input pin:
  sensorState1 = digitalRead(sensorPin1);

  // compare the sensornState1 to its previous state
  if (sensorState1 != lastSensorState1) {
    // if the state has changed, check to see if it is a change 
   //from high to low or low to high
    if (sensorState1 == HIGH) {
      // if the current state is HIGH then increment the counter
      
      counter1++;
      Serial.println(counter1);
    } 
    else {
      // if the current state is LOW then the button
      // went from on to off:
      Serial.println(counter1); 
    }
  }
  // save the current state as the last state, 
  //for next time through the loop
  lastSensorState1 = sensorState1;
  delay(20);
}

How can I make it so that this same code runs with the other button as the input at the same time so for example: if one button is being pressed with 2 second hold and 2 second intervals and increments its counter, the other button could be pressed for 1 second hold and 1 second intervals and increment its counter at the same time.

thank you in advance for any suggestions you may have! (I'm a noob so I apologise if I am missing something obvious!!)

I use Mr. Gammon’s Switch Manager library for switch handling.
See post #1
http://www.gammon.com.au/forum/?id=11955
http://gammon.com.au/Arduino/SwitchManager.zip
.

Have a look at the code in Several Things at a Time. It includes one button but could easily be extended.

...R

You could just poll the two buttons one right after the other. Copy this code and change the variables to the other button and put it after this code in the loop. What you have here isn't blocking, so both buttons will be being polled continuously.

I will try all suggestions, did this one first, can someone explain why it doesn't like this:

// --------CONSTANTS (won't change)---------------
const int sensorPinIn = 1; // the pin number for the button
const int sensorPinOut = 2;// the pin number for the button
//------------ VARIABLES (will change)---------------------
int sensorState1 = 1;
int sensorState2 = 1;
int lastSensorState1 = 1;
int lastSensorState2 = 1;
int inputs = 0;
int outputs = 0;

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

void setup() {

  Serial.begin(9600);
  
      // set the button pin as input with a pullup resistor to ensure it defaults to HIGH
  pinMode(sensorPinIn, INPUT_PULLUP);
  pinMode(sensorPinOut, INPUT_PULLUP);
 
}

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

void loop() {

  readButton(sensorPinIn);               // call the functions that do the work
  readButton(sensorPinOut);
  Serial.println("inputs = ", inputs);
  Serial.println("outputs = ", outpus);

}

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

void readButton(sensorPinIn) {
  digitalRead(sensorPinIn) = sensorState1;
  if (sensorState1 != lastSensorState1) {
    if (sensorState1 = 0) {
      inputs++;
    }
  }
}

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

void readButton(sensorPinOut) {
  digitalRead(sensorPinOut) = sensorState2;
  if (sensorState2 != lastSensorState2) {
    if (sensorState2 = 0) {
      outputs++;
    }
  }  
}
//========================================END

Explain what you mean by "doesn't like this"

it won’t compile:

Arduino: 1.6.4 (Windows 8.1), Board: “Arduino Uno”

SeveralThingsAtTheSameTimeRev1:5: error: variable or field ‘readButton’ declared void
SeveralThingsAtTheSameTimeRev1:5: error: ‘sensorPinIn’ was not declared in this scope
SeveralThingsAtTheSameTimeRev1:6: error: variable or field ‘readButton’ declared void
SeveralThingsAtTheSameTimeRev1:6: error: ‘sensorPinOut’ was not declared in this scope
SeveralThingsAtTheSameTimeRev1.ino: In function ‘void loop()’:
SeveralThingsAtTheSameTimeRev1:28: error: ‘readButton’ was not declared in this scope
SeveralThingsAtTheSameTimeRev1:30: error: call of overloaded ‘println(const char [10], int&)’ is ambiguous
SeveralThingsAtTheSameTimeRev1.ino:30:37: note: candidates are:
In file included from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Stream.h:26:0,
from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/HardwareSerial.h:29,
from C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:223,
from SeveralThingsAtTheSameTimeRev1.ino:2:
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:74:12: note: size_t Print::println(unsigned char, int)
size_t println(unsigned char, int = DEC);
^
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:74:12: note: no known conversion for argument 1 from ‘const char [10]’ to ‘unsigned char’
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:75:12: note: size_t Print::println(int, int)
size_t println(int, int = DEC);
^
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:75:12: note: no known conversion for argument 1 from ‘const char [10]’ to ‘int’
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:76:12: note: size_t Print::println(unsigned int, int)
size_t println(unsigned int, int = DEC);
^
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:76:12: note: no known conversion for argument 1 from ‘const char [10]’ to ‘unsigned int’
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:77:12: note: size_t Print::println(long int, int)
size_t println(long, int = DEC);
^
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:77:12: note: no known conversion for argument 1 from ‘const char [10]’ to ‘long int’
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:78:12: note: size_t Print::println(long unsigned int, int)
size_t println(unsigned long, int = DEC);
^
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:78:12: note: no known conversion for argument 1 from ‘const char [10]’ to ‘long unsigned int’
SeveralThingsAtTheSameTimeRev1:31: error: ‘outpus’ was not declared in this scope
SeveralThingsAtTheSameTimeRev1.ino: At global scope:
SeveralThingsAtTheSameTimeRev1:37: error: variable or field ‘readButton’ declared void
variable or field ‘readButton’ declared void

This report would have more information with
“Show verbose output during compilation”
enabled in File > Preferences.

Have you ever used digitalRead()?

digitalRead(sensorPinIn) = sensorState1;
. . .
digitalRead(sensorPinOut) = sensorState2;

Also, you have two functions with the same name:

void readButton(sensorPinIn) {
. . .
void readButton(sensorPinOut) {

LarryD:
Have you ever used digitalRead()?

digitalRead(sensorPinIn) = sensorState1;
. . .
digitalRead(sensorPinOut) = sensorState2;

wrong way around my bad,

It happens :art:

BTW, const int sensorPinIn = 1; // the pin number for the button
Since pin 1 is serial TX, maybe use a different one.

.

void readButton2(sensorPinOut) {
  sensorState2 = digitalRead(sensorPin2);
  if (sensorState2 != lastSensorState2) {
    if (sensorState2 = 0) {
      outputs++;
    }
  }  
}

changed second function to this ^ and put this in void loop: readButton2(sensorPinOut);

it wont compile now, the compiling progress bar just sits there at like 1/4. tried restarting everything still doing it...?

Attach the sketch as it is now.

  Serial.println("outputs = ", outpus);

Looks like a typo (misspelled).

I have rectified this

FYI
This may be of some interest later.

/*SwitchManager skeleton 
 LarryD
 
 This is 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\YouName\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 += wait;  
    }
    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
//======================================================================

yes that looks interesting but I am reluctant to use time for debouncing as the buttons may need to be pressed and held for long periods of time

SeveralThingsAtTheSameTimeRev1.ino (1.32 KB)

This library accommodates extended presses.

okay, where can I download this library?