PDA

View Full Version : Single button function



DynamoBen
- 2nd March 2006, 02:26
I have a single button that needs to allow users to navigate menus and increment selections.

I have tried a few things, but wanted to ask the group for ideas. As usual I'm short on space.

Function 1: Press and Release = Increment
Function 2: Press and Hold = Enter

What I have now works ok until you move onto the next submenu and the value increments right away. (BTW ButtonCnt is tied to TMR1 to count how long the button has been held)

While Switch=0
IF ButtonCnt>30 Then SubMenu=SubMenu+1
Wend

value=value+1

Thoughts on this one?

sougata
- 6th March 2006, 18:02
Hey,

Just kidding. For user friendliness ,I beleive follow the mouse. Click, Double Click, Hold and any combination of the three.

1. Hold to enter menu.

2. Click to cycle between items

3. Double Click to enter submenu incr/decr

4. click + Click hold increase / decrease alternate

5. Double click back to main menu

6. Double click quit menu

Please post the code if it works.

Regards

Sougata

DynamoBen
- 6th March 2006, 18:56
I found a similar device and will be using the method I described above.

My conditional statements needed some alteration to function properly.

Problem solved.

jessey
- 7th March 2006, 11:01
Hi DynamoBen,

I wrote a short bit of code here that compiles to 74 words. I'm not sure if it's what you were looking for but I thought I'd post it anyway.

The first press and release of the button after a hearing a single beep of the buzzer will INCREMENT your variable. Any further (single quick press's) that sounds a single beep will continue to increment the variable and when your finished incrementing then holding the button down for 4.5 seconds will ENTER the variable and exit the loop.

If you wanted to increment and enter another variable using the same push button then you could place another IF-THEN in the loop and when it beeps a set number of times then the code could jump out of that loop into another loop and the same basic code could be repeated for a different variable (with a little modification to the original code below).

Also an Led could be used instead of the buzzer. I'm not sure but I think this is what you wanted?

IF Settings_Push_Button = Is_Pressed THEN
For i = 0 to 100'this ensures that we return to mainloop
WHILE Settings_Push_Button = Is_Pressed
PWM Buzzer,250,1 : PAUSE 1500 : Y = Y + 1
IF Y = 3 THEN
'Do the ENTER
Y = 0
IF Y = 0 THEN EXIT
ENDIF
WEND

IF Y = 2 THEN
Y = 0
'Do the Increment
ENDIF

PAUSE 100
NEXT i
ENDIF

EXIT:

jessey

DynamoBen
- 6th June 2006, 05:34
Alright I'm back at this again. I can’t figure out an efficient way to do this. My original solution was:

ButtonHeld con 30

Switch_Routine:
ButtonCnt=0
While Switch=0:Wend
Pause 250
Return

Main:
' display lcd info here

IF Switch=0 Then
GoSub Switch_Routine

IF ButtonCnt>ButtonHeld Then
' change menu option
Else
' increment value
EndIF
EndIF

Goto Main


Timer1 counts how long (100 ms interval) the switch is held. Once the user releases the switch then it would reenter the Main to execute the code. The problem is there is no feedback to the user if the button has been held long enough. The program stays at the While:Wend until the user releases the button. If I jump out of the switch prior to the release of the switch the loop keeps executing the same switch command until the user releases the switch. Remember: the switch is still being held down.

I’m looking for ideas. If the user presses and releases the switch the program would increment value. If the user presses and holds the switch for 3 seconds or more it would change menu options.

Basically I want two buttons in one.

Melanie
- 6th June 2006, 08:25
MyButton var PortB.0 ' Your Button can be anywhere
' Connect between PIC pin and Vss
' Use Weak Pull-Up or Resistor to Vdd

ButtonPress var BYTE ' Button Counter Variable

LongPress con 20 ' Change this value for desired SET
' function trip-point in 50mS steps
' Currently set for 1 Second


MainLoop:
LCDOut $FE,1,"Go Press..."
ButtonLoop:
Gosub GetButton
If ButtonPress>0 then
If ButtonPress=1
LCDOut $FE,1,"Short Press"
else
LCDOut $FE,1,"Long Press"
endif
Pause 1000
Goto MainLoop
endif
Goto ButtonLoop

'
' Subroutine weighs-up users finger
' in multiples of 50mS
' Constant LONGPRESS determines boredom level
' -------------------------------------------
' on Exit...
' ButtonPress=0 - No Press
' ButtonPress=1 - Short Press
' ButtonPress=2 - Long Press
GetButton:
ButtonPress=0
While MyButton=0
If ButtonPress<255 then ButtonPress=ButtonPress+1
Pause 50 ' This is also our Debounce value
Wend
If ButtonPress>0 then
If ButtonPress=>LongPress then
ButtonPress=2
else
ButtonPress=1
endif
endif
Return

If you have an LCD for example, you can always clear the display (or light a LED if you have one) to indicate that a SET has been performed. Here's a variation..



MyButton var PortB.0 ' Your Button can be anywhere
' Connect between PIC pin and Vss
' Use Weak Pull-Up or Resistor to Vdd

ButtonPress var BYTE ' Button Counter Variable

LongPress con 20 ' Change this value for desired SET
' function trip-point in 50mS steps
' Currently set for 1 Second


MainLoop:
LCDOut $FE,1,"Go Press..."
ButtonLoop:
Gosub GetButton
If ButtonPress>0 then
If ButtonPress=1
LCDOut $FE,1,"Short Press"
else
LCDOut $FE,1,"Long Press"
endif
Pause 1000
Goto MainLoop
endif
Goto ButtonLoop

'
' Subroutine weighs-up users finger
' in multiples of 50mS
' Constant LONGPRESS determines boredom level
' -------------------------------------------
' on Exit...
' ButtonPress=0 - No Press
' ButtonPress=1 - Short Press
' ButtonPress=2 - Long Press
GetButton:
ButtonPress=0
While MyButton=0
If ButtonPress<255 then ButtonPress=ButtonPress+1
Pause 50 ' This is also our Debounce value
If ButtonPress=LongPress then LCDOut $FE,1
Wend
If ButtonPress>0 then
If ButtonPress=>LongPress then
ButtonPress=2
else
ButtonPress=1
endif
endif
Return

Another variation which I tend to use, is if you have a Piezo, beep it at every Button Press start (ie ButtonCount=1) as a confidence indicator for the user (they like things like that), and then Beep Constantly once the LONGPRESS value has been reached. example...



'
' Subroutine weighs-up users finger
' in multiples of 50mS
' Constant LONGPRESS determines boredom level
' -------------------------------------------
' on Exit...
' ButtonPress=0 - No Press
' ButtonPress=1 - Short Press
' ButtonPress=2 - Long Press
GetButton:
ButtonPress=0
While MyButton=0
If ButtonPress<255 then ButtonPress=ButtonPress+1
Pause 50 ' This is also our Debounce value
If ButtonPress=1 then Gosub Beep
If ButtonPress=>LongPress then Gosub Beep
Wend
If ButtonPress>0 then
If ButtonPress=>LongPress then
ButtonPress=2
else
ButtonPress=1
endif
endif
Return

You can go on with variations for ever....



'
' Subroutine weighs-up users finger
' in multiples of 50mS
' Constant LONGPRESS determines boredom level
' -------------------------------------------
' on Exit...
' ButtonPress=0 - No Press
' ButtonPress=1 - Short Press
' ButtonPress=2 - Long Press
GetButton:
ButtonPress=0
While MyButton=0
If ButtonPress<255 then ButtonPress=ButtonPress+1
Pause 50 ' This is also our Debounce value
If ButtonPress=1 then Gosub Beep
If ButtonPress=>LongPress then Gosub Beep
If ButtonPress=255 then Gosub Klaxon ' Users fallen asleep
Wend
If ButtonPress>0 then
If ButtonPress=>LongPress then
ButtonPress=2
else
ButtonPress=1
endif
endif
Return

I use a WORD as the Counter in many cases, and if the Button is held for a really long time (eg 30 Seconds or even a Minute), it lets me jump into a Secret Set-Up Menu or just display an unexpected message for the User if I'm feeling devilish... or just as a 'Granny Button' to erase Passwords, Contrast and LCD Backlight levels that have been messed up. Users are a peculiar bunch... they put a password into the Menu (which they promptly forget) or save a near Invisible LCD Contrast setting and then they call Tech-Support to pull them out of the sh*t. It's nice to tell them to Press and Hold the Button for 30 minutes (or until their finger goes numb - whichever comes first) and everything will reset back to the factory default settings... (it'll reset after a minute, but if you tell them 30 they'll not do it a second time).

DynamoBen
- 6th June 2006, 17:33
Melanie as always thank you for your examples and advice.

What I'm seeing in your examples is what I'm already doing. A single short press functions normally and the user sees a value increment when they release the switch. However in the case of a long press (ENTER) they have no idea, short of adding an led/buzzer/clear screen, that they have held the switch long enough to change menus. Basically they have to count in their head.

Is this just something I need to live with? Do you run into any problems with this type of interface?

Melanie
- 6th June 2006, 18:04
Wherever possible I use a 3-button interface (Up/Down/Set), but if I'm stuck with one button, I try to provide some kind of user feedback so they know where they stand...

Example 1... www.k3planet.com/Datasheet-9910-1.pdf

...and people thought I was kidding when I said I put "Yankee Doodle" into a commercial product!

DynamoBen
- 6th June 2006, 18:22
Nice!

Alright I give; I either need to use another pin for feedback or add another switch. I guess I need to move from a minimalist single switch project to a two switch project.

Thanks for the assistance.

Archilochus
- 6th June 2006, 21:04
However in the case of a long press (ENTER) they have no idea, short of adding an led/buzzer/clear screen, that they have held the switch long enough to change menus. Basically they have to count in their head.
Is this just something I need to live with? Do you run into any problems with this type of interface?

What about having the menu change happen automatically after a button HOLD of say 1.5 seconds.
The user sees the menu change, so they know they've held the button long enough.
After the menu changes, your code then waits for the button to be released before continuing - avoiding spurious inputs at the new menu.
If the user is goofy enough to continue holding the button, the program just sits waiting until they release it (or rig up a shocker on the button so they get zapped after 20 seconds :-)

Only quicly looked over Melanies samples - maybe she already suggested something like that?

Arch

DynamoBen
- 6th June 2006, 21:37
What about having the menu change happen automatically after a button HOLD of say 1.5 seconds.
The user sees the menu change, so they know they've held the button long enough.
After the menu changes, your code then waits for the button to be released before continuing - avoiding spurious inputs at the new menu.
If the user is goofy enough to continue holding the button, the program just sits waiting until they release it (or rig up a shocker on the button so they get zapped after 20 seconds :-)

Only quicly looked over Melanies samples - maybe she already suggested something like that?

Arch

This is exactly what I wanted to do. However it’s a programming nightmare. I have been working on this for days and have come up with nothing. It is simple to describe but difficult to implement.

Melanie
- 6th June 2006, 23:31
Do you not have anything that can be used as feedback to the user? Describe your User Interface (OK, so we know it's got ONE button) - but what else has your device got in the way of LEDs LCDs or Beepers? And what do you want the Button to Do?

DynamoBen
- 7th June 2006, 00:37
The UI currently consists of one switch and an LCD. The switch is used to change time/date in normal mode. In the backdoor setup its used to set the time/date on a RTC.

The advantage to having two switches is that the user could have autorepeat functionality when setting the clock in setup. The disadvantage is that the second switch would go unused the rest of the time, which is most of the time.

Archilochus
- 7th June 2006, 01:18
This is cut & adapted from an old piece of graphical LCD menu / sub-menu code that I had laying about. There was more to it, but I removed some stuff that didn't apply. I *think* this code worked OK, but it's been a long time since I played with it. I added some comments to it...



; Button press pulls input pin LOW

; This next is placed with the subroutines...
CountButn: ; Count button press duration during a ~2s loop.
; Loop auto-exits after either 2 seconds, or when user releases the button
; (if released before 2 seconds are up).
; "HoldFlag" used to flag if button pressed (HoldFlag=0), or held (HoldFlag=1).
pause 50 : HoldFlag = 0 ; Pause to ignore switch bounce, clear flag
For CounterC = 0 to 49 ; 2s loop checks button input state...
Pause 40
if Butn then Exit_CountButn ; When button released, end loop
Next CounterC ; Increment counter each loop
Exit_CountButn: ; Test # loops button held for. If > 20 (0.8s), set 'HoldFlag'
if CounterC > 20 then HoldFlag = 1
Return
;
; ####################################
;
; Here we're in the "main menu" section and looking for a button press OR hold.
if Butn = 0 then ; On button press...
gosub CountButn ; check button press duration (press / hold)
WHILE Butn = 0 ; On return from sub, if button still held,
WEND ; wait until user releases button.
if HoldFlag then ; if HELD more than 0.8S, HoldFlag will be set
gosub PressPower : goto SecureChk ; Turn OFF, jump to security mode menu
EndIF
; if only pressed, NOT held, HoldFlag=0, so continue with whatever you need to do...
; Clear out previous arrow before drawing new...
CS_Left=0 : CS_Right=1 : GraphicFlag=1 : TextFlag=0
LoopStop=7 : StartADR=7690 ; graphic memory address
TempXY = PageFlag : gosub SetXY ; Set LCD X, Y locations
gosub Write_Data ; Write commands to LCD
PageFlag = PageFlag + 1 ; Increment page counter after button press
if PageFlag > 3 then PageFlag=1 ; Limits page counter to 1-3
gosub DrawArrow ; Draw new 8 byte arrow
CounterA = 74 ; After any press, loop continues 6sec looking for more presses.
EndIF

Archilochus
- 7th June 2006, 02:15
Oops - when I cut and altered that example, I messed up...
The "WHILE / WEND" test for release of the button should be placed AFTER you jump to and write the new menu.
Otherwise, without the new menu appearing, the user will not know when to let go of the button, and would stand there forever after holding the button... waiting, and waiting...

Arch

DynamoBen
- 7th June 2006, 04:50
Your example had the same issue. User sees no change in the display until the button is released.

I will look into placing the while:wend after display update.

Melanie
- 7th June 2006, 12:30
This appended example is the basis for the worlds most inaccurate clock.

It’s demonstrating ONE Button usage.

Press the Button momentarily and it will flip the display between 12/24 Hour Mode.

Press the Button for an extended time and it will jump into a Menu for you to set the time. Note the creative use of the CURSOR to indicate when a SET Function has been executed...

It’s just a ditty to show how you can do things with ONE Button.

And shows that code previously written (Olympic Timer) for a PIC16F876 can be quickly and easily ported and modified for a PIC16F628, or PIC16F628A or B or C...

It’s also a teaser for half a dozen recent (Timer) threads (and for a gentleman searching for an elapsed timer – hint – hint – somebody nudge him to look at this thread!!!!) to show what can be done with 10 minutes worth of code, half a bucket of Cafe Nero's finest and a plastic straw...



'
' Buttons.bas
' ---------------
' by Melanie
' written on a Laptop in a lunchbreak in a Cafe Nero
' in Londons famous Regent Street... 7th June 2006
'
' A simple demonstrator as to what can be done
' with just ONE Button and an LCD...
' Some Code stolen from OLYMPIC TIMER
'

'
' Device Programming Options
' --------------------------
@ DEVICE pic16F628, INTRC_OSC_NOCLKOUT
' System Clock Options
@ DEVICE pic16F628, WDT_ON ' Watchdog Timer
@ DEVICE pic16F628, PWRT_ON ' Power-On Timer
@ DEVICE pic16F628, BOD_ON ' Brown-Out Detect
@ DEVICE pic16F628, MCLR_OFF ' Master Clear Options (Internal)
@ DEVICE pic16F628, LVP_OFF ' Low-Voltage Programming
@ DEVICE pic16F628, CPD_OFF ' Data Memory Code Protect
@ DEVICE pic16F628, PROTECT_OFF ' Program Code Protection

'
' Hardware Defines
' ----------------
'
' LCD Display
' -----------
Define LCD_DREG PORTB ' Port for LCD Data
Define LCD_DBIT 4 ' Use upper 4 bits of Port
Define LCD_RSREG PORTB ' Port for RegisterSelect (RS) bit
Define LCD_RSBIT 3 ' Port Pin for RS bit
Define LCD_EREG PORTB ' Port for Enable (E) bit
Define LCD_EBIT 2 ' Port Pin for E bit
Define LCB_BITS 4 ' Using 4-bit bus
Define LCD_LINES 2 ' Using 2 line Display
Define LCD_COMMANDUS 2000 ' Command Delay (uS)
Define LCD_DATAUS 50 ' Data Delay (uS)
'
' Buttons
' -------
MyButton var PortB.0

'
' Software Defines
' ----------------
AMPMFlag var BYTE ' Flag for 12/24 Hour Mode 0=24, 1=12
' - Yes I know it's a BYTE but I can't be bothered
ButtonPress var BYTE ' Button Counter Variable
DataA var BYTE
Hours var BYTE
Hundredths var BYTE
MenuStep var BYTE ' Status Indicator for Menu Display
Minutes var BYTE
Seconds var BYTE
TMR1Cal var BYTE ' Timer Calibration Value
TMR1CalAR var BYTE ' Timer Advance/Retard Indicator
TMR1RunOn var WORD ' variable holding TMR1 Run-On value


'
' EEPROM Settings
' ---------------
Data @0,0 ' Advance/Retard Indicator
Data 0 ' Calibration Value
Data 0 ' 12/24 Hour Flag

'
' Software Constants
' ------------------
LongPress con 20 ' Change this value for desired SET
' function trip-point in 50mS steps
' Currently set for 1 Second
TMR1CalMax con 100 ' Maximum adjustment (+/-100uS per 10mS interrupt)
TMR1Preset con $D910 ' 10mS Timer Reload value, offset by 20uS
' to allow for TMR1 Setting Calculations
'
' Initialise PIC
' --------------
TRISA=%00000000 ' PortA I/O Configuration
TRISB=%00000001 ' PortB I/O Configuration
CMCON=%00000111 ' Comparators OFF
OPTION_REG.7=0 ' Enable weak Pull-Ups (used for PressButton)

'
' Initialise Main Program
' -----------------------
Pause 2000 ' Timeout for LCD Hardware to wake-up...
Read 0,TMR1CalAR ' Read Calibration Advance/Retard Indicator
Read 1,TMR1Cal ' Read Calibration Value
Read 2,AMPMFlag ' It's what it says...
Hundredths=0 ' Reset Timer Counter variables
Seconds=0
Minutes=0
Hours=0
'
' Initialise TMR1 Interrupts
' --------------------------
Gosub SetTimer ' Set the Timer for next 10mS Interrupt
On Interrupt goto TickCount
PIE1.0=1 ' Enable TMR1 Interrupts
INTCON.6=1 ' Enable all unmasked Interrupts
INTCON.7=1 ' Enable Global Interrupts
DisplayRestart:
LCDOut $FE,1 ' Clear Display
'
' Main Program Loop
' -----------------
Enable
DisplayLoop:
LCDOut $FE,$0C
If AMPMFlag=0 then
'
' Here we have got a 24 Hour Clock Display
' ----------------------------------------
LCDOut $FE,$84,DEC2 Hours,":",DEC2 Minutes,":",DEC2 Seconds
else
'
' and here we have a 12 Hour Clock Display
' ----------------------------------------
LCDOut $FE,$82
DataA=Hours
If DataA=0 then DataA=12
If DataA>12 then DataA=DataA-12
If DataA<10 then LCDOut " "
LCDOut #DataA,":",DEC2 Minutes,":",DEC2 Seconds," "
If Hours>11 then
LCDOut "PM"
else
LCDOut "AM"
endif
endif
'
' Check For Button Press
' ----------------------
Gosub GetButton
'
' Toggle 24 Hour Mode
' -------------------
If ButtonPress=1 then
AMPMFlag=AMPMFlag^1
Write 2,AMPMFlag
Goto DisplayRestart
endif
If ButtonPress<>2 then goto DisplayLoop
Disable
'
' Setup Mode
' ----------
LCDOut $FE,1,"Set Time Please:"
LCDOut $FE,$C4,DEC2 Hours,":",DEC2 Minutes,":",DEC2 Seconds,$FE,$C5
MenuStep=0
MenuLoop:
Gosub GetButton
'
' SET Mode
' --------
If ButtonPress=2 then
MenuStep=MenuStep+1
If MenuStep=3 then
LCDOut $FE,1,$FE,$83,"Thank You",$FE,$C0,"Have a Nice Day"
Pause 2000
Goto DisplayRestart
endif
endif
If ButtonPress=1 then
'
' Hours
' -----
If MenuStep=0 then
Hours=Hours+1
If Hours>23 then Hours=0
LCDOut $FE,$C4,DEC2 Hours
endif
'
' Minutes
' -------
If MenuStep=1 then
Minutes=Minutes+1
If Minutes>59 then Minutes=0
LCDOut $FE,$C7,DEC2 Minutes
endif
'
' Seconds
' -------
If MenuStep=2 then
Seconds=Seconds+1
If Seconds>59 then Seconds=0
LCDOut $FE,$CA,DEC2 Seconds
endif
endif
'
' Ensure Cursor is in a nice place...
' --------------------------------
LCDOut $FE,$0E
If MenuStep=0 then
LCDOut $FE,$C5
else
If MenuStep=1 then
LCDOut $FE,$C8
else
LCDOut $FE,$CB
endif
endif
Goto MenuLoop

'
' Subroutine weighs-up users finger
' in multiples of 50mS
' Constant LONGPRESS determines boredom level
' -------------------------------------------
' on Exit...
' ButtonPress=0 - No Press
' ButtonPress=1 - Short Press
' ButtonPress=2 - Long Press
GetButton:
ButtonPress=0
While MyButton=0
If ButtonPress<255 then ButtonPress=ButtonPress+1
Pause 50 ' This is also our Debounce value
If ButtonPress=>LongPress then LCDOut $FE,$0F
Wend
If ButtonPress>0 then
If ButtonPress=>LongPress then
ButtonPress=2
else
ButtonPress=1
endif
endif
Return

'
' Subroutine Loads TMR1 values
' ============================
SetTimer:
T1CON.0=0 ' Stop the Clock
TMR1RunOn.Highbyte=TMR1H ' Load the Run-On (Over-Run) value (if any)
TMR1RunOn.Lowbyte=TMR1L
TMR1RunOn=TMR1Preset+TMR1RunOn ' Calculate the New (adjusted) value for TMR1
If TMR1CalAR=0 then ' Calibration ADVANCE (add) or RETARD (subtract)
TMR1RunOn=TMR1RunOn+TMR1Cal
else
TMR1RunOn=TMR1RunOn-TMR1Cal
endif
TMR1H=TMR1RunOn.Highbyte ' Save new values to TMR1
TMR1L=TMR1RunOn.Lowbyte
T1CON.0=1 ' Restart the Clock
PIR1.0=0 ' Reset TMR1's Interupt Flag
Return

'
' Timer Interrupt Handler
' =======================
TickCount:
Gosub SetTimer ' Set the Timer for next 10mS Interrupt
Hundredths=Hundredths+1 ' Increment 10mS Seconds Counter
If Hundredths>99 then
Hundredths=0
Seconds=Seconds+1
' Increment the Seconds
If Seconds>59 then
Seconds=0
Minutes=Minutes+1
' Increment the Minutes
If Minutes>59 then
Minutes=0
Hours=Hours+1
' Increment the Hours
If Hours>23 then Hours=0
endif
endif
endif
Resume

End

Archilochus
- 7th June 2006, 17:15
Your example had the same issue. User sees no change in the display until the button is released.

I will look into placing the while:wend after display update.

Other than my goof with the WHILE / WEND, the code will jump to a new menu after a HOLD of ~ 1 second. If only pressed, the button test loop ends immediately, and the code continues as needed after a press & release.

The button test loop auto-terminates after 2 seconds, so even if the user continues holding the button, the code will jump to the new menu anyway, and only after writing the new menu, does it then wait for a button release.

Arch

DynamoBen
- 7th June 2006, 17:47
Melanie I've added your code into my project. When setting the times hours, minutes, or seconds the display clears and only displays the value that is currently being altered. Are you seeing the same thing or am I missing something?

Melanie
- 7th June 2006, 18:53
You're doing something wrong...

When setting the Time, you can see all the fields (by field, you can see Hours, Minutes and Seconds on the same line, and as you press momentarilly, only the field you are currently parked on will change. When you hold for SET, the cursor changes from an underscore to a Block and on finger release moves to the next field, leaving the previous one with the content you set.

I refer you to the Button-02 picture... there you can see the underscore cursor parked in the Hours field... pressing momentarily will advance Hours through to 23 then cycle around starting from zero. Hold the Button for SET and the cursor changes to a BLOCK, and on finger release moves to Minutes changing back to an Underscore.

Check your $FE,xx's are the same as mine...

Melanie

DynamoBen
- 7th June 2006, 19:16
Duh! <smacks forehead> my switch routine had a LCD clear command in it.

leisryan
- 5th August 2006, 00:22
Good day

I'm a picbasic newbie i'd like to ask these syntaxes do?

AMPMFlag=AMPMFlag^1 '>>>>>>>>>>>>>>>>>>>what does this do?

Lc var byte [15]
For i = 0 to 15 : read i, b0:if b0 = 0 then
lookup i,[1,2,3,11,4,5,6,11,7,8,9,10,11,12,13,14], b0
Lc(i)=b0 '>>>>>>>>>>>>>>>>>>>>>>>>>>>what does this do?
goto Address

I would gladly appreciate for any response
thanks
ryan

Melanie
- 5th August 2006, 10:24
AMPMFlag=AMPMFlag^1 '>>>>>>>>>>>>>>>>>>>what does this do?

AMPMFlag is a BIT variable.
All this does is toggle the BIT variable, if it was zero it will be set to 1, if it was 1 it will be set to 0. It is the equivallent of...

IF AMPMFlag=0 then
AMPMFlag=1
else
AMPMFlag=0
endif



Lc var byte [15]
For i = 0 to 15 : read i, b0:if b0 = 0 then
lookup i,[1,2,3,11,4,5,6,11,7,8,9,10,11,12,13,14], b0
Lc(i)=b0 '>>>>>>>>>>>>>>>>>>>>>>>>>>>what does this do?

Lc is a BYTE array 15 elements deep in the range Lc(0) to Lc(14)
You are loading Lc at array location i with the contents of variable b0

leisryan
- 6th August 2006, 22:28
Thank you Mel,
I am incorporating your olympic timer in my medicine scheduler project I used some code snippets from les Johnson's book "experimenting with picbasic" I also read your thread with bits,byte, and arrray handling and found it intuitive!!!
I am still fixing my keypad routine to scan and output to LCD like a mobile fone does(",) I am trying to find a lcd menu routine for my display I will post it later on a new thread

thanks again
ryan

bbarney
- 7th August 2006, 17:55
here is a chip that will give you 2 button's on one i/o
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/4588

Melanie
- 7th August 2006, 21:18
You seriously want to pay $1 for a 2 I/O expander?

If you need two buttons on one I/O, then you can achieve that with a different value of Capacitor on each of two Buttons and measure the time period for charge. Cost about 5 cents and a bit of magic in software...

DynamoBen
- 7th August 2006, 21:24
You could also use the pot command and tie each button to a different value resistor.

This gives you the added ability of determining when both buttons are being pressed.

bbarney
- 7th August 2006, 22:14
Well if I had been trying to solve this problem since March I think a $1 part would be cheap,sorry you didn't like my feable attempt at helping out :)
I'll go to my room now and keep quiet.

Melanie
- 7th August 2006, 22:55
Don't get the hump over my comment... I'm NOT criticising your contribution which is perfectly valid, but think about a $1....

For $1 you can get a PIC with a heap of I/O's...

For an extra $1 added to whatever PIC you are currently using would probably give you a dozen I/O's more

For 75 cents you can get an I2C 8 channel I/O expander...

For 45 cents you can get a PIC10F to give you your extra I/O's...

Adding I/O's at the rate of 50 cents per I/O is nonsensical... there's just so many options available for less money - but...

you've brought it to everyone's attention, and that just might be exactly the product someone is looking for, so thank you for that.

bbarney
- 7th August 2006, 23:03
Melanie
I was not in the least bit offended,you must have missed the happy face :)and it did spur you to give Ben another cheaper option not to mention Ben's idea so in around about way I guess I've helped.

Melanie
- 8th August 2006, 08:06
I like to think that every comment on this forum, good or bad, is a valid one and holds as much weight as every other. What's wrong for one person may be someone elses perfect "cup of tea" (beer). Even 'crazy price' Maxim must be doing something right - after all, they're still in business....

DynamoBen
- 12th August 2006, 18:41
After working on this for some time I have come up with a routine that does what I need it to do. I may use Timer1 to keep track of how long the button is held in place of PAUSE, but it works as is.

There are three button states 0, 1, 2:
0=no action
1=short press/release
2=Held


Switch_Routine:
ButtonState=0
IF Switch=1 Then ButtonCnt=0

IF Switch=0 Then
While Switch=0
Pause 250
ButtonCnt=ButtonCnt+1

IF ButtonCnt=ButtonHeld Then
ButtonState=2
Return
EndIF
Wend

IF ButtonCnt<ButtonHeld Then ButtonState=1
EndIF
Return

vtt-info
- 15th January 2008, 11:42
Say hello to everyone,

where is the fault in this example:


ButtonPress var BYTE ' Button Counter Variable

LongPress con 20 ' Change this value for desired SET
' function trip-point in 50mS steps
' Currently set for 1 Second


MainLoop:
LCDOut $FE,1,"Go Press..."
ButtonLoop:
Gosub GetButton
If ButtonPress>0 then
If ButtonPress=1
LCDOut $FE,1,"Short Press"
else
LCDOut $FE,1,"Long Press"
endif
Pause 1000
Goto MainLoop
endif
Goto ButtonLoop

'
' Subroutine weighs-up users finger
' in multiples of 50mS
' Constant LONGPRESS determines boredom level
' -------------------------------------------
' on Exit...
' ButtonPress=0 - No Press
' ButtonPress=1 - Short Press
' ButtonPress=2 - Long Press
GetButton:
ButtonPress=0
While MyButton=0
If ButtonPress<255 then ButtonPress=ButtonPress+1
Pause 50 ' This is also our Debounce value
If ButtonPress=LongPress then LCDOut $FE,1
Wend
If ButtonPress>0 then
If ButtonPress=>LongPress then
ButtonPress=2
else
ButtonPress=1
endif
endif
Return

I have this Sample code compiled and get this error message:

ERROR Line 18: Bad expression or missing THEN, (Button_01.php)

See attachment

I am here new and am pleased about every help.

Konrad

Acetronics2
- 15th January 2008, 12:43
Hi, Konrad

I used such a "multi role" button simply by using the BUTTON Command in a loop...

the example is here,




'************************************************* ****************************
'Servotest 84 D'après Elektor
'************************************************* ****************************
'
'16F84A à 20 Mhz

' Barregraph 7 leds sur PortB
' résolution variable 2-6-20 µS
' Mémorisation réglage " moyen"

@ __config _HS_OSC & _WDT_ON & _CP_ON

DEFINE OSC 20 '
DEFINE BUTTON_PAUSE 18

Signal var PortA.0
Writeok var PortA.1 ' Indicateur mode : 0 = manuel 1 = Cycle
Up var PortA.2 ' Rotation à Droite
Down var PortA.3 ' Rotation à gauche
Prog var PortA.4 ' Bouton mémorisation

pos var Word
posn var Word

compte var Byte
dir var Byte
delay var Byte
N var Byte

PORTA = 0
PORTB = %00001000 'PortB.7 libre, Led centrale allumée.

TRISA = %00011100
TRISB = %00000000


READ 1, Posn.HighByte
READ 2, Posn.LowByte

IF posn = $FFFF OR posn < 750 OR posn > 2250 THEN posn = 1500
pos = posn

'************************************************* ****************************
mainloop:

Writeok = 0

delay = 0

button Up, 0, 255, 0, delay, 1, upbutton
button Down, 0, 255, 0, delay, 1, dwnbutton
button Prog, 0, 255, 0, delay, 1, Program

Gosub Outsig
PAUSE 18
compte = 0

Goto Mainloop


'************************************************* ****************************
upbutton:

IF Down = 0 THEN

Pos = posn
Goto Jump1

Endif

Compte = compte + 1

Select Case Compte

Case 255
Compte = Compte-1
N = 10

Case is > 50
N = 10

Case is > 15
N = 3

Case else
N = 1

End Select

pos = pos + 2*N

if pos > 2250 then pos = 2250

Jump1:

For delay = 1 to 9

Gosub Outsig
Pause 18

Next delay

Gosub Outsig

Goto mainloop


'************************************************* ****************************
dwnbutton:

IF Up = 0 THEN

Pos = posn
Goto Jump2

Endif

Compte = compte + 1

Select Case Compte

Case 255
Compte = Compte - 1
N = 10

Case is > 50
N = 10

Case is > 10
N = 3

Case else
N = 1

End Select

pos = pos - 2*N

if pos < 750 then pos = 750

Jump2:

For delay = 1 to 9

Gosub Outsig
Pause 18

Next delay

Gosub Outsig

Goto mainloop


'************************************************* ****************************
Program:

Compte = 0

Test:

IF Prog = 0 Then

compte = compte + 1
Gosub Outsig
Pause 18

IF Compte > 250 THEN Compte = 250: Goto Test
IF Compte >= 80 THEN WriteoK = Compte .4 : Goto Test
IF Compte >= 20 THEN WriteoK = Compte .2

Goto Test 'Attendre relâchement bouton ...

Endif

IF Compte > 250 OR Compte < 20 Then mainloop

IF Compte >= 80 Then

pos = 1500
Goto Save 'remise au Neutre

Endif

'Position "moyenne"


Save:

WRITE 1, Pos.HighByte ' 10ms
WRITE 2, Pos.LowByte ' 10ms

Posn = pos
Gosub Outsig

For delay = 1 to 25

WriteoK = 1
Gosub Outsig
Pause 18

Next Delay

Goto mainloop



'************************************************* ****************************
Outsig:

Select Case pos 'Allumage Bargraph

Case 750

PortB = %01100001

Case is <= posn - 635

PortB = %01000000

Case is <= posn - 519

PortB = %01100000

Case is <= posn - 404

PortB = %00100000

Case is <= posn - 288

PortB = %00110000

Case is <= Posn - 173

PortB = %00010000

Case is <= Posn - 58

PortB = %00011000

Case is <= Posn

PortB = %01001000

'************************************************* ****************************
Case posn ' Position centrée

PortB = %01001001
'************************************************* ****************************

Case is <= posn + 58

PortB = %00001001

Case is <= posn + 173

PortB = %00001100

Case is <= posn + 288

PortB = %00000100

Case is <= posn + 404

PortB = %00000110

Case is <= posn + 519

PortB = %00000010

Case is <= posn + 635

PortB = %00000011

Case is < posn + 750

PortB = %00000001

Case 2250

PortB = %01000011

END Select

Low Signal
Pulsout Signal, pos /2 'Envoi Signal servo

RETURN

END




The "important" sections have been Highlighted ...

Here, the more the pressing UP and DOWN buttons speed up the 'count speed' ... pressing "prog" permits to choose beetween options ...
Note WriteOk is a led that shows the delay increasing value when pushing the button ...

Alain

vtt-info
- 15th January 2008, 16:37
Hi, Alain,

thanks for the fast reaction and the Code sample.

I would like to build a "One Button Dimmer"

1. Short Press Button T1: Toggle LED1 on/off or off/on.

2. Long Press Button T1: Ramp the Light von LED1 up or Ramp the Light down depending on the one last "Long Press", Ramp direction toggle every "Long Press".

3. Before power off store the last Ramp value

See the schematic in the attachment

Every help is welcome,

Konrad

Acetronics2
- 16th January 2008, 09:25
Hi, Vtt

A look Here, may be ...

http://www.electronique-diffusion.fr/advanced_search_result.php?keywords=slb0587&x=2&y=8

...

some chips still on the market !!! ... and in my drawers ... LOL !

Alain

CuriousOne
- 23rd March 2020, 18:01
Due to my lack of knowledge, when facing same problem, I did the following - while user keeps button pressed, value of needed variable is being increased and value of waiting variable reset. As user releases the button, waiting variable is being increased, and after it reaches some value (say for 2 seconds), next chunk of code is required. I'd like to do the same with long press, but still can't figure how.

Any ideas to add long press detection to this code?



setuploop:
if but2=0 then
dlycnt=dlycnt+1 'increase debounce variable while button is pressed

pause 1
endif

if BUT2=1 and dlycnt>100 then 'if button pressed long enough
dlycnt=0
high buz 'enable buzzer pin
menuitem=menuitem+1
lcdout $fe,1, #menuitem, " pressed "
pause 5
low buz 'disable buzzer
endif
goto setuploop

mpgmike
- 24th March 2020, 22:45
IF Button = Pressed THEN
WHILE Button = Pressed
LOOP
ENDIF

CuriousOne
- 25th March 2020, 05:26
I did it in the different way:


setuploop:
if but2=0 then
dlycnt=dlycnt+1 'increase debounce variable while button is pressed
ticker=ticker+1
pause 1
endif
if ticker>1500 and BUT2=0 then gasvla 'if long pressed, then exit and (or) go to selector item
if BUT2=1 and dlycnt>100 then 'if short pressed, then do the rap
ticker=0
dlycnt=0
menuitem=menuitem+1 'this is incremental variable, substitute another next time you need it
lcdout $fe,$c0, " selection: " #menuitem," " 'debug just for case
pause 1
endif
goto setuploop

amgen
- 26th March 2020, 22:19
I did a setup to check for...... short press, then 2 second or 5 second then long press to enter program mode, for next for the timing, then go on to next check and goto's


FOR A1= 1 TO 5 '<.1 SECONDS FOR TIMER
PAUSE 3
GOSUB RDSW
if SWCH=0 then start
NEXT A1
HIGH 2
read 1,A4 :PAUSE 10: C1=60*A4:C2=C1

FOR A1 = 1 TO 100 '2 SECONDS FOR 8 HR
PAUSE 8
GOSUB RDSW
if SWCH=0 then TIMER
NEXT A1
C1=28800 '8 HRS
HIGH 5

FOR A1 = 1 TO 100 'CHECK FOR PROGRAM 5 SEC TOTAL
PAUSE 40
GOSUB RDSW
if SWCH=0 then TIMER
NEXT A1
LOW 2:GOTO PROGRAM

Ioannis
- 4th April 2020, 18:33
All the above methods block the program execution. If this is not a problem then it I guess ok.

But if the PIC must do other things, it is better to have a ticker in a timer interrupt routine and count up when a key is pressed. Periodically check the ticker for the required value and decide what to do.

That way, program does not stay in a closed loop until button release.

Ioannis