Pushbotton Counter

I am working on some software where I have three different cases. I want it so when the push button is pushed the first time, the first routine occurs. Then when pushed again, the second routine and then the third. After the third routine I want the counter to reset to 0. And then start over again.

I conceptually understand how I want to do it, but I can't think of how to program it correctly. I am an EE lol software is not my expertise.

Thanks in advance.

// <http://arduino.cc/forum/index.php/topic,142400.0.html>

class push_button_t
{
    const uint8_t   _pin;
    const uint8_t   _transition_level;
    const uint8_t   _number_of_states;

    uint8_t         _press_counter;
    uint8_t         _state_then;

public:
    push_button_t(uint8_t pin, uint8_t transition_level = LOW, uint8_t number_of_states = 2)
        : _pin(pin)
        , _transition_level(transition_level)
        , _number_of_states(number_of_states)
        
        , _press_counter(0)
        , _state_then(0)
    {}

    void begin()
    {
        pinMode(_pin, INPUT);
    }

    operator uint8_t()
    {
        uint8_t state_now = digitalRead(_pin);
        if ( state_now != _state_then )
        {
            if ( state_now == _transition_level )
            {
                _press_counter++;
                _press_counter %= _number_of_states;
            }
        }
        
       _state_then = state_now;

       return _press_counter;
    }
};

class led_t
{
    const uint8_t     _pin;

public:    
    led_t(uint8_t pin) : _pin(pin)      {}

    void begin()                        { pinMode(_pin, OUTPUT); }
    
    uint8_t operator = (uint8_t rhs)    { digitalWrite(_pin, rhs); return rhs; }
    operator uint8_t ()                 { return ((LOW == digitalRead(_pin)) ? LOW : HIGH); }
};


const uint8_t   pinLED      = 33;   // chipKIT Basic I/O Shield LD1
const uint8_t   pinBUTTON   =  4;   // chipKIT Basic I/O Shield BN1

led_t           led(pinLED);
push_button_t   button(pinBUTTON, LOW, 4);

void loop()
{
    switch ( button )
    {
        case 0: led = 0;                    break;
        case 1: led = !led;  delay(125UL);  break;
        case 2: led = !led;  delay(250UL);  break;
        case 3: led = !led;  delay(500UL);  break;
    }
}

void setup()
{
    led.begin();
    button.begin();
}
push_button_t   button(pinBUTTON, LOW, 4);

void loop()
{
    switch ( button )
    {

The variable button is an instance of a class. It can't be used as in a switch statement.

You might think so but due to the use of the conversion operator 'operator uint8_t()' it can, and does, work just fine.

Try it!

A version for you to test with below, just adjust 'pinBUTTON' as required.

//#define NDEBUG

#include <Arduino.h>


#if !defined(NDEBUG)

#define DebugStr(STR)           Serial.print(STR)
#define DebugStrln(STR)         Serial.println(STR)
#define DebugDelay(MILLIS)      delay(MILLIS)

#else

#define DebugStr(STR)
#define DebugStrln(STR)
#define DebugDelay(MILLIS)

#endif


class push_button_t
{
    const uint8_t   _pin;
    const uint8_t   _transition_level;
    const uint8_t   _number_of_states;

    uint8_t         _press_counter;
    uint8_t         _state_then;

public:
    push_button_t(uint8_t pin, uint8_t transition_level = LOW, uint8_t number_of_states = 2)
        : _pin(pin)
        , _transition_level(transition_level)
        , _number_of_states(number_of_states)
        
        , _press_counter(0)
        , _state_then(0)
    {}

    void begin()
    {
        DebugStrln(__PRETTY_FUNCTION__);
    
        pinMode(_pin, INPUT);
    }

    operator uint8_t()
    {
        DebugStrln(__PRETTY_FUNCTION__);
    
        uint8_t state_now = digitalRead(_pin);
        if ( state_now != _state_then )
        {
            if ( state_now == _transition_level )
            {
                _press_counter++;
                _press_counter %= _number_of_states;
            }
        }
        
       _state_then = state_now;

       return _press_counter;
    }
};


const uint8_t   pinBUTTON = 4;


push_button_t   button(pinBUTTON, HIGH, 4);


void funct4()   { DebugStrln(__PRETTY_FUNCTION__); }
void funct3()   { DebugStrln(__PRETTY_FUNCTION__); }
void funct2()   { DebugStrln(__PRETTY_FUNCTION__); }
void funct1()   { DebugStrln(__PRETTY_FUNCTION__); }

void loop()
{
    switch ( button )
    {
        case 0: funct1(); break;
        case 1: funct2(); break;
        case 2: funct3(); break;
        case 3: funct4(); break;
    }
}

void setup()
{
#if !defined(NDEBUG)
    Serial.begin(9600);
#endif

    button.begin();
}

You might think so but due to the use of the conversion operator 'operator uint8_t()' it can, and does, work just fine.

In most cases, operators are defined to make a class behave in a manner that the users expect. For instance, one would, in a string class, overload the + operator, or, for a list class, one would overload the {} operator.

I don't see a reasonable use for the () operator in a button class. One does not expect an instance name by itself to be equivalent to a function call. Adding a method to the class, with a meaningful name to get that value returned by the () operator is a MUCH better idea, in my opinion.

And yet this is exactly what conversion operators are for. They are a type of 'getter' function.

If you are going to have a conversion operator, is there any reason not to provide conversion to bool instead of to uint8_t?

Or is this just me still having mental problems with digitalWrite( int,int) vs digitalWrite( int, bool)

Or is this just me still having mental problems with digitalWrite( int,int) vs digitalWrite( int, bool)

For that matter, are there really plans to create an Arduino with more than 255 pins? Does digitalWrite() need to use an int as the pin number?

'digitalWrite' uses 'uint8_t' for both parameters. And yes other conversion operator can be defined.