9 years, 1 month ago.

Asserted_held when released triggers deassert

Hi

I have set up a button "sw2" the following way on my FRDM-K64F board:

sw2.attach_deasserted( &sw2Frequency );

sw2.attach_asserted_held( &sw2TransceiveMode_held );

sw2.setSamplesTillAssert( 1 );

sw2.setSamplesTillHeld( 100 ); Held press for 20*100ms = 2 seconds

sw2.setAssertValue( 0 );

sw2.setSampleFrequency( 20000 );

What I want is:

- when sw2 is pushed and quickly released, sw2Frequency function is called.

- when sw2 is pushed and held for 2 seconds, sw2TransceiveMode_held function is called.

What I get is:

- when sw2 is pushed and quickly released, sw2Frequency function is called. (as I expect)

- when sw2 is pushed and held for 2 seconds, sw2TransceiveMode_held function is called. As I expect, EXCEPT when the button is released again, sw2Frequency function gets called.

How can I avoid calling sw2Frequency when releasing after a held press?

Thank you!

Question relating to:

InterruptIn style DigitalIn debounced with callbacks for pin state change and pin state hold. debounce, DigitalIn, InterruptIn

I found a solution!

EDIT: NOPE - still not working properly.

EDIT EDIT: Now it works as I want it to! Thanks to Andy A for helping me along the way.

See code below for my edit of the library (replace in PinDetect.h from line 459 till the end of the file).

void isr(void) {
        int currentState = _in->read();
    
        if ( currentState != _prevState ) { // only runs when change occur (switch)
            if ( _samplesTillAssert == 0 ) {
                _prevState = currentState;
                if ( currentState == _assertValue ){ 
                    _callbackAsserted.call();
                    _samplesTillHeld = _samplesTillHeldReload;
                }
                if ( currentState != _assertValue && _samplesTillHeld ){                              
                    _callbackDeasserted.call();
                    _samplesTillHeld = 0;
                }
                _samplesTillAssert = _samplesTillAssertReload;
            }
            else {
                _samplesTillAssert--;
            }
        }

        if ( _samplesTillHeld ) {
            if ( _prevState == currentState ) {
                _samplesTillHeld--;
                if ( _samplesTillHeld == 0 ) {
                    if ( currentState == _assertValue ) {
                        _callbackAssertedHeld.call();
                    } else {                              
                        _callbackDeassertedHeld.call();
                    }
                }
            }
        }
    }
};

}; // namespace AjK ends.

using namespace AjK;

#endif
posted by Mathias Johnsen 21 Sep 2015

1 Answer

9 years, 1 month ago.

The library is doing exactly what you'd expect, when a button is released you get the callback for the button being released.

Two options to get what you want: 1: Change your code so that it ignores the first deasserted callback after an asserted held callback.

2: Change the library so that it does what you want..

Looking at the library if I'm understanding what it does correctly it's a case of adding one line and moving one other.

  void isr(void) {
        int currentState = _in->read();
    
        if ( currentState != _prevState ) {
            if ( _samplesTillAssert == 0 ) {
                _prevState = currentState;

                if (_samplesTillHeld)               // This if added.  - only call callback if button held count hasn't been reached.
                  if ( currentState == _assertValue ) 
                      _callbackAsserted.call();
                  else                              
                      _callbackDeasserted.call();

                _samplesTillHeld = _samplesTillHeldReload;  // This line moved down
            }
            else {
                _samplesTillAssert--;
            }
        }
        else {
            _samplesTillAssert = _samplesTillAssertReload;
        }
        
        if ( _samplesTillHeld ) {
            if ( _prevState == currentState ) {
                _samplesTillHeld--;
                if ( _samplesTillHeld == 0 ) {
                    if ( currentState == _assertValue ) 
                        _callbackAssertedHeld.call();
                    else                              
                        _callbackDeassertedHeld.call();
                }
            }
            else {
                _samplesTillHeld = 0;
            }
        }
    }
    
};

Thank you for your helpful reply! Unfortunately, changing the library the way you suggested does not seem to work quite as expected. Now, nothing happens with a short press.

posted by Mathias Johnsen 21 Sep 2015

Hi again

It still does not work, but I think I'm getting there.

The problem with the code you suggested, is that _samplesTillHeld is defined as 0 (false) at the top.

Thus if (_samplesTillHeld) statement is never true, which is why no short press can ever be recognized.

I tried this instead, but it still does not work.

The idea is that the reloading of _sampleTillHeld only happens when an asserted press is performed and that the deasserted press only can occur if _sampleTillHeld is true (above zero, e.i. haven't been held for 2 seconds)

void isr(void) {
        int currentState = _in->read();
    
        if ( currentState != _prevState ) { // only runs when change occur (switch)
            if ( _samplesTillAssert == 0 ) {
                _prevState = currentState;
                if ( currentState == _assertValue ){ 
                    _callbackAsserted.call();
                    _samplesTillHeld = _samplesTillHeldReload;       // reload held samples only when asserted press
                }
                if ( currentState != _assertValue && _samplesTillHeld ){    // _samplesTillHeld moved here                          
                    _callbackDeasserted.call();
                }
            }
            else {
                _samplesTillAssert--;
            }
        }
        else {
            _samplesTillAssert = _samplesTillAssertReload;
        }

        if ( _samplesTillHeld ) {
            if ( _prevState == currentState ) {
                _samplesTillHeld--;
                if ( _samplesTillHeld == 0 ) {
                    if ( currentState == _assertValue ) 
                        _callbackAssertedHeld.call();
                    else                              
                        _callbackDeassertedHeld.call();
                }
            }
            else {
                _samplesTillHeld = 0;
            }
        }
    }
posted by Mathias Johnsen 21 Sep 2015

I'm not entirely sure why the posted change didn't work.

_samplesTillHeld should be 0 normally since the button has been deasserted for more than the hold period. When the button is first pressed no asserted callback will be generated and _samplesTillHeld will be set to the timeout vale.

_samplesTillHeld then counts down. If the button is released before _samplesTillHeld reaches 0 the deasserted callback should be triggered. If the counter reaches 0 the asserted held callback is triggered and the next deasserted callback won't be generated.

Personally I would have said it would be far easier and cleaner to fix it in your code. Set a flag in sw2TransceiveMode_held, in sw2Frequency check the flag, if it's set then clear it and exit otherwise carry on as normal. I make that a total of 5 lines of code.

posted by Andy A 21 Sep 2015

Thank you for your help - definitely guided me in the right direction! I found a solution by modifying the library as you suggested. I believe it to be the best way to modify the library to operate in a way that I find intuitive (that is, do one thing on a short press, do another on a long press - to me this means "two buttons in one"). I always prefer not to have too many "Flag hacks" in my main code just to make it more readable.

EDIT: Mmm.. still not working as I want actually. Back to the drawing board.

EDIT EDIT: Oh well, this is becoming confusing, I made a simple mistake in my callback function, but, it actually works with the code I posted as a comment to my own question.

posted by Mathias Johnsen 21 Sep 2015