News:

;) This forum is the property of Proton software developers

Main Menu

abnormal behaviour of INKEY

Started by basiclover, Apr 09, 2022, 08:51 AM

Previous topic - Next topic

basiclover

wrote 2 simple codes for preliminary test of INKEY on PIC16F788A instead of PIC16F84 as shown in the manual
first code with keypad on PORT B.As expected my LCD displays bvar=16 when no key pressed
second code with keypad on PORT D with 10K pullup resistors as port D doesn't have interna pullups. Now the LCD displays bvar=1 instead of 16 when no key pressed
I suspect there is something going wrong with "Declare Keypad Port Port"
FIRST CODE:

''****************************************************************
'*  Name    : 16F877 Keypad test on port B.BAS                                      *
'*  Author  : basiclover                                        *
'*  Notice  : Copyright (c) 2022 [select VIEW...EDITOR OPTIONS] *
'*          : All Rights Reserved                               *
'*  Date    : 4/07/2022                                         *
'*  Version : 1                                                *
'*  Note    :                                                   *                     
'*          :                                                   *
'*                                                              *
'****************************************************************

;-------------------------------------------------------------------------------
;**** Added by Fuse Configurator ****
; Use the Fuse Configurator plug-in to change these settings

Device = 16F877A

Config FOSC_HS, WDTE_OFF, PWRTE_OFF, BOREN_ON, LVP_OFF, CPD_OFF, WRT_OFF, DEBUG_OFF, CP_OFF

;**** End of Fuse Configurator Settings ****
;-------------------------------------------------------------------------------
    Declare Xtal = 20                            ' Tell the compiler what speed the device will be operating at
    ' Setup the alphanumeric LCD on PORT D for DATA and PORT E for control
    'Declare LCD_Type = 0       'HITACHI HD44780 controller
    Declare LCD_Type = Alphanumeric
    Declare LCD_DTPin = PORTD.4  '4 pin config, data on 4 top pins(PortD4 to D7) of port D
    Declare LCD_RSPin = PORTE.0
    Declare LCD_ENPin = PORTE.1
    Declare LCD_Lines = 4
    Declare Float_Display_Type = Fast           ' Use the faster, more accurate, but larger, floating point display library routine
    '
'-------------------------------------------------------------------------------------
 
'read a 3x4 keypad
   
    Declare Keypad_Port PORTB 
   
'                                     RB4 RB5  RB6   as in manual example for Inkey function
'                             RB3 --  1   2    3
'                             RB2 --  4   5    6
'                             RB1 --  7   8    9
'                             RB0 --  *   0    #
                             
   
    Dim Num As Byte 
    Dim bvar As Byte
    Cls
   
    'While InKey=16: Wend
    bvar =InKey
    Num=2.43
    DelayMS 50
    'Num = LookUpL bvar,[49, 50, 51, 16,                ' \ my note:caract ASCII 49,50,51,16 = 1,2,3,DLE  (# =ASCII DLE)
    '                    52, 53, 54, 16,                ' |         caract ASCII 52,53,54,16 = 4,5,6,DLE
    '                   55, 56, 57, 16,                 ' |         caract ASCII 55,56,57,16 = 7,8,9,DLE
    '                    16, 48, 13, 16]                ' |         caract ASCII 16,48,13,16 = DLE,0,CR,DLE
    Print At 1,1,Dec,Num
    Print At 2,1,Dec ,bvar, "=bvar"
    Print At 3,1,Dec 31 'check disolay
    Print At 4,1,Dec 41  'check disolay


SECOND CODE (problematic one)
''****************************************************************
'*  Name    : 16F877 Keypad test on PORT D.BAS                  *
'*  Author  : basiclover                                        *
'*  Notice  : Copyright (c) 2022 [select VIEW...EDITOR OPTIONS] *
'*          : All Rights Reserved                               *
'*  Date    : 3/26/2022                                         *
'*  Version : 1                                                *
'*  Note    :                                                   *                     
'*          :                                                   *
'*                                                              *
'****************************************************************

;-------------------------------------------------------------------------------
;**** Added by Fuse Configurator ****
; Use the Fuse Configurator plug-in to change these settings

Device = 16F877A

Config FOSC_HS, WDTE_OFF, PWRTE_OFF, BOREN_ON, LVP_OFF, CPD_OFF, WRT_OFF, DEBUG_OFF, CP_OFF

;**** End of Fuse Configurator Settings ****
;-------------------------------------------------------------------------------
    Declare Xtal = 20                            ' Tell the compiler what speed the device will be operating at
    Declare Float_Display_Type = Fast           ' Use the faster, more accurate, but larger, floating point display library routine
'
' Setup the alphanumeric LCD
    Declare LCD_Type = 0       'HITACHI HD44780 controller
    Declare LCD_DTPin = PORTB.4  '4 pin config, data on 4 top pins(PortB4 to B7) of port B
    Declare LCD_RSPin = PORTB.3
    Declare LCD_ENPin = PORTB.2
    Declare LCD_Lines = 4
    Declare LCD_DataUs 75     'LCD time to wait beween data sent(microsec)for some older 16x2 44780 compatible displays (default = 50)
'-------------------------------------------------------------------------------------
 
'read a 3x4 keypad on PORT D (10K pullup resistors on each PORT D pin)
    PORTE.4=0  '0 = PORTD functions in general purpose I/O mode

    Declare Keypad_Port PORTD 
   
'                                     RD4 RD5  RD6   as in manual example for Inkey function
'                             RD3 --  1   2    3     but on Port D instead of Port B
'                             RD2 --  4   5    6     with 10K pullup resistors on all ports D
'                             RD1 --  7   8    9
'                             RD0 --  *   0    #
                             
   
    Dim Num As Byte 
    Dim bvar As Byte
    Cls
   
    'While InKey=16: Wend
    bvar =InKey
    DelayMS 50
    'Num = LookUpL bvar,[49, 50, 51, 16,                ' \ my note:caract ASCII 49,50,51,16 = 1,2,3,DLE  (# =ASCII DLE)
    '                    52, 53, 54, 16,                ' |         caract ASCII 52,53,54,16 = 4,5,6,DLE
    '                    55, 56, 57, 16,                ' |         caract ASCII 55,56,57,16 = 7,8,9,DLE
    '                    16, 48, 13, 16]                ' |         caract ASCII 16,48,13,16 = DLE,0,CR,DLE
    Print At 1,1,Dec,222 'check display
    Print At 2,1,Dec ,bvar, "=bvar"
    Print At 4,1,Dec 35 'check display

---------------------------------------------
Any help apreciated

basiclover


Must read 16F877 and not 15F788A
wrote 2 simple codes for preliminary test of INKEY on PIC16F788A instead of PIC16F84 as shown in the manual
first code with keypad on PORT B.As expected my LCD displays bvar=16 when no key pressed
second code with keypad on PORT D with 10K pullup resistors as port D doesn't have interna pullups. Now the LCD displays bvar=1 instead of 16 when no key pressed
I suspect there is something going wrong with "Declare Keypad Port Port"
FIRST CODE:

Code Select Expand
''****************************************************************
'*  Name    : 16F877 Keypad test on port B.BAS                                      *
'*  Author  : basiclover                                        *
'*  Notice  : Copyright (c) 2022 [select VIEW...EDITOR OPTIONS] *
'*          : All Rights Reserved                               *
'*  Date    : 4/07/2022                                         *
'*  Version : 1                                                *
'*  Note    :                                                   *                     
'*          :                                                   *
'*                                                              *
'****************************************************************

;-------------------------------------------------------------------------------
;**** Added by Fuse Configurator ****
; Use the Fuse Configurator plug-in to change these settings

Device = 16F877A

Config FOSC_HS, WDTE_OFF, PWRTE_OFF, BOREN_ON, LVP_OFF, CPD_OFF, WRT_OFF, DEBUG_OFF, CP_OFF

;**** End of Fuse Configurator Settings ****
;-------------------------------------------------------------------------------
    Declare Xtal = 20                            ' Tell the compiler what speed the device will be operating at
    ' Setup the alphanumeric LCD on PORT D for DATA and PORT E for control
    'Declare LCD_Type = 0       'HITACHI HD44780 controller
    Declare LCD_Type = Alphanumeric
    Declare LCD_DTPin = PORTD.4  '4 pin config, data on 4 top pins(PortD4 to D7) of port D
    Declare LCD_RSPin = PORTE.0
    Declare LCD_ENPin = PORTE.1
    Declare LCD_Lines = 4
    Declare Float_Display_Type = Fast           ' Use the faster, more accurate, but larger, floating point display library routine
    '
'-------------------------------------------------------------------------------------
 
'read a 3x4 keypad
   
    Declare Keypad_Port PORTB
   
'                                     RB4 RB5  RB6   as in manual example for Inkey function
'                             RB3 --  1   2    3
'                             RB2 --  4   5    6
'                             RB1 --  7   8    9
'                             RB0 --  *   0    #
                             
   
    Dim Num As Byte
    Dim bvar As Byte
    Cls
   
    'While InKey=16: Wend
    bvar =InKey
    Num=2.43
    DelayMS 50
    'Num = LookUpL bvar,[49, 50, 51, 16,                ' \ my note:caract ASCII 49,50,51,16 = 1,2,3,DLE  (# =ASCII DLE)
    '                    52, 53, 54, 16,                ' |         caract ASCII 52,53,54,16 = 4,5,6,DLE
    '                   55, 56, 57, 16,                 ' |         caract ASCII 55,56,57,16 = 7,8,9,DLE
    '                    16, 48, 13, 16]                ' |         caract ASCII 16,48,13,16 = DLE,0,CR,DLE
    Print At 1,1,Dec,Num
    Print At 2,1,Dec ,bvar, "=bvar"
    Print At 3,1,Dec 31 'check disolay
    Print At 4,1,Dec 41  'check disolay


SECOND CODE (problematic one)
Code Select Expand
''****************************************************************
'*  Name    : 16F877 Keypad test on PORT D.BAS                  *
'*  Author  : basiclover                                        *
'*  Notice  : Copyright (c) 2022 [select VIEW...EDITOR OPTIONS] *
'*          : All Rights Reserved                               *
'*  Date    : 3/26/2022                                         *
'*  Version : 1                                                *
'*  Note    :                                                   *                     
'*          :                                                   *
'*                                                              *
'****************************************************************

;-------------------------------------------------------------------------------
;**** Added by Fuse Configurator ****
; Use the Fuse Configurator plug-in to change these settings

Device = 16F877A

Config FOSC_HS, WDTE_OFF, PWRTE_OFF, BOREN_ON, LVP_OFF, CPD_OFF, WRT_OFF, DEBUG_OFF, CP_OFF

;**** End of Fuse Configurator Settings ****
;-------------------------------------------------------------------------------
    Declare Xtal = 20                            ' Tell the compiler what speed the device will be operating at
    Declare Float_Display_Type = Fast           ' Use the faster, more accurate, but larger, floating point display library routine
'
' Setup the alphanumeric LCD
    Declare LCD_Type = 0       'HITACHI HD44780 controller
    Declare LCD_DTPin = PORTB.4  '4 pin config, data on 4 top pins(PortB4 to B7) of port B
    Declare LCD_RSPin = PORTB.3
    Declare LCD_ENPin = PORTB.2
    Declare LCD_Lines = 4
    Declare LCD_DataUs 75     'LCD time to wait beween data sent(microsec)for some older 16x2 44780 compatible displays (default = 50)
'-------------------------------------------------------------------------------------
 
'read a 3x4 keypad on PORT D (10K pullup resistors on each PORT D pin)
    PORTE.4=0  '0 = PORTD functions in general purpose I/O mode

    Declare Keypad_Port PORTD
   
'                                     RD4 RD5  RD6   as in manual example for Inkey function
'                             RD3 --  1   2    3     but on Port D instead of Port B
'                             RD2 --  4   5    6     with 10K pullup resistors on all ports D
'                             RD1 --  7   8    9
'                             RD0 --  *   0    #
                             
   
    Dim Num As Byte
    Dim bvar As Byte
    Cls
   
    'While InKey=16: Wend
    bvar =InKey
    DelayMS 50
    'Num = LookUpL bvar,[49, 50, 51, 16,                ' \ my note:caract ASCII 49,50,51,16 = 1,2,3,DLE  (# =ASCII DLE)
    '                    52, 53, 54, 16,                ' |         caract ASCII 52,53,54,16 = 4,5,6,DLE
    '                    55, 56, 57, 16,                ' |         caract ASCII 55,56,57,16 = 7,8,9,DLE
    '                    16, 48, 13, 16]                ' |         caract ASCII 16,48,13,16 = DLE,0,CR,DLE
    Print At 1,1,Dec,222 'check display
    Print At 2,1,Dec ,bvar, "=bvar"
    Print At 4,1,Dec 35 'check display

---------------------------------------------
Any help apreciated

top204

#2
You must place pull-up resistors on all four of the pins used for the column lines of the keypad, otherwise the Inkey routine will see floating pins and sometimes exit the routine early with invalid values.

To test it, I created the simple demo program below, using PORTD for the keypad's pins:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Inkey demo using PORTD for the keypad.
' Make sure there are pull-up resistors on PORTD.4 to PORTD.7
' Otherwise, the keypad will fail to return a valid value because it will see floating pins.
'
' Written for the Positron8 compiler by Les Johnson
'
    Device = 16F877                             ' Tell the compiler what device is being compiled for
    Declare Xtal = 10                           ' Tell the compiler what speed the device will be operating at
'
' Setup USART1
'  
    Declare Hserial_Baud = 9600
    Declare HRSOut_Pin = PORTC.6
'
' Set the port to use for the keypad
'
    Declare Keypad_Port = PORTD
'
' Create some variables
'  
    Dim bKeyValue As Byte                       ' Holds the key pressed value
    Dim PrevKeyValue As Byte = 255              ' Holds the previous key press value
   
'-------------------------------------------------------------------
' Read a keypad and display the ASCII keypad characters on a serial terminal
'
Main:
    Do                                                          ' Create a loop
        bKeyValue = InKey                                       ' Read the keypad
        If bKeyValue <> 16 Then                                 ' Is the keypad value 16. i.e. No key pressed?
            bKeyValue = LookUpL bKeyValue, [16, "1", "2", "3",  ' \
                                            16, "4", "5", "6",  ' |
                                            16, "7", "8", "9",  ' | No. So convert the value into a keypad character
                                            16, "*", "0", "#"]  ' /               
            If bKeyValue <> PrevKeyValue Then                   ' Is the current key press the same as the previous key press?
                HRSOutLn "Key Pressed is ", bKeyValue           ' No. So display the key press character on the serial terminal
            EndIf          
        EndIf
        PrevKeyValue = bKeyValue                                ' Keep a copy of the previous key press value
        DelayMS 100                                             ' A delay for debouncing
    Loop                                                        ' Do it forever

I then ran the above program in a simulator to make sure everything was OK, and, as can be seen below, it is. :-) I will add to the Inkey section of the manuals, to show what is required if pins are used that have no internal pull-up resistors. However, all new devices have internal pull-up resistors on all pins, and most can be enabled/disabled individually.

KeyPad on PORTD.jpg

basiclover

I have put 10K pullups on colums and rows and also 470 ohm in series with rows as shown on the schematic in the manual.
maybe that is wrong

basiclover

Thanks for the reply Les. I will try that
But I'm completely lost in which order the rows and columns must be connected to the 7 pins of the port, because what you do here is completely different of the 16F84 schematic in the manual.
Inter alia D4 is not used and D7 is used while the manual states D7 is  for the fourth column of a 4x4 keypad
Can you more accurately specify the rules for connecting rows and columns

top204

With keypad schematics, there are always the Row and Column pins, and they are normally designated A onwards for the row and 1 onwards for the column. But these days, that has probably changed because there are no such thing as standards anymore. :-)

I'll create a new schematic for the manual based upon the more recent devices. Remember, I created the circuit diagram for Inkey in the manual back in about 2002, when there were only a few flash PIC microcontrollers. LOL

The pull-up resistors go on the Column pins of the microcontroller, and the feed resistors are there to stop any overloads if a keypad shorts etc... But they can be removed, or reduced in resistance. If it is a keypad that uses carbon for the contacts, instead of true switches, the 470 Ohm resistors may not be letting enough voltage through to register as a high.








top204

#6
The program below will allow you to see how the compiler's Inkey function works more clearly, so you can have a better understanding of it. It creates a procedure to scan a keypad in a similar manner to the compiler's Inkey function..

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Keypad scanning procedure demo using PORTD for the keypad's pins.
' Make sure there are pull-up resistors on PORTD.4 to PORTD.7
' Otherwise, the keypad will fail to return a valid value because it will see floating pins.
'
' Written for the Positron8 compiler by Les Johnson
'
    Device = 16F877                                 ' Tell the compiler what device is being compiled for
    Declare Xtal = 10                               ' Tell the compiler what speed the device will be operating at
'
' Setup USART1
'  
    Declare Hserial_Baud = 9600
    Declare HRSOut_Pin = PORTC.6
'
' Set the port to use for the keypad
'
$define Key_Port PORTD
'
' Create some variables
'  
    Dim bKeyValue As Byte                           ' Holds the key pressed value
    Dim PrevKeyValue As Byte = 255                  ' Holds the previous key press value
   
'-------------------------------------------------------------------
' Read a keypad and display the converted values on a serial terminal
'
Main:
    Do                                                          ' Create a loop
        bKeyValue = GetKey()                                    ' Read the keypad
        If bKeyValue <> 16 Then                                 ' Is the keypad value 16. i.e. No key pressed?
            bKeyValue = LookUpL bKeyValue, [16, "1", "2", "3",  ' \
                                            16, "4", "5", "6",  ' |
                                            16, "7", "8", "9",  ' | No. So convert the value into a keypad character
                                            16, "*", "0", "#"]  ' /               
            If bKeyValue <> PrevKeyValue Then                   ' Is the current key press the same as the previous key press?
                HRSOutLn "Key Pressed is ", bKeyValue           ' No. So display the key press character on the serial terminal
            EndIf          
        EndIf
        PrevKeyValue = bKeyValue                                ' Keep a copy of the previous key value
        DelayMS 50                                              ' A delay for simple debouncing
    Loop                                                        ' Do it forever

'-------------------------------------------------------------------
' Read a 4x4 keypad, in a similar manner as the compiler's Inkey function does
' Input     : The $define "Key_Port" holds the port to use for the keypad
' Output    : Returns a value for the key pressed, 16 if no key pressed
' Notes     : Requires pull-up resistors on pins 4 to 7 of the port
'
Proc GetKey(), Byte
    Dim tPressed As STATUSbits_C                ' Set to 1 if a relevant key is pressed
 
    PinOutput Key_Port.0                        ' \
    PinOutput Key_Port.1                        ' |
    PinOutput Key_Port.2                        ' | Make the row pins outputs
    PinOutput Key_Port.3                        ' /
    PinInput Key_Port.4                         ' \
    PinInput Key_Port.5                         ' | Make the column pins inputs
    PinInput Key_Port.6                         ' |
    PinInput Key_Port.7                         ' /
    Result = 0                                  ' Clear the result variable
   
    Key_Port = %00001110                        ' Pull pin PortX.0 low
    GoSub ScanKeys                              ' Scan the keypad for a button press
    If tPressed = 1 Then ExitProc               ' Exit the procedure if a button press was detected 
    Key_Port = %00001101                        ' Pull pin PortX.1 low
    GoSub ScanKeys                              ' Scan the keypad for a button press
    If tPressed = 1 Then ExitProc               ' Exit the procedure if a button press was detected  
    Key_Port = %00001011                        ' Pull pin PortX.2 low
    GoSub ScanKeys                              ' Scan the keypad for a button press
    If tPressed = 1 Then ExitProc               ' Exit the procedure if a button press was detected 
    Key_Port = %00000111                        ' Pull pin PortX.3 low, and fall through to "ScanKeys"
ScanKeys:
    Set tPressed                                ' Default to a button pressed
    If Key_Port.4 = 0 Then Return               ' Return if a button was pressed 
    Inc Result                                  ' Increment the return value
    If Key_Port.5 = 0 Then Return               ' Return if a button was pressed  
    Inc Result                                  ' Increment the return value 
    If Key_Port.6 = 0 Then Return               ' Return if a button was pressed
    Inc Result                                  ' Increment the return value
    If Key_Port.7 = 0 Then Return               ' Return if a button was pressed  
    Inc Result                                  ' Increment the return value   
    Clear tPressed                              ' If reached here, no button was pressed
EndProc

It works the same as the above demo listing, and transmits the keypad's character when pressed.