Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
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:
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 21 Sep 2015Hi 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; } } }
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 21 Sep 2015Thank 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 21 Sep 2015
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).