B4R Question 4 x 4 Keypad: Conversion of string to integer.

Mark Read

Well-Known Member
Licensed User
Longtime User
I am using a 4x4 Keypad to enter data on an Arduino Uno. The letters A to D represent commands and the numbers will be values. For example: Pressing "A" followed by up to six further numbers and then "#" should give me a string "123456" which I then need to convert to an integer and store.

Something is not correct as you can see from the log output but I cannot see my mistake. In this case the value 36 should be stored in "SpeedDown" but the log shows "##" ?????

B4X:
A
Speed down active ....
3
6
#
Speed down finished ...
Value: ##

B4X:
#Region Project Attributes
    #AutoFlushLogs: True
    #CheckArrayBounds: True
    #StackBufferSize: 300
#End Region


' planned screen
'
' (A) Speed Down: 20 mm/s
' (B) Hold Time:  10 mins
' (C) Speed Up:   40 mm/s
' (D) Run          (*) Reset

Sub Process_Globals
    Public Serial1 As Serial
    Private pad As Keypad
    Private KeyBuffer(6) As String
    Dim vKey As Int=0
    Private SpeedDown As Double=0
    Private Holdtime As Long=0
    Private Speedup As Double=0
    Private timer1 As Timer
    Private CommandActive As Int=0
    Dim bc As ByteConverter
End Sub

Private Sub AppStart
    Serial1.Initialize(115200)
    Log("AppStart")
    pad.Initialize("123A456B789C*0#D", Array As Byte(9, 8, 7, 6),  Array As Byte(5, 4, 3, 2), _
     "pad_KeyPressed")
    timer1.Initialize("timer1_Tick",1000)
End Sub


Sub timer1_Tick
 
End Sub

Sub Pad_KeyPressed (Key As String)
 
    Log(Key)
 
    If Key = "*" Then
        SpeedDown=0
        Holdtime=0
        Speedup=0
        'ResetDisplay
    Else if Key = "A" Then
        'Speed down
        If CommandActive>0 Then Return        ' a different command key is active
        CommandActive=1
        Log("Speed down active ....")
      
        vKey=0
    Else if Key = "B" Then
        'Hold time
        If CommandActive>0 Then Return
        CommandActive=2
        Log("Hold time active ....")
      
        vKey=0
    Else if Key = "C" Then
        'Speed up
        If CommandActive>0 Then Return
        CommandActive=3
        Log("Speed up active ....")
      
        vKey=0
    Else if Key = "D" Then
        'Run
        Log("Speed down: ", SpeedDown)
        Log("Hold time: ", Holdtime)
        Log("Speed up: ", Speedup)
      
    else if Key = "#" Then
        'Enter pressed
        Select Case CommandActive
            Case 1
                Log("Speed down finished ...")
                SpeedDown=TransferBuffer
                CommandActive=0
            Case 2
                Holdtime=TransferBuffer
                Log("Hold time not finished ...")
                CommandActive=0
            Case 3
                Speedup=TransferBuffer
                Log("Speed up not finished ...")
                CommandActive=0
              
        End Select
      
    else if vKey<6 Then 
        'put the key in the buffer.
        KeyBuffer(vKey)=Key
        vKey=vKey+1
    End If

End Sub

Sub TransferBuffer As Int
    Dim vv As String=JoinStrings(KeyBuffer)
 
    Dim v As Int=vv
    Log("Value: ",vv)
    Return v
End Sub
 

derez

Expert
Licensed User
Longtime User
In the if-then there is no place for key = a number, so it does not do anything when a number key is pressed.
Probably this
"else if vKey<6 Then "
should be
"else if Key<6 Then " but even with this it will not read the "6"
 
Upvote 0

Mark Read

Well-Known Member
Licensed User
Longtime User
"vKey" is used to store the number of digits. Up to 6 can be entered with index 0 to 5 and then stored in KeyBuffer(index).

At present I have no check for entering "000234" for example.
 
Upvote 0

Mark Read

Well-Known Member
Licensed User
Longtime User
This seems to work:

B4X:
#Region Project Attributes
    #AutoFlushLogs: True
    #CheckArrayBounds: True
    #StackBufferSize: 300
#End Region


' planned screen
'
' (A) Speed Down: 20 mm/s
' (B) Hold Time:  10 mins
' (C) Speed Up:   40 mm/s
' (D) Run          (*) Reset

Sub Process_Globals
    Dim Serial1 As Serial
    Dim pad As Keypad
    Dim KeyBuffer(6) As Byte
    Dim vKey As Int=0
    Dim SpeedDown As UInt=0
    Dim Holdtime As UInt=0
    Dim Speedup As UInt=0
    Dim timer1 As Timer
    Dim CommandActive As UInt=0
    Dim bc As ByteConverter
End Sub

Private Sub AppStart
    Serial1.Initialize(115200)
    Log("AppStart")
    pad.Initialize("123A456B789C*0#D", Array As Byte(9, 8, 7, 6),  Array As Byte(5, 4, 3, 2), _
     "pad_KeyPressed")
    timer1.Initialize("timer1_Tick",1000)
End Sub


Sub timer1_Tick
   
End Sub

Sub Pad_KeyPressed (Key As String)
    If Key = "*" Then
        SpeedDown=0
        Holdtime=0
        Speedup=0
        'ResetDisplay
    Else if Key = "A" Then
        'Speed down
        If CommandActive>0 Then Return        ' a different command key is active
        CommandActive=1
        Log("Speed down active ....")
       
        vKey=0
    Else if Key = "B" Then
        'Hold time
        If CommandActive>0 Then Return
        CommandActive=2
        Log("Hold time active ....")
       
        vKey=0
    Else if Key = "C" Then
        'Speed up
        If CommandActive>0 Then Return
        CommandActive=3
        Log("Speed up active ....")
       
        vKey=0
    Else if Key = "D" Then
        'Run
        Log("Speed down: ", SpeedDown, " mm/s")
        Log("Hold time: ", Holdtime)
        Log("Speed up: ", Speedup, " mm/s")
   
    else if Key = "#" Then
        'Enter pressed
        Select Case CommandActive
            Case 1
                'Log("Speed down finished ...")
                'Log("KeyBuffer: ", KeyBuffer)
                SpeedDown=bc.StringFromBytes(KeyBuffer)
                Log("Speed down: ", SpeedDown)
                CommandActive=0
            Case 2
                Holdtime=bc.StringFromBytes(KeyBuffer)
                Log("Hold time not finished ...")
                CommandActive=0
            Case 3
                Speedup=bc.StringFromBytes(KeyBuffer)
                Log("Speed up not finished ...")
                CommandActive=0
               
        End Select
       
    else if vKey<6 Then  
        'put the key in the buffer.
        KeyBuffer(vKey)= Asc(Key)
        Log("Key: ", vKey, " Value: ", KeyBuffer(vKey))
        vKey=vKey+1
    End If

End Sub

and the log after pressing A 3 6 5 9 9 # D:

B4X:
Speed down active ....
Key: 0 Value: 51
Key: 1 Value: 54
Key: 2 Value: 53
Key: 3 Value: 57
Key: 4 Value: 57
Speed down: 36599 mm/s
Hold time: 0
Speed up: 0 mm/s
 
Upvote 0

Mark Read

Well-Known Member
Licensed User
Longtime User
With the above code, it works as required but if the next command is used eg "B" then the array KeyBuffer is not cleared and only the first values are swaped - logical. Need to clear the buffer somehow.
 
Upvote 0

Mark Read

Well-Known Member
Licensed User
Longtime User
This is my final effort and works as required:

B4X:
#Region Project Attributes
    #AutoFlushLogs: True
    #CheckArrayBounds: True
    #StackBufferSize: 300
#End Region


' planned screen
'
' (A) Speed Down: 20 mm/s
' (B) Hold Time:  10 mins
' (C) Speed Up:   40 mm/s
' (D) Run          (*) Reset

Sub Process_Globals
    Dim Serial1 As Serial
    Dim pad As Keypad
    Dim KeyBuffer(6) As Byte
    Dim vKey As Int=0
    Dim SpeedDown As Long=0
    Dim Holdtime As Long=0
    Dim Speedup As Long=0
    Dim timer1 As Timer
    Dim CommandActive As UInt=0
    Dim bc As ByteConverter
End Sub

Private Sub AppStart
    Serial1.Initialize(115200)
    Log("AppStart")
    pad.Initialize("123A456B789C*0#D", Array As Byte(9, 8, 7, 6),  Array As Byte(5, 4, 3, 2), _
     "pad_KeyPressed")
    timer1.Initialize("timer1_Tick",1000)
End Sub


Sub timer1_Tick
    
End Sub

Sub Pad_KeyPressed (Key As String)
    If Key = "*" Then
        SpeedDown=0
        Holdtime=0
        Speedup=0
        'ResetDisplay
    Else if Key = "A" Then
        'Speed down
        If CommandActive>0 Then Return        ' a different command key is active
        CommandActive=1
        Log("Speed down active ....")
        
        vKey=0
    Else if Key = "B" Then
        'Hold time
        If CommandActive>0 Then Return
        CommandActive=2
        Log("Hold time active ....")
        
        vKey=0
    Else if Key = "C" Then
        'Speed up
        If CommandActive>0 Then Return
        CommandActive=3
        Log("Speed up active ....")
        
        vKey=0
    Else if Key = "D" Then
        'Run
        Log(CRLF, "Show all values")
        Log("Speed down: ", SpeedDown, " mm/s")
        Log("Hold time: ", Holdtime)
        Log("Speed up: ", Speedup, " mm/s", CRLF)
    
    else if Key = "#" Then
        'Enter pressed
        Select Case CommandActive
            Case 1
                Log("Speed down changed")
                SpeedDown=bc.StringFromBytes(KeyBuffer)
                Log("Speed down is now: ", SpeedDown, " mm/s")
                CommandActive=0
                ClearKeyBuffer
            Case 2
                Holdtime=bc.StringFromBytes(KeyBuffer)
                Log("Hold time changed")
                CommandActive=0
                ClearKeyBuffer
            Case 3
                Speedup=bc.StringFromBytes(KeyBuffer)
                Log("Speed up changed")
                CommandActive=0
                ClearKeyBuffer
        End Select
        
    else if vKey<6 Then   
        'put the key in the buffer.
        KeyBuffer(vKey)= Asc(Key)
        Log("Key: ", vKey, " Value: ", Key)
        vKey=vKey+1
    End If

End Sub

Sub ClearKeyBuffer
    Log("KeyBuffer before clear: ", KeyBuffer)
    For i=0 To KeyBuffer.Length-1
        KeyBuffer(i)=Asc(" ")       
    Next
    Log("KeyBuffer after clear: ", KeyBuffer)
End Sub
 
Upvote 0

Mark Read

Well-Known Member
Licensed User
Longtime User
@tigrot: thanks for your input but I have programmed the system so that if a "command" is being executed, pressing a new command does nothing. The current command must be terminated but can be repeated if required. If the wrong data is entered, the data can be stopped with "#" and the command repeated. If I was to do it your way, I think the code would be more complicated.

This is just a small building block in a much larger process. I have never worked with the keypad before. In the actual process, all values are 0 before starting. That is required by the client to ensure that run cannot be selected with old values.

I have also changed the thread title accordingly.
 
Upvote 0
Top