Keypad Program

SilentScreamer

Senior Member
I am trying to program an alarm using 28X1 chip for my GCSE Electronics coursework. I am going to try and use a reprogrammable 4 digit code and a keypad. I've already made the code below but haven't made a prototype yet (I'm still awaiting delivery of the chip ect.), so I'm uncertain if the code works (it seems to when I simulate it). Assuming it does, is there anyway I can reduce the size of the code? Else if anyone knows anything that will not work could I have suggestions on alternative methods of doing it?

Code:
NewPassChar1:
	'Check column 1
	let pins=%00000001
	if pin0=1 then
		let b0=1
		goto NewPassChar2
		endif
	if pin1=1 then
		let b0=4
		goto NewPassChar2
		endif
	if pin2=1 then
		let b0=7
		goto NewPassChar2
		endif
	'Check column 2
	let pins=%00000010
	if pin0=1 then
		let b0=2
		goto NewPassChar2
		endif
	if pin1=1 then
		let b0=5
		goto NewPassChar2
		endif
	if pin2=1 then
		let b0=8
		goto NewPassChar2
		endif
	if pin3=1 then
		let b0=0
		goto NewPassChar2
		endif
	'Check column 3
	let pins=%00000100
	if pin0=1 then
		let b0=3
		goto NewPassChar2
		endif
	if pin1=1 then
		let b0=6
		goto NewPassChar2
		endif
	if pin2=1 then
		let b0=9
		goto NewPassChar2
		endif
	'Loop
	goto NewPassChar1
'                                                      Charactor Two
NewPassChar2:
	'Check column 1
	let pins=%00000001
	if pin0=1 then
		let b1=1
		goto NewPassChar3
		endif
	if pin1=1 then
		let b1=4
		goto NewPassChar3
		endif
	if pin2=1 then
		let b1=7
		goto NewPassChar3
		endif
	'Check column 2
	let pins=%00000010
	if pin0=1 then
		let b1=2
		goto NewPassChar3
		endif
	if pin1=1 then
		let b1=5
		goto NewPassChar3
		endif
	if pin2=1 then
		let b1=8
		goto NewPassChar3
		endif
	if pin3=1 then
		let b1=0
		goto NewPassChar3
		endif
	'Check column 3
	let pins=%00000100
	if pin0=1 then
		let b1=3
		goto NewPassChar3
		endif
	if pin1=1 then
		let b1=6
		goto NewPassChar3
		endif
	if pin2=1 then
		let b1=9
		goto NewPassChar3
		endif
	'Loop
	goto NewPassChar2
'                                                    Charactor Three
NewPassChar3:
	'Check column 1
	let pins=%00000001
	if pin0=1 then
		let b2=1
		goto NewPassChar4
		endif
	if pin1=1 then
		let b2=4
		goto NewPassChar4
		endif
	if pin2=1 then
		let b2=7
		goto NewPassChar4
		endif
	'Check column 2
	let pins=%00000010
	if pin0=1 then
		let b2=2
		goto NewPassChar4
		endif
	if pin1=1 then
		let b2=5
		goto NewPassChar4
		endif
	if pin2=1 then
		let b2=8
		goto NewPassChar4
		endif
	if pin3=1 then
		let b2=0
		goto NewPassChar4
		endif
	'Check column 3
	let pins=%00000100
	if pin0=1 then
		let b2=3
		goto NewPassChar4
		endif
	if pin1=1 then
		let b2=6
		goto NewPassChar4
		endif
	if pin2=1 then
		let b2=9
		goto NewPassChar4
		endif
	'Loop
	goto NewPassChar3
'                                                     Charactor Four
NewPassChar4:
	'Check column 1
	let pins=%00000001
	if pin0=1 then
		let b3=1
		goto Main
		endif
	if pin1=1 then
		let b3=4
		goto Main
		endif
	if pin2=1 then
		let b3=7
		goto Main
		endif
	'Check column 2
	let pins=%00000010
	if pin0=1 then
		let b3=2
		goto Main
		endif
	if pin1=1 then
		let b3=5
		goto Main
		endif
	if pin2=1 then
		let b3=8
		goto Main
		endif
	if pin3=1 then
		let b3=0
		goto Main
		endif
	'Check column 3
	let pins=%00000100
	if pin0=1 then
		let b3=3
		goto Main
		endif
	if pin1=1 then
		let b3=6
		goto Main
		endif
	if pin2=1 then
		let b3=9
		goto Main
		endif
		'Check column 3
	let pins = %00000000
	'Loop
	goto NewPassChar4
EDIT: I have my Keypad connected so that the columns are connected to Inputs 0-2 and the rows connected to Outputs 0-3
 

bgrabowski

Senior Member
There is an example of compact coding for a keypad in the Keypad Lock example project. It can be found amongst the example projects in programming editor help.
 

inglewoodpete

Senior Member
SS, From your code you will see that each digit being input is causing the size of your code the jump radically with each additional digit. You will also have noticed that reading the keypad is the same for each digit: only the storage location for each digit changes.

So you can make use of the subroutine concept: where a common piece of code can be reused over and over for slightly different purposes. Eg Get digit #1, Get Digit #2 etc.

You will see that you need to set only 1 of 4 outputs (0-3) and then read 3 inputs (0-2), ensuring that 1 and only 1 input is 'active'. So the range of ouput values will be '0000' (no columns active), and 0001, 0010, 0100 & 1000 (to activate each column in turn). Each time a single column is activated, the PICAXE would read all 3 input lines, check that only 0 or 1 lines are active and if so, store the value. Valid 'read' codes would be '000' (no keys pressed), 001, 010 and 100.

If you were to combine these two values (output and input), you can see that you could have a 7-bit pattern which is valid only when 2 bits are set to 1.

At this point, have a look at the operators "AND", "OR" and "*" (multiply) and "pins"

Multiply (and divide) is(are) very useful when doing binary manipulation. A binary value of %0001 multiplied by 2 gives %0010. Similarly, a binary value of %0001 multiplied by 4 gives %0100. ...and by 8 gives %1000. So, a bit pattern can be "shifted" left by multipying by 2, 4, 8 etc. Similarly, a bit pattern can be "shifted" right by dividing by 2, 4, 8 etc.

I'm out of time, I have a bus to catch. I hope this gives you a clue or 2 on using bit manipulation to reduce the size of your code. If this doesn't make sense yet, ask more questions: other will help. Hopefully, they won't do your project for you, though :)

Peter
 

westaust55

Moderator
A bit more explanation on how to get to the keypad lock example project.

With the Program Editor running and a program window open,
From the toolbar select Help / Picaxe Catalogue.

A small window will pop up. At the bottom right of that window is a button labeled "Exemplar Projects".

Click that button and you see a list of projects. Select the Keypadlock project and connect which will open the pdf file for that project. The pdf includes a program listing for a keypad such as you are using.

This uses subroutines as Inglewoodpete has mentioned.

Suggest that you also have a read in the PICAXE manual 2 about GOSUB and RETURN commands as these are the key comamnds for subroutines.
 
Last edited:

SilentScreamer

Senior Member
Thanks all,

I have looked at the example project and I've spent a little time trying to understand it and think I just about do and I think I have also worked out how to apply the same idea to a reprogrammable code. However for now the keypad is going onto the back burner as my LCD Firmware chip has arrived with my screen and the keypad and my PICAXE chip is still yet to arrive (being purchased via school so its going to be a fair while yet).

As for any concerns about me having someone do my project for me I'm not interested, my only interest in seeing example code is from past experience learning Visual Basic and ActionScript 3 which seeing code and "playing" with it is what taught me. However as this is GCSE I'm not going to be adapting code (as I only ever have done with VB) I'm going to be writing it taking only concepts from existing code (as I do with ActionScript as its for GCSE ICT).

So I will probably post my code If it has any issues with running, or I may do anyway to see if they're are any mistakes that don't affect the code's function but for now I am going to be breadboarding my LCD screen (my mums going to flip at all the bits spread over my bedroom) and testing it on a 8 pin PIC.

Until my next problem...
 

westaust55

Moderator
I like the idea but could it be applied to a keypad setup in a 3X4 matrix such as this one?
While the suggested key input circuit using an analogue input will work it cannot be used with a pre-wired/configured key matrix such as that which you have/reference.
As per the previously mentioned Exemplar projects, that uses a matrix type keypad.
An alternative is saving memory (and maybe some speed in fast applications) does become a priority with a “smaller” PICAXE is to consider a 74C922 (16 key) or 74C923 (20 key) encoder chip. Still needs as many IO but does some of the logic onboard so you get a binary number with less decoding.
 

SilentScreamer

Senior Member
While the suggested key input circuit using an analogue input will work it cannot be used with a pre-wired/configured key matrix such as that which you have/reference.
As per the previously mentioned Exemplar projects, that uses a matrix type keypad.
An alternative is saving memory (and maybe some speed in fast applications) does become a priority with a “smaller” PICAXE is to consider a 74C922 (16 key) or 74C923 (20 key) encoder chip. Still needs as many IO but does some of the logic onboard so you get a binary number with less decoding.
I think I shall keep to original idea with wiring the keypad directly to the PICAXE chip as speed and memory shouldn't become an issue and also my teacher is against me using my LCD Driver chip, i think two extra chips may cause him to stop me from using any additional chips (other than decade counters and 555 timers which I think are pointless with a PICAXE chip)
 

BCJKiwi

Senior Member
@ Westy;

Actually the 'one wire' readADC type analysis can be applied to matrix type keypads just as successfully as discrete keys.

The added complication with matrix keypads is the resistor values have to be carefully selected but there is an Excel spreadsheet calculator to assist with this and there are simple 'near enough' approaches if there are not too many keys.

see here;

http://www.picaxeforum.co.uk/showthread.php?t=7791
 

westaust55

Moderator
One Wire Keypad using Matrix

Thanks BCJ.

A different format to that proposed by Jon Henry but useful to know a matrix format will work.
 

SilentScreamer

Senior Member
While the suggested key input circuit using an analogue input will work it cannot be used with a pre-wired/configured key matrix such as that which you have/reference.
As per the previously mentioned Exemplar projects, that uses a matrix type keypad.
An alternative is saving memory (and maybe some speed in fast applications) does become a priority with a “smaller” PICAXE is to consider a 74C922 (16 key) or 74C923 (20 key) encoder chip. Still needs as many IO but does some of the logic onboard so you get a binary number with less decoding.
I think I shall keep to the original plan of using 7 I/O pins, my alarm doesn't require that many pins, I'm only using the 28X1 for the additional storage the chip has.

One question though, when using sub routines how many can I return back from if this makes sence?
 

SilentScreamer

Senior Member
I've managed to get chance to rewrite my code. Is this more efficient(and hopefully still functional)?

Code:
'*****Symbols*****

symbol PassEnter_Temp = b0 'The digit currently being entered
symbol Pass_1 = b1 'The first digit of the password
symbol Pass_2 = b2 'The second digit of the password
symbol Pass_3 = b3 'The third digit of the password
symbol Pass_4 = b4 'The fourth digit of the password
'symbol ** = b5
'symbol ** = b6
'symbol ** = b7
'symbol ** = b8
'symbol ** = b9



'******************
'****Procedures****
'******************

'*****Initiate*****
Alarm_Initiate:
	goto New_Pass

'*****Standby******
Alarm_Standby_Init:
	goto Alarm_Standby
Alarm_Standby:
	goto Alarm_Standby

'***New Password***
New_Pass:
	'Clear the LCD Display and set the text to "New Password"
	gosub Serout_Clear
	gosub Serout_NewPass
	'1st Digit
	gosub Charactor_Scan 'Goto the charactor entry sub routine
	let Pass_1 = PassEnter_Temp 'Set digit 1
	gosub Serout_1Star
	'2nd Digit
	gosub Charactor_Scan 'Goto the charactor entry sub routine
	let Pass_2 = PassEnter_Temp 'Set digit 2
	gosub Serout_2Star
	'3rd Digit
	gosub Charactor_Scan 'Goto the charactor entry sub routine
	let Pass_3 = PassEnter_Temp 'Set digit 3
	gosub Serout_3Star
	'4th Digit
	gosub Charactor_Scan 'Goto the charactor entry sub routine
	let Pass_4 = PassEnter_Temp 'Set digit 4
	gosub Serout_4Star
	goto Alarm_Standby_Init



'******************
'**Sub-Procedures**
'******************

'**Enter Password**


'***LCD Messages***
Serout_Clear:
	'Set the top row of the LCD to "New Password:"
	serout 7,T2400,(254,1) 'Clear the LCD Display
	pause 30 'Pause to allow the screen to clear
	return

Serout_NewPass:
	serout 7,T2400,(254,128,"New Password:") 'Set the top row text
	pause 30 'Pause to allow the screen to set text
	return
	
Serout_1Star:
	serout 7,T2400,(254,192,"*") 'Set the bottom row text
	pause 1000 'Pause to allow the screen to set text
	return

Serout_2Star:
	serout 7,T2400,(254,192,"**") 'Set the bottom row text
	pause 1000 'Pause to allow the screen to set text
	return

Serout_3Star:
	serout 7,T2400,(254,192,"***") 'Set the bottom row text
	pause 1000 'Pause to allow the screen to set text
	return

Serout_4Star:
	serout 7,T2400,(254,192,"****") 'Set the bottom row text
	pause 1000 'Pause to allow the screen to set text
	return


'**Charactor Scan**
Charactor_Scan:
	'Check column 1
	let pins=%00000001
	if pin0=1 then
		let PassEnter_Temp=1
		return
		endif
	if pin1=1 then
		let PassEnter_Temp=4
		return
		endif
	if pin2=1 then
		let PassEnter_Temp=7
		return
		endif
	'Check column 2
	let pins=%00000010
	if pin0=1 then
		let PassEnter_Temp=2
		return
		endif
	if pin1=1 then
		let PassEnter_Temp=5
		return
		endif
	if pin2=1 then
		let PassEnter_Temp=8
		return
		endif
	if pin3=1 then
		let PassEnter_Temp=0
		return
		endif
	'Check column 3
	let pins=%00000100
	if pin0=1 then
		let PassEnter_Temp=3
		return
		endif
	if pin1=1 then
		let PassEnter_Temp=6
		return
		endif
	if pin2=1 then
		let PassEnter_Temp=9
		return
		endif
	goto Charactor_Scan
Also can I use a symbol to do "serout LCD_Driver" instead of "serout 7"?

EDIT: Another question how can I make the below code work (I hope you can see what im trying to do)

Code:
if b0 != b1
 
Last edited:

westaust55

Moderator
One question though, when using sub routines how many can I return back from if this makes sence?
Have a look at Manual 2 page 47.

There is a table there showing how many GOSUB commands are permitted depending upon the PICAXE "size".

There is also a limit (mentioned on the same page) as to how deep/many Gosubs can be nested. That is one GOSUB within another subroutine, etc
 

SilentScreamer

Senior Member
Have a look at Manual 2 page 47.

There is a table there showing how many GOSUB commands are permitted depending upon the PICAXE "size".

There is also a limit (mentioned on the same page) as to how deep/many Gosubs can be nested. That is one GOSUB within another subroutine, etc
PICAXE-28X1 / 40X1
gosub - 255
Interrupts - 1
Stack - 8

I assume this means that my 28X1 chip can have a total of 255 subroutines and i can use gosub upto 8 times without having to return?
 

atharvai

Senior Member
just a thought on you code.
where you print * to the LCD instead of using 4 diff subroutines can you use just one subroutine and use on of you spare variables to store the character position.

Code:
Serout_Star:
        ' can use b5. increment everytime number is pressed and then change the serout slightly
	serout 7,T2400,(254,192+b5,"*") 'Set the bottom row text
	pause 1000 'Pause to allow the screen to set text
	return
You can then call this one sub routine again and again. increment you b5 at the end of Character_scan.
just check that 192+b5 actually will compile in the serout line.
 

westaust55

Moderator
PICAXE-28X1 / 40X1
gosub - 255
Interrupts - 1
Stack - 8

I assume this means that my 28X1 chip can have a total of 255 subroutines and i can use gosub upto 8 times without having to return?
correct.


=====================================================
hmmm - tried for my shortest answer ever :)
and the system says I must have 10 or more character so here they are. :D
 

SilentScreamer

Senior Member
just a thought on you code.
where you print * to the LCD instead of using 4 diff subroutines can you use just one subroutine and use on of you spare variables to store the character position.

Code:
Serout_Star:
        ' can use b5. increment everytime number is pressed and then change the serout slightly
	serout 7,T2400,(254,192+b5,"*") 'Set the bottom row text
	pause 1000 'Pause to allow the screen to set text
	return
You can then call this one sub routine again and again. increment you b5 at the end of Character_scan.
just check that 192+b5 actually will compile in the serout line.
It wont compile, complains about a syntax error, I think this is because the 192 is telling the LCD screen to display it on the bottom row adding to it would only tell it to do a different function, and my driver specification sheet thing says that 192 is the highest number it accepts.
 

Technical

Technical Support
Staff member
serout 7,T2400,(254,192+b5,"*") 'Set the bottom row text

is wrong syntax, you can't use addition within the serout data
you need something like

b13 = 192 + b3
serout 7,T2400,(254,b13,"*") 'Set the bottom row text
 

SilentScreamer

Senior Member
serout 7,T2400,(254,192+b5,"*") 'Set the bottom row text

is wrong syntax, you can't use addition within the serout data
you need something like

b13 = 192 + b3
serout 7,T2400,(254,b13,"*") 'Set the bottom row text
Working now thanks all who helped.

How can I make this code work?

if b0 != b1

I want to be able to use it to compare my password that has been programmed with the character just entered. I am using if not because I will get it to cancel checking the pass then.
 
Last edited:

SilentScreamer

Senior Member
Thanks thats working now.

Another question though (sorry :() Is it possible to use let pins and tell it to keep some pins at the existing state (without using variables I mean, if the only way is to use variables then it'll be simpler to use several pin x = )?

E.g.
let pins = %----0101
Where dashes are pins that keep there current state and only pin 0-3 changes
 

eclectic

Moderator
SS
First, have a look at Manual 2, page 19

Then run this program in the Simulator.

Code:
#picaxe 20m

main:
b1 = pins

b1 = b1 AND %00001111

outpins = b1

pause 1000
goto main
Thirdly, try changing "AND" to say "OR", "NOT", and so on.

Fourth, change the values within "00001111"

e
 

SilentScreamer

Senior Member
SS
First, have a look at Manual 2, page 19

Then run this program in the Simulator.

Code:
#picaxe 20m

main:
b1 = pins

b1 = b1 AND %00001111

outpins = b1

pause 1000
goto main
Thirdly, try changing "AND" to say "OR", "NOT", and so on.

Fourth, change the values within "00001111"

e
Right so just to make my testing is correct

To get a high in the final variable:
AND - Requires both to be high
OR - Requires at least one to be high
XOR - Requires on to be high but not both
NOR - Requires both to be low
XNOR - Requires them to both be the same
ANDNOT - Requires first one to be low and second one to be high

To get a low in the final variable:
NAND - Requires both to be high
ORNOT - Requires first to be low and the second to be high

Also NOT won't compile.

I'm still unsure however how I can use this to only change specific bits and not others though?
 

eclectic

Moderator
I'm impressed. Sunday morning homework.

Now, have a look at the program again.
Watch what happens, in the simulator, to

pins 7 - 4 and to pins 3 - 0

when you change inputs.

Both the "picture" and the b1 values.

e
 
Last edited:

SilentScreamer

Senior Member
Ahh I didn't see that because I changed your code to this to make it easier to work out what the functions did.

Code:
#picaxe 20m

main:
let b1 = 		%01010000
let b2 = 		%01001111

b1 = b1 AND b2

outpins = b1

pause 1000
goto main
My only problem is this method loses any existing outputs I have. If pin 7 lets say is high I need it to stay high and add pin 0-2 to be high as well and pin 3 to be low. The only way I can see to do this is to do:

let pin0 = 1
let pin1 = 1
let pin2 = 1
let pin3 = 0

But I know this wastes space on my chip is there another way?
 
Top