Paul B. Webster wrote: >Quentin wrote: > >> 1---(7)-(8)-(9) >> | | | >> 2---(4)-(5)-(6) >> | | | >> 3---(1)-(2)-(3) >> | | | >> | | | >> 4 5 6 > >> You make pin 1 high, then read 4, then 5, then 6 to see which one is >> high, then you make pin 1 low and 2 high and read 4, 5, 6 again, etc. > > That's not *quite* correct. > > Firstly, pins you are using as an input must be given a known state. >The PIC has built-in pull-ups on port B which you may care to use or you >can use external pull-up resistors for all keyboard lines. > > Note that for protection against shorts to ground, which are rather >more likely than shorts to supply, it is usual to use pull-ups rather >than pull-downs as in a short to ground (being in effect the same as a >switch closure to ground) the current will be safely limited by the >pull-up. > > Secondly, you "strobe" each row (or if you wish, column) in turn by >making it an output and pulling it *low*, but the rows you are *not* >strobing, you do *not* pull high, but rather open-circuit them by making >them inputs. > > If both rows and columns are part of port B and you elected to use the >internal pull-ups, then the non-selected rows will be pulled up by the >pull-ups as well as the columns but this does not matter (in fact, you >don't really want any inputs to float). The point is that by this means >multiple switch closures in any given row will *not* cause high and low >outputs to conflict. > > When one row, say pin 1, is low, then any column may be pulled down by >a corresponding closed switch on that row, while all other columns are >pulled up by their pull-ups. By pulling each row low in turn, and >reading (generally in one I/O operation, using a shift operation to >test each in turn) all columns, all the switches can be read. > > You may note a couple of cunning tricks which may or may not be >useful. One is to hold *all* rows low whilst reading the columns, >waiting for *any* closure before strobing them individually. This makes >it very simple to perform a status check on the keyboard as a whole, it >can even be done in SLEEP using the Port B interrupt-on-change. > > Also, a quite fast way of finding a single key closure (i.e., does not >work if more than one key is pressed), is to pull all rows low and read >the columns, then pull all columns low and read the rows. As long as >you only see one column and one row pulled down as a result, this >uniquely indicates the closure. > > Note that the PORT register is kept clear to do this, (do not use >read-modify-write instructions on it) and only the TRIS register is >changed (use the TRIS instruction!) but the PORT is read each time. >-- > Cheers, > Paul B. Good advice! I just happened to have an example sitting around. It is for a 4x4 keypad connected to a 17C756 on PORTB. It doesn't do the fast scan ... just a plain old one-row-at-a-time scan. I had PORTB (output latch) set to 0. Weak pullups were enabled. Pinout is kinda funky (to make PCB layout easier): 6---(1)-(2)-(3)-(A) | | | | 7---(4)-(5)-(6)-(B) | | | | 5---(7)-(8)-(9)-(C) | | | | 2---(*)-(0)-(#)-(D) | | | | 3 4 0 1 ;------------------------------------------------------------ ;Called by interrupt handler to scan the keypad ;Returns with W=ASCII if a key is pressed, W=0 otherwise ;Interrupt handler performs debounce SCAN1 MOVLW ~0X40 ;Enable ROW0 output MOVWF DDRB NOP NOP BTFSS PORTB,3 RETLW '1' BTFSS PORTB,4 RETLW '2' BTFSS PORTB,0 RETLW '3' BTFSS PORTB,1 RETLW 'A' MOVLW ~0X80 ;ROW1 MOVWF DDRB NOP NOP BTFSS PORTB,3 RETLW '4' BTFSS PORTB,4 RETLW '5' BTFSS PORTB,0 RETLW '6' BTFSS PORTB,1 RETLW 'B' MOVLW ~0X20 ;ROW2 MOVWF DDRB NOP NOP BTFSS PORTB,3 RETLW '7' BTFSS PORTB,4 RETLW '8' BTFSS PORTB,0 RETLW '9' BTFSS PORTB,1 RETLW 'C' MOVLW ~0X04 ;ROW3 MOVWF DDRB NOP NOP BTFSS PORTB,3 RETLW '*' BTFSS PORTB,4 RETLW '0' BTFSS PORTB,0 RETLW '#' BTFSS PORTB,1 RETLW 'D' RETLW 0 Cheers, Ken