![]() |
![]() |
![]() |
|
|
|||||||
| Electronic Projects A collection of small electronic circuits and projects you can build. |
|
|
Tools | Display Modes |
|
|
#1 (permalink) |
|
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, ![]() 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, ![]() Closer, ![]() 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, ![]() The code, Code:
;******************************************************************* ; 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 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. Last edited by Pommie; 12th January 2009 at 10:49 AM. |
|
|
|
|
|
#6 (permalink) |
|
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. |
|
|
|
|
|
#7 (permalink) |
|
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 |
|
|
|
|
|
#8 (permalink) | |
|
Quote:
It is so d*** hard to do just that.
__________________
L.Chung |
||
|
|
|
|
#9 (permalink) | |
|
Quote:
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. |
||
|
|
|
|
#14 (permalink) | |
|
Quote:
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. |
||
|
|
| Bookmarks |
| Thread Tools | |
| Display Modes | |
|
|
|
|
||||
| Title | Starter | Forum | Replies | Latest |
| Lizard PIC16F628A LCD, 4x4 keypad, relay, buzzer RS232 | William At MyBlueRoom | Electronic Projects Design/Ideas/Reviews | 0 | 13th October 2006 04:19 PM |
| keypad help... | jrz126 | Micro Controllers | 6 | 8th November 2005 11:47 PM |
| keypad in a RC car | dukeoverl | General Electronics Chat | 1 | 14th December 2004 06:33 PM |
| rs232 to rs232 data logger with 1meg buffer -help needed | ccaammaaccaazzii | Electronic Projects Design/Ideas/Reviews | 11 | 20th October 2004 09:43 PM |
| Keypad ? | lil_sti | Electronic Projects Design/Ideas/Reviews | 2 | 6th March 2004 02:31 PM |