I planned to add a time setting mode to the alarm clock later, as gravy-- thought I wouldn't need one since the clock chip keeps time-- but with the board not yet built, I keep accidentally disconnecting the DS1307's battery and needing to reset it with a special sketch.
That's a pain, so I'm adding it to the PPAC program next, and to keep the interface simple-- jog/shuttle and a button-- a press and hold event seems appropriate for switching into an otherwise hidden mode, like shutting down a MacBook by holding down the button instead of just clicking it.
Despite a few posted examples on debouncing a button press (explicitly or with a library), I couldn't find any press+hold examples, so I took a stab at it and got a test sketch working pretty quickly with a button and two indicator LEDs. The code is posted below, as a comment.
Subscribe to:
Post Comments (Atom)
/* Click and Press+Hold Test Sketch
ReplyDeleteBy Jeff Saltzman
To keep input interfaces simple, I want to use a single button to:
1) click (fast press and release) for regular button use, and
2) press and hold to enter a configuration mode.
*/
#define buttonPin 19 // analog input pin to use as a digital input
#define ledPin1 9 // digital output pin for LED 1 indicator
#define ledPin2 8 // digital output pin for LED 2 indicator
#define debounce 20 // ms debounce period to prevent flickering when pressing or releasing the button
#define holdTime 2000 // ms hold period: how long to wait for press+hold event
// Button variables
int buttonVal = 0; // value read from button
int buttonLast = 0; // buffered value of the button's previous state
long btnDnTime; // time the button was pressed down
long btnUpTime; // time the button was released
boolean ignoreUp = false; // whether to ignore the button release because the click+hold was triggered
// LED variables
boolean ledVal1 = false; // state of LED 1
boolean ledVal2 = false; // state of LED 2
//=================================================
void setup()
{
// Set button input pin
pinMode(buttonPin, INPUT);
digitalWrite(buttonPin, HIGH );
// Set LED output pins
pinMode(ledPin1, OUTPUT);
digitalWrite(ledPin1, ledVal1);
pinMode(ledPin2, OUTPUT);
digitalWrite(ledPin2, ledVal2);
}
//=================================================
void loop()
{
// Read the state of the button
buttonVal = digitalRead(buttonPin);
// Test for button pressed and store the down time
if (buttonVal == LOW && buttonLast == HIGH && (millis() - btnUpTime) > long(debounce))
{
btnDnTime = millis();
}
// Test for button release and store the up time
if (buttonVal == HIGH && buttonLast == LOW && (millis() - btnDnTime) > long(debounce))
{
if (ignoreUp == false) event1();
else ignoreUp = false;
btnUpTime = millis();
}
// Test for button held down for longer than the hold time
if (buttonVal == LOW && (millis() - btnDnTime) > long(holdTime))
{
event2();
ignoreUp = true;
btnDnTime = millis();
}
buttonLast = buttonVal;
}
//=================================================
// Events to trigger by click and press+hold
void event1()
{
ledVal1 = !ledVal1;
digitalWrite(ledPin1, ledVal1);
}
void event2()
{
ledVal2 = !ledVal2;
digitalWrite(ledPin2, ledVal2);
}
how do you have it wired. i tried on my arduino uno and i get nothing.
DeleteHi! I tried to modify your code to work in a different way: press-on (led1) / hold-off (led1)... i need only to on and off the same output but doesn\t work like i want.
Deletevery, very nice! I think a lot of 'duino with LCD's just got nested menus because of you!
ReplyDeleteGotta say that's a great idea. Seems so simply obvious to do that now that you've stated it. :-)
ReplyDeleteI think that's begging to become a compliment to AlphaBeta's Button abstraction layer: http://www.arduino.cc/playground/Code/Button.
We could start coding all that in two lines like this, and get down to the fun stuff:
Button pressMe = button(2, PULLUP);
if (pressMe.held(1000)) someFunction();
I used something like this in a project I was working on. Though I think this could be compacted further. If you use a simple counter 'while' or 'for' loop, you can have the led turn on, or the function occur right when the threshold between a 'press' and a 'hold' is crossed.
ReplyDeleteAttach this function to an interrupt pin
int ButtonCheck(){
count = 0;
while(digitalRead(But)==HIGH){
delay(10);
count++;
}
if (count > 100){ /button held
return 2; /button held
else if count > 0
return 1; /button pressed
}
}
What about a double press?
ReplyDeleteI'm working on a similar code but with a sensor instead. I've been trying for days to convert the code but no luck.
ReplyDeleteHere's the code I have for the sensor to turn off a single led.
void loop() {
val = analogRead(LDR);
if (val2 < 28)
{digitalWrite(ledPin, HIGH);
//delay(3000);
} else {
digitalWrite(ledPin, LOW); // turn the ledPin off
}
//delay(1000);
}
Thanks, 12 year old from Toronto
You are awesome, this code is flawless.
ReplyDeletei try this code with keys, but i get ever a 'g' and one second later a 'h'.
ReplyDeletei try click, double click long click. always the same --> gh
complete code:
http://pastebin.com/hmSEJgDN
Sorry I don't have time to debug your code but maybe somebody else does.
DeleteAmazing many thanks
ReplyDeleteTHANKS SIR....GREAT CODING
ReplyDeleteYour code is amazingly stupendous!!! I will forever owe you!
ReplyDeleteThanks Jeff, you're a legend for posting this! Believe it or not, I stumbled upon this post just now as I was coming to the final stages of my first ever electronics project which I named "JeffBot". As much as I'd love to say I'd named it after you as gratitude to this post... it was actually due to it being a physical soundboard inspired by the meme quote "My name is Jeff" (by Channing Tatum in the movie 22 Jump Street).
ReplyDeleteUsing an LM386-1 audio amp and an Atmega328p chip (coded on Arduino Uno but later moved to PCB to save on space and costs) I was limited in the amount of buttons I could have. With digital pins 0 and 1 reserved for serial rx and tx, digital 9 as audio input and digital 10 as chip select (for SD card) I was left with 13 pins total for buttons (digital 2, 3, 4, 5, 6, 7, 8 + analog 0, 1, 2, 3, 4, 5). Incorporating your code (tweaked a little for my needs) I now have 24 sounds instead of 12 (I went with 12 buttons instead of 13 for design reasons) which is more than enough, especially as I can have multiple 128Mb SD cards available each with 24 sounds that I can quickly pop in and out!
I can't paste the code as it goes over the comment character limit... I'll try in a second comment in case anyone is interested or would like to try to adopt it for their own project at all.
Very good implementation. I modified for use with a bunch of buttons in a resistor ladder, for those who need it:
ReplyDelete#include
#define debounce 20 // ms debounce period to prevent flickering when pressing or releasing the button
#define holdTime 2000 // ms hold period: how long to wait for press+hold event
#define NO_BTN 0
#define A1_BTN 1
#define A2_BTN 2
#define F1_BTN 3
#define F2_BTN 4
#define F3_BTN 5
#define F4_BTN 6
#define F5_BTN 7
#define DI_BTN 8
#define LF_BTN 9
#define RT_BTN 10
#define SB_BTN 11
#define PW_BTN 12
#define BB_BTN 13
// Button variables
int buttonVal = 0; // value read from button
int buttonLast = 0; // buffered value of the button's previous state
long btnDnTime; // time the button was pressed down
long btnUpTime; // time the button was released
boolean ignoreUp = false; // whether to ignore the button release because the click+hold was triggered
void setup() {
Serial.begin(115200);
}
void loop() {
buttonVal = matrixRead();
// Test for button pressed and store the down time
if (buttonVal != NO_BTN && buttonLast == NO_BTN && (millis() - btnUpTime) > long(debounce)) {
btnDnTime = millis();
}
// Test for button release and store the up time
if (buttonVal == NO_BTN && buttonLast != NO_BTN && (millis() - btnDnTime) > long(debounce)) {
if (ignoreUp == false) buttonPress(buttonLast);
else ignoreUp = false;
btnUpTime = millis();
}
// Test for button held down for longer than the hold time
if (buttonVal != NO_BTN && (millis() - btnDnTime) > long(holdTime)) {
buttonHold(buttonLast);
ignoreUp = true;
btnDnTime = millis();
}
buttonLast = buttonVal;
}
void buttonPress(int btn) {
printf("Received press event for %d\n", btn);
}
void buttonHold(int btn) {
printf("Received hold event for %d\n", btn);
}
int matrixRead() {
int aVal = analogRead(A1);
int bVal = analogRead(A2);
int rtn = NO_BTN;
if (aVal < 1000) {
if (aVal < 40 ) rtn = A1_BTN;
else if (aVal < 100) rtn = A2_BTN;
else if (aVal < 200) rtn = F1_BTN;
else if (aVal < 300) rtn = F2_BTN;
else if (aVal < 400) rtn = F3_BTN;
else if (aVal < 500) rtn = F4_BTN;
else rtn = F5_BTN;
}
if (bVal < 1000) {
if (bVal < 40 ) rtn = DI_BTN;
else if (bVal < 100) rtn = LF_BTN;
else if (bVal < 200) rtn = RT_BTN;
else if (bVal < 300) rtn = SB_BTN;
else if (bVal < 400) rtn = PW_BTN;
else rtn = BB_BTN;
}
return rtn;
}