Dude. Can you post some pictures? I have read through both your threads and I am really curious what this alarm clock you intend to recreate looks like...
florinc:
You could also have 4 distinct functions per button (simple push, double, long, extra-long).
Also, if you are looking for compactness, you can replace (hardware-wise) 2 simple buttons with a rotary encoder. Which rotary encoder could also have another push button by itself.
Or, you could use a piezo sensor and program it to detect all kinds of knocks or pressures. With only one input you could have a lot of inputs.
Out of interest, could you point me in the direction of the code to detect the length of button press?
(oh, and that is only 3 functions per button.)
#ifndef _CBUTTON_
#define _CBUTTON_
#if ARDUINO < 100
#include <WProgram.h>
#else
#include <Arduino.h>
#endif
// user input actions;
enum {NO_ACTION, BTN_PUSH, BTN_DBL_PUSH, BTN_HOLD, BTN_HOLD_LONG};
class CButton
{
public:
CButton(byte pin);
int checkButton();
private:
byte buttonPin;
// Button timing variables
static const int debounce = 20; // ms debounce period to prevent flickering when pressing or releasing the button
static const int DCgap = 250; // max ms between clicks for a double click event
static const int holdTimeShort = 1000; // ms hold period: how long to wait for press+hold event
static const int holdTimeLong = 5000; // ms long hold period: how long to wait for press+hold event
// Button variables
boolean buttonVal; // value read from button
boolean buttonLast; // buffered value of the button's previous state
boolean DCwaiting; // whether we're waiting for a double click (down)
boolean DConUp; // whether to register a double click on next release, or whether to wait and click
boolean singleOK; // whether it's OK to do a single click
long downTime; // time the button was pressed down
long upTime; // time the button was released
boolean ignoreUp; // whether to ignore the button release because the click+hold was triggered
boolean waitForUp; // when held, whether to wait for the up event
boolean holdEventPast; // whether or not the hold event happened already
boolean longHoldEventPast; // whether or not the long hold event happened already
};
#endif
CButton.cpp:
#include "CButton.h"
CButton::CButton(byte pin)
{
buttonPin = pin;
pinMode(pin, INPUT);
digitalWrite(pin, HIGH);
// Button variables
buttonVal = HIGH; // value read from button
buttonLast = HIGH; // buffered value of the button's previous state
DCwaiting = false; // whether we're waiting for a double click (down)
DConUp = false; // whether to register a double click on next release, or whether to wait and click
singleOK = true; // whether it's OK to do a single click
downTime = -1; // time the button was pressed down
upTime = -1; // time the button was released
ignoreUp = false; // whether to ignore the button release because the click+hold was triggered
waitForUp = false; // when held, whether to wait for the up event
holdEventPast = false; // whether or not the hold event happened already
longHoldEventPast = false;// whether or not the long hold event happened already
}
int CButton::checkButton()
{
int event = NO_ACTION;
buttonVal = digitalRead(buttonPin);
// Button pressed down
if (buttonVal == LOW && buttonLast == HIGH && (millis() - upTime) > debounce) {
downTime = millis();
ignoreUp = false;
waitForUp = false;
singleOK = true;
holdEventPast = false;
longHoldEventPast = false;
if ((millis()-upTime) < DCgap && DConUp == false && DCwaiting == true) DConUp = true;
else DConUp = false;
DCwaiting = false;
}
// Button released
else if (buttonVal == HIGH && buttonLast == LOW && (millis() - downTime) > debounce) {
if (not ignoreUp) {
upTime = millis();
if (DConUp == false) DCwaiting = true;
else {
event = BTN_DBL_PUSH;
DConUp = false;
DCwaiting = false;
singleOK = false;
}
}
}
// Test for normal click event: DCgap expired
if ( buttonVal == HIGH && (millis()-upTime) >= DCgap && DCwaiting == true && DConUp == false && singleOK == true && event != BTN_DBL_PUSH) {
event = BTN_PUSH;
DCwaiting = false;
}
// Test for hold
if (buttonVal == LOW && (millis() - downTime) >= holdTimeShort) {
// Trigger "normal" hold
if (not holdEventPast) {
event = BTN_HOLD;
waitForUp = true;
ignoreUp = true;
DConUp = false;
DCwaiting = false;
//downTime = millis();
holdEventPast = true;
}
// Trigger "long" hold
if ((millis() - downTime) >= holdTimeLong) {
if (not longHoldEventPast) {
event = BTN_HOLD_LONG;
longHoldEventPast = true;
}
}
}
buttonLast = buttonVal;
return event;
}
A rotary switch - to call it - would need two inputs, right?
The rotary encoder I use can replace with two switches. Each click rotating the encoder is equivalent to a button push.
Actually, the second version of the same clock
uses just one button to simulate an encoder that rotates one way.
I'm not sure what you want all these buttons to do with regard to your clock but I built a clock that uses this encoder using only 3 I/O pins to set hours, minutes, day, month, year, day of week & daylight saving.
That infrared idea sounds like the easiest expansion, you can get a remote with a hundred buttons and. All the arduino uses is one pin,
or have it that after a certain setup period the buttons change function