PDA

View Full Version : debouncing switches with a timer interrupt?



DDDvvv
- 24th July 2010, 16:33
hi everyone,
im experimenting with the "menu builder" application on a 18f2431 and im having a bit of a problem. it inserts a lot of "pause 200" commands, to debounce the switches, which is causing havoc on my real time timer on an lcd. if i remove the pauses, there's no debounce, and one push of a button cycles through alot of menus. i tried the portb interrupt on change, and im getting the same results. i've read some rumours that debouncing can be done using a timer interrupt. is it possible? im using 4 buttons: up, down, enter, exit. any help/idea on pseudocode will really be appreciated; portb interrupt, timer interrupt, software debounce, etc

Kamikaze47
- 25th July 2010, 04:16
If you can change the hardware, one option would be to use capacitors across the switches. Software denounce would no longer be required.

Otherwise you do do this:

port b change interrupt: detects a button press and takes action, an the end of the interrupt it sets a timer so that it will overflow in say 50ms, and then disables the port b interrupt.

when the timer interrupt goes off 50ms later it simply needs to re-enable the port b interrupt and stop the timer.

Charles Linquis
- 25th July 2010, 06:41
Could it be that you don't need a debouncer at all?

If you are polling the pin that is connected the switch every program loop, and the loop is longer than the switch bounce time, you don't need a debounce, since it will see the transition, and the "bounces" will be over before you check the switch again.

Dave
- 25th July 2010, 14:33
Charles, I do just exactly that. In my interrupt routine. I copy th state of my button and add it to a shifted result. When the button is connected to ground with a pullup to VDD, the value after the 8 cycle (interrupt) debounce is equal to zero. When the button is released the value after the 8 cycle (interrupt) debounce is equal to 255. I use a 10 millisecond interrupt timer so the debounce time is 80 milliseconds. That way all the main has to do is interrogate debounce variable for it's value.

Dave Purola,
N8NTA

aratti
- 25th July 2010, 16:02
if i remove the pauses, there's no debounce, and one push of a button cycles through alot of menus.

I would apply a flag condition to control the key state.



False CON 0
True CON 1
KEYPRESS VAR portXx
KeyFlag VAR BIT
Counter VAR WORD

LOOP:

PAUSE 1

IF KEYPRESS = False then

IF KeyFlag = False Then
Counter = Counter + 1
KeyFlag = True
ENDIF

ELSE
KeyFlag = False
ENDIF
.
.
.
.
.
GOTO LOOP


In the above snippet every time you press the key "KEYPRESS" the word variable "Counter" will increment of one unit, no matter how long you keep the key down. If you remove the flag control using pauses, it will be rather complicate to reach the same results.



Al.

Kamikaze47
- 25th July 2010, 17:37
I would apply a flag condition to control the key state.

This would still require some kind of debouncing. The logic state can "bounce" a number of times when pressing a button, so if it toggles back and forth a few times it could still advance the counter more than once for a single key press if the loop is quick enough.

aratti
- 25th July 2010, 23:54
This would still require some kind of debouncing. The logic state can "bounce" a number of times when pressing a button

Contact's debouncing should be solved with proper RC filter! If proper filtering is not possible an additional IF/THEN statement should reduce greatly the debouncing effect.



False CON 0
True CON 1
KEYPRESS VAR portXx
KeyFlag VAR BIT
Counter VAR WORD

LOOP:

PAUSE 1

IF KEYPRESS = False then

IF KeyFlag = False Then
Counter = Counter + 1
KeyFlag = True
ENDIF

ELSE
KeyFlag = False
IF KEYPRESS = False THEN KeyFlag = True ' re-checks the key logic state
ENDIF
.
.
.
.
.
GOTO LOOP


Al.

DDDvvv
- 27th July 2010, 17:17
thanks guys.

i tried the capacitor method, and that did not work well. still skipping menu items.

im using proteus simulation, and i tried every value of cap, 1000uf to 0.000001 uf., and everything in between.

ill try integrate the software flag idea into the problem, and hope that it fixes it. thanks

DDDvvv
- 30th July 2010, 01:10
hi all
i tried to implement the flag idea, but still the same result. menu item cycles through 3 to 6 items with one push of a button. here's the code snippet


RB_MainMenuLoop:
' BTN_PLUS is the Next Choice button
PAUSE 1
IF BTN_PLUS=0 THEN
;PAUSE 200
IF FLAG_PLUS = 0 THEN
bMenuPos=bMenuPos+1
FLAG_PLUS = 1
ELSE
FLAG_PLUS = 0
IF BTN_PLUS = 0 THEN FLAG_PLUS = 1
;ENDIF
IF bMenuPos>22 THEN
bMenuPos=1
ENDIF
ENDIF
Goto DisplayMainMenuLoop:
ENDIF


im beginning to think that debouncing is not the problem. is there any other way to skin this cat?

aratti
- 30th July 2010, 08:09
Counter Var Byte

RB_MainMenuLoop:
' BTN_PLUS is the Next Choice button

PAUSE 1

IF BTN_PLUS=0 THEN

IF FLAG_PLUS = 0 THEN
bMenuPos = bMenuPos + 1
FLAG_PLUS = 1
Counter = 0
ENDIF

ELSE
Pause = 10
Counter = Counter + 1
IF Counter > 50 THEN FLAG_PLUS = 0 : Counter = 0
ENDIF

IF bMenuPos>22 THEN
bMenuPos=1
ENDIF

Goto DisplayMainMenuLoop:

================================================== ===============

Try this snippet and see how it works. You can tune the PAUSE 10 and Counter > 5, to better values to suite your need.

Al.

Acetronics2
- 30th July 2010, 14:06
hi all
i tried to implement the flag idea, but still the same result.

Hi,

You should understand debouncing NEED time, where ever this time comes from ( capacitor, timer ...)

the idea of debouncing is :

" Does the electrical state of pin still changes afer X milliseconds ??? "

so, you can't get a correct answer before X milliseconds !!! - Obvious -

But 200 ms is debouncing time for really poor quality switches, 20 ms can be obtained easily.

note also switches " bounce " when closing its contact ... not when opening it !!!

so, ... is it here THE good idea ??? :rolleyes:

Further, May I tell you a real time timer might not be disturbed by a keypress ... - or your program is " not so good " ...

the delay needed by the RTC to be updated is so far smaller than a key press action ... ;)

Alain

Mike, K8LH
- 31st July 2010, 01:54
Consider using a switch state latch and relatively simple logic to sample your switches and detect the "new press" state while ignoring the other switch states. Here are the switch states;


swnew swold switch state
1 0 a "new press"
1 1 still pressed
0 1 a "new release"
0 0 still released


Sample the switches at a decent debounce interval (16 to 25 msecs) either in your main program loop or in a timer based interrupt service routine. You only need a few lines of code to implement the switch state logic for multiple switches (perhaps one of the PBP gurus can interpret the C code? Sorry!);


// swnew ____---____-----_____ new switch sample
// swold _____---____-----____ switch state latch
// delta ____-__-___-____-____ changes, press or release
// newhi ____-______-_________ filter out release bits
//

while(1) //
{ //
delay_ms(24) // 24-msec debounce interval
swnew = ~porta; // sample active-lo switches
swnew &= 0x0F; // on RA3..RA0 pins
swnew ^= swold; // changes, press or release
swold ^= swnew; // update switch state latch
swnew &= swold; // filter out "new release" bits
if(swnew) // if any "new press" bits
{ beep(); // task a "new press" beep
}

if(swnew.0) // if RB0 "new press"
{ //
} //

if(swnew.1) // if RB1 "new press"
{ //
} //
}


If you implement the method in an ISR you'll need to inclusive-or "swnew" with a "flags" register for your main program.

Kind regards, Mike

Charles Linquis
- 31st July 2010, 21:47
The code below was written to use a momentary pushbutton switch as an ON/OFF control.

It is written to be used in a Timer interrupt routine.

PowerOnDelayTimer is the number of interrupts that the button must be held before turning ON the unit.

PowerOFFDelayTimer is the number of interrupts that the button must be held before turning OFF the unit

SwitchUpDelayTimer is the number of interrupts that must expire before the button can be pushed again (useful when you don't want someone rapidly turning ON and OFF a piece of hardware).






IF !EnableSw THEN ; Aliased pin, goes low when button pushed.

IF SwitchFlag THEN ; Switch has been pushed, but prevously released.

IF PowerSwitchCounter < 250 THEN
PowerSwitchCounter = PowerSwitchCounter + 1 ; don't let it overflow
ENDIF


IF PowerONstate = 0 THEN ; Currently OFF
If PowerSwitchCounter >= PowerOnDelayTimer then ; Turn on or off
Gosub PowerOn
SwitchFlag = 0
SwitchUpCounter = 0
ENDIF
ELSE ; Currently OFF
If PowerSwitchCounter >= PowerOffDelayTimer then
GOSUB PowerOff
SwitchFlag = 0
SwitchUpCounter = 0
ENDIF
ENDIF

ENDIF

ELSE
IF SwitchUpCounter < 250 THEN
SwitchUpCounter = SwitchUpCounter + 1
ENDIF
IF SwitchUpCounter > SwitchUpDelayTimer THEN
SwitchFlag = 1 ; Switch has been released
PowerSwitchCounter = 0
ENDIF
ENDIF

Charles Linquis
- 1st August 2010, 00:01
I should state that SwitchFlag must be initialized to a non-zero value at the top of the program.

Mike, K8LH
- 1st August 2010, 00:17
I'd like to supplement Charles' fine example with an interrupt driven version of the "parallel switch state logic" example I posted earlier.

This example uses a 1-msec timer driven interrupt "heart beat" which is perfect for toggling a piezo speaker at 500-Hz and it uses a simple counter to produce a 32-msec debounce/sample interval.

Using a momentary switch to emulate a "toggle" switch (press to toggle from on-to-off or from off-to-on) can be accomplished directly by the driver by exclusive-or'ing the debounced "new press" bits with the "flags" switch flag bits variable. Main should test the switch flag bit and then clear it for "momentary" switches or simply test the switch flag bit for an emulated "toggle" switch.


void interrupt() // 1-msec Timer 2 interrupts
{
pir1.TMR2IF = 0; // clear TMR2 interrupt flag
//
// beep task (32-msec 500-Hz tone using 1-msec interrupts)
//
if(beep) // if beep task running
{ spkrpin ^= 1; // toggle speaker pin and
beep--; // decrement beep msec counter
}
//
// switch state management (multi-switch "parallel" logic)
//
if(--dbcount == 0) // if 32-msec debounce interval
{ dbcount = 32; // reset debounce timer and
swnew = ~porta; // sample active low switches
swnew &= 0x0F; // on RA3..RA0 pins
swnew ^= swold; // changes, press or release
swold ^= swnew; // update switch state latch
swnew &= swold; // filter out "new release" bits
flags ^= swnew; // toggle flag bits for 'main'
if(swnew) // if any "new press" bits
beep = 32; // task a "new press" beep
}
}


// in "main"

while(flags.0) // while sw0 (RA0) "on" (toggle), do this block
{ // until new sw0 press toggles flags.0 to "off"
if(flags.1) // if sw1 (RA1) "new press" (momentary)
{ flags.1 = 0; // turn off flag and
... // do something
}
}

Bruce
- 1st August 2010, 01:45
Can you post the code you're having problems with? I suspect there's a very simple solution.

DDDvvv
- 1st August 2010, 18:48
thanks for all the replies guys. ive been away for the weekend, with no computer access. here's the code, fresh from the menubuilder application.

its a gadget that im making, to keep track/records of my workout sessions. it will also have a realtime clock/stopwatch, all displayed on a 20x2 lcd with 4 menu buttons (next, previous, up down.)

even with the "pause 200" debouncing, (default) everytime i try to cycle through menu items, with the push of a button, it skips three to six items. (same goes when you try to change a variable) at first, i thought that proteus simulation on my pentium 4 was slow (always bitching about "simulation not running in real time because of excessive cpu load" ) so i transferred the simulation to my intel i7 laptop, and proteus is not complaining any more. still having the same skipping items problem.

ill try mr Arrati's snipet again, but meanwhile, here's the code.




clear
define OSC 16 ;40 MHZ HS CRYSTAL
OSCCON = %01110000
ADCON0= %00000000 ;PORT A ALL DIGITAL
ANSEL0= %00000000 ;PORT A ALL DIGITAL
TRISA = %00000000 ;
TRISB = %11111100 ;
TRISC = %10111000 ;
;
LATA = %00000000 ;
LATB = %00000000 ;
LATC = %00000000 ;



'VARIABLE DECLARATION
bMenuPos var Byte 'Main menu position
bSubMenuPos var Byte 'Sub menu position
BTN_NEXT var PORTB.4 'Next button
BTN_PREV var PORTB.5 'Previous button
BTN_PLUS var PORTB.6 'Plus button
BTN_MINUS var PORTB.7 'Minus button
SQUATS_WT VAR Byte
SQUATS_RP VAR Byte
PULLDOWN_WT VAR Byte
PULLDOWN_RP VAR Byte
LATRAISE_WT VAR Byte
LATRAISE_RP VAR Byte
OVHEADPRESS_WT VAR Byte
OVHEADPRESS_RP VAR Byte
PREACHERCURL_WT VAR Byte
PREACHERCURL_RP VAR Byte
PUSHDOWN_WT VAR Byte
PUSHDOWN_RP VAR Byte
PECDECK_WT VAR Byte
PECDECK_RP VAR Byte
CABLESHRUG_WT VAR Byte
CABLESHRUG_RP VAR Byte
CALFRAISES_WT VAR Byte
CALFRAISES_RP VAR Byte
DBWRISTCURL_WT VAR Byte
DBWRISTCURL_RP VAR Byte
DECLINESITUP_WT VAR Byte
DECLINESITUP_RP VAR Byte
'END OF VARIABLE DECLARATION



DEFINE LCD_DREG PORTA
DEFINE LCD_DBIT 0
DEFINE LCD_BITS 4
DEFINE LCD_RSREG PORTC
DEFINE LCD_RSBIT 0
DEFINE LCD_EREG PORTC
DEFINE LCD_EBIT 1


PAUSE 500

LCDOUT $FE, $01

LCDOUT $FE, $80, " FITNESS GYM ASSIST"
LCDOUT $FE, $C0, " COPYRIGHT DAVID M"

PAUSE 1000

MAIN

GOSUB DisplayMainMenu
GOTO MAIN


'SUB ROUTINES

'************************************************* *****
'ROUTINE DisplayMainMenu
'This routine handles the display of the main menu choices
'All you need is to call from your main program this routine,
'and have the button ports setup,
'************************************************* *****
DisplayMainMenu:
bMenuPos=1 'This is the default menu option
DisplayMainMenuLoop:
IF bMenuPos=1 THEN
LCDOUT $FE,1,"SQUATS WT"
ENDIF
IF bMenuPos=2 THEN
LCDOUT $FE,1,"SQUATS RP"
ENDIF
IF bMenuPos=3 THEN
LCDOUT $FE,1,"PULLDOWN WT"
ENDIF
IF bMenuPos=4 THEN
LCDOUT $FE,1,"PULLDOWN RP"
ENDIF
IF bMenuPos=5 THEN
LCDOUT $FE,1,"LAT RAISE WT"
ENDIF
IF bMenuPos=6 THEN
LCDOUT $FE,1,"LAT RAISE RP"
ENDIF
IF bMenuPos=7 THEN
LCDOUT $FE,1,"OVHEAD PRESS WT"
ENDIF
IF bMenuPos=8 THEN
LCDOUT $FE,1,"OVHEAD PRESS RP"
ENDIF
IF bMenuPos=9 THEN
LCDOUT $FE,1,"PREACHER CURL WT"
ENDIF
IF bMenuPos=10 THEN
LCDOUT $FE,1,"PREACHER CURL RP"
ENDIF
IF bMenuPos=11 THEN
LCDOUT $FE,1,"PUSHDOWN WT"
ENDIF
IF bMenuPos=12 THEN
LCDOUT $FE,1,"PUSHDOWN RP"
ENDIF
IF bMenuPos=13 THEN
LCDOUT $FE,1,"PEC DECK WT"
ENDIF
IF bMenuPos=14 THEN
LCDOUT $FE,1,"PEC DECK RP"
ENDIF
IF bMenuPos=15 THEN
LCDOUT $FE,1,"CABLE SHRUG WT"
ENDIF
IF bMenuPos=16 THEN
LCDOUT $FE,1,"CABLE SHRUG RP"
ENDIF
IF bMenuPos=17 THEN
LCDOUT $FE,1,"CALF RAISES WT"
ENDIF
IF bMenuPos=18 THEN
LCDOUT $FE,1,"CALF RAISES RP"
ENDIF
IF bMenuPos=19 THEN
LCDOUT $FE,1,"DBWRIST CURL WT"
ENDIF
IF bMenuPos=20 THEN
LCDOUT $FE,1,"DBWRIST CURL RP"
ENDIF
IF bMenuPos=21 THEN
LCDOUT $FE,1,"DECLINE SITUP WT"
ENDIF
IF bMenuPos=22 THEN
LCDOUT $FE,1,"DECLINE SITUP RP"
ENDIF
RB_MainMenuLoop:
' BTN_PLUS is the Next Choice button
IF BTN_PLUS=0 THEN
PAUSE 200
bMenuPos=bMenuPos+1
IF bMenuPos>22 THEN
bMenuPos=1
ENDIF
Goto DisplayMainMenuLoop:
ENDIF
' BTN_PREV is the Exit button
IF BTN_PREV=0 THEN
PAUSE 200
RETURN
ENDIF
' BTN_NEXT is the Goto SubMenu Choice button
IF BTN_NEXT=0 THEN
PAUSE 200
GoSub DisplaySubMenu
Goto DisplayMainMenuLoop
ENDIF
Goto RB_MainMenuLoop:
'************************************************* *****
'ROUTINE DisplaySubMenu
'This routine handles the display of the sub menu choices
'************************************************* *****
DisplaySubMenu:
bSubMenuPos=1 'This is the default menu option
DisplaySubMenuLoop:
IF bMenuPos=1 AND bSubMenuPos=1 THEN
LCDOUT $FE,1,"SQUATS WT ADJ"
ENDIF
IF bMenuPos=2 AND bSubMenuPos=1 THEN
LCDOUT $FE,1,"SQUATS RP ADJ"
ENDIF
IF bMenuPos=3 AND bSubMenuPos=1 THEN
LCDOUT $FE,1,"PULLDOWN WT ADJ"
ENDIF
IF bMenuPos=4 AND bSubMenuPos=1 THEN
LCDOUT $FE,1,"PULLDOWN RP ADJ"
ENDIF
IF bMenuPos=5 AND bSubMenuPos=1 THEN
LCDOUT $FE,1,"LAT RAISE WT ADJ"
ENDIF
IF bMenuPos=6 AND bSubMenuPos=1 THEN
LCDOUT $FE,1,"LAT RAISE RP ADJ"
ENDIF
IF bMenuPos=7 AND bSubMenuPos=1 THEN
LCDOUT $FE,1,"OVHEAD PRESS WT"
ENDIF
IF bMenuPos=8 AND bSubMenuPos=1 THEN
LCDOUT $FE,1,"OVHEAD PRESS RP ADJ"
ENDIF
IF bMenuPos=9 AND bSubMenuPos=1 THEN
LCDOUT $FE,1,"PREACHER CURL WT ADJ"
ENDIF
IF bMenuPos=10 AND bSubMenuPos=1 THEN
LCDOUT $FE,1,"PREACHER CURL RP ADJ"
ENDIF
IF bMenuPos=11 AND bSubMenuPos=1 THEN
LCDOUT $FE,1,"PUSHDOWN WT ADJ"
ENDIF
IF bMenuPos=12 AND bSubMenuPos=1 THEN
LCDOUT $FE,1,"PUSHDOWN RP ADJ"
ENDIF
IF bMenuPos=13 AND bSubMenuPos=1 THEN
LCDOUT $FE,1,"PEC DECK WT ADJ"
ENDIF
IF bMenuPos=14 AND bSubMenuPos=1 THEN
LCDOUT $FE,1,"PEC DECK RP ADJ"
ENDIF
IF bMenuPos=15 AND bSubMenuPos=1 THEN
LCDOUT $FE,1,"CABLE SHRUG WT ADJ"
ENDIF
IF bMenuPos=16 AND bSubMenuPos=1 THEN
LCDOUT $FE,1,"CABLE SHRUG RP ADJ"
ENDIF
IF bMenuPos=17 AND bSubMenuPos=1 THEN
LCDOUT $FE,1,"CALF RAISES WT ADJ"
ENDIF
IF bMenuPos=18 AND bSubMenuPos=1 THEN
LCDOUT $FE,1,"CALF RAISES RP ADJ"
ENDIF
IF bMenuPos=19 AND bSubMenuPos=1 THEN
LCDOUT $FE,1,"DBWRIST CURL WT ADJ"
ENDIF
IF bMenuPos=20 AND bSubMenuPos=1 THEN
LCDOUT $FE,1,"DBWRIST CURL RP ADJ"
ENDIF
IF bMenuPos=21 AND bSubMenuPos=1 THEN
LCDOUT $FE,1,"DECLINE SITUP WT ADJ"
ENDIF
IF bMenuPos=22 AND bSubMenuPos=1 THEN
LCDOUT $FE,1,"DECLINE SITUP RP ADJ"
ENDIF
RB_SUBMenuLoop:
' BTN_PLUS is the Next Choice button
IF BTN_PLUS=0 THEN
PAUSE 200
bSubMenuPos=bSubMenuPos+1
IF bMenuPos=1 AND bSubMenuPos>1 THEN
bSubMenuPos=1
ENDIF
IF bMenuPos=2 AND bSubMenuPos>1 THEN
bSubMenuPos=1
ENDIF
IF bMenuPos=3 AND bSubMenuPos>1 THEN
bSubMenuPos=1
ENDIF
IF bMenuPos=4 AND bSubMenuPos>1 THEN
bSubMenuPos=1
ENDIF
IF bMenuPos=5 AND bSubMenuPos>1 THEN
bSubMenuPos=1
ENDIF
IF bMenuPos=6 AND bSubMenuPos>1 THEN
bSubMenuPos=1
ENDIF
IF bMenuPos=7 AND bSubMenuPos>1 THEN
bSubMenuPos=1
ENDIF
IF bMenuPos=8 AND bSubMenuPos>1 THEN
bSubMenuPos=1
ENDIF
IF bMenuPos=9 AND bSubMenuPos>1 THEN
bSubMenuPos=1
ENDIF
IF bMenuPos=10 AND bSubMenuPos>1 THEN
bSubMenuPos=1
ENDIF
IF bMenuPos=11 AND bSubMenuPos>1 THEN
bSubMenuPos=1
ENDIF
IF bMenuPos=12 AND bSubMenuPos>1 THEN
bSubMenuPos=1
ENDIF
IF bMenuPos=13 AND bSubMenuPos>1 THEN
bSubMenuPos=1
ENDIF
IF bMenuPos=14 AND bSubMenuPos>1 THEN
bSubMenuPos=1
ENDIF
IF bMenuPos=15 AND bSubMenuPos>1 THEN
bSubMenuPos=1
ENDIF
IF bMenuPos=16 AND bSubMenuPos>1 THEN
bSubMenuPos=1
ENDIF
IF bMenuPos=17 AND bSubMenuPos>1 THEN
bSubMenuPos=1
ENDIF
IF bMenuPos=18 AND bSubMenuPos>1 THEN
bSubMenuPos=1
ENDIF
IF bMenuPos=19 AND bSubMenuPos>1 THEN
bSubMenuPos=1
ENDIF
IF bMenuPos=20 AND bSubMenuPos>1 THEN
bSubMenuPos=1
ENDIF
IF bMenuPos=21 AND bSubMenuPos>1 THEN
bSubMenuPos=1
ENDIF
IF bMenuPos=22 AND bSubMenuPos>1 THEN
bSubMenuPos=1
ENDIF
GoTo DisplaySubMenuLoop
ENDIF
' BTN_PREV is the Exit button
IF BTN_PREV=0 THEN
PAUSE 200
RETURN
ENDIF
' BTN_NEXT is the Goto SubMenu Choice button
IF BTN_NEXT=0 THEN
PAUSE 200
IF bMenuPos=1 AND bSubMenuPos=1 THEN
GoSub SUB_1_1
ENDIF
IF bMenuPos=2 AND bSubMenuPos=1 THEN
GoSub SUB_2_1
ENDIF
IF bMenuPos=3 AND bSubMenuPos=1 THEN
GoSub SUB_3_1
ENDIF
IF bMenuPos=4 AND bSubMenuPos=1 THEN
GoSub SUB_4_1
ENDIF
IF bMenuPos=5 AND bSubMenuPos=1 THEN
GoSub SUB_5_1
ENDIF
IF bMenuPos=6 AND bSubMenuPos=1 THEN
GoSub SUB_6_1
ENDIF
IF bMenuPos=7 AND bSubMenuPos=1 THEN
GoSub SUB_7_1
ENDIF
IF bMenuPos=8 AND bSubMenuPos=1 THEN
GoSub SUB_8_1
ENDIF
IF bMenuPos=9 AND bSubMenuPos=1 THEN
GoSub SUB_9_1
ENDIF
IF bMenuPos=10 AND bSubMenuPos=1 THEN
GoSub SUB_10_1
ENDIF
IF bMenuPos=11 AND bSubMenuPos=1 THEN
GoSub SUB_11_1
ENDIF
IF bMenuPos=12 AND bSubMenuPos=1 THEN
GoSub SUB_12_1
ENDIF
IF bMenuPos=13 AND bSubMenuPos=1 THEN
GoSub SUB_13_1
ENDIF
IF bMenuPos=14 AND bSubMenuPos=1 THEN
GoSub SUB_14_1
ENDIF
IF bMenuPos=15 AND bSubMenuPos=1 THEN
GoSub SUB_15_1
ENDIF
IF bMenuPos=16 AND bSubMenuPos=1 THEN
GoSub SUB_16_1
ENDIF
IF bMenuPos=17 AND bSubMenuPos=1 THEN
GoSub SUB_17_1
ENDIF
IF bMenuPos=18 AND bSubMenuPos=1 THEN
GoSub SUB_18_1
ENDIF
IF bMenuPos=19 AND bSubMenuPos=1 THEN
GoSub SUB_19_1
ENDIF
IF bMenuPos=20 AND bSubMenuPos=1 THEN
GoSub SUB_20_1
ENDIF
IF bMenuPos=21 AND bSubMenuPos=1 THEN
GoSub SUB_21_1
ENDIF
IF bMenuPos=22 AND bSubMenuPos=1 THEN
GoSub SUB_22_1
ENDIF
GoTo DisplaySubMenuLoop
ENDIF
GoTo RB_SUBMenuLoop
'*************** SUB SUB_1_1*********
SUB_1_1:
'First read the variables from eprom
READ 1,SQUATS_WT
SUB_1_1MDLoop:
LCDOUT $FE,192," ",$FE,192,DEC SQUATS_WT
SUB_1_1MLoop:
IF BTN_PLUS=0 THEN
PAUSE 100
IF SQUATS_WT>=255 THEN
SQUATS_WT=0
ELSE
SQUATS_WT=SQUATS_WT+1
ENDIF
GoTo SUB_1_1MDLoop
ENDIF
IF BTN_MINUS=0 THEN
PAUSE 100
IF SQUATS_WT<=0 THEN
SQUATS_WT=255
ELSE
SQUATS_WT=SQUATS_WT-1
ENDIF
GoTo SUB_1_1MDLoop
ENDIF
IF BTN_PREV=0 THEN
PAUSE 100
WRITE 1,SQUATS_WT
RETURN
ENDIF
GoTo SUB_1_1MLoop
RETURN
'*************** SUB SUB_2_1*********
SUB_2_1:
'First read the variables from eprom
READ 2,SQUATS_RP
SUB_2_1MDLoop:
LCDOUT $FE,192," ",$FE,192,DEC SQUATS_RP
SUB_2_1MLoop:
IF BTN_PLUS=0 THEN
PAUSE 100
IF SQUATS_RP>=255 THEN
SQUATS_RP=0
ELSE
SQUATS_RP=SQUATS_RP+1
ENDIF
GoTo SUB_2_1MDLoop
ENDIF
IF BTN_MINUS=0 THEN
PAUSE 100
IF SQUATS_RP<=0 THEN
SQUATS_RP=255
ELSE
SQUATS_RP=SQUATS_RP-1
ENDIF
GoTo SUB_2_1MDLoop
ENDIF
IF BTN_PREV=0 THEN
PAUSE 100
WRITE 2,SQUATS_RP
RETURN
ENDIF
GoTo SUB_2_1MLoop
RETURN
'*************** SUB SUB_3_1*********
SUB_3_1:
'First read the variables from eprom
READ 3,PULLDOWN_WT
SUB_3_1MDLoop:
LCDOUT $FE,192," ",$FE,192,DEC PULLDOWN_WT
SUB_3_1MLoop:
IF BTN_PLUS=0 THEN
PAUSE 100
IF PULLDOWN_WT>=255 THEN
PULLDOWN_WT=0
ELSE
PULLDOWN_WT=PULLDOWN_WT+1
ENDIF
GoTo SUB_3_1MDLoop
ENDIF
IF BTN_MINUS=0 THEN
PAUSE 100
IF PULLDOWN_WT<=0 THEN
PULLDOWN_WT=255
ELSE
PULLDOWN_WT=PULLDOWN_WT-1
ENDIF
GoTo SUB_3_1MDLoop
ENDIF
IF BTN_PREV=0 THEN
PAUSE 100
WRITE 3,PULLDOWN_WT
RETURN
ENDIF
GoTo SUB_3_1MLoop
RETURN
'*************** SUB SUB_4_1*********
SUB_4_1:
'First read the variables from eprom
READ 4,PULLDOWN_RP
SUB_4_1MDLoop:
LCDOUT $FE,192," ",$FE,192,DEC PULLDOWN_RP
SUB_4_1MLoop:
IF BTN_PLUS=0 THEN
PAUSE 100
IF PULLDOWN_RP>=255 THEN
PULLDOWN_RP=0
ELSE
PULLDOWN_RP=PULLDOWN_RP+1
ENDIF
GoTo SUB_4_1MDLoop
ENDIF
IF BTN_MINUS=0 THEN
PAUSE 100
IF PULLDOWN_RP<=0 THEN
PULLDOWN_RP=255
ELSE
PULLDOWN_RP=PULLDOWN_RP-1
ENDIF
GoTo SUB_4_1MDLoop
ENDIF
IF BTN_PREV=0 THEN
PAUSE 100
WRITE 4,PULLDOWN_RP
RETURN
ENDIF
GoTo SUB_4_1MLoop
RETURN
'*************** SUB SUB_5_1*********
SUB_5_1:
'First read the variables from eprom
READ 5,LATRAISE_WT
SUB_5_1MDLoop:
LCDOUT $FE,192," ",$FE,192,DEC LATRAISE_WT
SUB_5_1MLoop:
IF BTN_PLUS=0 THEN
PAUSE 100
IF LATRAISE_WT>=255 THEN
LATRAISE_WT=0
ELSE
LATRAISE_WT=LATRAISE_WT+1
ENDIF
GoTo SUB_5_1MDLoop
ENDIF
IF BTN_MINUS=0 THEN
PAUSE 100
IF LATRAISE_WT<=0 THEN
LATRAISE_WT=255
ELSE
LATRAISE_WT=LATRAISE_WT-1
ENDIF
GoTo SUB_5_1MDLoop
ENDIF
IF BTN_PREV=0 THEN
PAUSE 100
WRITE 5,LATRAISE_WT
RETURN
ENDIF
GoTo SUB_5_1MLoop
RETURN
'*************** SUB SUB_6_1*********
SUB_6_1:
'First read the variables from eprom
READ 6,LATRAISE_RP
SUB_6_1MDLoop:
LCDOUT $FE,192," ",$FE,192,DEC LATRAISE_RP
SUB_6_1MLoop:
IF BTN_PLUS=0 THEN
PAUSE 100
IF LATRAISE_RP>=255 THEN
LATRAISE_RP=0
ELSE
LATRAISE_RP=LATRAISE_RP+1
ENDIF
GoTo SUB_6_1MDLoop
ENDIF
IF BTN_MINUS=0 THEN
PAUSE 100
IF LATRAISE_RP<=0 THEN
LATRAISE_RP=255
ELSE
LATRAISE_RP=LATRAISE_RP-1
ENDIF
GoTo SUB_6_1MDLoop
ENDIF
IF BTN_PREV=0 THEN
PAUSE 100
WRITE 6,LATRAISE_RP
RETURN
ENDIF
GoTo SUB_6_1MLoop
RETURN
'*************** SUB SUB_7_1*********
SUB_7_1:
'First read the variables from eprom
READ 7,OVHEADPRESS_WT
SUB_7_1MDLoop:
LCDOUT $FE,192," ",$FE,192,DEC OVHEADPRESS_WT
SUB_7_1MLoop:
IF BTN_PLUS=0 THEN
PAUSE 100
IF OVHEADPRESS_WT>=255 THEN
OVHEADPRESS_WT=0
ELSE
OVHEADPRESS_WT=OVHEADPRESS_WT+1
ENDIF
GoTo SUB_7_1MDLoop
ENDIF
IF BTN_MINUS=0 THEN
PAUSE 100
IF OVHEADPRESS_WT<=0 THEN
OVHEADPRESS_WT=255
ELSE
OVHEADPRESS_WT=OVHEADPRESS_WT-1
ENDIF
GoTo SUB_7_1MDLoop
ENDIF
IF BTN_PREV=0 THEN
PAUSE 100
WRITE 7,OVHEADPRESS_WT
RETURN
ENDIF
GoTo SUB_7_1MLoop
RETURN
'*************** SUB SUB_8_1*********
SUB_8_1:
'First read the variables from eprom
READ 8,OVHEADPRESS_RP
SUB_8_1MDLoop:
LCDOUT $FE,192," ",$FE,192,DEC OVHEADPRESS_RP
SUB_8_1MLoop:
IF BTN_PLUS=0 THEN
PAUSE 100
IF OVHEADPRESS_RP>=255 THEN
OVHEADPRESS_RP=0
ELSE
OVHEADPRESS_RP=OVHEADPRESS_RP+1
ENDIF
GoTo SUB_8_1MDLoop
ENDIF
IF BTN_MINUS=0 THEN
PAUSE 100
IF OVHEADPRESS_RP<=0 THEN
OVHEADPRESS_RP=255
ELSE
OVHEADPRESS_RP=OVHEADPRESS_RP-1
ENDIF
GoTo SUB_8_1MDLoop
ENDIF
IF BTN_PREV=0 THEN
PAUSE 100
WRITE 8,OVHEADPRESS_RP
RETURN
ENDIF
GoTo SUB_8_1MLoop
RETURN
'*************** SUB SUB_9_1*********
SUB_9_1:
'First read the variables from eprom
READ 9,PREACHERCURL_WT
SUB_9_1MDLoop:
LCDOUT $FE,192," ",$FE,192,DEC PREACHERCURL_WT
SUB_9_1MLoop:
IF BTN_PLUS=0 THEN
PAUSE 100
IF PREACHERCURL_WT>=255 THEN
PREACHERCURL_WT=0
ELSE
PREACHERCURL_WT=PREACHERCURL_WT+1
ENDIF
GoTo SUB_9_1MDLoop
ENDIF
IF BTN_MINUS=0 THEN
PAUSE 100
IF PREACHERCURL_WT<=0 THEN
PREACHERCURL_WT=255
ELSE
PREACHERCURL_WT=PREACHERCURL_WT-1
ENDIF
GoTo SUB_9_1MDLoop
ENDIF
IF BTN_PREV=0 THEN
PAUSE 100
WRITE 9,PREACHERCURL_WT
RETURN
ENDIF
GoTo SUB_9_1MLoop
RETURN
'*************** SUB SUB_10_1*********
SUB_10_1:
'First read the variables from eprom
READ 10,PREACHERCURL_RP
SUB_10_1MDLoop:
LCDOUT $FE,192," ",$FE,192,DEC PREACHERCURL_RP
SUB_10_1MLoop:
IF BTN_PLUS=0 THEN
PAUSE 100
IF PREACHERCURL_RP>=255 THEN
PREACHERCURL_RP=0
ELSE
PREACHERCURL_RP=PREACHERCURL_RP+1
ENDIF
GoTo SUB_10_1MDLoop
ENDIF
IF BTN_MINUS=0 THEN
PAUSE 100
IF PREACHERCURL_RP<=0 THEN
PREACHERCURL_RP=255
ELSE
PREACHERCURL_RP=PREACHERCURL_RP-1
ENDIF
GoTo SUB_10_1MDLoop
ENDIF
IF BTN_PREV=0 THEN
PAUSE 100
WRITE 10,PREACHERCURL_RP
RETURN
ENDIF
GoTo SUB_10_1MLoop
RETURN
'*************** SUB SUB_11_1*********
SUB_11_1:
'First read the variables from eprom
READ 11,PUSHDOWN_WT
SUB_11_1MDLoop:
LCDOUT $FE,192," ",$FE,192,DEC PUSHDOWN_WT
SUB_11_1MLoop:
IF BTN_PLUS=0 THEN
PAUSE 100
IF PUSHDOWN_WT>=255 THEN
PUSHDOWN_WT=0
ELSE
PUSHDOWN_WT=PUSHDOWN_WT+1
ENDIF
GoTo SUB_11_1MDLoop
ENDIF
IF BTN_MINUS=0 THEN
PAUSE 100
IF PUSHDOWN_WT<=0 THEN
PUSHDOWN_WT=255
ELSE
PUSHDOWN_WT=PUSHDOWN_WT-1
ENDIF
GoTo SUB_11_1MDLoop
ENDIF
IF BTN_PREV=0 THEN
PAUSE 100
WRITE 11,PUSHDOWN_WT
RETURN
ENDIF
GoTo SUB_11_1MLoop
RETURN
'*************** SUB SUB_12_1*********
SUB_12_1:
'First read the variables from eprom
READ 12,PUSHDOWN_RP
SUB_12_1MDLoop:
LCDOUT $FE,192," ",$FE,192,DEC PUSHDOWN_RP
SUB_12_1MLoop:
IF BTN_PLUS=0 THEN
PAUSE 100
IF PUSHDOWN_RP>=255 THEN
PUSHDOWN_RP=0
ELSE
PUSHDOWN_RP=PUSHDOWN_RP+1
ENDIF
GoTo SUB_12_1MDLoop
ENDIF
IF BTN_MINUS=0 THEN
PAUSE 100
IF PUSHDOWN_RP<=0 THEN
PUSHDOWN_RP=255
ELSE
PUSHDOWN_RP=PUSHDOWN_RP-1
ENDIF
GoTo SUB_12_1MDLoop
ENDIF
IF BTN_PREV=0 THEN
PAUSE 100
WRITE 12,PUSHDOWN_RP
RETURN
ENDIF
GoTo SUB_12_1MLoop
RETURN
'*************** SUB SUB_13_1*********
SUB_13_1:
'First read the variables from eprom
READ 13,PECDECK_WT
SUB_13_1MDLoop:
LCDOUT $FE,192," ",$FE,192,DEC PECDECK_WT
SUB_13_1MLoop:
IF BTN_PLUS=0 THEN
PAUSE 100
IF PECDECK_WT>=255 THEN
PECDECK_WT=0
ELSE
PECDECK_WT=PECDECK_WT+1
ENDIF
GoTo SUB_13_1MDLoop
ENDIF
IF BTN_MINUS=0 THEN
PAUSE 100
IF PECDECK_WT<=0 THEN
PECDECK_WT=255
ELSE
PECDECK_WT=PECDECK_WT-1
ENDIF
GoTo SUB_13_1MDLoop
ENDIF
IF BTN_PREV=0 THEN
PAUSE 100
WRITE 13,PECDECK_WT
RETURN
ENDIF
GoTo SUB_13_1MLoop
RETURN
'*************** SUB SUB_14_1*********
SUB_14_1:
'First read the variables from eprom
READ 14,PECDECK_RP
SUB_14_1MDLoop:
LCDOUT $FE,192," ",$FE,192,DEC PECDECK_RP
SUB_14_1MLoop:
IF BTN_PLUS=0 THEN
PAUSE 100
IF PECDECK_RP>=255 THEN
PECDECK_RP=0
ELSE
PECDECK_RP=PECDECK_RP+1
ENDIF
GoTo SUB_14_1MDLoop
ENDIF
IF BTN_MINUS=0 THEN
PAUSE 100
IF PECDECK_RP<=0 THEN
PECDECK_RP=255
ELSE
PECDECK_RP=PECDECK_RP-1
ENDIF
GoTo SUB_14_1MDLoop
ENDIF
IF BTN_PREV=0 THEN
PAUSE 100
WRITE 14,PECDECK_RP
RETURN
ENDIF
GoTo SUB_14_1MLoop
RETURN
'*************** SUB SUB_15_1*********
SUB_15_1:
'First read the variables from eprom
READ 15,CABLESHRUG_WT
SUB_15_1MDLoop:
LCDOUT $FE,192," ",$FE,192,DEC CABLESHRUG_WT
SUB_15_1MLoop:
IF BTN_PLUS=0 THEN
PAUSE 100
IF CABLESHRUG_WT>=255 THEN
CABLESHRUG_WT=0
ELSE
CABLESHRUG_WT=CABLESHRUG_WT+1
ENDIF
GoTo SUB_15_1MDLoop
ENDIF
IF BTN_MINUS=0 THEN
PAUSE 100
IF CABLESHRUG_WT<=0 THEN
CABLESHRUG_WT=255
ELSE
CABLESHRUG_WT=CABLESHRUG_WT-1
ENDIF
GoTo SUB_15_1MDLoop
ENDIF
IF BTN_PREV=0 THEN
PAUSE 100
WRITE 15,CABLESHRUG_WT
RETURN
ENDIF
GoTo SUB_15_1MLoop
RETURN
'*************** SUB SUB_16_1*********
SUB_16_1:
'First read the variables from eprom
READ 16,CABLESHRUG_RP
SUB_16_1MDLoop:
LCDOUT $FE,192," ",$FE,192,DEC CABLESHRUG_RP
SUB_16_1MLoop:
IF BTN_PLUS=0 THEN
PAUSE 100
IF CABLESHRUG_RP>=255 THEN
CABLESHRUG_RP=0
ELSE
CABLESHRUG_RP=CABLESHRUG_RP+1
ENDIF
GoTo SUB_16_1MDLoop
ENDIF
IF BTN_MINUS=0 THEN
PAUSE 100
IF CABLESHRUG_RP<=0 THEN
CABLESHRUG_RP=255
ELSE
CABLESHRUG_RP=CABLESHRUG_RP-1
ENDIF
GoTo SUB_16_1MDLoop
ENDIF
IF BTN_PREV=0 THEN
PAUSE 100
WRITE 16,CABLESHRUG_RP
RETURN
ENDIF
GoTo SUB_16_1MLoop
RETURN
'*************** SUB SUB_17_1*********
SUB_17_1:
'First read the variables from eprom
READ 17,CALFRAISES_WT
SUB_17_1MDLoop:
LCDOUT $FE,192," ",$FE,192,DEC CALFRAISES_WT
SUB_17_1MLoop:
IF BTN_PLUS=0 THEN
PAUSE 100
IF CALFRAISES_WT>=255 THEN
CALFRAISES_WT=0
ELSE
CALFRAISES_WT=CALFRAISES_WT+1
ENDIF
GoTo SUB_17_1MDLoop
ENDIF
IF BTN_MINUS=0 THEN
PAUSE 100
IF CALFRAISES_WT<=0 THEN
CALFRAISES_WT=255
ELSE
CALFRAISES_WT=CALFRAISES_WT-1
ENDIF
GoTo SUB_17_1MDLoop
ENDIF
IF BTN_PREV=0 THEN
PAUSE 100
WRITE 17,CALFRAISES_WT
RETURN
ENDIF
GoTo SUB_17_1MLoop
RETURN
'*************** SUB SUB_18_1*********
SUB_18_1:
'First read the variables from eprom
READ 18,CALFRAISES_RP
SUB_18_1MDLoop:
LCDOUT $FE,192," ",$FE,192,DEC CALFRAISES_RP
SUB_18_1MLoop:
IF BTN_PLUS=0 THEN
PAUSE 100
IF CALFRAISES_RP>=255 THEN
CALFRAISES_RP=0
ELSE
CALFRAISES_RP=CALFRAISES_RP+1
ENDIF
GoTo SUB_18_1MDLoop
ENDIF
IF BTN_MINUS=0 THEN
PAUSE 100
IF CALFRAISES_RP<=0 THEN
CALFRAISES_RP=255
ELSE
CALFRAISES_RP=CALFRAISES_RP-1
ENDIF
GoTo SUB_18_1MDLoop
ENDIF
IF BTN_PREV=0 THEN
PAUSE 100
WRITE 18,CALFRAISES_RP
RETURN
ENDIF
GoTo SUB_18_1MLoop
RETURN
'*************** SUB SUB_19_1*********
SUB_19_1:
'First read the variables from eprom
READ 19,DBWRISTCURL_WT
SUB_19_1MDLoop:
LCDOUT $FE,192," ",$FE,192,DEC DBWRISTCURL_WT
SUB_19_1MLoop:
IF BTN_PLUS=0 THEN
PAUSE 100
IF DBWRISTCURL_WT>=255 THEN
DBWRISTCURL_WT=0
ELSE
DBWRISTCURL_WT=DBWRISTCURL_WT+1
ENDIF
GoTo SUB_19_1MDLoop
ENDIF
IF BTN_MINUS=0 THEN
PAUSE 100
IF DBWRISTCURL_WT<=0 THEN
DBWRISTCURL_WT=255
ELSE
DBWRISTCURL_WT=DBWRISTCURL_WT-1
ENDIF
GoTo SUB_19_1MDLoop
ENDIF
IF BTN_PREV=0 THEN
PAUSE 100
WRITE 19,DBWRISTCURL_WT
RETURN
ENDIF
GoTo SUB_19_1MLoop
RETURN
'*************** SUB SUB_20_1*********
SUB_20_1:
'First read the variables from eprom
READ 20,DBWRISTCURL_RP
SUB_20_1MDLoop:
LCDOUT $FE,192," ",$FE,192,DEC DBWRISTCURL_RP
SUB_20_1MLoop:
IF BTN_PLUS=0 THEN
PAUSE 100
IF DBWRISTCURL_RP>=255 THEN
DBWRISTCURL_RP=0
ELSE
DBWRISTCURL_RP=DBWRISTCURL_RP+1
ENDIF
GoTo SUB_20_1MDLoop
ENDIF
IF BTN_MINUS=0 THEN
PAUSE 100
IF DBWRISTCURL_RP<=0 THEN
DBWRISTCURL_RP=255
ELSE
DBWRISTCURL_RP=DBWRISTCURL_RP-1
ENDIF
GoTo SUB_20_1MDLoop
ENDIF
IF BTN_PREV=0 THEN
PAUSE 100
WRITE 20,DBWRISTCURL_RP
RETURN
ENDIF
GoTo SUB_20_1MLoop
RETURN
'*************** SUB SUB_21_1*********
SUB_21_1:
'First read the variables from eprom
READ 21,DECLINESITUP_WT
SUB_21_1MDLoop:
LCDOUT $FE,192," ",$FE,192,DEC DECLINESITUP_WT
SUB_21_1MLoop:
IF BTN_PLUS=0 THEN
PAUSE 100
IF DECLINESITUP_WT>=255 THEN
DECLINESITUP_WT=0
ELSE
DECLINESITUP_WT=DECLINESITUP_WT+1
ENDIF
GoTo SUB_21_1MDLoop
ENDIF
IF BTN_MINUS=0 THEN
PAUSE 100
IF DECLINESITUP_WT<=0 THEN
DECLINESITUP_WT=255
ELSE
DECLINESITUP_WT=DECLINESITUP_WT-1
ENDIF
GoTo SUB_21_1MDLoop
ENDIF
IF BTN_PREV=0 THEN
PAUSE 100
WRITE 21,DECLINESITUP_WT
RETURN
ENDIF
GoTo SUB_21_1MLoop
RETURN
'*************** SUB SUB_22_1*********
SUB_22_1:
'First read the variables from eprom
READ 22,DECLINESITUP_RP
SUB_22_1MDLoop:
LCDOUT $FE,192," ",$FE,192,DEC DECLINESITUP_RP
SUB_22_1MLoop:
IF BTN_PLUS=0 THEN
PAUSE 100
IF DECLINESITUP_RP>=255 THEN
DECLINESITUP_RP=0
ELSE
DECLINESITUP_RP=DECLINESITUP_RP+1
ENDIF
GoTo SUB_22_1MDLoop
ENDIF
IF BTN_MINUS=0 THEN
PAUSE 100
IF DECLINESITUP_RP<=0 THEN
DECLINESITUP_RP=255
ELSE
DECLINESITUP_RP=DECLINESITUP_RP-1
ENDIF
GoTo SUB_22_1MDLoop
ENDIF
IF BTN_PREV=0 THEN
PAUSE 100
WRITE 22,DECLINESITUP_RP
RETURN
ENDIF
GoTo SUB_22_1MLoop
RETURN

Bruce
- 1st August 2010, 19:43
Instead of a pause after any button press try using WHILE WEND to wait for it to be released.



IF BTN_PLUS=0 THEN
WHILE BTN_PLUS = 0
WEND


Also - you have a ton of RETURN statements after GOTOs' so it never lands on these. I haven't followed your code all the way through, but if it needs to land on the returns, that could be another problem.

See if the attached works without skipping menu options.

Mike, K8LH
- 1st August 2010, 22:06
That's the easy fix but I cringe every time someone suggests waiting for a switch release.

Since you'll probably be using interrupts eventually to support an RTC or Timer function, I would suggest delegating switch debounce/management to the ISR. Then you're working with fully debounced real-time "new press" flag bits. Your program would need the ISR and a couple subtle changes;


SWNEW var Byte '
SWOLD var Byte ' switch state latch
FLAGS var Byte ' switch flag bits
BTN_NEXT var FLAGS.4 'Next button
BTN_PREV var FLAGS.5 'Previous button
BTN_PLUS var FLAGS.6 'Plus button
BTN_MINUS var FLAGS.7 'Minus button

Changes to your main program include testing for a '1' instead of a '0' and clearing the flag bit when you use it.


RB_SUBMenuLoop:
' BTN_PLUS is the Next Choice button
IF BTN_PLUS=1 THEN
BTN_PLUS=0
...
ENDIF
' BTN_PREV is the Exit button
IF BTN_PREV=1 THEN
BTN_PREV=0
RETURN
ENDIF
' BTN_NEXT is the Goto SubMenu Choice button
IF BTN_NEXT=1 THEN
BTN_NEXT=0
...
ENDIF
GoTo RB_SUBMenuLoop


If you're interested, you might consider trying out a non-interrupt version by adding a sample/debounce subroutine to your program;


'
' I need help with PBP commands for a "delay" and for "compliment"
'
SUB_SWITCHES '
delay_ms(16) ' 16-msec debounce interval ??? how
SWNEW = ~PORTB ' sample active lo switches ??? how
SWNEW = SWNEW AND 0xF0 ' on RB7..RB4 pins
SWNEW = SWNEW XOR SWOLD ' changes, press or release
SWOLD = SWOLD XOR SWNEW ' update switch state latch
SWNEW = SWNEW AND SWOLD ' filter out "new release" bits
FLAGS = FLAGS XOR SWNEW ' toggle switch flag bits
RETURN


Then you would need to call the subroutine at the top of each of your switch test loops (forgive me for shortening your program and for any PBP syntax errors);


RB_SUBMenuLoop:
GoSub SUB_SWITCHES ' sample switches
' BTN_PLUS is the Next Choice button
IF BTN_PLUS=1 THEN
BTN_PLUS=0
bSubMenuPos=bSubMenuPos+1
IF bSubMenuPos>1 THEN
bSubMenuPos=1
ENDIF
GoTo DisplaySubMenuLoop
ENDIF
' BTN_PREV is the Exit button
IF BTN_PREV=1 THEN
BTN_PREV=0
RETURN
ENDIF
' BTN_NEXT is the Goto SubMenu Choice button
IF BTN_NEXT=1 THEN
BTN_NEXT=0
IF bSubMenuPos=1 THEN
GoSub SUB_ADJ
ENDIF
GoTo DisplaySubMenuLoop
ENDIF
GoTo RB_SUBMenuLoop

'----------------------------------------------------------------
'
' adjust EEPROM value indexed by 'bMenuPos' variable (1..22)
'
' 1 SQUATS_WT 9 PREACHER CURL WT 17 CALF RAISES WT
' 2 SQUATS_RP 10 PREACHER CURL RP 18 CALF RAISES RP
' 3 PULLDOWN WT 11 PUSHDOWN WT 19 DBWRIST CURL WT
' 4 PULLDOWN RP 12 PUSHDOWN RP 20 DBWRIST CURL RP
' 5 LAT RAISE WT 13 PEC DECK WT 21 DECLINE SITUP WT
' 6 LAT RAISE RP 14 PEC DECK RP 22 DECLINE SITUP RP
' 7 OVHEAD PRESS WT 15 CABLE SHRUG WT
' 8 OVHEAD PRESS RP 16 CABLE SHRUG RP
'
SUB_ADJ: '
READ bMenuPos,COUNTER ' read EEPROM location 1..22
SUB_ADJ_1MDLoop: '
LCDOUT $FE,192," "
LCDOUT $FE,192,DEC COUNTER '
SUB_ADJ_1MLoop: '
GoSub SUB_SWITCHES ' sample switches
IF BTN_PLUS = 1 THEN ' if BTN_PLUS press
BTN_PLUS = 0 ' clear switch flag
IF COUNTER>=255 THEN '
COUNTER=0 '
ELSE '
COUNTER=COUNTER+1 '
ENDIF '
GoTo SUB_ADJ_1MDLoop ' refresh displayed count
ENDIF '
IF BTN_MINUS=1 THEN ' if BTN_MINUS press
BTN_MINUS=0 ' clear switch flag
IF COUNTER<=0 THEN '
COUNTER=255 '
ELSE '
COUNTER=COUNTER-1 '
ENDIF '
GoTo SUB_ADJ_1MDLoop ' refresh displayed count
ENDIF '
IF BTN_PREV=1 THEN ' if BTN_PREV press
BTN_PREV=0 ' clear switch flag
WRITE bMenuPos,COUNTER ' update EEPROM
RETURN ' exit
ENDIF '
GoTo SUB_X_1MLoop ' loop (for key press)
RETURN '


Have fun. Cheerful regards, Mike

Bruce
- 2nd August 2010, 00:58
Mike,


I would suggest delegating switch debounce/management to the ISR
With his switch inputs on RB7-RB4, how would you go about that without waiting for a switch release, and then clearing the int-on-change flag bit?

Wouldn't releasing the switch re-trigger the interrupt?

Mike, K8LH
- 2nd August 2010, 03:37
Mike,

With his switch inputs on RB7-RB4, how would you go about that without waiting for a switch release, and then clearing the int-on-change flag bit?

Wouldn't releasing the switch re-trigger the interrupt?

Oh no, I wouldn't use IOC interrupts in this application Bruce. Bouncing would be problematic. I would use periodic timer interrupts and poll the switches as in the example in post #15. And since OP is going to include RTC or Stopwatch functionality, periodic timer interrupts make sense.

Bruce
- 2nd August 2010, 14:40
Oh! I see what you meant now. Good idea.

Newer types like the 16F193x series IOC are a lot easier to use. These don't require reading the port to clear IOC flag bits, and they can be set to trigger on any edge..

DDDvvv
- 3rd August 2010, 05:13
thanks guys, all this ideas work! now, all i have to do is implement the rtc and beeper, which are ready to be merged with this code.

once again, thanks.

ps; not that im complaining, but is there any other menu builder app in picbasic?

dagger
- 4th August 2010, 22:43
yo he implementado esto y funciona correctamente

DDDvvv
- 8th September 2010, 21:19
hi, again, im trying this piece of code, from a previous post


RB_SUBMenuLoop:
' BTN_PLUS is the Next Choice button
IF BTN_PLUS=1 THEN
BTN_PLUS=0
...
ENDIF
' BTN_PREV is the Exit button
IF BTN_PREV=1 THEN
BTN_PREV=0
RETURN
ENDIF
' BTN_NEXT is the Goto SubMenu Choice button
IF BTN_NEXT=1 THEN
BTN_NEXT=0
...
ENDIF
GoTo RB_SUBMenuLoop

then i have this code scanning port b, through a 1ms interrupt:


Changed = PortB ^ OldPort
IF Changed.4 = 1 THEN ; Pick your pin
OldPort = PortB
BTN_PLUS = 1
ENDIF

this code is incrementing one at a time, which is what i want, but the only problem is that it is incrementing on a rising and falling edge of a button push. so if i push the btn_plus, bmenupos increments by 1, and if i release it, bmenupos increments again.

i want it to increment only on the rising edge, not on the falling edge. any ideas?

Mike, K8LH
- 8th September 2010, 22:58
When you exclusive-or "new" and "old" a resulting 1 bit indicates a change of state (either a new hi or new press, or a new lo or new release). You need to filter these "change" bits. If you AND the "change" bit with the "old" bit you filter out the "new press" bits and you're left with "new release" bits. If you AND the "change" bit with the "new" bit you filter out the "new release" bits and you're left with the "new press" bits.

Hope this helps.

Cheerful regards, Mike



'
' swnew ____-----_____-----_____ new switch sample (positive logic)
' swold _____-----_____-----____ switch state latch
' delta ____-____-____-____-____ changes, press or release
' newhi ____-_________-_________ new press bits
' newlo _________-_________-____ new release bits
'
swnew = PortB ' sample active hi switches
delta = swnew ^ swold ' changes, press or release
newhi = delta & swnew ' get "new press" bits
newlo = delta & swold ' get "new release" bits
swold = swnew ' update switch state latch
IF newhi.4 = 1 THEN '
BTN_PLUS = 1 '
ENDIF

DDDvvv
- 9th September 2010, 03:45
that is just great. thanks for pointing me to the right direction, Mr Mike. its all fixed now.

cheers:)

Mike, K8LH
- 9th September 2010, 08:19
that is just great. thanks for pointing me to the right direction, Mr Mike. its all fixed now.

cheers:)
You're very welcome Sir.

Please note that the previous example can be optimized a bit. Since you're using the "new press" state as the action state in your program you don't need the "newlo" variable and its assignment statement. You can also retask the "swnew" variable and eliminate the "newhi" variable. Some XOR trickery is used to update the "swold" switch state latch to the new PortB pattern.


'
' swnew ____-----_____-----_____ new switch sample (positive logic)
' swold _____-----_____-----____ switch state latch
' swnew ____-____-____-____-____ changes, press or release
' swnew ____-_________-_________ new press bits
'
swnew = PortB ' sample active hi switches
swnew = swnew ^ swold ' changes, press or release
swold = swold ^ swnew ' update switch state latch (swold = new PortB)
swnew = swnew & swold ' get "new press" bits
IF swnew.4 = 1 THEN ' if RB4 "new press"
BTN_PLUS = 1 ' set flag for main
ENDIF


With your 1-msec interrupt intervals you might consider adding a piezo speaker and code for "new press" beeps;

'
' beep task (32-msec 500-Hz beep using 1-msec interrupts)
'
IF beepctr > 0 THEN ' if beep task running
PortB = PortB ^ spkrpinmask ' toggle piezo speaker pin
beepctr = beepctr - 1 ' decrement beep msec counter
ENDIF
'
' swnew ____-----_____-----_____ new switch sample (positive logic)
' swold _____-----_____-----____ switch state latch
' swnew ____-____-____-____-____ changes, press or release
' swnew ____-_________-_________ new press bits
'
swnew = PortB ' sample active hi switches
swnew = swnew ^ swold ' changes, press or release
swold = swold ^ swnew ' update switch state latch (swold = new PortB)
swnew = swnew & swold ' get "new press" bits
IF swnew.4 = 1 THEN ' if RB4 "new press"
BTN_PLUS = 1 ' set flag for main and
beepctr = 32 ' task a new press beep
ENDIF

If you experience bounce problems with a 1-msec sampling interval you might consider adding a counter and executing the switch sample code at some interval between 16 and 32 msecs.

BTW, assembly language "parallel switch state logic" is incredibly efficient (6 or 8 words);


;
; wreg ___-----_____-----____ new switch sample (positive logic)
; swold ____-----_____-----___ switch state latch
; wreg ___-____-____-____-___ changes, press or release
; wreg ___-_________-________ filter out new release bits
; flags ___-----------________ toggle sw flags for main
;
comf PORTB,W ; sample active lo switches
; movf PORTB,W ; sample active hi switches
andlw b'11110000' ; on RB7..RB4 pins
xorwf swold,W ; changes, press or release
xorwf swold,F ; update switch state latch
andwf swold,W ; filter out "new release" bits
skpz ; new press? no, skip, else
bsf beepctr,5 ; task a "new press" beep
xorwf flags,F ; toggle sw flags for main



Cheerful regards, Mike