PDA

View Full Version : a little help with keypad on 18f4520 please



Dennis
- 19th November 2009, 23:35
Hi there

I'm at wit's end ...

I have been battling to get my matrix keypad(s) working, I have both a 4x3 and a 4x4 keypad.
Two nights ago I stunbled across some postings and code in the forums which looked like they may be what I am looking for (with a few changes perhaps).

After trying out both (namely the one from mister e and Steve) I still have not come right and can't understand what I am doing wrong.

Please see my other posts on mister e's keypad code pages here
http://www.picbasic.co.uk/forum/showthread.php?t=3250&page=3
as well as Steve's on this post(hope cross posting is ok):

http://www.picbasic.co.uk/forum/showthread.php?p=80999#post80999.

With Steve's implemetation I get only a "||" character on the LCD.

Attached is my code.

I am almost convinced I am not setting the registers correctly or calling a variable correctly :-( I was quite happy working with a 16f628 but now that I've re-kindled PIC's as hobby again I decided to go with an 18F series and it's taking some getting used to.

If some kind soul would help me I would really appreciate it.
Comments and suggestion or tips and tricks would be more than welcomed too.

Kind regards

Dennis


'*************************************
'LCD code for 16 X 2 HD4x lcd
'*************************************

'Ocsillator selections here
OSCCON = $70 'Int CLK 8MHz
OSCTUNE.6 = 1 'PLL 4x
ADCON1= %00001111 '$0F = disable A/D converter
'END of oscillator selections


'Port IO directions and presets for port pins begin here
'TRISA = %11111111 'All pins are outputs
'TRISB = %00000000
'for keypad
'// Define port pins as inputs and outputs ...
TRISA = %00001000
TRISB = %00001101
TRISC = %00000000
TRISD = %00000000
TRISE.0 = 0
TRISE.1 = 0
TRISE.2 = 0
'End of Port IO directions and presets for port pins begin here

'timer/oscillator defines
DEFINE OSC 32 '4x 8MHz
'END of timer/oscillator defines

'variables begin here
myvar var byte

'LCD defines begin here
DEFINE LCD_BITS 4 'defines the number of data interface lines (4 or 8)
DEFINE LCD_DREG PORTD 'defines the port where data lines are connected to
DEFINE LCD_DBIT 4 'defines the position of data lines for 4-bit interface (0 or 4)
DEFINE LCD_RSREG PORTD 'defines the port where RS line is connected to
DEFINE LCD_RSBIT 2 'defines the pin where RS line is connected to
DEFINE LCD_EREG PORTD 'defines the port where E line is connected to
DEFINE LCD_EBIT 3 'defines the pin where E line is connected
DEFINE LCD_RWREG 0 'defines the port where R/W line is connected to (set to 0 if not used)
DEFINE LCD_RWBIT 0 'defines the pin where R/W line is connected to (set to 0 if not used)
DEFINE LCD_COMMANDUS 2000 'defines the delay after LCDOUT statement
DEFINE LCD_DATAUS 200 'delay in micro seconds
'END of LCD DEFINES

'keypad code here
'// 3x3 Keypad - Rows as inputs, Cols as outputs...
'Rows: RA3 Cols: RB1
' RB3 RA2
' RB2 RA4
' RB0
'//
' RB5: LED & Buzzer ...
' RA0: TX to PC's Serial Port


'// Declare Variables...
Col_A VAR PORTB.1
Col_B VAR PORTA.2
Col_C VAR PORTA.4

Row_A VAR PORTA.3
Row_B VAR PORTB.3
Row_C VAR PORTB.2
Row_D VAR PORTB.0

Buzzer VAR PORTB.5
RX_To_PC VAR PORTA.0

Scan_Col VAR BYTE ' Counter - denoting current col in scan
Key_Press VAR BYTE ' Contains value of key (0-9) & * + #
Key_Down VAR BYTE ' Flag set true when key is depressed
Allow_Key VAR BYTE ' Flag - disallow multiple keys being pressed
I VAR byte ' General working var

Scan_Keypad:

'// Scan cols
@ incf _Scan_Col, 1 ' Inc col pos...

SELECT CASE Scan_Col ' Col (1-3)

CASE 1
Col_A = 0 ' Switch on col (active low)
Col_B = 1 ' Col off
Col_C = 1 ' Col off

'// 3 Key
IF Row_A = 0 THEN ' Key down? ...
IF Allow_Key = 0 THEN ' Any other key down?
Key_Press = 3 ' Load var w/value of key
Allow_Key = 1 ' Disallow other keys
ENDIF
ENDIF
'// 6 Key
IF Row_B = 0 THEN
IF Allow_Key = 0 THEN
Key_Press = 6
Allow_Key = 1
ENDIF
ENDIF
'// 9 Key
IF Row_C = 0 THEN
IF Allow_Key = 0 THEN
Key_Press = 9
Allow_Key = 1
ENDIF
ENDIF
'// # Key
IF Row_D = 0 THEN
IF Allow_Key = 0 THEN
Key_Press = 35
Allow_Key = 1
ENDIF
ENDIF

CASE 2
Col_A = 1
Col_B = 0
Col_C = 1

'// 2 Key
IF Row_A = 0 THEN
IF Allow_Key = 0 THEN
Key_Press = 2
Allow_Key = 1
ENDIF
ENDIF
'// 5 Key
IF Row_B = 0 THEN
IF Allow_Key = 0 THEN
Key_Press = 5
Allow_Key = 1
ENDIF
ENDIF
'// 8 Key
IF Row_C = 0 THEN
IF Allow_Key = 0 THEN
Key_Press = 8
Allow_Key = 1
ENDIF
ENDIF
'// 0 Key
IF Row_D = 0 THEN
IF Allow_Key = 0 THEN
Key_Press = 0
Allow_Key = 1
ENDIF
ENDIF

CASE 3
Col_A = 1
Col_B = 1
Col_C = 0

'// 1 Key
IF Row_A = 0 THEN
IF Allow_Key = 0 THEN
Key_Press = 1
Allow_Key = 1
ENDIF
ENDIF
'// 4 Key
IF Row_B = 0 THEN
IF Allow_Key = 0 THEN
Key_Press = 4
Allow_Key = 1
ENDIF
ENDIF
'// 7 Key
IF Row_C = 0 THEN
IF Allow_Key = 0 THEN
Key_Press = 7
Allow_Key = 1
ENDIF
ENDIF
'// * Key
IF Row_D = 0 THEN
IF Allow_Key = 0 THEN
Key_Press = 42
Allow_Key = 1
ENDIF
ENDIF
end select
'end keypad code

'*********************Includes******

'Includes end here




Pause 500 ' Wait for LCD to startup

'loop1:
' Lcdout $fe, 1 ' Clear LCD screen
' Lcdout "Hello" ' Display Hello
'Pause 1000 ' Wait .5 second
'Lcdout $fe, $C0 ' Clear LCD screen
'Lcdout "World"
'pAUSE 1000
'Lcdout $fe, 1 ' Clear LCD screen

'Pause 1000 ' Wait .5 second

'Goto loop1 ' Do it forever

'start:
'@ READKEYPAD _myvar
'lcdout $fe, 1
lcdout Key_Press
'goto start

Dennis
- 20th November 2009, 13:17
OKay I have even tried this example
http://www.rentron.com/serkey16.htm
and still get || on my lcd but the display does hange to things like ||| when I press some keys.

I really can't see where I am messing up ... please please could someone help me with this

aratti
- 20th November 2009, 15:27
Tray to use LCDout Dec Key_Press and see if you get the correct ascii value.

Al.

Dennis
- 20th November 2009, 17:31
Thanks Al

I now see numbers and not ||

OK so this is how I am now setup ...
http://www.rentron.com/serkey16.htm
notice there are no pull-ups on the rows.

I have series resistors on for the columns (100 OHM)
In other words KEYPAD >> RESISTOR >> PIC (PortB4-7)
Aah at least I am now seeing characters
When Idle the LCD just displays 4 8 12 and the 16 and then it repeats :-(
What's wrong :-(

My wishlist
A schematic( where to wire the pull-ups and where to wire the pull downs.
I would prefer not to use Port.B since I have the pickit 2 setup for ICSP on PortB.6 and B.7.
So which ports are advisable to use ? How should I TRIS each ?

Some code shows keypad ports as input tohers as output ... some show pull-ups others show no pull-ups ?

This is getting mega confusing :(

Should I just stick with dipswitches and give up on the dream of using a keypad for input ?

Any more help or comments would be seriously appreciated

aratti
- 20th November 2009, 18:22
OK so this is how I am now setup ...
http://www.rentron.com/serkey16.htm
notice there are no pull-ups on the rows.

You don't see any pullup because they are using internal pullup on portB

See the instruction that activate the weak pullup in the code.

OPTION_REG.7 = 0 ' Enable PORTB pull-ups

If you use different port then you have to use external resistors.

Al.

Dennis
- 20th November 2009, 18:38
Hi again Al

Thank you again for the reply :-)

Adding OPTION_REG.7 = 0 ' Enable PORTB pull-ups
Shows a compile error in Microstudio
Does not compile
I am using an 18F4520

So I am back to square one

Any suggestions

Gusse
- 20th November 2009, 19:02
INTCON2.7 = 0 'switch pull-ups ON

"Each of the PORTB pins has a weak internal pull-up. A single control bit can turn on all the pull-ups. This is performed by clearing bit, RBPU (INTCON2<7>). The weak pull-up is automatically turned off when the port pin is configured as an output. The pull-ups are disabled on a Power-on Reset."
(Page 96 on PIC18F4520 (http://ww1.microchip.com/downloads/en/DeviceDoc/39631E.pdf) manual)

BR,
-Gusse-

aratti
- 20th November 2009, 19:08
Adding OPTION_REG.7 = 0 ' Enable PORTB pull-ups
Shows a compile error in Microstudio
Does not compile
I am using an 18F4520

Dennis not all pic has the internal pullup, could be that your mcu has not pullup.
(Check the datasheet).



Since you will need the pullups (otherwise the keypad will not work), so add four external 10K resistors.

Al.

Edit:

Gusse has read the datasheet for you: Replace OPTION_REG.7 = 0 with INTCON2.7 = 0

Dennis
- 21st November 2009, 13:40
Al, Gusse
Thank you both I implemented mister e's keypad using the whole of port B as an input had to perform some pin swaps on row and column order and it's working .
I have two more questions :

1.How do I set the keys to display the correct characters as per the keypad
my matrix key's are labeled is as follows:

1 2 3 A
4 5 6 B
7 8 9 C
* 0 # D

but when I press the keys for example 1,2,3,A
My readout is 1,2,3,4

Would I have to do a lookup or re-assignment ?

2. How do i capture a number ending with a hash for example

The reason I am asking is because I would like to type in a number for example 135 end it with a # to signify an enter and then store and send the number (TX).

Any further help would be appreciated

aratti
- 21st November 2009, 15:09
1 2 3 A
4 5 6 B
7 8 9 C
* 0 # D

but when I press the keys for example 1,2,3,A
My readout is 1,2,3,4

Would I have to do a lookup or re-assignment ?


I am not familiar with mister e's keypad program, but if you get the sequence from 1 to 16, then use an array to code out what you need.



Kp_Array var byte [17]


Kp_Array[1] = "1"
Kp_Array[1] = "2"
.
.
.
Kp_Array[15] = "#"
Kp_Array[16] = "D"




2. How do i capture a number ending with a hash for example

If Kp_Array[keypress] = "#" then ........


Al.

Dennis
- 21st November 2009, 16:55
Thanks again for the tip Al :-)

I was thinking along the same lines although I don't think this is exactly what I'm after.
You see the keypad code only allows for a single keypress at a time at the moment.
So the largest number you can type in is 16 (the highest key on the keypad)
I want to be able to type in a number like 124 and end it with a #
So this number (the actual number 124) can be transmitted.
If you could imagine a cellphone or cordless landline...
As you type in the numbers on the keypad you can see them on the screen and then you press dial or possibly C(clear or *) to backspace one digit.
And when you are happy with the number on screen you press dial (in my case #) then your number is dialled (in my case TX'd)

Does this make sense ?

Kind regards
Dennis

aratti
- 21st November 2009, 19:28
I want to be able to type in a number like 124 and end it with a #
So this number (the actual number 124) can be transmitted.
If you could imagine a cellphone or cordless landline...
As you type in the numbers on the keypad you can see them on the screen and then you press dial or possibly C(clear or *) to backspace one digit.
And when you are happy with the number on screen you press dial (in my case #) then your number is dialled (in my case TX'd)

So that means that now the keypad works correctly, and when you press the wanted key you obtain the correct caracter.

To acheive what you want, you will need an additional array and a few variables:

The array will retain the numbers you key in and a variable should keep track of the number of time you have pressed the keys.

Here a snippet





Ratain var byte
Ret_Char var byte [10]
Ret_Count var byte
Ret_Prnt var byte
Ret_Clst var byte

Ret:Prnt = "#"
Ret_Clst = "*"

Loop:
Ret_Char[Ret_Count]=Key_Char ' here you transfer the char of the key pressed

If Retain = 0 then ' Retain is a flag then if set will do your job
Hserout [Ret_Char[Ret_Count]]
else

If Ret_Char[Ret_Count] = Ret_Clst then ' if key = "*" then step-back counter
Ret_Count = Ret_Count - 1
goto Clear_Count
endif

If Ret_Char[Ret_Count] = Ret_Prnt then ' if key = "#" then send string
Hserout [str Ret_Char \ Ret_count-1]
RetCount = 0
goto Clear_Count
endif
Ret_Count = Ret_Count + 1
Clear_Count:
endif
return



I set the array Ret_Char to 10 elements, if you need more then adjiust it for your need. The snippet is not tested so some adjustment could be necessary.

Al.

Dennis
- 21st November 2009, 19:49
Al

:-)
WOW thank you ... wasn't expecting you to code it for me :-)

The array idea is perfect for capturing the keypresses and also the option to loop until we see a # or *

The code snippet raises a few questions though....

On receipt of a # it sends off a string of characters (those encountered before the #..not so ?
For example I key in 134#
First keypress to first variable in the array [1]
Second to the second variable [3]
Third to third variable [4]

Then the # is encountered and we do an hserout

Will we send a total of a 3 character string using hserout (in other words 24bits)

Apologies if I have the workings of the code wrong ...I am not clued up on the workings of hserout yet but I am reading up.

Once again any suggestions or guidance would be appreciated.

Kind regards

Dennis

aratti
- 21st November 2009, 20:01
Then the # is encountered and we do an hserout

Will we send a total of a 3 character string using hserout (in other words 24bits)



Hserout [str Ret_Char \ Ret_count-1], will send out a string of Ret_count-1 bytes, so "#" will not be sent

You could use SEROUT2

SEROUT2,pin,baud,[str Ret_Char \ Ret_count-1]

or you could use SEROUT

For A0 = 1 to Ret_count-1
Serout pin,baud,[Ret_Char [A0]]
NEXT A0


Al.

Dennis
- 21st November 2009, 20:16
Thanks for hserout clairfying the code and the option for serout2.

Let me re-phrase that last question
"Then the # is encountered and we do an hserout

Will we send a total of a 3 character string using hserout (in other words 24bits)"

So it will be 24 bits ... 134 (0000001 11000000 01000000) as opposed to the 8 bit number 134 (10000110)

I am after a single 8 bit number , at the end of the key capture
(or more depending on whether the number keyed in is larger than 255- perhaps I should cap it at 255).

So perhaps I need to do a little math in the array, perhaps (+) OR-ing ?

Dennis
- 23rd November 2009, 23:23
Hi Al

How are you ?

I am experimenting with your code snippet .. here's what I have so far.


'keypad variables for array keypress capture begin here
Retain var byte
Ret_Char var byte [10]
Ret_Count var byte
Ret_Prnt var byte
Ret_Clst var byte
Ret_Prnt = "#"
Ret_Clst = "*"
'keypad capture code begins here
Ret_Char[Ret_Count]=datatx ' here you transfer the char of the key pressed

If Retain = 0 then ' Retain is a flag then if set will do your job
For A0 = 1 to Ret_count -1
Serout portc.6,T2400,baud,[Ret_Char [A0]]
NEXT A0

lcdout datatx 'display the variable on the LCD
pause 1000
lcdout $fe,1 'clear lcd screen
else

If Ret_Char[Ret_Count] = Ret_Clst then ' if key = "*" then step-back counter
Ret_Count = Ret_Count - 1
goto Clear_Count
endif

If Ret_Char[Ret_Count] = Ret_Prnt then ' if key = "#" then send string
For A0 = 1 to Ret_count -1
Serout portc.6,T2400,[Ret_Char [A0]]
NEXT A0

lcdout datatx 'display the variable on the LCD
pause 1000
lcdout $fe,1 'clear lcd screen
RetCount = 0
goto Clear_Count
endif
Ret_Count = Ret_Count + 1
Clear_Count:
endif
goto start

As i try to compile I encounter an error here
For A0 = 1 to Ret_count -1

Not quite sure why ?

Do you think I could attain the same thing with either a case select statement or a do...while loop ?
So if I were using a do ... while (or while wend) for example
do
keep allowing keypress
While
key_press_variable is not equal to '#" 'until we see #

then serout

Kind regards
Dennis

aratti
- 24th November 2009, 07:54
...... As i try to compile I encounter an error here
For A0 = 1 to Ret_count -1
Not quite sure why ?


Simply because variable A0 has not been declared! Add A0 var Byte to your code.

While wend loop could work as well, if properly structured.

Remember you should place two limits: Ret_Count cannot be greater then the array dimension and # command should be ignored if Ret_Count = 0.

Al.

Dennis
- 24th November 2009, 20:38
Al

I feel a little stupid for missing that obvious one :-)

Will make the change and feedback asap :-)

Stay tuned :-)

And once again thanks for the reply and help :-)

Kind regards
Dennis