currently a button number is generated when a button is pressed, then a "0" gets returned
"Generated" isn't really correct. "Determined" is.
You already know which switch is pressed - you have it's number - if any. You can determine that it is the same number as last time, or it isn't. When the number changes (the current number isn't the same as the previous number), you would take the same action as you would take if the switch state changed, were you using digital switches.
So I tried MorganS's code example and what happened is what i was thinking might...It doesn't do the long press action, it immediately goes to the " if pressed_button == 1" command. If I change that button number to a
different one(thats not declared in the "getButton" function), the long press does work.
I currently have 2 pushbuttons with a breadboard and resistors for my inputs, so I can test at least
2 different buttons. This modified code now has button 1 for one hardware button, and button 3 for
my second hardware button. I want button 1 press/release to trigger "volume+" then press and hold button 1 to do "volume-" .
void loop(void)
{
int button, button2, pressed_button;
static unsigned long buttonPressTime;
static boolean buttonWasHeldDown = false;
const unsigned long BUTTON_LONG_PRESS = 2000; //milliseconds - the duration of a 'long' press
button = getButton();
if (button != old_button)
{
delay(50); // debounce
button2 = getButton();
if (button == button2)
{
old_button = button;
pressed_button = button;
Serial.println(pressed_button);
if (pressed_button == 1)
{
ble.print("AT+BleHidControlKey=");
ble.println("VOLUME+");
}
if (pressed_button == 3)
{
ble.print("AT+BleHidControlKey=");
ble.println("PLAYPAUSE");
}
}
buttonWasHeldDown = false;
buttonPressTime = millis(); //record when the button was initially pressed
} else {
//the button is not a new button - is it held down long enough?
//Well, first we are only interested in one or two buttons that have the long-press function
if(button == 1)
{
if(!buttonWasHeldDown)
{
//so far, we have not detected it as a held-down button
if(millis() - buttonPressTime > BUTTON_LONG_PRESS)
{
buttonWasHeldDown = true; //set this so we don't do the held-down action more than once
Serial.println("button was held down");
//do the held-down action
ble.print("AT+BleHidControlKey=");
ble.println("VOLUME-") ;
}
}
}
}
}
/**************************************************************************/
/*!
Checks for user input via the Steering Wheel Control wire
*/
/**************************************************************************/
int getButton()
{
int i, z, sum ;
int button;
sum = 0;
for (i=0; i < 4; i++)
{
sum += analogRead(A0);
}
z = sum / 4;
if (z > 650 && z < 690) button = 0;
else if (z > 840 && z < 860) button = 1;
else if (z > 970 && z < 1010) button = 3;
else button = 0;
return button;
}
Just to expand the conversation (and for my own curiosity) -- why are you attempting to do an inherently digital thing (detect pressed / not-pressed) by analog means? Are you really that short of digital GPIO that you can’t assign each button its own digital input?
Doing so would immediately solve your problem of mapping different input voltage ranges to individual button pressed / not-pressed states. And, it would have the added benefit of being able to detect if more than one button is being pressed at a time. I don’t see any provision for doing so in your current code -- it would be difficult since 5 buttons represent 32 different combinations of pressed / not-pressed. Given 5 buttons, I guarantee that some user will try to press more than one of them simultaneously. At that point the operation of your system will be undefined.
gfvalvo:
Just to expand the conversation (and for my own curiosity) -- why are you attempting to do an inherently digital thing (detect pressed / not-pressed) by analog means? Are you really that short of digital GPIO that you can’t assign each button its own digital input?
Doing so would immediately solve your problem of mapping different input voltage ranges to individual button pressed / not-pressed states. And, it would have the added benefit of being able to detect if more than one button is being pressed at a time. I don’t see any provision for doing so in your current code -- it would be difficult since 5 buttons represent 32 different combinations of pressed / not-pressed. Given 5 buttons, I guarantee that some user will try to press more than one of them simultaneously. At that point the operation of your system will be undefined.
I think I get what your're saying, but the hardware config is a steering wheel with media buttons on it, that outputs to one wire, multiplexed through different resistances on each button..maybe i'm not really understanding. I suppose if each wheel button had it's own output wire... ?
If so, that’s unfortunate. You’ll just have to keep pounding that square peg into the round hole. As I said, consider the multiple buttons pressed scenario.
If so, that’s unfortunate. You’ll just have to keep pounding that square peg into the round hole. As I said, consider the multiple buttons pressed scenario.
Yes that's exactly how it works. I could do two buttons pressed at the same time, but received analog
voltage can't overlap any other button value..I have no way to adjust the resistance values per switch, as
that is all built into the steering wheel switches. So the only other real option is to use more than one
function per switch value, such as double click, press/hold, press/release. Having more than one click do something may get complicated as you'd have to remember how many clicks does what on the same button..
Press/release and Press/hold could give a total of 10 different operations, with 5 available buttons. Not sure
how much interaction with a phone/tablet you want to do while driving!
Matt1995:
I could do two buttons pressed at the same time .....
My point wasn’t that you should add MORE functionality by encoding multiple button presses into even more actions. It’s that you should consider what will happen IF (really when) the user presses two or more buttons at the same time. Will something unexpected (bad) happen? Like I said, at this point it’s undefined and that’s never a good thing in control applications.
Matt1995:
how do I go about translating these statements?
That code depends on the value in buttonVal. You just need to use your analogRead() to put a suitable value in buttonVal in place of using digitalRead(). So, something like this
boolean buttonVal = HIGH; // value read from button
boolean buttonLast = HIGH; // buffered value of the button's previous state
analogVal = analogRead(analogInputPin);
if (analogVal > NNN) {
buttonVal = LOW; // assuming LOW means that the button was pressed
}
// Button pressed down
if (buttonVal == LOW && buttonLast == HIGH && (millis() - upTime) > debounce)
Thank you all for your help. I really do appreciate it. Using Morgan's code example, I was able to get
it to work for the most part. Only one issue..To trigger the press/hold event, it first triggers the push/release event. This code is setup for pushbutton 1 to go volume+ with press/release, then volume-
with press/hold. So to be clear, if i press/hold it for volume down, it first does volume up, wait the hold time, then it does volume down. Thinking this should be an easy fix?
void loop(void)
{
int button, button2, pressed_button;
static unsigned long buttonPressTime;
static boolean buttonWasHeldDown = false;
const unsigned long BUTTON_LONG_PRESS = 2000; //milliseconds - the duration of a 'long' press
button = getButton();
if (button != old_button)
{
delay(50); // debounce
button2 = getButton();
if (button == button2)
{
old_button = button;
pressed_button = button;
Serial.println(pressed_button);
if (pressed_button == 1)
{
ble.print("AT+BleHidControlKey=");
ble.println("VOLUME+");
}
if (pressed_button == 2)
{
ble.print("AT+BleHidControlKey=");
ble.println("PLAYPAUSE");
}
}
buttonWasHeldDown = false;
buttonPressTime = millis(); //record when the button was initially pressed
} else {
//the button is not a new button - is it held down long enough?
//Well, first we are only interested in one or two buttons that have the long-press function
if(button == 1)
{
if(!buttonWasHeldDown)
{
//so far, we have not detected it as a held-down button
if(millis() - buttonPressTime > BUTTON_LONG_PRESS)
{
buttonWasHeldDown = true; //set this so we don't do the held-down action more than once
Serial.println("button was held down");
ble.print("AT+HidBleControlKey=");
ble.println("VOLUME-");
}
}
}
}
}
/**************************************************************************/
/*!
Checks for user input via the Steering Wheel Control wire
*/
/**************************************************************************/
int getButton()
{
int i, z, sum ;
int button;
sum = 0;
for (i=0; i < 4; i++)
{
sum += analogRead(A0);
}
z = sum / 4;
if (z > 650 && z < 690) button = 0;
else if (z > 840 && z < 860) button = 1;
else if (z > 970 && z < 1010) button = 2;
else button = 0;
return button;
}
It might be if your quick press and long press functions for one switch did similar things. But, volume up for short press and volume down for long press are not similar things.
You could wait for the release event to do anything. If the switch that was released had been held a short time, do one thing. If it had been held a long time, do something else. Nothing would happen on press, except for recording the time that the press started.
PaulS:
You could wait for the release event to do anything. If the switch that was released had been held a short time, do one thing. If it had been held a long time, do something else. Nothing would happen on press, except for recording the time that the press started.
I believe I was looking at an "instructable" that did this. The button press didn't do anything but
set a timer, then when released did the event. How long it took from press to release was then mapped out
to 2 different events. Is this what you are describing? Knowing what i'm trying to do, does this seem the best approach? Again, Thank you.
Anyone have any code examples to try?...I just cant figure this out. About to ditch the one-button-two-function idea completely...frustration is setting in...
Matt1995:
Anyone have any code examples to try?...I just cant figure this out. About to ditch the one-button-two-function idea completely...frustration is setting in...
Post the latest version of your program - the complete program.
This is the code version that was suggested by Morgan, and i made it work. This activates volume+ first, then hold button, then it does volume down. Press/release needs to be volume up, press/hold needs to be volume down without vol up first. Thanks for the help.
void loop(void)
{
int button, button2, pressed_button;
static unsigned long buttonPressTime;
static boolean buttonWasHeldDown = false;
const unsigned long BUTTON_LONG_PRESS = 2000; //milliseconds - the duration of a 'long' press
button = getButton();
if (button != old_button)
{
delay(50); // debounce
button2 = getButton();
if (button == button2)
{
old_button = button;
pressed_button = button;
Serial.println(pressed_button);
if (pressed_button == 1)
{
ble.print("AT+BleHidControlKey=");
ble.println("VOLUME+");
}
if (pressed_button == 2)
{
ble.print("AT+BleHidControlKey=");
ble.println("PLAYPAUSE");
}
}
buttonWasHeldDown = false;
buttonPressTime = millis(); //record when the button was initially pressed
} else {
//the button is not a new button - is it held down long enough?
//Well, first we are only interested in one or two buttons that have the long-press function
if(button == 1)
{
if(!buttonWasHeldDown)
{
//so far, we have not detected it as a held-down button
if(millis() - buttonPressTime > BUTTON_LONG_PRESS)
{
buttonWasHeldDown = true; //set this so we don't do the held-down action more than once
Serial.println("button was held down");
ble.print("AT+HidBleControlKey=");
ble.println("VOLUME-");
}
}
}
}
}
/**************************************************************************/
/*!
Checks for user input via the Steering Wheel Control wire
*/
/**************************************************************************/
int getButton()
{
int i, z, sum ;
int button;
sum = 0;
for (i=0; i < 4; i++)
{
sum += analogRead(A0);
}
z = sum / 4;
if (z > 650 && z < 690) button = 0;
else if (z > 840 && z < 860) button = 1;
else if (z > 970 && z < 1010) button = 2;
else button = 0;
return button;
}
Ok..finally got something working. After you guys explaining to me about all this, I referenced this
code here
Made some changes, and pretty much ditched the whole loop from my original code, and just used
the "getButton()" function as that works perfectly. Now I just have to figure out adding regular buttons.
Really appreciate all the help here. Don't know how you guys do this lol.
Here's some example code which determines a short or long press on an analogReading. It waits for a button release to determine the timing, but the long press could be placed on a time out instead of a release.
I made the code to check the reading into a function. My test environment was to switch 3.3v to an analogPin, with a default to ground when no press. You may find some of this useful.
#define noEvent 0
#define shortPress 1
#define longPress 2
const byte analogReadPin = A5;
void setup() {
Serial.begin(115200);
Serial.println("Long/Short analogRead Button Press");
}
void loop() {
byte event = checkAnalogRead(analogReadPin);//checks for short or long press
switch (event) {
case shortPress:
Serial.println("Run Shortpress Event Code ");
//do short press code
break;
case longPress:
Serial.println("Run longPress Event Code ");
//do long press code
break;
}
}
byte checkAnalogRead(byte analogReadPin)
{
const unsigned long shortTime = 1500;// if values are the same, all presses are either short or long
const unsigned long longTime = 1500;
static boolean startTimeOut = false;
static int reading = 0;
static int previousReading = 0;
static unsigned long startOn = 0;
static unsigned long buttonPressDuration = 0;
const int targetReading = 685;//3.3v
const byte tolerance = 50;
#define lowBound targetReading - tolerance
#define highBound targetReading + tolerance
byte result = noEvent;
reading = analogRead(analogReadPin);
previousReading = reading;
delay(50);//debounce
reading = analogRead(analogReadPin);
//are the two reading the same and timeOut not started
if (startTimeOut == false && ((reading > lowBound && reading < highBound) && (previousReading > lowBound && previousReading < highBound))) //pressed
{
Serial.println("pressed");
startOn = millis();
startTimeOut = true;
}
if (startTimeOut == true && (reading < lowBound || reading > highBound))//released
{
Serial.println("released");
buttonPressDuration = millis() - startOn;
startTimeOut = false;
}
if (buttonPressDuration >= longTime)
{
Serial.print("long press ");
Serial.println(buttonPressDuration);
buttonPressDuration = 0;
result = longPress;
}
if (buttonPressDuration > 0 && buttonPressDuration <= shortTime)
{
Serial.print("shortpress ");
Serial.println(buttonPressDuration);
buttonPressDuration = 0;
result = shortPress;
}
return result;
}
Thanks cattledog! I'm actually in the process now of trying to make 2 separate functions for press/release
and press/hold. What I ended up doing was modifying the code I found on that Instructable link for the one button-two-function part, then using the code I originally posted in the start of this thread for press/release. Both are all in the loop(), but I want to clean it up a bit and put those into separate
functions. The way it works, the 2 function code can time it so it reads the duration of the button press, then after the defined time, issue the command, and then also keeps track of the button state for press/hold functionality. The button code for press/release only, makes it that only one command is issued, even if you hold the button down. Problem I was having is that I was trying to merge other example code that uses button timers of "on" duration, but the code was ignoring the "on" time because of several statements in the code to determine button states. Hope that's not confusing lol. Appreciate the code!