PDA

View Full Version : Using same button for entering/exiting some part of code?



CuriousOne
- 21st March 2023, 12:11
Hello. This might sound simple, but I can't find the reliable solution.

Say I have button, input pin, which is tied to VDD via 10K resistor.
Pressing button pulls input pin down.

There is in some code, say code1, which runs in loop.
When user press button, execution goes to code2, which also runs in loop.
While in loop2, when user presses the button, execution is returned to code1

The issue is, if user keeps button pressed, the code will jump from code1 to code2 and back from code2 to code1.

To avoid this, the button state should be checked, so when user presses the button while in code1, jump to code2 will not occur until he releases the button.

I tried to use BUTTON statement, but it is not handy, since it only can do jump to label, and sometimes I just want to change value of some variable. And sometimes buttons are tied to ADC, so different button returns different ADC value.

Is there a simple way for fixing the issue I have?

amgen
- 21st March 2023, 15:37
I made a multi-function timer that deals with that and does different things according to how long sw is pressed ( and improved it to a touch sw using a/d)...... simply loops through routines using counts of pauses between sw presses.

part of sw press checks......

FOR B5= 1 TO 10 '.1 SECONDS FOR TIMER
PAUSE 6
if GPIO.1= 1 then start
NEXT B5

read 1,b6 :PAUSE 10: W0=60*B6:W1=W0
HIGH 4 ': HIGH 2

FOR B5 = 1 TO 100 '2 SECONDS FOR 6 HR
PAUSE 10
if GPIO.1=1 then TIMER
NEXT B5
W0=28800 '8 HRS
HIGH 2

HenrikOlsson
- 21st March 2023, 21:34
You might do something like this:
Obvioulsy you can't have code that takes a long time to exectute in each section or you'll miss the button press. If that's the case, move the code that handles the button to a subroutine and call that routine multiple times from within the section(s) that takes the longest time.


ButtonPressed CON 0
FirstPieceOfCode CON 1
LastPieceOfCode CON 3

CodeToRun VAR BYTE
ButtonHasBeenPressed VAR BIT

ChangeButton VAR PortB.2

CodeToRun = FirstPieceOfcode
ButtonHasBeenPressed = 0

Main:

If ChangeButton = ButtonPressed THEN
ButtonHasBeenPressed = 1
ENDIF

IF (ButtonHasBeenPressed = 1) AND (ChangeButton <> ButtonPressed) THEN ' But was pressed but is now released
ButtonHasBeenPressed = 0
CodeToRun = CodeToRun + 1 ' Advance to next code section
If CodeToRun > LastPieceOfCode THEN ' Wrap around and start over
CodeToRun = FirstPieceOfCode
ENDIF
ENDIF


Select Case CodeToRun

Case 1
'Some code

Case 2
'Some other code

Case 3
'Yet some other code

END SELECT

Goto Main


This is not tested or even compiled so use it as an idea.

CuriousOne
- 22nd March 2023, 03:59
I think, there is some misunderstanding.

Here what I need



code1:
if button=0 then goto code2
'somecode here
goto code1

code2:
if button=0 then goto code1
'somecode here
goto code2


So all I need is when user presses the button in code1, execution won't jump to code2 until he releases the button. And same for code2.

HenrikOlsson
- 22nd March 2023, 05:32
The code I posted should do exactly with that, with the advantage that the section of code you're currently in will continue to run UNTIL you release the button. What you're proposing will HANG the current program section until you release the button. But here you go:

code1:
if button=0 then 'check if button is pressed
PAUSE 5 'allow some contact bounce
WHILE button=0 : WEND 'wait for it to be released
PAUSE 5 'allow some contact bounce
goto code2
ENDIF
'somecode here
goto code1

code2:
if button=0 then
WHILE button = 0 : WEND
goto code1
ENDIF
'somecode here
goto code2
and obviously, button is a reserved word.

CuriousOne
- 22nd March 2023, 07:12
Thanks!
No problem for code to "Hang", since this is for going from main menu to sub-menu and back.

amgen
- 23rd March 2023, 14:17
my experience with button press usage is to have to wait for button release, can either stay in present routine and wait before switching OR moving to other routine and wait for release before looking for new press and going back.

CuriousOne
- 21st April 2023, 06:36
Here is the practical code I'm using, but it sometimes behaves strangely.
Say, button was pressed, action was made once, user still holds button, so no advance in code. But when user releases the button, sometimes it acts as button was pressed once again. Any ideas how to fix it?



MENULOOP: 'MAIN CONFIG SCREEN
IF UPBT=0 THEN
MENUITEM=MENUITEM+1
IF MENUITEM>4 THEN MENUITEM=1
GOSUB CENTRAL
pause 200 'debounce
ENDIF
WHILE UPBT=0:WEND


IF DNBT=0 THEN
MENUITEM=MENUITEM-1
IF MENUITEM<1 THEN MENUITEM=4
GOSUB CENTRAL
pause 200 'debounce
ENDIF
WHILE DNBT=0:WEND
if menuitem=1 and rbut=0 then
pause 5
while rbut=0: wend
goto clockconfig
endif
GOTO MENULOOP

HenrikOlsson
- 21st April 2023, 08:46
There does not seem to be any debounce on button release. Try

IF UPBT=0 THEN
MENUITEM = MENUITEM+1

IF MENUITEM > 4 THEN MENUITEM = 1
GOSUB CENTRAL
' PAUSE 20 ' May be needed if subroutine CENTRAL executes very fast.
WHILE UPBT = 0 : WEND
PAUSE 20 'debounce
ENDIF

amgen
- 21st April 2023, 15:24
read switch a few times to be sure and debounce......

IF UPBT=0 THEN
PAUSE 20 ' or 40 or 50
IF UPBT=0 THEN 'go ahead........

MENUITEM = MENUITEM+1

do same for release check .... if upbt=1 then.....

CuriousOne
- 21st May 2023, 14:27
For couple of buttons this code works fine, but when I increase number of button handling operations, some weird things occur - the further from beginning is the button handling routine, more rarely it responds to user.

The code below has 8 "blocks" of button handling.

first 3 work fine, 4th one works only maybe on 10 or 15th press. 5th and further - do not work at all.
And this is not issue of particular code - if I move say "5th block" to 1st place of this code, then it works fine.

PIC18F45K80 @64mhz.





IF UPBT=0 THEN
MENUITEM=MENUITEM+1
IF MENUITEM>6 THEN MENUITEM=1
pause 200
ENDIF
WHILE UPBT=0:WEND


IF DNBT=0 THEN
MENUITEM=MENUITEM-1
IF MENUITEM<1 THEN MENUITEM=6
pause 200
ENDIF
WHILE DNBT=0:WEND




IF LBUT=0 AND MENUITEM=2 THEN
RICXVI=RICXVI+1
IF RICXVI>31 THEN RICXVI=1
pause 200
GOSUB SETTIME
ENDIF
WHILE LBUT=0:WEND


IF RBUT=0 AND MENUITEM=2 THEN
RICXVI=RICXVI-1
IF RICXVI<1 THEN RICXVI=31
pause 200
GOSUB SETTIME
ENDIF
WHILE RBUT=0:WEND




IF LBUT=0 AND MENUITEM=1 THEN
TVE=TVE+1
IF TVE>13 THEN TVE=1
pause 200
GOSUB SETTIME
ENDIF
WHILE LBUT=0:WEND


IF RBUT=0 AND MENUITEM=1 THEN
TVE=TVE-1
IF TVE<1 THEN TVE=13
pause 200
GOSUB SETTIME
ENDIF
WHILE RBUT=0:WEND






IF LBUT=0 AND MENUITEM=3 THEN
DGE=DGE+1
IF DGE>7 THEN DGE=1
pause 200
GOSUB SETTIME
ENDIF
WHILE LBUT=0:WEND


IF RBUT=0 AND MENUITEM=3 THEN
DGE=DGE-1
IF DGE<1 THEN DGE=7
pause 200
GOSUB SETTIME
ENDIF
WHILE RBUT=0:WEND

CuriousOne
- 21st May 2023, 14:40
I tried to reduce PAUSE 200 to 20 or even 2 - no change.

tumbleweed
- 21st May 2023, 16:11
what about something like this instead?


IF UPBT=0 THEN
MENUITEM=MENUITEM+1
IF MENUITEM>6 THEN MENUITEM=1
PAUSE 20
WHILE UPBT=0:WEND
PAUSE 20
ENDIF

IF DNBT=0 THEN
MENUITEM=MENUITEM-1
IF MENUITEM<1 THEN MENUITEM=6
PAUSE 20
WHILE DNBT=0:WEND
PAUSE 20
ENDIF

IF LBUT=0 THEN
IF MENUITEM=1 THEN
TVE=TVE+1
IF TVE>13 THEN TVE=1
GOSUB SETTIME
ENDIF
IF MENUITEM=2 THEN
RICXVI=RICXVI+1
IF RICXVI>31 THEN RICXVI=1
GOSUB SETTIME
ENDIF
IF MENUITEM=3 THEN
DGE=DGE+1
IF DGE>7 THEN DGE=1
GOSUB SETTIME
ENDIF

PAUSE 20
WHILE LBUT=0:WEND
PAUSE 20
ENDIF

IF RBUT=0 THEN
IF MENUITEM=1 THEN
TVE=TVE-1
IF TVE<1 THEN TVE=13
GOSUB SETTIME
ENDIF
IF MENUITEM=2 THEN
RICXVI=RICXVI-1
IF RICXVI<1 THEN RICXVI=31
GOSUB SETTIME
ENDIF
IF MENUITEM=3 THEN
DGE=DGE-1
IF DGE<1 THEN DGE=7
GOSUB SETTIME
ENDIF

PAUSE 20
WHILE RBUT=0:WEND
PAUSE 20
ENDIF



it could be simplified even more, but...

mpgmike
- 21st May 2023, 16:17
You could create a bit Flag. When the Button is pressed, the Flag is toggled. When you get to a reasonable point in Code1 Routine, check your Flag. If it has toggled (is now a 1 for example), use GOTO to jump to Code2. Put "IF Flag = 0 THEN : GOTO Code1" in convenient spots throughout in Code2, etc.

amgen
- 21st May 2023, 17:54
debounce button check... and instead of while-wend .... use for/next pause here is 2 second check so if holding button > 2 seconds, can advance MENUitem then check again for release


HERE:
IF UPBT=0 THEN
pause 50
IF UPBT=0 THEN ..............................#debounce check
MENUITEM=MENUITEM+1
IF MENUITEM>6 THEN MENUITEM=1
PAUSE 20

for a=1 to 20
pause 50................................................ ............# if 2 second press, advance item and wait again
IF UPBT=1 THEN ---leave to somewhere .................# XXXXX WHILE UPBT=0:WEND
next a
goto HERE

ENDIF

Ioannis
- 21st May 2023, 20:50
First I would read all button input at once. Debounce and then decide what to do.

This is like a state machine coding and you will not loose any keypress, especially if it is interrupt driven. Or if you do not want interrupts, then a tight loop can do the job just fine.

Spaghetti coding unfortunately leads to such results.

Ioannis

CuriousOne
- 28th May 2023, 19:05
Thanks everyone. I've modified that code in the way that it now works - there is additional check for MENUITEM value inside a button press loop, but the question is still active - why the code above slows down in that way? That's simply not logical.

amgen
- 28th May 2023, 21:43
if there is room, you could put some 'temporary' code to serout or debug at a few locations and see where it isn't doing what is expected ! looks like there are quite a number of 'states' your program could be looping through.