Go Down

Topic: One button, press and press+hold analog input (Read 677 times) previous topic - next topic

Matt1995

Hello, I'm having some difficulty trying to get a button to perform 2 separate commands.
Project is 5 switches all going through resistors, but I need only ONE to have a press, along
with a press+hold function.  The code posted is some nice analog debounce code i've found on
the net, merged with my own code for performing the commands. I've been working on this for a few
days and most examples i've seen using millis() use led's, and digital inputs/outputs, so the
translation is confusing for me..i'm a hardware guy, not software. I'd appreciate any advise.

 
Code: [Select]
[/int getButton()       
 {
 
  int i, z, sum ;
  int button;

  sum = 0;
  for (i=0; i < 4; i++)
  {
     sum += analogRead(A0);        // will have 5 buttons through resistors on one input
  }
  z = sum / 4;
  if (z > 650 && z < 690) button = 0;             //aplication requires rest at 3 volts//                               
  else if (z > 840 && z < 860)  button = 1;       // analog input range for a button                                   
  else if (z > 970 && z < 1010) button = 2;       //will have 5 total buttons
             
  else button = 0;
  return button;
 
 }


 void loop(void)
{
 int button, button2, pressed_button; 
  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("VOLUME-"); 
            }
       }           
   }             
}code]

MorganS

Quote
Code: [Select]
      delay(50);                   // debounce
Yes, the old reliable stick-your-head-in-the-sand method of debouncing.

Well, I guess it kind of works. You could say with a pretty high confidence that if it's the same before and after 50ms then it's no longer bouncing and it's probably not detecting button 1 on the way over to visit button 2.

So when button == old_button, don't you think that might be the place to check if this button was held down? When you first detected this as a "new" button, you should remember the time on the millis() clock when you detected that. Then keep glancing at the clock while the button is held down.
"The problem is in the code you didn't post."

Matt1995

Thanks for the reply.  So after  "old button= new button", I should use millis() and if statements
to record button press time? Just trying to wrap my head around this..

Presently, the code works perfectly for single button presses. On serial monitor, a button press registers only once, even if held down, then registers a "button 0" only when released. This is fine, and is actually what is best.  Project involves a car steering wheel control buttons to control an Android phone over bluetooth emulating an HID keyboard...I'd like to use one button on my wheel for a "play/pause" single press, and hold it down for some other random functionality(quite a few HID codes work!)

Is the loop the best place to do this, or would the getbutton function be better? If there is a better or
even simple way to do the above as described, then that's fine too. Basically, can I do what I want
with the code as written? Still tyring to learn, and honestly have a hard time understanding anything
other than simple beginner code..Appreciate the help.

Robin2

Two or three hours spent thinking and reading documentation solves most programming problems.

Matt1995

Thanks for the links. In your example, this is where I start to get confused. Most every example I find for button presses are using digital high/ low and then turning something on/off. Since I'm using an analog input, I dont get how to assign switch states for using millis (). Also, my application needs to see around 3 volts as a no button pushed, rest state. This is also the higest voltage recorded from all 5 buttons I'll be using. Thanks for any insight.

Robin2

#5
Sep 11, 2017, 02:26 pm Last Edit: Sep 11, 2017, 02:26 pm by Robin2
Presumably some value for analogRead() indicates that a particular button is pressed. Just treat that the same as if the button was detected with digitalRead().

On the one hand you might have
Code: [Select]
if (digitalRead( buttonPin ) == LOW) {
   // do stuff;
}

and on the other hand
Code: [Select]
if (analogRead( buttonPin ) > NNN) {
   // do stuff
}


...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Matt1995

That part I understand, but after that, confusion. Most millis () with button examples i find, they are toggling a button state with a boolean eg "ledState= !ledState, then performing a digitalWrite to an led, using the new ledState. Since I'll have a total of 6 different analog range values, with 3 volts value at rest, I dont understand how to go about it. Maybe I don't need to, I just don't know. The code i posted works so well for single button presses, but since it's not all mine, I'm just wondering if I need to scrap it and try something completely differnt..Again, thanks for your time and patience.

Robin2

That part I understand, but after that, confusion. Most millis () with button examples i find, they are toggling a button state with a boolean eg "ledState= !ledState, then performing a digitalWrite to an led, using the new ledState.
What do you want to do instead of toggling an LED?

The program logic will probably be very similar. Think of it this way. If there is someone upstairs who can hear me but can't see me. Suppose I shout OK and he does something. We could have arranged for him to do any of several things such as open a window; turn off a light; dance; wash the floor. But the logic of shouting OK to start the thing is exactly the same.

If you need to do several different things then you just need variables to keep track of the state of each of them.

Have a look at Planning and Implementing a Program and especially how the code is organized into separate single purpose functions. You can think of the functions as equivalent to the tasks open-window, dance etc. And you can arrange for your code to call the appropriate function when the relevant button press is detected.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Matt1995

#8
Sep 11, 2017, 05:00 pm Last Edit: Sep 11, 2017, 06:19 pm by Matt1995
Thank you. In the code I posted, and what I'm trying to do, is take 6 different analog input ranges, compare ranges to account for any slight voltage fluctuations, then assign a button number to each. In the loop, the code recognizes and maps each button number to two lines of code(the two "ble.print") lines to send the media command eg "volume up, vol down, next track". I'm  confused about the toggle part, as I dont need to toggle anything on or off, just send one command. Button state cant be toggled "high or low", as its analog.So I want to take one of those analog input ranges, and have it map to TWO different   commands, depending on if just pressed and released, or pressed and held down.  Also, when no buttons are pressed, it needs to rest at 3 volts, which is around 640 analog (not sure specific, but eg). Hopefully this makes sense.

EDIT...

Would it be good to create 2 variables for each compared analog input value, for each button? Example,

In the code, "z "= a compared input range

Then assign a "high" and "low" to each imput range

Eg ..     if( z <670 && z > 630 ) button1Off= LOW
           if (z < 840  && z >800) button1On= HIGH

Then use this with millis () code, and THEN assign a button number? This would have to be done in the "getbutton" function, not loop...does that matter? This is all i can think of at the moment..right track? Not sure if if the HIGH and LOW variables are correct since I'm not reference a digital output..just a command.

PaulS

Code: [Select]
Then assign a "high" and "low" to each imput range

Eg ..     if( z <670 && z > 630 ) button1Off= LOW

Do you think that way? Most people don't. The usual way to test that a value is in range is to compare the value to the low end first and then to the high end:

Code: [Select]
    if(z > 630 && z < 670)

A particular switch is pressed, or it isn't. That the switch is connected through an resistor ladder and an analog pin isn't relevant.

If the switch being pressed this time is not the same switch that was being pressed last time, a change has occurred. THAT is what you want to record the time of. The change from a switch being pressed to no switch being pressed is important, too.
The art of getting good answers lies in asking good questions.

Robin2

I'm not sure how you want to interpret the buttons. If you are treating them as momentary press buttons then I would set all the button values to 0 before the analogRead() and then set the appropriate ones to 1 depending on what is pressed.

However things would be a little more complicated if you want one press to turn on a buttonState and a subsequent press of the same button to turn it off.

By the way if you test the values in sequence the code can be simplified to
Code: [Select]
if (x < 50) {

}
else if (x < 100) {

}
else if (x < 150 {

}
// etc


...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Matt1995

The code as posted works how I want it with simple button presses (momentary). When a button is pressed, weather held or not, sends a button number 1 for example and executes a volume up command, ONLY ONCE, then after button is released, the code sends a "button = 0" command, which is declared in the "getbutton" function with z= the analog range of no buttons pressed.

I want to take only one button analog input range, and map that to TWO "button=" numbers in the getbutton function. So if i press and release a button, i want this to eventually = "button = 1". Then if i press and hold the same button, have this equal "button=2. Then i can reference these button numbers in the loop to perform 2 separate commands(as posted in my loop code). Hopefully this makes sense..

PaulS

Quote
Hopefully this makes sense..
Not entirely.

You need a function that returns the number of the button being pressed. When the value returned by that function is not the same as the value returned last time, you need to record when the current switch became pressed, if the current switch is not whatever corresponds to no switch.

When the current switch is not the same as the previous switch, you can determine how long it has been since the current switch became pressed. That is how you distinguish between a short and long press.

Something vaguely like this:
Code: [Select]
int prevNumber = 0;
int currNumber = 0;

unsigned long differentSwitchBecamePressed = 0;

void loop()
{
   currNumber = getButton(); // stupid name for function that determines which SWITCH is pressed
   if(currNumber != prevNumber)
   {
      // The current switch is not the same as the previous switch
      if(currNumber == 0)
      {
         // The switch that was pressed no longer is
         unsigned long holdTime = millis() - differentSwitchBecamePressed;
         if(holdTime >= longHoldTime)
         {
            // Switch was held down for a while
         }
         else
         {
            // Switch was pressed and released "quickly"
         }
      }
      else
      {
         // A different switch became pressed
         differentSwitchBecamePressed = millis();
      }
   }
   prevNumber = currNUmber;
}
The art of getting good answers lies in asking good questions.

Robin2

So if i press and release a button, i want this to eventually = "button = 1". Then if i press and hold the same button, have this equal "button=2.
Then the code I linked to in Reply #3 will be suitable.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Matt1995

Thanks guys. I'll see what I can come up with and post it.I'll  have to digest this info a bit.

Go Up