That uses the I2C bus and that's what I shall use.
Having said that, the SPI bus pins are now "free" for me to use - which is kind of ironic.
The "lack of inputs" (and outputs) is nearly resolved with those two pins being usable.
But!
For the sake of "future proofing" the project, I shall install the MCP chip.
What about using an infrared remote?
The sensor and remotes are cheap an it only uses a single Arduino pin.
There is a great IR library that makes the software side easy.
Originally I was confused to what to do, but after a lot of bashing my head against the wall and studying the code, I have "learnt" that the EXISTING 6 buttons can be used for different things depending on what the program is doing.
So though they are "scroll buttons" for menus, ENTER and ESCAPE, I have used 5 of those 6 for other things when the clock is displaying.
When the clock was showing, ANY key would excape back to the menu.
That was a severe waste of 5 buttons.
So now, ONLY the ESCAPE key exits the clock.
The other 4 buttons (up, down, left and right) do other things.
I have a "spare button" which is the ENTER one.
Alas the big problem is WHERE these buttons are. As I have a PHI-2 shield, and a LCD ontop of this, the buttons are back from the front of the panel. So they are not visible.
Sure I can put longer thingies on teh buttons so they extend past the front panel and so I can get to them when the unit is mounted in the box.
So really there aren't that many buttons to "put on it". But initially I was confused knowing about this "trick" I since learnt.
As I do'nt like to waste things learnt, and I researched the MCP 23017 which will givev me more I/O I am going to install it anyway as the beauty with this project is that it ca grow easier than the older one I had which if it "grew" mean more wires, a lot more electronics and the linke. This only needs a few more lines of code to do things.
I have bigger ideas for it once I get the next couple of problems resolved.
I did upload a couple of piccies, but can't find them now.
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.
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;
}