1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

RS232 keypad with autorepeat and 2 key rollover.

Discussion in 'Electronic Projects' started by Pommie, Jan 12, 2009.

Thread Status:
Not open for further replies.
  1. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,011
    Likes:
    316
    Location:
    Brisbane Australia
    ONLINE
    This project uses a 12F508 (or 12F509) to read a keypad and send the results over RS232. It is most useful as an add-on to other pic projects that require some way to input numbers. This keypad acts the same way as your PC keyboard in that when a key is held down, it has the short delay before it repeats the key. Both the delay and repeat speed are settable in software just like your PC keyboard.

    Many people will wonder what "2 key rollover" means. The best answer is with a little demonstration. Open your favourite text editor, hold down the "A" key and when it starts repeating press the "B" key. Even though 2 keys are now held down the keyboard sends the last key pressed. This is useful because many people will press the keys so fast that they inadvertently press two keys at once.

    How does it work.
    The Schematic,
    [​IMG]

    The 12F508 only has 6 input/output (I/O) pins and we need 1 to send the serial data out which leaves only 5 left to read the keypad. The keypad has 4 rows and 3 columns which is too many for our little pic chip. The way we get around this problem is by using the same pins twice. You see the three resistors in the diagram, well they will make the three pic pins low by connecting them to ground. If we now make GP4 high the diode on row 1 will conduct and if any keys are pressed in row 1 then the corresponding pin GP0, GP1 or GP3 will also go high. We have successfully read row 1. We can repeat this with GP4 and read row 3.

    Now comes the tricky part because the diodes on rows 0 and 2 are backward and so the only way to read those rows is by outputting a zero on GP4 and GP5 thus making the input pins low. But, wait a minute, they are already low due to those resistors and so we won't see any change. Luckily for us the pics have internal resistors that connect the (input) pins to the 5V line that we can turn on and off in software. These resistors have a value around 20k and so will overpower the 200k external ones and make the input pins 5V. So, with these internal resistors turned on we can make GP4 an output, set it low and any pins that are now low will indicate a key pressed on row 0. We can repeat this using GP5 to read row 2.

    The board,
    [​IMG]

    Closer,
    [​IMG]
    The two sets of connectors are just for convenience, I added the second set to enable me to use it on a breadboard.

    The finished article,
    [​IMG]

    The code,
    Code (text):

    ;*******************************************************************
    ;       Title   12F509 RS232 KeyPad
    ;       Author  Mike Webb
    ;       Date    12th January 2009
    ;       Version 1.0
    ;*******************************************************************
    ;
        processor   12F509

        include "p12f509.inc"

        errorlevel  -302
        radix   dec

        __CONFIG   _MCLRE_OFF & _CP_OFF & _WDT_OFF & _IntRC_OSC

    ;uncomment the following line to invert the RS232 signal.
    ;when inverted it can connect straight to a PC without a MAX232

    ;#define        Inverted

    #define     GPIO0   0
    #define     GPIO1   1
    #define     GPIO2   2
    #define     GPIO3   3
    #define     GPIO4   4
    #define     GPIO5   5

    #define     b_GPIO0 GPIO,0
    #define     b_GPIO1 GPIO,1
    #define     b_GPIO2 GPIO,2
    #define     b_GPIO3 GPIO,3
    #define     b_GPIO4 GPIO,4
    #define     b_GPIO5 GPIO,5


    #define     RS232   2
    #define     b_RS232Out GPIO,RS232

            cblock  07h
    OutByte
    Temp
    Count
    Key0
    Key1
    Old0
    Old1
    Edge0
    Edge1
    KeyCount
            endc

    KeyDelay    equ 35  ;delay in 100th second until repeat kicks in
    KeyRepeat   equ 10  ;delay between repeated keys


            org     0h

    ;********************************************************************
    ;   4 meg clock = 1.0 meg instructions


            org     0h
            movwf   OSCCAL      ;write calibration value

    start       movlw   0
            OPTION
        #ifdef  Inverted
            bcf b_RS232Out  ;ensure RS232 is high
        #else
            bsf b_RS232Out  ;ensure RS232 is high
        #endif
            movlw   b'11111111'-(1<<RS232)
            TRIS    GPIO        ;all input except RS232 output


            call    Wait100th
            call    Wait100th

    Loop        Call    Wait100th   ;needed for timing and debounce
            movfw   Key0
            movwf   Old0        ;keep copy of previous keys
            movfw   Key1
            movwf   Old1
            call    ReadKeys    ;read the key matrix into Key0 and Key1
            movfw   Key0
            iorwf   Key1,W      ;any key pressed
            btfsc   STATUS,Z
            goto    Loop
            movfw   Key0        ;get key state
            xorwf   Old0,W      ;keep changed bits (pressed and released)
            andwf   Key0,W      ;keep only new presses
            btfss   STATUS,Z
            goto    NewKeyDown
            movfw   Key1
            xorwf   Old1,W
            andwf   Key1,W
            btfsc   STATUS,Z
            goto    KeySame
    NewKeyDown  movlw   KeyDelay    ;start key delay
            movwf   KeyCount   
            movfw   Key0        ;edge = (key^old)&key
            xorwf   Old0,W
            andwf   Key0,W
            movwf   Edge0       ;edges contains a 1 for each new key press
            movfw   Key1
            xorwf   Old1,W
            andwf   Key1,W
            movwf   Edge1
            goto    HaveKey
    KeySame     decfsz  KeyCount,F  ;key delay
            goto    Loop
            movlw   KeyDelay    ;if KeyDelay is zero
            iorlw   0       ;then no repeat allowed
            btfsc   STATUS,Z
            goto    Loop
            movlw   KeyRepeat
            movwf   KeyCount
    HaveKey
    ;   having got to here then a key is pressed for the first time
    ;   or the repeat time is up and so it needs repeating.
    ;   Edge0 or Edge1 contain the key pressed.

            movfw   Edge0       ;does edge0 have a bit set
            btfsc   STATUS,Z
            goto    IsEdge1     ;no so must be edge1
            movwf   Temp
            movlw   255     ;set count to -1
            goto    CountBits
    IsEdge1     movfw   Edge1       ;move edge1
            movwf   Temp        ;into temp and
            movlw   7       ;count to 7
    CountBits   movwf   Count
            bsf STATUS,C    ;ensure it can't get stuck in loop
    CountBitsL  incf    Count,F     ;increment counter
            rrf Temp,F      ;until we find a set bit
            btfss   STATUS,C
            goto    CountBitsL
            movfw   Count       ;W=key number 0-15
            Call    Bit2Key     ;convert to key character
            call    Send        ;send key via RS232
            goto    Loop



    ReadKeys    movlw   0<<NOT_GPPU     ;   WPUs ON
            OPTION
            movlw   b'11111111'-(1<<GPIO5)-(1<<RS232)
            tris    GPIO            ;make I/O 5 output
            bcf b_GPIO5         ;and make it low
            call    BitDelay        ;avoid RMW
            clrf    Key0            ;will hold key state
            btfss   b_GPIO0         ;if I/O 0 low then key pressed
            bsf Key0,0          ;so set the bit
            btfss   b_GPIO1         ;repeat
            bsf Key0,1          ;for
            btfss   b_GPIO3         ;other
            bsf Key0,2          ;keys
            movlw   b'11111111'-(1<<GPIO4)-(1<<RS232)
            tris    GPIO            ;make I/O 4 output
            bcf b_GPIO4         ;and make it low
            Call    BitDelay
            btfss   b_GPIO0         ;read next row
            bsf Key0,4
            btfss   b_GPIO1
            bsf Key0,5
            btfss   b_GPIO3
            bsf Key0,6
            movlw   1<<NOT_GPPU     ;WPUs OFF
            OPTION
            movlw   b'11111111'-(1<<GPIO5)-(1<<RS232)
            tris    GPIO            ;make I/O 5 output
            bsf b_GPIO5         ;and make it high
            call    BitDelay
            clrf    Key1
            btfsc   b_GPIO0         ;I/O 0 will be pulled low by
            bsf Key1,0          ;220k resistors unless key pressed
            btfsc   b_GPIO1
            bsf Key1,1          ;same for rest of row
            btfsc   b_GPIO3
            bsf Key1,2
            movlw   b'11111111'-(1<<GPIO4)-(1<<RS232)
            tris    GPIO            ;make I/O 4 output
            bsf b_GPIO4         ;and high
            call    BitDelay
            btfsc   b_GPIO0
            bsf Key1,4          ;read next row
            btfsc   b_GPIO1
            bsf Key1,5
            btfsc   b_GPIO3
            bsf Key1,6
            retlw   0
           
    Bit2Key     andlw   15
    KeyTable    addwf   PCL,F
            retlw   '7'
            retlw   '8'
            retlw   '9'
            retlw   'x'
            retlw   '1'
            retlw   '2'
            retlw   '3'
            retlw   'x'
            retlw   '*'
            retlw   '0'
            retlw   '#'
            retlw   'x'
            retlw   '4'
            retlw   '5'
            retlw   '6'
            retlw   'x'

        #ifdef  Inverted

    Send        movwf   OutByte
            bsf b_RS232Out
            call    BitDelay
            bsf STATUS,C
    SendLoop    rrf OutByte,F
            movfw   OutByte
            btfsc   STATUS,Z
            goto    EndTransmit
            bsf b_RS232Out
            btfsc   STATUS,C
            bcf b_RS232Out
            call    BitDelay
            bcf STATUS,C
            goto    SendLoop
    EndTransmit bcf b_RS232Out
            call    BitDelay
            call    BitDelay
            retlw   0

        #else

    Send        movwf   OutByte
            bcf b_RS232Out
            call    BitDelay
            bsf STATUS,C
    SendLoop    rrf OutByte,F
            movfw   OutByte
            btfsc   STATUS,Z
            goto    EndTransmit
            bcf b_RS232Out
            btfsc   STATUS,C
            bsf b_RS232Out
            call    BitDelay
            bcf STATUS,C
            goto    SendLoop
    EndTransmit bsf b_RS232Out
            call    BitDelay
            call    BitDelay
            retlw   0

        #endif


    ; at 1 meg instructions and 2400 baud
    ; delay is 1,000,000/2400 = 416 cc
    ; the calling loop and the call/return = 13
    ; therefore delay needs to be 403 cycles

    ; to change to 9600 baud
    ; delay needs to be 104 - 13 = 91
    ; which would be (3*30)-1 = 89 + 2 = 91

    BitDelay    movlw   30  ;134    change back to 134 for 2400 baud
            movwf   Temp
    DelayLoop   decfsz  Temp,F;     (3*134)-1 = 401 + 2 = 403
            goto    DelayLoop
            retlw   0

    Wait100th   clrf    Count
            movlw   13
            movwf   Temp
    Delay100L   decfsz  Count,F;    (256*3)-1 = 767
            goto    Delay100L
            decfsz  Temp,F;     (13*(767+3))-1 = 10009 + 3 = 10012
            goto    Delay100L
            retlw   0

            END
     
    A video.
    [embed]http://www.youtube.com/v/Q2xrVV9w-yE&hl=en&fs=1[/embed]

    Note, this will not work with newer pic chips as they don't have the WPU on I/O 3.

    <edit>Somethings I forgot,
    The connections from left to right are GND, RS232 out and 5V.
    The output is TTL and so can be connected straight to a pic RX pin without a MAX232 chip.
    If you want an inverted signal to connect to a PC then uncomment the #define inverted line in the source.
    You can change the repeat delay and repeat rate in the source.
    </edit>

    Mike.
     

    Attached Files:

    Last edited: Jan 12, 2009
  2. Gayan Soyza

    Gayan Soyza Active Member

    Joined:
    Oct 23, 2006
    Messages:
    1,821
    Likes:
    19
    Location:
    Colombo
    Wow what a smooth functioning same like a PC keyboard.

    Again a very nice compact project.Nicely done :)
     
  3. bassnut

    bassnut New Member

    Joined:
    Dec 17, 2008
    Messages:
    119
    Likes:
    1
    Location:
    Sydney
    Excellent report Pommie, a pleasure to view, and very informative.
     
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,011
    Likes:
    316
    Location:
    Brisbane Australia
    ONLINE

    Hi Gayan,

    It behaves exactly like a PC keyboard. You can even set the repeat delay and repeat speed the same as a PC keyboard.

    Mike.
     
  6. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,637
    Likes:
    109
    Location:
    Michigan, USA
    Mike, you're posting these interesting projects too fast.

    I'm still studying the rom search algorithm in your DS18x20 project code (grin).

    Regards, Mike
     
  7. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,011
    Likes:
    316
    Location:
    Brisbane Australia
    ONLINE
    I actually wrote this code about 2 years ago and have just gotten around to posting it and so you'll probably have a few years to study these two before there is any more.

    As far as I am aware I think this is the first charlieplexed(ish) keypad code/circuit around. It reads 12 keys with 5 I/O pins so not quite n*(n-1).

    Mike.
     
  8. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,637
    Likes:
    109
    Location:
    Michigan, USA
    I dismissed the idea of using a standard multiplexed keypad in a Charlieplexed matrix a long time ago because of the "float" pin wiring. I never thought of using an additional pin to get around the problem.

    Be careful Mike, there are moments when you could be mistaken for a bloomin' genius (grin).

    Nice job. I look forware to studying the code, as always.

    Mike, K8LH
     
  9. eblc1388

    eblc1388 Active Member

    Joined:
    Jan 25, 2005
    Messages:
    2,228
    Likes:
    18
    Location:
    UK
    I have tried all kind of external hardware tricks trying to provide a HIGH to the GPIO3 pin to mimic missing WPU so your code can also be used for newer 8-pin PICs like 12F629, 12F635 or 12F675 but so far all my efforts failed.

    It is so d*** hard to do just that.:mad:
     
  10. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,011
    Likes:
    316
    Location:
    Brisbane Australia
    ONLINE
    Believe me I've tried. I wanted to make a combination lock with one of the newer 8 pin chips and store the code in EEPROM. Alas, it's not doable because of that missing WPU.

    Doing a combination lock with a fixed code would be doable with the above code but that wouldn't be much use, or would it?

    Mike.
     
  11. Gayan Soyza

    Gayan Soyza Active Member

    Joined:
    Oct 23, 2006
    Messages:
    1,821
    Likes:
    19
    Location:
    Colombo
    What about using 1 wire keypad & measure the AD Value to detect which key has pressed like (Kifo) did his keypad thing?Never tried auto repeat feature with that method.May be a good project :)
     
    Last edited: Jan 13, 2009
  12. zedy22

    zedy22 New Member

    Joined:
    Apr 10, 2009
    Messages:
    1
    Likes:
    0
    what type capacitor u use??
     
    Last edited: Apr 11, 2009
  13. camelush

    camelush New Member

    Joined:
    Apr 13, 2009
    Messages:
    1
    Likes:
    0
    nice project
     
  14. red light

    red light New Member

    Joined:
    Nov 27, 2008
    Messages:
    4
    Likes:
    0
    good project
     
  15. dougy83

    dougy83 Well-Known Member

    Joined:
    May 18, 2008
    Messages:
    2,672
    Likes:
    215
    Location:
    Brisbane, Australia
    Don't give up so soon! There's more ways to skin this cat. For the cost of an extra resistor you can remove all pullups.

    Or use 4 I/O lines, 3 resistors and 3 capacitors for the keypad.

    Or use 1 I/O line, 5 resistors & 3 caps...

    See attached schems for examples. I'm sure there's more ways that I haven't thought of..

    Of course it would. The single fixed code could be the 'master reset' code, which could be entered to set the other code(s). So long as power is never interrupted (e.g. it's on batteries), then the code(s) remains. If the pic's in sleep most of the time, battery changes may not be for years.
     

    Attached Files:

  16. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,011
    Likes:
    316
    Location:
    Brisbane Australia
    ONLINE
    I don't like any scheme that involves analogue voltages or timed RC solutions as it really messes up the simple debounce and 2 key rollover code. However, the third diagram is interesting. Can you explain how you read this matrix?

    Mike.
     
  17. dougy83

    dougy83 Well-Known Member

    Joined:
    May 18, 2008
    Messages:
    2,672
    Likes:
    215
    Location:
    Brisbane, Australia
    Only the 3rd cct fits into that category.

    pressing a switch connect 2 unique resistors in series to a cap. The IO pin can time the charge/discharge rate of the cap by switching between output (to provide current) & input (to monitor voltage). There's a function in Proton+ picbasic called 'pot' (I think) that will do this for you.

    If you wanted to make the code easier, in addition to allowing a simple wake up on key press, an IO pin would also be connected directly to the capacitor.
     
    • Like Like x 1
  18. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,011
    Likes:
    316
    Location:
    Brisbane Australia
    ONLINE
    I was looking at the page in portrait layout and so I was counting the first (left) as the third (bottom). Now I've turned it around the one that's interesting is the first one. That diagram will work without using the internal pullups and so solves the lack of pullups on the newer pic chips. I may have a play with this tomorrow just to make sure it works as I envisage. Assuming it does a programmable combination lock with one of the 8 pin pic chips should be doable.

    Will you be watching "State of Origin" tonight?

    Mike.
     
    Last edited: Jun 2, 2009
  19. dougy83

    dougy83 Well-Known Member

    Joined:
    May 18, 2008
    Messages:
    2,672
    Likes:
    215
    Location:
    Brisbane, Australia
    Nah, sounds too much like sport:eek:
     
Thread Status:
Not open for further replies.

Share This Page