Hi,
Want to share library I've created for buttons. I've checked a few existing libraries, but didn't find one with support almost use cases (for example repeat) and at the same time with small memory footprint. So I decided to implement my own:
It requires only 4 bytes per button, and supports single press, repeat, release, check state and other combinations.
Feel free to provide your feedback, ask questions.
p.s. I didn't create any examples, because thought they are too trivial, like:
TinyButton button(A0);
if(button.get() & TinyButton::PRESS) Serial.println("Button pressed");
is not robust for all architectures if you define (as would almost everyone) your button statically as a global instance. The reason is that the constructor is called very early in the process, before main() is called and thus before the Arduino supplied init() function is called. So if you set the pin as INPUT_PULLUP for example this might be undone later on when main() and init() are called.
This was a bug for example in the OneButton library that appeared on a few recent platforms (see this issue)
That’s why you’ll see lots of libraries having a begin() or init() function that you call from your setup() function and you’ll handle the pinMode in there.
Also your debounce test is an issue upon your 16 bit variable rollover
Thanks for pointing that, I forgot to add casting to uint16_t of subtraction result. But the concept is correct, in your version it won't work on overrun case. I've created test here:
Well, for me it looks like a bug in the Arduino initialization code, but maybe there are some compelling arguments.. My goal was to avoid excessive operations as much as possible. C++ constructor was intended to init object, and reduce programmer mistakes, like forget to call separate init function.
Anyway, I'll add begin() method, but I think to keep it call from the constructor, what do you say?
Since constructors are called in an undefined order, it's a general problem for any C++ code. The constructor should only initialize it's own members, and not make any calls outside the class.
If you don't want to rely on the user, a typical way to do is to set a flag when initialized and call init() if not set.
I'm using standard c++ data type (uint16_t) - it must be processed the same way on all platforms.
Regarding tests on Arduino - it can be added, I just have a concern that it is common practice for Arduino libraries to delivery tests within it.
I've prepared file structure, but realized that there is already registered TinyButton library. Need to invent new name And as far as I understand, it is better to rename files and class also, to prevent name collision.
I've added begin() method which can be called from setup(), so I think I'm following the Arduino guidelines.
But I kept begin() call from the constructor, which should not break anything. Am I wrong?