1. DESIGN
The following contents describe the design of a 12-button Princess Auto Keypad decoder. The purpose of designing the keypad decoder is to devise a logic machine to detect the status of all 12 buttons (i.e. button pressed or released) at the same time through only 9 I/O provided by the keypad. This decoder will provide easier integration of the keypad to other digital logic system.
The following diagram displays the circuitry of a 12-button Princess Auto Keypad.
Click here for the image
Description of the circuit by example:
When button#1 is pressed: line B and line 3 is connected together.
When button#1 is released: line B and line 3 is not connected together.
Button#1 is only associated with line B and line 3.
The label "B3" next to the button#1 specifies that line B and line 3 is connected together when the button is pressed.
The decoder should be able to detect the present of a pressed key and send out a
signal which specifies what key is pressed. The following block diagram illustrates the I/O pins of the decoder and its interfacing with the keypad.
The only assumption made here for the decoder design is that no two keys are pressed at the same time. That is, no key-combinations because they will complicate the design a lot.
1.2.2 Design of the Keypad Interfacing
The following diagram show the I/O interfacing design between the Keypad and the Decoder.
Click here for the actual connection
Key Pressed | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | | ¯ |
Line connected | A,3 | B,3 | A,4 | B,4 | A,5 | B,5 | A,6 | B,6 | A,7 | B,7 | A,8 | A,9 |
From the above table, for example, when key "8" is pressed, the line "A" and line "7" as shown on the diagram are connected together. Normally when no key is pressed, line "3" to line "9" are all grounded to zero and the "KeyIn" port of the decoder will read "0000000". If the decoder applied a high signal (logic 1) to pin "A" while the user pressed the key "8", then the decoder will read on its "KeyIn" port a signal "0000100". That is, the pin "7", which is connected to pin "A" when the key "8" is pressed, will be pulled up to a high signal (logic 1). To detect the keys "1", "3", "5", "7" and "9", the decoder should apply a high signal (logic 1) to pin B and waits to see if it reads any bit '1' on its "KeyIn" port. For example, when key "9" is pressed while pin B is high, the decoder should read "0000100" on its "KeyIn" port.
Assuming no two keys being pressed at the same time, the decoder can alternately send a high signal and a low signal to its pin "A" and "B" in regular time interval. For example, when "A" is "high", "B" should be "low". Then the next cycle will be "B" connected to "high", while "A" is "low". This cycling can be regulated by sending a clock signal to the decoder. Therefore, when a user pressed a key, the decoder will eventually detect a "high" bit on its "KeyIn" port. During that instant, the decoder will check to see whether "A" or "B" is "high" to determine what key is begin pressed, and it waits until the key is released before it goes to the next scanning cycle.
There is no better way to test the circuit design than to build a prototype circuit and test it physically. However, we can still validate the circuit design methodology by simulating the design in the Altera Max+Plus II software package.
The main concern when designing this circuit is that whether the user will usually press a button long enough, such that the decoder is fast enough to detect the present of a key and determine what key is being pressed before the user releases the key. However, a normal human will usually press a key for at least some milliseconds before he/she releases it. Therefore, as long as the clock signal applied to the decoder has a period that is much smaller than 1 millisecond, the decoder should be able to finish its "job" before users release a key. The enclosed "Registered Performance" chart (next page) from circuit simulation verified that indeed the circuit's clock period is much smaller than 1 millisecond--the circuit requires a minimum clock period of 8ns.
The next concern is that how to simulate the pressing of a keypad button(12 buttons in total) when only 7 pins (pin 3 to pin 9 of the keypad) is available for input to the decoder in the simulation. For example, how to simulate the pressing of button "8" by setting the bits of pin 3 to pin 9 of the keypad appropriately. We know that button "8" is associated with pin 7 (or KeyIn(2) on the decoder), however, button "9" is also associated with pin7. Whether button "8" or button "9" is pressed depends on whether pin "A" or pin "B" is connected to pin 7 at that time. Therefore, we can only set the pin 7 to high (or KeyIn(2) on the decoder) during the "A-scanning" cycle to test for the button "8". When testing for button "9", we set the pin 7 to high(or KeyIn(2) on the decoder) during the "B-scanning" cycle. A/B-scanning cycle means pin "A" is "high" and pin "B" is low" or vice versa.
3. VHDL Code:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity keypad is --princess auto keypad
port(
keyin: in std_logic_vector (6 downto 0); --pin 3 to pin 9 on keypad
a,b: out std_logic; --pin A and pin B on keypad
clock,reset: in std_logic;
keyout: out std_logic_vector (11 downto 0)); -- active low output
end entity;
--key: 0 1 2 3 4 5 6 7
8 9 up down
-- a6 b6 a5 b5 a4 b4
a3 b3 a2 b2 a1 a0
architecture structure of keypad is
signal deb_key: std_logic_vector (6 downto 0); --debounced keyin
signal a_detect,b_detect: std_logic; --row A detected a key, row B
detected a key
signal deb_reset,keyPress: std_logic; --keyPress: a key is pressed,
deb_reset: for resetting the debounce circuit
type statetype is (initialize,scan_a,scan_b);
signal state, next_state: statetype;
begin
--debounce circuit (combinational part)
--set/reset active low flipflop, use "keyin" to set, and "deb_reset"
to reset the ff.
--with asychronous reset
deb_key(6) <= ((deb_key(6) nand keyin(6)) nand deb_reset) or reset;
deb_key(5) <= ((deb_key(5) nand keyin(5)) nand deb_reset) or reset;
deb_key(4) <= ((deb_key(4) nand keyin(4)) nand deb_reset) or reset;
deb_key(3) <= ((deb_key(3) nand keyin(3)) nand deb_reset) or reset;
deb_key(2) <= ((deb_key(2) nand keyin(2)) nand deb_reset) or reset;
deb_key(1) <= ((deb_key(1) nand keyin(1)) nand deb_reset) or reset;
deb_key(0) <= ((deb_key(0) nand keyin(0)) nand deb_reset) or reset;
keyPress <= not ((((((deb_key(6) and deb_key(5)) and deb_key(4)) and deb_key(3)) and deb_key(2)) and deb_key(1)) and deb_key(0));
--debounce circuit (delay part)
--once a key is pressed ("KeyPress" = '1') then set "deb_reset" = '1',
delay 1ms, then set "deb_reset" = '0'
delay: process(keyPress,clock,reset)
variable count: std_logic_vector(14 downto 0):=(others => '0');
begin
if reset = '1' then
deb_reset <= '1';
elsif rising_edge(clock)
then
if keyPress = '1' then
if count = "110001001010111" then
deb_reset <= '0';
count:= "000000000000000";
else
deb_reset <= '1'; -- a key is being pressed
count := count + 1;
end if;
else
count:= "000000000000000";
end if;
end if;
end process;
--detect what key is being pressed---- a key on the "a" row or a key
on the "b" row
--if an "a" row key is detected then "a_detect" = '1'
--if a "b" row key is detected then "b_detect" = '1'
detect_key: process (state,keyPress)
begin
case state is
when initialize =>
a <= '1';
b <= '1';
a_detect <= '1';
b_detect <= '1';
next_state <= scan_a;
when scan_a =>
b <= '1';
a <= '0';
if keyPress = '1' then
a_detect <= '0';
next_state <= scan_a;
else
a_detect <= '1';
next_state <= scan_b;
end if;
when scan_b =>
a <= '1';
b <= '0';
if keyPress = '1' then
b_detect <= '0';
next_state <= scan_b;
else
b_detect <= '1';
next_state <= scan_a;
end if;
end case;
end process;
clocking: process (clock,reset)
begin
if reset = '1' then
state <= initialize;
elsif rising_edge(clock)
then
state <= next_state;
end if;
end process;
--key: 0 1 2 3 4 5 6 7
8 9 up down
-- a6 b6 a5 b5 a4 b4
a3 b3 a2 b2 a1 a0
-- determine which key is being pressed
keyout <= "011111111111" when
(deb_key(6) nor a_detect) = '1' else --0
"101111111111" when (deb_key(6) nor b_detect) = '1' else --1
"110111111111" when (deb_key(5) nor a_detect) = '1' else --2
"111011111111" when (deb_key(5) nor b_detect) = '1' else --3
"111101111111" when (deb_key(4) nor a_detect) = '1' else --4
"111110111111" when (deb_key(4) nor b_detect) = '1' else --5
"111111011111" when (deb_key(3) nor a_detect) = '1' else --6
"111111101111" when (deb_key(3) nor b_detect) = '1' else --7
"111111110111" when (deb_key(2) nor a_detect) = '1' else --8
"111111111011" when (deb_key(2) nor b_detect) = '1' else --9
"111111111101" when (deb_key(1) nor a_detect) = '1' else --up
"111111111110" when (deb_key(0) nor a_detect) = '1' else --down
"111111111111";
end structure;
Edward Wong | ecw@ualberta.ca |
Edgar Wong | edgar@ualberta.ca |
Howard Shum | kshum@ualberta.ca |
Patrick Li | pwli@ualberta.ca |