News:

;) This forum is the property of Proton software developers

Main Menu

Altering a Large Integer Value on an LCD with only Three Buttons

Started by top204, Jun 25, 2022, 08:29 PM

Previous topic - Next topic

top204

Here is a page I have just created on my google web site that may be useful to some users. The demo program's procedure is for inside a menu system that uses 3 buttons. i.e Left, Select and Right.

It allows very large integer values to be altered without having to increment or decrement 10s of thousands of values, by moving up the value displayed on an LCD and altering the individual digits of it. The digit being altered flashes to show the menu user what is happening.

Altering a Large Integer Value on an LCD with only Three Buttons


shantanu@india

This is going to be handy Les. I use a time trigger i. e initially the value increments/decrements by one.... if the button is kept pressed for 10 seconds then it increments/decrements by 10 and in case it is kept pressed for 15 or more seconds then by 100. I adapted this method from the operation console of VFD's.
Can you upgrade your code to enter alphanumeric password characters where the ASCII character appears for an instant and then is hidden by a '*'
Regards
Shantanu

top204

I once made a mechanism to increment by magnitudes of 10 if the button is pressed for longer, but when a value in the 1000000s needs changing, it can be very frustrating and time consuming. :-) This is why I created the digit by digit value manipulation procedure.

Using alphanumeric values instead of digits would be quite straightforward to change, because the digits of the value are held in an array. So where the  code increments values 0 to 9, and decrements 9 to 0, it would increment "A" to "Z" and decrement "Z" to "A". The LCD is only used to display the values and has nothing to do with their manipulation.

The digit flash mechanism would also be very easy to change because it uses a bit flag to flash the digit when loop iterations reach a particular value, so it would not need toggling, so when the character is altered, it will trigger it to be displayed, then on the press of the Select button it will be replaced by a "*" character.



top204

#3
In order to show how straightforward it was to make the procedure alter a text string instead of a value, I created the demo program below that has the Text_Adjust procedure in it:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Text String alteration with only 3 buttons: Left, Right and Select
'
' The Select button moves along the text displayed on the LCD, character by character
' The Left button decrements the character
' The Right button increments the character
' When the Select button is pressed on the last character, the text will be fully altered
'
' Written by Les Johnson for the Positron8 compiler versions 4.0.1.9 and over.
'
    Device = 18F25K20                                              ' Tell the compiler what device to compile for
    Declare Xtal = 64                                              ' Tell the compiler what frequency the device will be operating at
'
' Setup the Alphanumeric LCD
'
    Declare LCD_DTPin     = PORTA.0
    Declare LCD_RSPin     = PORTA.4
    Declare LCD_ENPin     = PORTA.5
    Declare LCD_Interface = 4
    Declare LCD_Lines     = 2
    Declare LCD_Type      = Alphanumeric
    Declare LCD_CommandUs = 2000
    Declare LCD_DataUs    = 50
'
' Define the button pins
'
$define Left_Button_Pin   PORTB.0                                   ' The Port.Pin used for the Left button
$define Right_Button_Pin  PORTB.1                                   ' The Port.Pin used for the Right button
$define Select_Button_Pin PORTB.2                                   ' The Port.Pin used for the Select button
'
' Values for button presses
'
    Symbol cNoButton_Pressed     = 0                                ' No button is pressed
    Symbol cLeftButton_Pressed   = 1                                ' The Left button is pressed
    Symbol cRightButton_Pressed  = 2                                ' The Right button is pressed
    Symbol cSelectButton_Pressed = 3                                ' The Select button is pressed
'
' Create a variable for the demo
'
    Dim MyText As String * 16                                       ' Holds the text that has been altered
   
'--------------------------------------------------------------------
' The main program starts here
'
Main:
    DelayMS 100                                                     ' Give the LCD time to settle
    Cls                                                             ' Clear the LCD's display
    MyText = Text_Adjust(1, "PASSWORD")                             ' Adjust the text sent, character by character from left to right
    Print At 2, 1, MyText                                           ' Display the text on the LCD, because the text has been altered

'--------------------------------------------------------------------
' Adjust a sequence of letters held in pText, character by character from left to right
' The letters displayed will be "*" characters until the letter being altered is chosen
' Using Left, Right and Select buttons
' Input     : pXpos holds the X position on line 1 of the LCD, where the characters will be displayed
'           : pText holds the text to alter. Maximum 16 characters
' Output    : Returns the altered text
' Notes     : The character that is being altered will flash and the Select button will move to the next character in the text
'           : When the Select button is pressed on the last character, the altered text will be returned
'           : Does not support spaces in pText, only upper-case letters
'
Proc Text_Adjust(pXpos As Byte, pText As String * 16), pText  
    Dim tCharFlash   As Bit                                         ' Set to 1 if a space is to be placed as the character, to flash it
    Dim bFlashCount  As Byte                                        ' Holds a loop iterations counter to flash a character  
    Dim bCharPos     As Byte                                        ' Holds the X position of the character that is being altered in the value   
    Dim bCharAltVal  As Byte                                        ' Holds the value of the character to be altered within the main value
    Dim bTextLen     As Byte                                        ' Holds the length of the text held in "pText"
    Dim bElements    As Byte                                        ' Used for loops
    Dim sChars       As String * 16 Heap                            ' Holds the individual characters of the text to alter
   
    bTextLen = Len(pText)                                           ' Find the length of String "pText"
    pText = ToUpper(pText)                                          ' Make the letters in "pText" all Upper-Case
   
    Print At 1, pXpos, pText                                        ' Display the actual text on the LCD
    DelayMS 1000                                                    ' Wait for 1 second before masking it with "*" characters and allowing to it be changed
   
    bCharAltVal = pText[0]                                          ' Load the alterable character with element 0 of "pText"
    bCharPos = 0                                                    ' Start at character 0 of the text to alter (Left Hand Character)
    bFlashCount = 0                                                 ' Reset the flash iterations counter
    tCharFlash = 0                                                  ' Start with the character displayed and not the flashing space character
    GoSub hDisplayText                                              ' Display the text on line 1 of the LCD
    Do                                                              ' Create a loop to alter the text character by character
        Select Buttons_Get()                                        ' Compare the button pressed value
            Case cLeftButton_Pressed                                ' Is the left button pressed?
                tCharFlash = 0                                      ' Yes. So make it so the character is displayed first, before the space character for the flash
                bFlashCount = 0                                     ' Reset the character flash iterations counter
                Dec bCharAltVal                                     ' Decrement the chosen character's value
                If bCharAltVal < "A" Then bCharAltVal = "Z"         ' Make sure the character does not go below "A" or above "Z"
                pText[bCharPos] = bCharAltVal                       ' Transfer the character being altered into the appropriate character of the text
               
            Case cRightButton_Pressed                               ' Is the right button pressed?
                tCharFlash = 0                                      ' Yes. So make it so the character is displayed first, before the space character for the flash
                bFlashCount = 0                                     ' Reset the character flash iterations counter
                Inc bCharAltVal                                     ' Increment the chosen character's value
                If bCharAltVal > "Z" Then bCharAltVal = "A"         ' Make sure the character does not go above "Z" or below "A"
                pText[bCharPos] = bCharAltVal                       ' Transfer the character being altered into the appropriate character of the text
                   
            Case cSelectButton_Pressed                              ' Is the select button pressed?
                tCharFlash = 0                                      ' Yes. So make it so the character is displayed first, before the space for the flash
                bFlashCount = 0                                     ' Reset the character flash iterations counter
                Inc bCharPos                                        ' Increment the character to be altered's position
                If bCharPos >= bTextLen Then                        ' Is the character position beyond the amount of characters?
                    Break                                           ' Yes. So exit the loop
                EndIf
                bCharAltVal = pText[bCharPos]                       ' Transfer the element of "pText" that holds the character being altered
        EndSelect
        '
        ' A loop iterations counter to flash the character that is being altered
        '
        Inc bFlashCount                                             ' Increment the loop iterations counter
        If bFlashCount > 50 Then                                    ' Has it gone over its limit?
            bFlashCount = 0                                         ' Yes. So reset it
            Toggle tCharFlash                                       ' Toggle the bit flag to flash the character being altered
        EndIf
        GoSub hDisplayText                                          ' Display the text on line 1 of the LCD
        DelayMS 10                                                  ' A small delay to flash the character and keep "bFlashCount" down to an 8-bit variable
    Loop
'
' Helper subroutine to display the text on line 1 of the LCD
'
hDisplayText:
    For bElements = Bound(sChars) DownTo 0                          ' \
        sChars[bElements] = "*"                                     ' | Fill the String "cChars" with "*" characters
    Next                                                            ' /
    If tCharFlash = 1 Then                                          ' Is the character flash flag set?
        sChars[bCharPos] = " "                                      ' Yes. So place a space in the text's flashing character
    Else                                                            ' Otherwise...
        sChars[bCharPos] = pText[bCharPos]                          ' Place the letter in the text's flashing character
    EndIf
    Cursor 1, pXpos                                                 ' Position the LCD's cursor
    For bElements =  0 UpTo bTextLen - 1                            ' \
        Print sChars[bElements]                                     ' | Display the text held in String "sChars" on the LCD
    Next                                                            ' /
EndProc

'--------------------------------------------------------------------
' Detect a button press and return what button was pressed
' Input     : None
' Output    : Returns a value for a particular button pressed:
'               0 = No button, 1 = Left button, 2 = Right button, 3 = Select button
' Notes     : Uses the micrcontroller's internal pull-up resistors for the button pins
'
Proc Buttons_Get(), Byte
    PinMode(Left_Button_Pin, Input_PullUp)                          ' Make sure the left button's pin is an input with an internal pull-up resistor
    PinMode(Right_Button_Pin, Input_PullUp)                         ' Make sure the right button's pin is an input with an internal pull-up resistor
    PinMode(Select_Button_Pin, Input_PullUp)                        ' Make sure the select button's pin is an input with an internal pull-up resistor

    Result = cNoButton_Pressed                                      ' Default to a return of no button pressed
    If Button_SingleGet(Left_Button_Pin) = 1 Then                   ' Is the Left button pressed?
        Result = cLeftButton_Pressed                                ' Yes. So return a value for the button pressed

    ElseIf Button_SingleGet(Right_Button_Pin) = 1 Then              ' Is the Right button pressed?
        Result = cRightButton_Pressed                               ' Yes. So return a value for the button pressed

    ElseIf Button_SingleGet(Select_Button_Pin) = 1 Then             ' Is the Select button pressed?
        Result = cSelectButton_Pressed                              ' Yes. So return a value for the button pressed
    EndIf
EndProc

'--------------------------------------------------------------------
' Detect a single button press
' Input     : pButton holds the Port.Pin that the button is attached to
' 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 static variable "lStateBits" hold the previous states of the pins
'           : For active low button presses with a pull-up resistor
'
Proc Button_SingleGet(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 lStateBits As Long = 0                                   ' Create, and reset, a static variable to hold the states of 24 pins

    Result = 0                                                      ' Default to a false result
    If GetBit(lStateBits, 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(lStateBits, 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?
            LoadBit(lStateBits, pButton, 0)                         ' 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

Below is a screenshot of the above program working within a simulator. And a video of it working can be found on youtube here:
Positron8 - Text_Change_With_3_Buttons Video Demo

The source code and simulator file can be downloaded from here:
Positron8 - Text_Change_With_3_Buttons Source

Text_Alter_With_Three_Buttons.jpg





shantanu@india

This is absolutely great Les!!
Shall definitely incorporate in my upcoming projects.
Regards
Shantanu

keytapper

I made mine some time earlier.
The principle is similar. The cursor will move over the digit to be altered, then a button will set the confirmation, whilst the other two may cycle the value. Even one button can do but it will only loop over the end to zero.
So just opt for the number of key can be done with one or more button, depending how the function of one button is interpreted.
So, that project works for 7SD or LCD. Clearly is not the Mr Les class  :D
Ignorance comes with a cost

top204

That's a nice article in your link keytapper, and the videos help a lot to show what the code and circuit do.


keytapper

Quote from: top204 on Jun 28, 2022, 07:19 PMand the videos help a lot to show what the code and circuit do.
I'm sorry that the video quality is very poor. I need a deeper experience.
Ignorance comes with a cost