Help sought using a button to change a value

I want to develop a sketch that (in part) does the following

Monitor a button continuously

Detect a long press (eg 2 seconds)

  • set state to INCREASE
  • for every subsequent short press increase a value by 1

Detect next long press

  • set state to DECREASE
  • for every subsequent short press decrease the same value by 1

Detect next long press

  • exit routine and continue monitoring

-*-

I found this example in the Arduino Library (JC_BUTTON)

// Arduino Button Library
// https://github.com/JChristensen/JC_Button
// Copyright (C) 2018 by Jack Christensen and licensed under
// GNU GPL v3.0, https://www.gnu.org/licenses/gpl.html
//
// Example sketch that uses both short and long button presses to adjust
// a number up and down, between two limits. Short presses increment
// or decrement by one, long presses repeat at a specified rate.
// Every time the number changes, it is written to the serial monitor.

#include <JC_Button.h>              // https://github.com/JChristensen/JC_Button

// pin assignments
const byte
    DN_PIN(4),                      // connect a button switch from this pin to ground
    UP_PIN(5);                      // ditto

Button btnUP(UP_PIN), btnDN(DN_PIN);    // define the buttons

const unsigned long
    REPEAT_FIRST(500),              // ms required before repeating on long press
    REPEAT_INCR(100);               // repeat interval for long press
const int
    MIN_COUNT(0),
    MAX_COUNT(100);

void setup()
{
    btnUP.begin();
    btnDN.begin();
    Serial.begin(9600);
}

void loop()
{
    static int
        count,                          // the number that is adjusted
        lastCount(-1);                  // previous value of count (initialized to ensure it's different when the sketch starts)
    static unsigned long
        rpt(REPEAT_FIRST);              // a variable time that is used to drive the repeats for long presses
    enum states_t {WAIT, INCR, DECR};   // states for the state machine
    static states_t STATE;              // current state machine state

    btnUP.read();                   // read the buttons
    btnDN.read();

    if (count != lastCount)         // print the count if it has changed
    {
        lastCount = count;
        Serial.println(count, DEC);
    }

    switch (STATE)
    {
        case WAIT:                              // wait for a button event
            if (btnUP.wasPressed())
                STATE = INCR;
            else if (btnDN.wasPressed())
                STATE = DECR;
            else if (btnUP.wasReleased())       // reset the long press interval
                rpt = REPEAT_FIRST;
            else if (btnDN.wasReleased())
                rpt = REPEAT_FIRST;
            else if (btnUP.pressedFor(rpt))     // check for long press
            {
                rpt += REPEAT_INCR;             // increment the long press interval
                STATE = INCR;
            }
            else if (btnDN.pressedFor(rpt))
            {
                rpt += REPEAT_INCR;             // decrement the long press interval
                STATE = DECR;
            }
            break;

        case INCR:                              // increment the counter
            count = min(count++, MAX_COUNT);    // but not more than the specified maximum
            STATE = WAIT;
            break;

        case DECR:                              // decrement the counter
            count = max(count--, MIN_COUNT);    // but not less than the specified minimum
            STATE = WAIT;
            break;
    }
}

but it uses two buttons.

Is it possible to achieve this sequence (with or without the longpress auto increment/decrement) with just one button?

Any help or suggestion greatly appreciated, thanks :slight_smile:

Should be possible, you will need to define a long press though.
I would make each long press increment a counter then 1 = increment, 2 = decrement, 3 = exit and reset count to 0.
I would then read the count and use that to decide the action, I would also have a "time out" function so if no button presses for x time exit and reset count to 0.

What else are you controlling?

Is it possible to achieve this sequence (with or without the longpress auto increment/decrement) with just one button?

Consider using a state machine. The system will be in one of several states at a time (see your original post) and the function of the button can be different in each of them

Jack Christensen’s library is quite good.

Another option is Nick Gammon’s switch manager.
http://gammon.com.au/Arduino/SwitchManager.zip

Thanks to all for your replies, I will look into the various suggestions to see what I can figure out. :slight_smile:

Kiwi_Bloke:
Should be possible, you will need to define a long press though.
I would make each long press increment a counter then 1 = increment, 2 = decrement, 3 = exit and reset count to 0.
I would then read the count and use that to decide the action, I would also have a "time out" function so if no button presses for x time exit and reset count to 0.

What else are you controlling?

The project is a small altimeter that I can mount into a water rocket.

The system will be reading a BMP280 pressure/temperature sensor, doing some calculations to determine minimum and maximum altitude and displaying info on an OLED. I have this part working, but it currently requires a fixed reference sea level air pressure to be uploaded with the sketch.

What I am trying to achieve is a means of adjusting that reference pressure while the program is running so that I can calibrate the starting altitude to zero.