News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

Button Workspace?

Started by Yves, Jun 20, 2023, 10:06 AM

Previous topic - Next topic

Yves

Hello all,
I never use the button before but for one project I will find it useful. Reading the manual, there is something I didn't understood well, it is the "Workspace" variable. Is someone can tell me in some simple terms what is it  for? 

Button Pin, DownState, Delay, Rate, Workspace, TargetState, Label

Regards,

Yves
Yves

joesaliba

Yves,

As I see it, it is something that button use in it's internal timing for debounce or autorepeat. The user has nothing to do with this. I think that Les wrote the button software like that so the user will be in charge of all variables used.

From the manual: -

The Workspace variable is used by Button to
keep track of how many cycles have occurred since the pin switched to TargetState or
since the last auto-repeat.

Wimax

I add :"It must be cleared to 0 before being used by Button for the first time and should not be adjusted outside of the Button command." ;)

top204

The Button command is a remnant of the BASIC Stamp II syntax that the compiler originally used, and it can be useful. However, with the addition of procedures, more flexibility can be added to a program. The work variable is what the Button command uses between calls to remember its states, so it could not be a compiler system variable because they get altered all the time.

An example of the flexability that procedures bring is the code listing below that shows a good method of detecting a single button press and not blocking the program's flow. I designed it especially to show the practicalities of Static  variables and it works well. It keeps a record of the button pin's condition as a bit within a large variable type, so it can hold 32 button states that must initially have a default value of 0 (no buttons pressed). This allows multiple button operations to be detected, and still detect a single press/release on each of them. In order to make the storage variable a local type, but not have it being loaded with zero everytime the procedure is called, the variable is made a Static  type and loaded with 0:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' A simple button press procedure that detects a single button press
' and does not detect it again until the button is released and pressed again
'
' No blocking is performed within the program's flow while waiting for button modes
'
' Written for the Positron compilers by Les Johnson
'
    Device = 18F25K20
    Declare Xtal = 64
'
' Setup USART1
'
    Declare Hserial_Baud = 9600
    Declare HRSOut1_Pin = PORTC.6

$define True 1
$define False 0

'----------------------------------------------------------------
' The main program starts here
' Transmits to a serial terminal when a button is pressed
' But does not continuously transmit while the button is pressed
'
Main:
    Do                                                  ' Create a loop
        If Button_Get(Pin_A1) = True Then               ' Has the button connected to RA1 been activated?
            HRSOutLn "Button on RA1 Pressed"            ' Yes. So transmit a message to the serial terminal

        ElseIf Button_Get(Pin_A2) = True Then           ' Has the button connected to RA2 been activated?
            HRSOutLn "Button on RA2 Pressed"            ' Yes. So transmit a message to the serial terminal

        ElseIf Button_Get(Pin_A3) = True Then           ' Has the button connected to RA3 been activated?
            HRSOutLn "Button on RA3 Pressed"            ' Yes. So transmit a message to the serial terminal

        EndIf
    Loop                                                ' Do it forever

'----------------------------------------------------------------
' Detect a button press
' Input     : pButton holds the pin number that the button is attached too (0 to 31)
' Output    : Returns 1 if a button press is detected
' Notes     : Once the button has been detected and a result returned,
'             it will not detect the button again until it has been released
'           : The bits within the variable "dStateBits" hold the previous states of the pins
'           : For active low button presses with a pull-up resistor
'
Proc Button_Get(pButton As Pin), Bit
    Symbol cPressed = 0                                 ' The value for a button pressed
    Symbol cNotPressed = 1                              ' The value for a button not pressed
Static Dim dStateBits As Dword = 0                      ' Create, and reset, a static variable to hold the states of 32 pins

    PinInput pButton                                    ' Set the button's pin as an input (just in case)
    Result = 0                                          ' Default to a false result (no button pressed)

    If GetBit(dStateBits, pButton) = 0 Then             ' Has the button already been pressed?
        If GetPin(pButton) = cPressed Then              ' No. So is the button pressed?
            Result = 1                                  ' Yes. So return a true result
        EndIf
        LoadBit dStateBits, pButton, Result             ' Store the button's previous state
    Else                                                ' Otherwise... The button has not been previously pressed
        If GetPin(pButton) = cNotPressed Then           ' So... Is the button pressed?
            ClearBit(dStateBits, pButton)               ' No. So reset the previous button state
        EndIf
    EndIf
EndProc

'-------------------------------------------------------------
' Setup the fuses on a PIC18F25K20 device, for the 4xPLL with an external crystal
'
Config_Start
    FOSC = HSPLL        ' HS oscillator, PLL enabled and under software control
    Debug = Off         ' Background debugger disabled' RB6 and RB7 configured as general purpose I/O pins
    XINST = Off         ' Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
    STVREN = Off        ' Reset on stack overflow/underflow disabled
    WDTEN = Off         ' WDT disabled (control is placed on SWDTEN bit)
    FCMEN = Off         ' Fail-Safe Clock Monitor disabled
    IESO = Off          ' Two-Speed Start-up disabled
    WDTPS = 128         ' Watchdog is 1:128
    BOREN = Off         ' Brown-out Reset disabled in hardware and software
    BORV = 18           ' VBOR set to 1.8 V nominal
    MCLRE = On          ' MCLR pin enabled, RE3 input pin disabled
    HFOFST = Off        ' The system clock is held Off until the HF-INTOSC is stable.
    LPT1OSC = Off       ' T1 operates in standard power mode
    PBADEN = Off        ' PORTB<4:0> pins are configured as digital I/O on Reset
    CCP2MX = PORTC      ' CCP2 input/output is multiplexed with RC1
    LVP = Off           ' Single-Supply ICSP disabled
    Cp0 = Off           ' Block 0 (000800-001FFFh) not code-protected
    CP1 = Off           ' Block 1 (002000-003FFFh) not code-protected
    CPB = Off           ' Boot block (000000-0007FFh) not code-protected
    CPD = Off           ' Data eeprom not code-protected
    WRT0 = Off          ' Block 0 (000800-001FFFh) not write-protected
    WRT1 = Off          ' Block 1 (002000-003FFFh) not write-protected
    WRTB = Off          ' Boot block (000000-0007FFh) not write-protected
    WRTC = Off          ' Configuration registers (300000-3000FFh) not write-protected
    WRTD = Off          ' Data eeprom not write-protected
    EBTR0 = Off         ' Block 0 (000800-001FFFh) not protected from table reads executed in other blocks
    EBTR1 = Off         ' Block 1 (002000-003FFFh) not protected from table reads executed in other blocks
    EBTRB = Off         ' Boot block (000000-0007FFh) not protected from table reads executed in other blocks
Config_End

Notice, within the "Button_Get" procedure, the Static  variable "dStateBits" is loaded with 0? But that zero will not be loaded into the variable at that position, it will be loaded into it before the main program starts, so it is given a default value. This can easily be seen in the assembler code, because I have commented its section for clarity to the users:

;---------------------------------------------
; START OF THE USER'S PROGRAM CODE
;---------------------------------------------
; STATIC VARIABLE ASSIGNMENTS
    clrf Button_GetdStateBitsHHH,0
    clrf Button_GetdStateBitsHH,0
    clrf Button_GetdStateBitsH,0
    clrf Button_GetdStateBits,0

The program above will not keep transmitting while a button is pressed, it will transmit once. Then once the button is released, it will transmit again if a button is pressed, but not block any program flow while waiting for button movements. :-) It may need some small DelayMs commands in the procedure for simple debouncing, but I found it worked well without them.

RGV250

Hi Les,
Thanks for this, it was something on my "will do sometime" list.
I have a couple of questions, could you explain how the compiler allocates the statebit to each pin as I cannot figure it out. Also, is it possible to invert it so that the output is on for one cycle if the pin goes from high to low. I don't want you to do it, I need something to do myself :-)

Regards,
Bob