News:

;) This forum is the property of Proton software developers

Main Menu

Inkey

Started by Dolci, Jul 01, 2025, 07:50 AM

Previous topic - Next topic

Dolci

Is there a way to re-assign port in INKEY command . I have a free port RD0 to RD3 and RE0 to RE2 on existing circuit. I want to use 3x4 matrix keypad. Any help is appreciated.

Dolci

RGV250

Hi,
Looking at the manual it has to be continuous on one port. Have you considered writing your own procedure as you could then do as you require. I might have some code hidden away I will post if i find it.

Bob

RGV250

#2
Hi,
Not Positron but should give you some idea.
https://circuitdigest.com/microcontroller-projects/4x4-keypad-interfacing-with-pic16f877a

Also look at Keypad in the samples folder, uses one port but may be possible to alter.

Bob

Gamboa

Long live for you

RGV250

Hi Gamboa,
That example (good as it is) still uses Inkey and on one port. Dolci requires to be able to use a different port for rows and columns.

Bob

Pepe

#5
Simulation in Proteus and modified Les code for RD0 to RD3 and RE0 to RE2

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

Device = 16F877A

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

'**** End of Fuse Configurator Settings ****
'-------------------------------------------------------------------------------

Declare Xtal = 10
Declare Watchdog off
Declare Optimiser_Level = 0
Declare Bootloader off
Declare Float_Display_Type = Fast
Declare Dead_Code_Remove = 1        ' Remove dead code
Declare Reminders Off
Declare Hints Off
Declare Create_Coff On



    Declare Hserial_Baud = 9600
    Declare HRSOut_Pin = PORTC.6
'
' Set the port to use for the keypad
'
$define Column PORTE
$define row PORTD
'
' Create some variables

    Dim bKeyValue As Byte                           ' Holds the key pressed value
    Dim PrevKeyValue As Byte = 255                  ' Holds the previous key press value
   
    PinOutput row.0                             ' \
    PinOutput row.1                             ' | Make the row pins outputs
    PinOutput row.2                             ' |
    PinOutput row.3                             ' /

    PinInput Column.0                           ' \
    PinInput Column.1                           ' | Make the column pins inputs
    PinInput Column.2                           ' / 
'-------------------------------------------------------------------
' Read a keypad and display the converted values on a serial terminal
'
Main:
    Do                                                          ' Create a loop
        bKeyValue = GetKey()                                    ' Read the keypad
        If bKeyValue <> 12 Then                                 ' Is the keypad value 16. i.e. No key pressed?
            bKeyValue = LookUpL bKeyValue, [ "1", "2", "3",  ' \
                                             "4", "5", "6",  ' |
                                             "7", "8", "9",  ' | No. So convert the value into a keypad character
                                             "*", "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 4x3 keypad, in a similar manner as the compiler's Inkey function does
' Input     : The $define "row" $define "column" holds the ports 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 0 to 2 of the port
'
Proc GetKey(), Byte
    Dim tPressed As STATUSbits_C                ' Set to 1 if a relevant key is pressed
   
    row.1 = 1
    row.2 = 1
    row.3 = 1
   
    Result = 0                                  ' Clear the result variable
   
    row.0 = 0                                   ' 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
    row.0 = 1                               
    row.1 = 0                                   ' 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                                
    row.1 = 1                               
    row.2 = 0                                   ' 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                               
    row.2 = 1
    row.3 = 0                                   ' Pull pin PortX.3 low and fall through to "ScanKeys"
ScanKeys:
    Set tPressed                                ' Default to a button pressed
    If Column.0 = 0 Then Return                 ' Return if a button was pressed 
    Inc Result                                  ' Increment the return value
    If Column.1 = 0 Then Return                 ' Return if a button was pressed
    Inc Result                                  ' Increment the return value
    If Column.2 = 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


top204

#6
Nice coding Pepe.

The Inkey command dates back to around 2002/2003, when I was first writing the compiler, and was a simple mechanism I wrote, to help a user scan a keypad, and if it was used in a project, the user would choose the port for it. It was normally on PORTB, because this was the only port that had the ability to enable internal pull-up resistors on it.

However, since adding procedures to the 8-bit compiler, a lot of the compiler's built-in, generic, functions are no longer required, and more refined procedures can be created to perform a task better, if required.

To see what I mean... Below is a code listing I have just created, based on a procedure I wrote a few years ago for the forum, that scans a 4x4 keypad and returns a value for the key pressed. However, it uses a mechanism that will enable any port or pin to be used for the keypad's column and row pins:

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Demonstrate a procedure to read a 4x4 KeyPad connected to different Ports and Pins
'
' Written by Les Johnson for the Positron8 BASIC compiler.
' https://sites.google.com/view/rosetta-tech/home
'
    Device = 18F26K22                                           ' Tell the compiler what device to compile for
    Declare Xtal = 16                                           ' Tell the compiler what frequency the device is operating at (in MHz)
    Declare Auto_Heap_Strings = On                              ' Make all Strings created in high RAM, above standard variables
    Declare Auto_Variable_Bank_Cross = On                       ' Make sure multi-byte variables stay within a single RAM bank
'
' Setup USART1
'
    Declare HSerial1_Baud = 9600
    Declare HRsout1_Pin = PORTC.6
'
' Setup the port and pins to use for the Keypad reading procedure
'
$define Keypad_Row1_Pin PORTB.4                                 ' The keypad's Row 1 pin
$define Keypad_Row2_Pin PORTB.5                                 ' The keypad's Row 2 pin
$define Keypad_Row3_Pin PORTB.6                                 ' The keypad's Row 3 pin
$define Keypad_Row4_Pin PORTB.7                                 ' The keypad's Row 4 pin

$define Keypad_Col1_Pin PORTA.0                                 ' The keypad's Column 1 pin
$define Keypad_Col2_Pin PORTA.1                                 ' The keypad's Column 2 pin
$define Keypad_Col3_Pin PORTA.2                                 ' The keypad's Column 3 pin
$define Keypad_Col4_Pin PORTA.3                                 ' The keypad's Column 4 pin
'
' Create a variable for the demo
'
    Dim bKeyValue As Byte                                       ' Holds the value read from the keypad

'------------------------------------------------------------------------
' The main program starts here
' Scan a 4x4 KeyPad and transmit the values received from key presses to a serial terminal
'
    Do                                                          ' Create a loop
        bKeyValue = GetKey()                                    ' Read the KeyPad
        If bKeyValue <> 16 Then                                 ' Is it the value 16 (no key pressed)?
            HRsOutLn "Key Value is ", Dec bKeyValue             ' No. So transmit the value of the key pressed
        EndIf
        DelayMS 255                                             ' A small delay between keypad scans
    Loop                                                        ' Do it forever

'------------------------------------------------------------------------
' Scan a 16-button KeyPad
' Input     : None
' Output    : Returns with the value of the keypress. If no key pressed, a value of 16 is returned
'           : This procedure maps the legends on the keypad for the return value
' Notes     : Uses the Keypad_Row1_Pin to Keypad_Row4_Pin, and Keypad_Col1_Pin to Keypad_Col4_Pin $defines for the keypad's pins
'
Proc GetKey(), Byte
    Dim Legends As Flash8 = {07, 08, 09, 16,                    ' \
                             04, 05, 06, 16,                    ' | This flash memory table holds the legends on the keypad that correspond to the value scanned
                             01, 02, 03, 16,                    ' |
                             16, 00, 16, 16}                    ' /

    PinInput Keypad_Row1_Pin                                    ' \
    PinInput Keypad_Row2_Pin                                    ' |
    PinInput Keypad_Row3_Pin                                    ' | Make the keypad's row pins Inputs
    PinInput Keypad_Row4_Pin                                    ' /
    PinOutput Keypad_Col1_Pin                                   ' \
    PinOutput Keypad_Col2_Pin                                   ' | Make the keypad's column pins Outputs
    PinOutput Keypad_Col3_Pin                                   ' |
    PinOutput Keypad_Col4_Pin                                   ' /
'
' Scan the columns of the KeyPad
'
    Result = 0                                                  ' Reset the result before scanning for a key press
    PinClear Keypad_Col1_Pin                                    ' \
    PinSet Keypad_Col2_Pin                                      ' | Setup the pins for the First column
    PinSet Keypad_Col3_Pin                                      ' |
    PinSet Keypad_Col4_Pin                                      ' /
    GoSub ScanRow                                               ' Scan the row pins
    If STATUSbits_C = 1 Then                                    ' Key pressed?
        Goto LegendCalc                                         ' Yes. So find the keypad legend return for the key value
    EndIf

    PinSet Keypad_Col1_Pin                                      ' \
    PinClear Keypad_Col2_Pin                                    ' | Setup the pins for the Second column
    PinSet Keypad_Col3_Pin                                      ' |
    PinSet Keypad_Col4_Pin                                      ' /
    GoSub ScanRow                                               ' Scan the row pins
    If STATUSbits_C = 1 Then                                    ' Key pressed?
        Goto LegendCalc                                         ' Yes. So find the keypad legend return for the key value
    EndIf

    PinSet Keypad_Col1_Pin                                      ' \
    PinSet Keypad_Col2_Pin                                      ' | Setup the pins for the Third column
    PinClear Keypad_Col3_Pin                                    ' |
    PinSet Keypad_Col4_Pin                                      ' /
    GoSub ScanRow                                               ' Scan the row pins
    If STATUSbits_C = 1 Then                                    ' Key pressed?
        Goto LegendCalc                                         ' Yes. So find the keypad legend return for the key value
    EndIf

    PinSet Keypad_Col1_Pin                                      ' \
    PinSet Keypad_Col2_Pin                                      ' | Setup the pins for the Fourth column
    PinSet Keypad_Col3_Pin                                      ' |
    PinClear Keypad_Col4_Pin                                    ' /
    GoSub ScanRow                                               ' Scan the row pins
'
' Find the keypad legend return for the key value, based upon the Legends flash memory table
'
LegendCalc:
    If Result <> 16 Then                                        ' Is the scan value 16?
        Result = Cread8 Legends[Result]                         ' No. So return the legend value for the keypad used
    EndIf
    ExitProc                                                    ' Exit the procedure
'
' Scan a row of the KeyPad
' The subroutine returns with the Carry flag set if a key is pressed and clear if no key pressed
'
ScanRow:
    If Keypad_Row1_Pin = 0 Then                                 ' Is the first row pin low?
        GoTo SetCarry_Exit                                      ' Yes. So exit with Carry flag set because a key is pressed
    EndIf
    Inc Result                                                  ' Increment the resulting value for the next row check
    If Keypad_Row2_Pin = 0 Then                                 ' Is the second row pin low?
        GoTo SetCarry_Exit                                      ' Yes. So exit with Carry flag set because a key is pressed
    EndIf
    Inc Result                                                  ' Increment the resulting value for the next row check
    If Keypad_Row3_Pin = 0 Then                                 ' Is the third row pin low?
        GoTo SetCarry_Exit                                      ' Yes. So exit with Carry flag set because a key is pressed
    EndIf
    Inc Result                                                  ' Increment the resulting value for the next row check
    If Keypad_Row4_Pin = 0 Then                                 ' Is the fourth row pin low?
        GoTo SetCarry_Exit                                      ' Yes. So exit with Carry flag set because a key is pressed
    EndIf
    Inc Result                                                  ' Increment the resulting value
    STATUSbits_C = 0                                            ' Clear the Carry flag, to indicate no key pressed
    Return
'
' Jump here to return with the Carry flag set
'
SetCarry_Exit:
    STATUSbits_C = 1
EndProc

It follows exactly the same mechanism as the compiler's built-in Inkey command, but has been refined to set different ports and pins, and read different ports and pins. Instead of a single port, which is faster and smaller, but not as flexible.

Below is a screenshot of the above code listing running in the proteus simulator. See that the keypad's column pins are connected to PORTA, and the row pins are connected to PORTB, and these can be any pins of the ports. A zip file has been attached that has the source code and a proteus project file.

KeyPad_Scanner.jpg

ken_k


Dolci

what more I can say.. now I have more option to deal with this simple task yet powerful solution.
Again many thanks to all for answering my query.

Dolci

top204

Using an ADC input to read button presses is a commonly used mechanism in designs that are a bit short on pins, and it works well. So it can be expanded to work with keypads, and has been used in many projects that use a small microcontroller.

It relies on a button press altering a resistance connected to VDD to the ADC, thus altering the ADC reading for a particular button pressed. The layout of the resistors has many capable patterns, as long as the ADC sees a different voltage for a particular button pressed, and that particular ADC reading can easily be converted to a value that represents the pressed button.

Below is code listing for the Positron8 compiler that reads a 4x3 keypad using a particular resistor pattern, and it is ideal for 4x3 keypads, because it does not require a large array of different resistor values, as some do, but will need different values if a larger keypad matrix is used, to make sure there is a large enough voltage difference between the keys pressed:

'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Demonstrate a procedure to read a 4x3 KeyPad connected to the AN0 ADC input pin
'
' Written by Les Johnson for the Positron8 BASIC compiler.
' https://sites.google.com/view/rosetta-tech/home
'
    Device = 18F26K22                                          ' Tell the compiler what device to compile for
    Declare Xtal = 64                                          ' Tell the compiler what frequency the device is operating at (in MHz)
    Declare Auto_Heap_Strings = On                             ' Make all Strings created in high RAM, above standard variables
    Declare Auto_Variable_Bank_Cross = On                      ' Make sure multi-byte variables stay within a single RAM bank
'
' Setup USART1
'
    Declare HSerial1_Baud = 9600
    Declare HRsout1_Pin = PORTC.6
'
' Create a variable for the demo
'
    Dim bKeyValue As Byte                                      ' Holds the key pressed value

'-------------------------------------------------------------------------------------
' The main program starts here
' Read a 4x3 KeyPad and transmit the values received from key presses to a serial terminal
'
Main:
    Setup()                                                     ' Setup the program and peripherals

    Do                                                          ' Create a loop
        bKeyValue = GetKey()                                    ' Read the KeyPad
        If bKeyValue <> 12 Then                                 ' Is it the value 12 (no key pressed)?
            HRsOutLn "Key Value is ", Dec bKeyValue             ' No. So transmit the value of the key pressed
        EndIf
        DelayMS 255                                             ' A small delay between keypad checking
    Loop                                                        ' Do it forever

'-------------------------------------------------------------------------------------
' Setup the program and peripherals
' Input    : None
' Output   : None
' Notes    : None
'
Proc Setup()
    IntOsc_64MHz()                                              ' Set the device to operate at 64MHz with its internal oscillator
    ADC_Init()                                                  ' Setup the ADC
EndProc

'-------------------------------------------------------------------------------------
' Scan a 12-button (4x3) KeyPad using the ADC
' Input    : None
' Output   : Returns with the value of the keypress. If no key pressed, a value of 12 is returned
' Notes    : None
'
Proc GetKey(), Byte
    Result = 12                                                 ' Default to no button pressed

    Select ADC_Read10(0)                                        ' Compare the ADC reading
        Case 63 To 66                                           ' Is the ADC reading between these values?
            Result = 1                                          ' Yes. So the "1" button is pressed on the keypad
        Case 68 To 70                                           ' Is the ADC reading between these values?
            Result = 2                                          ' Yes. So the "2" button is pressed on the keypad
        Case 73 To 77                                           ' Is the ADC reading between these values?
            Result = 3                                          ' Yes. So the "3" button is pressed on the keypad
        Case 79 To 84                                           ' Is the ADC reading between these values?
            Result = 4                                          ' Yes. So the "4" button is pressed on the keypad
        Case 86 To 93                                           ' Is the ADC reading between these values?
            Result = 5                                          ' Yes. So the "5" button is pressed on the keypad
        Case 95 To 104                                          ' Is the ADC reading between these values?
            Result = 6                                          ' Yes. So the "6" button is pressed on the keypad
        Case 106 To 118                                         ' Is the ADC reading between these values?
            Result = 7                                          ' Yes. So the "7" button is pressed on the keypad
        Case 120 To 136                                         ' Is the ADC reading between these values?
            Result = 8                                          ' Yes. So the "8" button is pressed on the keypad
        Case 138 To 160                                         ' Is the ADC reading between these values?
            Result = 9                                          ' Yes. So the "9" button is pressed on the keypad
        'Case 163 To 196                                        ' Is the ADC reading between these values?
        '    Result = 12                                        ' Yes. So an invalid is pressed on the keypad, and return the value 12
        Case 198 To 250                                         ' Is the ADC reading between these values?
            Result = 0                                          ' Yes. So the "0" button is pressed on the keypad
        'Case 253 To 255                                        ' Is the ADC reading between these values?
        '    Result = 12                                        ' Yes. So an invalid is pressed on the keypad, and return the value 12
        'Case Else                                              ' Otherwise...
        '    Result = 12                                        ' An invalid button is pressed on the keypad, so return the value 12
    EndSelect
EndProc

'-------------------------------------------------------------------------------------
' Read the 10-bit ADC on a PIC18FxxK22 device
' Input    : pChan holds the ADC channel to read (0 to X)
' Output   : Returns the 10-bit ADC value
' Notes    : None
'
Proc ADC_Read10(pChan As Byte), Word
    Dim wADRES As ADRESL.Word                                  ' Create a 16-bit SFR from ADRESL and ADRESH

    ADCON0 = %00000001                                         ' Clear the channel bits and enable the ADC peripheral
    pChan = pChan << 2                                         ' Move the channel bits into the correct position for ADCON0
    ADCON0 = ADCON0 | pChan                                    ' Or the channel bits into ADCON0
    DelayUs 100                                                ' Give time for the capacitor to discharge
    ADCON0bits_GO_DONE = 1                                     ' \ Wait for the ADC to complete its reading
    Repeat : Until ADCON0bits_GO_DONE = 0                      ' /
    Result = wADRES                                            ' Load the result with the ADC value
EndProc

'-----------------------------------------------------------------------------------------
' Setup the ADC on a PIC18Fx6K22 device
' Input    : None
' Output   : None
' Notes    : Set for 10-bit operation
'          : Uses the Gnd and FVR as vref+
'          : Uses the FOSC/64 oscillator
'          : Sets AN0 as an analogue pin
'
Proc ADC_Init()
    VREFCON0 = %10110000                                        ' FVR enabled at 4.096 volts
    ADCON1 = %00001000                                          ' -Vref is VSS. +Vref is FVR
    ADCON2 = %10000110                                          ' Right Justified for 10-bit. ADCS is FOSC/64
    ADCON0 = %00000001                                          ' ADC enabled. Default Channel is AN0
    ANSELAbits_ANSA0 = 1                                        ' Setup AN0 as an analogue pin
EndProc

'-----------------------------------------------------------------------------------------
' Setup the device to use its internal oscillator at 64MHz
' Input    : None
' Output   : None
' Notes    : For use with PIC18Fx6K22 devices
'
Proc IntOsc_64MHz()
    OSCCON  = $70
    OSCCON2 = $04
    OSCTUNE = $40
    DelayMs 100                                                ' A small delay to wait for the PLL to stabilise
EndProc

'-----------------------------------------------------------------------------------------
' Configure the fuses to operate using the internal oscillator, on a PIC18Fx6K22 device
'
Config_Start
    FOSC    = INTIO67                                          ' Use the internal oscillator for the device's oscillator
    PLLCFG  = Off                                              ' Disable PLL
    PRICLKEN = On                                              ' Primary clock enabled
    FCMEN   = Off                                              ' Fail-Safe Clock Monitor disabled
    IESO    = Off                                              ' Internal/External Oscillator Switchover mode disabled
    PWRTEN  = On                                               ' Power up timer enabled
    BOREN   = SBORDIS                                          ' Brown-out Reset enabled in hardware only (SBOREN is disabled)
    BORV    = 190                                              ' Brown Out Reset Voltage set to 1.90 V nominal
    WDTEN   = Off                                              ' Watch dog timer is always disabled. SWDTEN has no effect.
    WDTPS   = 128                                              ' Watchdog Timer Postscale 1:128
    CCP2MX  = PORTC1                                           ' CCP2 input/output is multiplexed with RC1
    PBADEN  = Off                                              ' PORTB<5:0> pins are configured as digital I/O on Reset
    CCP3MX  = PORTB5                                           ' P3A/CCP3 input/output is multiplexed with RB5
    HFOFST  = On                                               ' HFINTOSC output and ready status are not delayed by the oscillator stable status
    T3CMX   = PORTC0                                           ' Timer3 Clock Input (T3CKI) is on RC0
    P2BMX   = PORTB5                                           ' ECCP2 B (P2B) is on RB5
    MCLRE   = EXTMCLR                                          ' MCLR pin enabled, RE3 input pin disabled
    STVREN  = Off                                              ' Stack full/underflow will not cause Reset
    LVP     = Off                                              ' Single-Supply ICSP disabled
    XINST   = Off                                              ' Instruction set extension mode disabled
    Debug   = Off                                              ' Debug Disabled
    Cp0     = Off                                              ' Block 0 (000800-001FFF) not code-protected
    CP1     = Off                                              ' Block 1 (002000-003FFF) not code-protected
    CP2     = Off                                              ' Block 2 (004000-005FFF) not code-protected
    CP3     = Off                                              ' Block 3 (006000-007FFF) not code-protected
    CPB     = Off                                              ' Boot block (000000-0007FF) not code-protected
    CPD     = Off                                              ' Data EEPROM not code-protected
    WRT0    = Off                                              ' Block 0 (000800-001FFF) not write-protected
    WRT1    = Off                                              ' Block 1 (002000-003FFF) not write-protected
    WRT2    = Off                                              ' Block 2 (004000-005FFF) not write-protected
    WRT3    = Off                                              ' Block 3 (006000-007FFF) not write-protected
    WRTC    = Off                                              ' Configuration registers (300000-3000FF) not write-protected
    WRTB    = Off                                              ' Boot Block (000000-0007FF) not write-protected
    WRTD    = Off                                              ' Data EEPROM not write-protected
    EBTR0   = Off                                              ' Block 0 (000800-001FFF) not protected from table reads executed in other blocks
    EBTR1   = Off                                              ' Block 1 (002000-003FFF) not protected from table reads executed in other blocks
    EBTR2   = Off                                              ' Block 2 (004000-005FFF) not protected from table reads executed in other blocks
    EBTR3   = Off                                              ' Block 3 (006000-007FFF) not protected from table reads executed in other blocks
    EBTRB   = Off                                              ' Boot Block (000000-0007FF) not protected from table reads executed in other blocks
Config_End

Below is a screenshot of the above code listing being operated in the proteus simulator on a PIC18F26K22 device:

Positron8 - ADC Keypad Reader.jpg

Attached to this post is a zip file that contains the source code for the Positron8 compiler, operating on a PIC18F26K22 device, but it can easily be changed for another device, by setting up the ADC on it. It also contains a proteus project file for the simulation, and a code listing to see what ADC value is read when a key is pressed.