I'm designing a keypad in VHDL and for protection purposes I disable pressing a second or more keys while one key is being pressed. Example while I'm pressing "7" a press of "2","3","5","4","1","0" etc. will be ignored and no tone will be heard. Each valid key press generates a tone. My keypad is consisting of 3 columns and 4 rows, 12 keys. I have 3 states in my FSM and I scan each column for a valid key press(states: scan_column1, scan_column2, scan_column3). I switch from state to state under the condition when no key is pressed. This way if I am scanning column3, all key presses in column2 and column1 are ignored and unseen. Now I have a final problem lets say I'm pressing "7" , tone of 7 is heard, I'm still holding my finger on "7" and then I press "3", 3 is of course ignored, but I'm still holding "3" and then I release "7", then 3 becomes a valid press and tone of "3" is heard. But 3 is not a new pressed key, it was being pressed while 7 was pressed, so I want to avoid tone generation in this case. Any suggestions? Because this is an ongoing project I can't upload my code 🙁
Key press/Key release
state-machinesvhdl
Related Solutions
I'm not surprised it's not working. Now, I don't know the slightest thing about VHDL, but I do know about programming in general.
Firstly: INDENT YOUR CODE With no indents the code is all but unreadable. Here is your code indented properly:
PORT (
KEY : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
);
SIGNAL A, B, C, D : STD_LOGIC_VECTOR(1 DOWNTO 0);
BEGIN
A <= KEY(0) & KEY(1);
B <= KEY(0) & KEY(2);
C <= KEY(0) & KEY(3);
Readkey: process(KEY)
begin
if (A = 1) then
D <= "00";
if (B = 1) then
D <= "01";
if (C = 1) then
D <= "10";
end if;
end if;
end if;
end process;
Now you can see one major flaw in your code at a glance.
C being 1 will only be tested if B is 1, which itself will only be tested if A is 1. The if
statements shouldn't be nested like that.
Secondly, (again, I don't know VHDL) is how A B and C are being assigned. In a classic programming language you would need to assign the incoming values to A B and C every time you want to test them, otherwise you won't ever see any changes. This may not be the case in VHDL, but it's something to look more closely at.
What you can do is create an idle state, and when you detect a button press you switch straight to the idle. Then you can have a counter in idle which waits for a while before you start scanning buttons again.
For example:
-- include numeric std
signal idle_counter : unsigned(31 downto 0);
...
when state3 =>
case bcd_val is
when "01" =>
Send <= '1';
scannel_val <= "0101";
fsm_state <= idle; -- switch to idle
when "10" =>
Send <= '1';
scannel_val <= "0110";
fsm_state <= idle; -- switch to idle
when others =>
scannel_val <= "0000";
Send <= '0';
fsm_state <= state1; -- carry on scanning
end case;
idle_counter <= (others => '0');
...
when idle =>
if (idle_counter < some_timeout) then -- some_timeout is how long you want to wait (in clock cycles)
idle_counter <= idle_counter + "1"; -- increment counter
fsm_state <= idle; -- stay here
else
idle_counter <= (others => '0'); -- reset counter
fsm_state <= state1; -- go back into checking
end
--scannel_val is valid here, so you can do something with it if you'd like.
...
when others => scannel_val <= "0000";
There is one process in this code you've posted.
It starts with
scan_fsm : process (reset, clk) <= Sensitivity list
begin -- process key_scanner
and ends with
end process scan_fsm;
The clock and reset are part of the sensitivity list. That means that this code is only going to be triggered when either clock changes or reset changes.
De-bouncing can be done in a separate process. Basically, you want to make sure that the button was pressed for a number of microseconds before it triggers. What we want to do is save the value of the input for a number of clock cycles. Then only register a 1 when the history has been constantly 1 for for the past 32 clock cycles.
Example:
-- these are our row inputs (to become bdc_val)
signal row1 : in std_logic;
signal row2 : in std_logic;
...
-- this is our history vector
signal row1_z : std_logic_vector(31 downto 0);
signal row2_z : std_logic_vector(31 downto 0);
-- debounced signal
signal bcd_val : std_logic_vector(1 downto 0);
-- a whole vector of ones for convenience
signal ones : std_logic_vector(31 downto 0);
...
ones <= (others => '1');
-- generate our histories
gen_z : process (reset, clk)
begin
if (reset = '1') then
row1_z <= (others => '0');
row2_z <= (others => '0');
bcd_val <= (others => '0');
elsif (rising_edge(clk)) then
row1_z(31 downto 1) <= row1_z(30 downto 0); -- shift everything up 1
row1_z(0) <= row1; -- save the most recent input
row2_z(31 downto 1) <= row2_z(30 downto 0); -- shift everything up 1
row2_z(0) <= row2; -- save the most recent input
-- we only want bcd_val to be 1 when the entire row history for the past 32 cc is 1
if (row1_z = ones) then
bcd_val(0) <= '1';
else
bcd_val(0) <= '0';
end
if (row2_z = ones) then
bcd_val(1) <= '1';
else
bcd_val(1) <= '0';
end
end
end
Related Topic
- Electronic – Set a constant high signal to low
- Electronic – Pressing same key rows at the same time
- Building a first State Machine circuit – Technical Help
- Keypad Scanner Verilog code problem with state machine and column input
- Electronic – Single input for consecutive state transitions in an FSM: preventing fall-through
- Electrical – VHDL: Detecting key pressed on PS/2 keyboard in FPGA
Best Answer
Define a bit vector that will hold the current state of all buttons. When you detect an edge caused by a press, you update the appropriate bit (set to 1) in the vector. When you detect the other edge caused by a release you update the bit again (back to 0 for example). When you detect a new key press all you need to do is check that the vector is
to find out if this is the only button currently being pressed. If the vector is not all 0's you can decide to do nothing and when the '3' is released you simply update its state in the vector and this does nothing as your code probably does not react to key releases. This way you simply add a single if statement and eliminate the problem. If you had posted some code I might be able to edit it to reflect this mechanism.