pull up resistors needed to connect keypad to PIC16f877A

Thread Starter

FG1

Joined Jun 11, 2010
6
i need to connect a 4x4 keypad to PIC16F877A. i have read about some pull up resistors needed to perform this connection and i don't quite get it. do they need to be connected on all the 8 lines (4 rows, 4 columns) of keypad. if yes, how?
also i have read somewhere that if keypad is being connected to portB of PIC then these resistors aren't needed. is that true? i am using port B only and confused about whether or not to use the resistors.
 

Vaughanabe13

Joined May 4, 2009
102
So you will have 4 rows and 4 columns. You connect the 4 rows to any 4 INPUTS, and the 4 coloumns to any 4 OUTPUTS. You can can use one port and make half input and half output, for convenience. It will look like this graphic:

Then put pullup resistors on each row of this grid. IE, attach a resistor from Row1 to VCC, Row2 to VCC, etc. (NOT shown in this graphic). This will make the rows be logic HIGH by default. Depending on your uC you can probably enable these pullup resistors in software, rather than adding physical resistors. I think PORTB on most PIC uC's has internal pullups, which is why you were told to use that port.
Now poll in software to see which button is being pressed. Drive all the columns low and wait for a low input on Rows 1-4 (this can be handled in interrupts if you have 4 pins that will throw an interrupt on a high-low transition). Lets say Row4 becomes low, so we know either C,D,E or F is being pressed. Now debounce the button by delaying about 5-10ms. Now to figure out which button in Row4 is pressed, go through the 4 combinations of low-high on the columns and look for a low value on the row. IE, make Col1 low, and Cols2-4 high and if Row4 is low it means button C is being pressed. etc.
 
Last edited:

Markd77

Joined Sep 7, 2009
2,806
If you do a quick search for keypad PIC16F877 you should find some examples.
Port B has internal pull up resistors when the pins are set as inputs, but they have to be turned on in software. Have a look at the OPTION register to turn them on.
 

Thread Starter

FG1

Joined Jun 11, 2010
6
thanks for the help.. here is what i have done (hoping its not wrong).
port B (0:3) used for column rows and connected directly to PIC
port B (4:7) connected to PIC via 10K resistors whose other end is grounded.

are these connections right? Also, i have no clue about how to program the keypad. I am using PicBasic Pro. can anyone please help and provide a relevant code that i may try and test my keypad with?
 

Vaughanabe13

Joined May 4, 2009
102
Um, I just told you exactly how to do it. You're not going to get any more clear of an explanation than that. I told you how to hook it up to the PIC and how to read the key presses in software.
 

John P

Joined Oct 14, 2008
2,026
I disagree with Vaughanabe13. Don't use any resistors at all, and don't connect anything to Vcc or Gnd. Just connect the 4 rows to (say) PortB pins 0-3 and the 4 columns to (say) PortB 4-7. Turn on the internal pullups (set Option reg bit 7 to 0) and decide whether your rows or columns will be the inputs: clear the Tris bits for those pins and set the Tris pins for the outputs. That's all you need to do.
 

MMcLaren

Joined Feb 14, 2010
861
I disagree with Vaughanabe13....
I disagree too.

A carefully designed keypad driver will scan one column at a time by making one column line "output low" and the other three column lines "input high" (using int/ext pull-up).

Caveat! If you drive one column line "output low" and the other three column lines "output high" then you can cause a dead short by pressing certain key combinations at the same time.

Cheerful regards, Mike
 
Last edited:

John P

Joined Oct 14, 2008
2,026
I think you mean "output high". But anyway, you can avoid the possibility of connecting two outputs together if you scan the keypad by setting all four of the column lines to 0 (if it's the columns that are the outputs) and then controlling the Tris bits for the columns. The way this works is that one column at a time can sink current, and none of them can source current, except from the internal pullups. I admit that earlier I said that the columns should all be made into outputs, and that was wrong; only one at a time should be an output.
 

Thread Starter

FG1

Joined Jun 11, 2010
6
thanks for the input from all you people..i have managed to get hold of it now and your comments have clarified a few more points =)
 
I disagree too.

A carefully designed keypad driver will scan one column at a time by making one column line "output low" and the other three column lines "input high" (using int/ext pull-up).

Caveat! If you drive one column line "output low" and the other three column lines "output high" then you can cause a dead short by pressing certain key combinations at the same time.

Cheerful regards, Mike
That is exactly what I said, therefore you do not disagree with me. If you drive all 4 columns high, set the 4 rows as inputs, tie them to VCC with internal pullups and set them to interrupt-on-negedge, then you can run other code instead of constantly checking the keypad. Then you use the interrupt service to handle the button press, as I already described in my earlier post. It is a more efficient and more versatile way of doing it.
 
Last edited:
I disagree with Vaughanabe13. Don't use any resistors at all, and don't connect anything to Vcc or Gnd. Just connect the 4 rows to (say) PortB pins 0-3 and the 4 columns to (say) PortB 4-7. Turn on the internal pullups (set Option reg bit 7 to 0) and decide whether your rows or columns will be the inputs: clear the Tris bits for those pins and set the Tris pins for the outputs. That's all you need to do.
Again, this is exactly what I said. I already mentioned using internal pullups instead of physical resistors, which is the same thing as connecting a line to VCC. You can do it in software or hardware, it doesn't matter. But the result is identical.
 

MMcLaren

Joined Feb 14, 2010
861
That is exactly what I said, therefore you do not disagree with me. If you drive all 4 columns high, set the 4 rows as inputs, tie them to VCC with internal pullups and set them to interrupt-on-negedge, then you can run other code instead of constantly checking the keypad. Then you use the interrupt service to handle the button press, as I already described in my earlier post. It is a more efficient and more versatile way of doing it.
I disagreed with you on a couple points;

(1) If you're using rows as inputs with pull-up resistors then you're looking for an active-low signal through the switches which requires one (or all) column outputs to be driven low and not high as you suggested.

(2) You weren't clear about how you set the column outputs low and high and so I suspect you were simply leaving them setup as outputs and setting the corresponding port latch bits low and high which is a potential hazard. That method works fine if you install diodes on the four column driver lines, otherwise you need to select column outputs using the TRIS bits so that only one of the column driver lines is an output.

If I misinterpreted your post, I apologize.

Cheerful regards, Mike
 
Last edited:

Thread Starter

FG1

Joined Jun 11, 2010
6
i am using the following code in Pic basic pro but only my first 2 rows seem to gvie the correct pressed number on LCD, the last two rows give the wrong value.

can anyone identify the problem in the code

HARDWARE CONNECTIONS: pin 0:3 connected to rows via `10k resistors
pin 4:7 connected to coulmns

' PicBasic Pro program to display key number on LCD
' Define LOADER_USED to allow use of the boot loader.
' This will not affect normal program operation.
Define LOADER_USED 1
' Define LCD connections
DEFINE OSC 20
DEFINE LCD_DREG PORTD
define LCD_DBIT 0
DEFINE LCD_RSREG PORTE
DEFINE LCD_RSBIT 0
DEFINE LCD_EREG PORTE
DEFINE LCD_EBIT 1
DEFINE LCD_RWREG PORTE
DEFINE LCD_RWBIT 2
DEFINE LCD_BITS 8
DEFINE LCD_LINES 2
DEFINE LCD_COMMANDUS 2000
DEFINE LCD_DATAUS 50
' Define program variables
col var byte ' Keypad column
row var byte ' Keypad row
key var byte ' Key value
OPTION_REG.7 = 0 ' Enable PORTB pullups
ADCON1 = 7 ' Make PORTA and PORTE digital
Low PORTE.2 ' LCD R/W low (write)
Pause 500 ' Wait for LCD to start
Lcdout $fe, 1
pause 250
lcdout "Press any key" ' Display sign on message
loop: Gosub getkey ' Get a key from the keypad
Lcdout $fe, 1, #key ' Display ASCII key number
Goto loop ' Do it forever
' Subroutine to get a key from keypad
getkey:
PAUSE 50 'Debounce key-input
getkeyu:' Wait for all keys up
PORTB = 0 ' All output-pins low
TRISB = $f0 ' Bottom 4-pins out, top 4-pins in
IF ((PORTB >> 4) = $f) THEN getkeyu'If keys down, loop
PAUSE 50 ' Debounce key-input
getkeyp:' Wait for keypress
FOR row = 0 TO 3 ' 4 rows in keypad
PORTB = 0 ' All output-pins low
TRISB = (DCD row) ^ $ff ' Set one row pin to output
col = PORTB >> 4 ' Read columns
IF col != $f THEN gotkey' If any keydown, exit
NEXT row
GOTO getkeyp ' No keys down, go look again
gotkey: ' Change row and column to key number 1 - 16
key = (row * 4) + (NCD (col ^ $f))
'NOTE: for 12-key keypad, change to key = (row * 3)
RETURN ' Subroutine over

END
 

MMcLaren

Joined Feb 14, 2010
861
Hi FG1,

What is "DCD"? Could this be a problem?
Rich (BB code):
    TRISB = (DCD row) ^ $ff    ' Set one row pin to output
Could this be generating TRISB values of '11111111' (row = 0), '11111110' (row = 1), '11111101' (row = 2), and '11111100' (row = 3)?

You want to generate TRISB values of '11111110', '11111101, '11111011', and '11110111' as you scan rows 0 through 3. I'm not familiar with PBP but couldn't that be done something like this?
Rich (BB code):
FOR row = 0 TO 3            ' 4 rows in keypad
  PORTB = 0                 ' All output-pins low
  TRISB = (1 << row) ^ $ff  ' Set one row pin to output
  col = PORTB >> 4          ' Read columns
  IF col != $f THEN gotkey  ' If any keydown, exit
NEXT row
Cheerful regards, Mike
 

Thread Starter

FG1

Joined Jun 11, 2010
6
DCD is actually decode...(DCD row) sets the corresponding bit position as indicated by the row value
DCD 0 = 00000001 (for row=0)
DCD 1 = 00000010 (for row=1) and so on..

so this cannot be the problem. i cant really seem to understand the fucntionality of the getkeyu loop.. what is its significance in this program?
 
Top