PDA

View Full Version : 1 switch, 1 pin, "single click, double click..."



erice1984
- 27th March 2009, 22:15
I have a PIC12F683
- 1 pin as an input.
- Using a momentary button

I want to be able to push the button once "single click" and have it execute one thing, and also have it if the button is pressed in quick succession "double click" it executes another thing.

I have looked at
-PULSIN - short click vs. long click
-RCTIME - same, short vs long
-COUNT - single versus double click
-IF..THEN - short vs long click

I want the most efficient way to get it done.

thanks
-eric

Archangel
- 27th March 2009, 22:19
I have a PIC12F683
- 1 pin as an input.
- Using a momentary button

I want to be able to push the button once "single click" and have it execute one thing, and also have it if the button is pressed in quick succession "double click" it executes another thing.

I have looked at
-PULSIN - short click vs. long click
-RCTIME - same, short vs long
-COUNT - single versus double click
-IF..THEN - short vs long click

I want the most efficient way to get it done.

thanks
-eric
You might try the Count command, store the count in a variable and compare the variable to what you want to do. You might get some problems from switch bounce that way though.

erice1984
- 27th March 2009, 22:30
MAIN:
low ind
if but = 0 then
pause 8
count but,500,b0
pause 5
goto bpres
else
goto main
endif

Yeah, I had ran through everything, count seems to be the easiest way to go, I added a small pause in there between BUT=0 and COUNT to wait for some bounce to settle. Only other option was looking to aid in the external debounce circuit area. It upped the consistency but sometimes my LED doesnt light when I hit the button, though I think it may be my button since it has a lot of travel.

Gusse
- 27th March 2009, 22:48
I would do it by defining a time window for input signal. After button is pressed you will wait certain time (loop) and if button is re-pressed during that time then excecute "button twice pressed" -task. If time runs out then "button once pressed" -task.

IF -THEN could be used, also to get debounce delay.

Also if button is held down then do check for that too and continue only after button is released. Then you can support both short and long clicks.

BR,
-Gusse-

mister_e
- 28th March 2009, 09:14
Probably thousand different ways to do it, but here's one top of my head.

Detect the first push button press, from there, start a timer, if you get another push-button press before the timer overflow, you have your double-click condition satisfied.
:o same thing as Gusse i guess... DOH!

Acetronics2
- 28th March 2009, 09:18
Hi, Steve

Might work with two " Button" commands following each other, as debounce time is effective ONLY if condition TRUE ...

he,he ...

Alain

mister_e
- 28th March 2009, 09:22
Maybe... but as you know, I never use Button, so... :(

Someone could also go crazy and use CLKI + timer interrupt.... this allow 1,2,3,4,5... click triggers for a x period of time, with a real minimum of code line, something <10 code line I guess.

Gusse
- 28th March 2009, 10:00
Hi, Steve

Might work with two " Button" commands following each other, as debounce time is effective ONLY if condition TRUE ...

he,he ...

Alain
I haven't use Button -command too, but couple of IF - THEN with PAUSE works for me.
IF But = 0 then 'Button is pressed and debounce detections starts
PAUSE 100 'wait 100ms or some other more suitable time
IF But = 0 then 'if button is still held down then do something
'start timer or loop for 2nd button press detection ...

I think, some time window must be defined otherwise you will be waiting that other press forever...

Also nice to hear that Steve had similar thoughts :)

BR,
-Gusse-

erice1984
- 30th March 2009, 00:29
thanks for all the input guys.

I played around with the count for a little while, thought it was working pretty consistently. I re-evaluated where the button was going to be positioned and thought the double clicking could become annoying.

The if-then statements turned out to be very nice change, and 10 fold more consistent.

peterdeco1
- 30th March 2009, 19:28
I did this a while ago. I just removed the "bells and whistles" and should work the way it is. It works like a single or double click on a mouse.

START:
IF PORTA.1 = 1 Then START 'BUTTON NOT PUSHED STAY HERE
GoSub MOUSECLICK 'CHECK FOR DOUBLE CLICK
if click = 1 then let click = 0 : goto something
if click = 2 then let click = 0 : goto somethingelse
goto start

MOUSECLICK:
IF PORTA.1 = 0 Then MOUSECLICK 'stay here until switch is released
LET CLICK = CLICK + 1 'switch released
IF CLICK >=2 Then Return 'LIMIT CLICKS TO 2
pause 500 'switch has to be pushed 2 times within 1/2 second for double click
IF PORTA.1 = 0 Then MOUSECLICK 'switch pushed again
Return

Gusse
- 30th March 2009, 22:12
I did this a while ago. I just removed the "bells and whistles" and should work the way it is. It works like a single or double click on a mouse.

START:
IF PORTA.1 = 1 Then START 'BUTTON NOT PUSHED STAY HERE
GoSub MOUSECLICK 'CHECK FOR DOUBLE CLICK
if click = 1 then let click = 0 : goto something
if click = 2 then let click = 0 : goto somethingelse
goto start

MOUSECLICK:
IF PORTA.1 = 0 Then MOUSECLICK 'stay here until switch is released
LET CLICK = CLICK + 1 'switch released
IF CLICK >=2 Then Return 'LIMIT CLICKS TO 2
pause 500 'switch has to be pushed 2 times within 1/2 second for double click
IF PORTA.1 = 0 Then MOUSECLICK 'switch pushed again
Return
As you can see from picture, debounce can make port to change state between 0 - 1 for several times. This would make code above to generate two clicks if pressed longer than 500ms (even button is pressed once). More reliable way is to check that button is still held down after some time (debounce delay) and after that go forward.
http://www.micahcarrick.com/files/atmega8/tutorial_3/debounce.png
Source of picture and some more info about debounce (http://www.micahcarrick.com/05-15-2006/avr-tutorial-switch-debounce.html)
(I hope it is OK to link this picture to this forum? If not then Admin can remove it.)

Problem is here

MOUSECLICK:
IF PORTA.1 = 0 Then MOUSECLICK 'stay here until switch is released
Click (similar to picture above): If shorter than 500ms then OK, but longer pulses than 500ms will generate 2 clicks. You have no debounce filtering in this loop.
Of cource, some can say that this is very unlikely scenario. Maybe, but it can happen if you don't have anykind of filter (i.e RC-loop) at input.

BR,
Gusse

peterdeco1
- 31st March 2009, 10:24
You are right Gusse. When I removed all the "bells and whistles" , I removed the debouncing and also a timer where "pause 500" is. If you double click before the 500 mS is up, it immediately makes click = 2 and returns.

turbokinetic
- 11th April 2009, 04:22
What is challenging is doing this without making the rest of the program be suspended waiting on the second click to happen or not.

The way I have been doing this is to set a bit for each of the following events:

Button pressed
Time expired without second press
Second press happened during time count.

The following sample works. It may look complicated, but it works well. It is part of my car lights controller code which has multiple inputs that have similar logic and all are active at once.

While one input is waiting on a possible second press, the rest of the program is still working and responding to inputs.

I've always found that for best reliability a pushbutton almost always need a small capacitor across the contacts to debounce it. Using the following program, the loop is so short the program can respond very fast. Without a capacitor, the bounce can cause it to give false operation. On a longer program, the remainder of the program loop will be enough delay to debounce the button signal.

The complete lights controller code has over 800 lines of code, and a good portion has to execute every program cycle. Each input is checked once per cycle so there is enough delay to keep bounce from being an issue.

Also, read the state of the input into a temp variable, then use the temp variable to do the logic. This will keep bounce from happening during the logic operations, and causing some really funky stuff to happen! Voice of experience!! :)

I used the hardware of the lights controller to test this program fragment, so that's why the relays are on it.

Hope this is helpful!
Thanks,
David



'Double-Click example For PIC16F88

'Header for 16F88 CPU I/O modes and Osc. speed...
CMCON=7 'Analog comparators OFF
ANSEL=0 'ADC inputs OFF
'OSCCON=%00000010 ' 31.25 KHz
'OSCCON=%00010010 ' 125 KHz
'OSCCON=%00100010 ' 250 KHz
'OSCCON=%00110010 ' 500 KHz
'OSCCON=%01000010 ' 1 MHz
'OSCCON=%01010010 ' 2 MHz
'OSCCON=%01100010 ' 4 MHz
OSCCON=%01110010 ' 8 MHz

SetupSwitch VAR PORTA.5 'This is a momentary pushbutton
Relay1 VAR PORTB.2 'These outputs close a relay when they are HIGH
Relay2 VAR PORTB.1

SStime VAR WORD 'this counts down to time the second press

x VAR BIT 'buffer variable to keep switch state changes during logic from causing issues.
SSx VAR BIT 'determines change of switch
SS1 VAR BIT 'Set once when SetupSwitch pressed once
SS2 VAR BIT 'Set once when SetupSwitch pressed twice within timefrave

SStime = 0 'These must be initialized to keep from having one false-trigger when circuit sterts up.
SSx = 0

:loop

'------
X = SetupSwitch
IF X <> SSx Then
PauseUs 1 'This will help de-bounce switch, but if program is long, you will not need!
LET SSx = X
IF X Then
IF SStime > 0 Then 'If the timer is still counting when a press happens
SS2 = 1 'set the "double press" variable and
SStime = 0 'reset the timer
Else
SStime = 10000 'When the first press happens, start counting at 10000.
EndIF
EndIF
Else
SS1 = 0
SS2 = 0
EndIF

IF SStime = 1 Then 'If no second press has occured, when timer reaches 1, set the "single press" bit.
SS1 = 1
SStime = 0
EndIF
'------

IF SStime > 0 Then 'This function to decrement the double-click timer would be done in another
LET SStime = SStime - 1 'part of the program, probably using a hardware timer. This is just an example.
EndIF

IF SS1 Then Toggle Relay1 'Each single-click toggles Relay # 1
IF SS2 Then Toggle Relay2 'Each double-click toggles Relay # 2

GoTo loop