PDA

View Full Version : 4x3 keypad



docwisdom
- 13th April 2006, 00:31
First off I would like to thank bruce for this code from his site.



'************************************************* ***********
'* Name : serkey16.bas *
'* Author : Reynolds Electronics *
'* Date : 07/12/2001 *
'* Version : 1.0 *
'* Notes : PicBasic Pro program for 16-key serial keypad *
'************************************************* ***********
INCLUDE "modedefs.bas"

col VAR BYTE ' Keypad column
row VAR BYTE ' Keypad row
key VAR BYTE ' Key value
baud VAR PortA.0 ' Baud select pin
serpin VAR PortA.1 ' Serial output pin
CMCON = 7 ' PortA = digital I/O
VRCON = 0 ' Voltage reference disabled
TRISA = %00000001' PortA.0 = baud select pin
OPTION_REG.7 = 0 ' Enable PORTB pull-ups

loop:
GOSUB getkey 'Get key from keypad
send:
IF baud = 1 THEN fast'If baud = 1 then N9600,else N2400
SEROUT serpin,N2400,[key]'Send key value out PortA.1
GOTO loop
fast:
SEROUT serpin,N9600,[key]
GOTO loop 'Do it forever
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



I would like to use this in only a 12 key configuration. This leaves me with 7 data pins required.
In this code Bruce makes use of all 8 PortB pins. Unfortunately these arent available to me because they are currently being used for HPWM and a parallel LCD.

My question is, with these ports available (no 8 in sequence) how can I modify this code to work.
RA0, RA1, RA2, RA3, RA4, RA5, RB7, RC0, RC4, RC5, RC6, RC7

I am using a 16F767.

Thanks in advance,
-brian

sayzer
- 13th April 2006, 06:53
May I recommend the attached schematic as a solution to your limited pins?

With the attached schematic, pot command can be used to read different values of each button hit. Even the combination of button hits can provide different readings.

The key points are as follows.

1. All resistors must be +/-1% or better tolerance.
2. This application may not be suitable in the environments where ambient temperature changes sharply.
3. “Select Case“command needs to be used to divert the resistor readings.

Example:

Pot porta.0, 255,BtnRead

Select Case BtnRead

Case is >20 and is <25 ‘Actual BtnRead=22, The safe reading range is wider then the resistor tolerance.
Goto Menu1

Case is >26 and is <31 'Actual BtnRead=28
Goto Menu2
.
..

….

End select

4. Resistor values need to be determined experimentally. If the values are too close then the range of one button may intersect with the range of another button.



--------------------------------------------------

mister_e
- 13th April 2006, 12:57
a custom copy/paste solution for any kinda matrix keypad... well max 8X8
http://www.picbasic.co.uk/forum/showthread.php?t=3250

Yeah i know it's code hungry... one day i'll work on it again... one day!

docwisdom
- 13th April 2006, 21:25
mr-e,
thanks for the code, it looks very simple and easy to use, however, it must be a little too complicated for me because I am getting nowhere. Maybe you can find something stupid and obvious, but I cant find it.


here is your code modified to my use


'************************************************* ***************
'* Name : UNTITLED.BAS *
'* Author : [select VIEW...EDITOR OPTIONS] *
'* Notice : Copyright (c) 2006 [select VIEW...EDITOR OPTIONS] *
'* : All Rights Reserved *
'* Date : 4/13/2006 *
'* Version : 1.0 *
'* Notes : *
'* : *
'************************************************* ***************
TRISB = %10000000
ADCON1 = %11111111 'all ports digital

INCLUDE "KeyPad.bas"

'
' Hardware connection
' ===================
DEFINE KEYPAD_ROW 4 ' 8 row
define KEYPAD_ROW_PORT PORTA ' on PORTA
DEFINE KEYPAD_ROW_BIT 0 ' <3:0>
DEFINE KEYPAD_COL 3 ' 3 col
DEFINE KEYPAD_COL_PORT PORTC ' on PORTC
DEFINE KEYPAD_COL_BIT 4 ' <7:4>
DEFINE KEYPAD_DEBOUNCEMS 200 ' debounce delay = 200 mSec
define KEYPAD_AUTOREPEAT 0 ' use auto-repeat

'
' Serial Communication definition
' ===============================
DEFINE LCD_DREG PORTB ' Set LCD Data port
DEFINE LCD_DBIT 0 ' Set starting Data bit (0)
DEFINE LCD_RSREG PORTB ' Set LCD Register Select port
DEFINE LCD_RSBIT 4 ' Set LCD Register Select bit
DEFINE LCD_EREG PORTB ' Set LCD Enable port
DEFINE LCD_EBIT 6 ' Set LCD Enable bit
DEFINE LCD_BITS 4 ' Set LCD bus size (4 or 8 bits)
DEFINE LCD_LINES 2 ' Set number of lines on LCD
DEFINE LCD_COMMANDUS 2000 ' Set command delay time in us
DEFINE LCD_DATAUS 50 ' Set data delay time in us
'
' Variables definition
' ===================
myvar var byte

' ---------------------------------[Program Start]----------------------------------------------
main:
lcdout $fe, 1, "Hello"
pause 500
start:
@ READKEYPAD _myvar
lcdout $fe, 1, "Key=", DEC myvar
goto start
END


I threw the "Hello" in there just to test that it programmed correctly and the LCD is functioning.
When I press any button, it still just says hello. So something in the button config aint workin.

I am using Microcode studio 2.3, PBP2.46, and MPASM.

I have my rows hooked up with 4.7k pullup resistors as you stated and they are pinned to RC4-6. I also have the columns hooked up with 4.7k series resistors (too high a value?) to RA0-3.

thanks again for posting your code.

mister_e
- 14th April 2006, 03:38
In fact you MUST use some low value for column, let's say 100-300 ohms. 4.7K is way too high. The PIC don't detect the LOW level signal. In best case the LOW level will be 2.5 volts... too high for a LOW level signal ;) Refer tosection 18.4 of your datasheet for that.

You can even remove the column resistor and plug it directly... it will work but it's not really recommended.

Another thing, you must disable analog comparator too on PORTA


ADCON1=$0F ' Disable AD converters
CMCON =7 ' Disable analog comparator
About now?

PS: you can remove the DEFINE KEYPAD_AUTOREPEAT line. If you don't write it, the program will set it to off for you. This refer to that section of the include file


@ ifndef KEYPAD_AUTOREPEAT ' If AutoRepeat is not DEFINE
repeat
Gosub readcol ' Wait until
until KeyTemp=keymask ' Key is released
@ endif

docwisdom
- 14th April 2006, 20:06
Thanks very much steve.
I have it running and the keys are being read. I tried using low value resistors on the columns but it didnt work, but low value resistors on the rows and it started reading.

One problem though, The first two rows are working perfect, but the second two rows will change values every time I press the button.
these columns.

The two affected rows are connected to the VREF pins on PORTA, is there a disable config for VREF? or is it default disabled?



one more question also while your peeking at this thread. is there a way to make the auto repeat work only on 2 buttons? Two buttons on my kepad are +- adjustments and all the others are command buttons. It would be great to make the +- buttons autorepeat.

mister_e
- 15th April 2006, 10:06
Did you modify your code and include those lines at the top?


ADCON1=$0F ' Disable AD converters
CMCON =7 ' Disable analog comparator


Comparator voltage reference is suppose to be set to off by default if you refer to the CVRCON POR. AND when you set ADCON1 to 0F, you set VREF- to Vss, VREF+ to VDD... so i can't understand why it doesn't work.



one more question also while your peeking at this thread. is there a way to make the auto repeat work only on 2 buttons? Two buttons on my kepad are +- adjustments and all the others are command buttons. It would be great to make the +- buttons autorepeat

The first thing spring to mind is to set the AUTOREPEAT to ON then read the MyVar value and if it's not one of your two keys... redo the keypad scan until it change.

PS: you're right, i did a mistake, low value resistor must be on ROWs, not colums... DOH!

docwisdom
- 16th April 2006, 02:27
we have operation. thanks very much steve.

it was the ADCON1 register. Do you have any resources to better explain registers and their settings. when I read about them in datasheets is all just a totally different language to me.


I have yet to implement the autorepeat. Ill post again with its results

docwisdom
- 16th April 2006, 03:21
I got my desired repeat with a simple loop comand.

thanks for all your help steve, its been invaluable.

If you feel so inclined, would you mind looking over my code and schematic to check for any changes that could be made for efficiency and design?

thanks
-brian

mister_e
- 16th April 2006, 08:50
You're welcome! Great to know it's working fine now.

No problem, post your stuff here. i'll post my own comments, i hope other will also do it too.



Do you have any resources to better explain registers and their settings. when I read about them in datasheets is all just a totally different language to me.

Sorry, i don't see any other reference. Sure sometimes datasheet are just Chinese to me (or greek depending of your local expression) but by using the trying/debuging/understanding method you'll never find any better reference. The first time is always the hardest... once you hit the wall and bang your head on your keyboard few times, you can't forget it. This is probably why i choosed this picture for my avatar <img src="http://www.picbasic.co.uk/forum/member.php?u=580">