首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

状态机实现的键扫,有问题,恳请大侠帮忙

状态机实现的键扫,有问题,恳请大侠帮忙

 


状态机实现的键扫,程序如下:


 


LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
ENTITY KeyBoard IS
PORT(
 rstn : IN STD_LOGIC;  --reset signal, active low
 clk  : IN STD_LOGIC;  --clock signal


 scan : OUT STD_LOGIC_VECTOR(3 DOWNTO 0); --
 retn : IN STD_LOGIC_VECTOR(3 DOWNTO 0); --


 keyokn : OUT STD_LOGIC;
 keycsn : IN STD_LOGIC;


 keycod : INOUT STD_LOGIC_VECTOR(3 DOWNTO 0)  --key value bus
 );
END KeyBoard;


ARCHITECTURE Behavior OF KeyBoard IS


 SIGNAL setf : STD_LOGIC;
 SIGNAL keyoktmp: STD_LOGIC; 


 SIGNAL s_cnt : STD_LOGIC_VECTOR(1 DOWNTO 0);


 SIGNAL keytmp : STD_LOGIC_VECTOR(3 DOWNTO 0); 


 SIGNAL keycode : STD_LOGIC_VECTOR(3 DOWNTO 0); 


 SIGNAL keysta : STD_LOGIC_VECTOR(3 DOWNTO 0);
 SIGNAL codtmp : STD_LOGIC_VECTOR(5 DOWNTO 0);


BEGIN
 codtmp <= s_cnt & keytmp;
PROCESS(rstn, clk)
 VARIABLE mscnt : INTEGER RANGE 0 TO 99999;--set delay time
BEGIN
 IF clk'EVENT AND clk = '1' THEN
  IF rstn = '0' THEN
   s_cnt  <= "00";
   keysta <= "0000";
   setf   <= '0';
  ELSE
   CASE keysta IS
    WHEN "0000" =>     --idle state
     s_cnt <= "11";
     keysta <= "0001";
     setf   <= '0';
    WHEN "0001" =>     --shift state
     s_cnt <= s_cnt + 1;
     keysta <= "0011";
     setf   <= '0';
    WHEN "0011" =>     --check out any key pressed
     IF retn /= "1111" THEN
      keysta <= "0010";
     ELSE
      keysta <= "0001";
     END IF;
     s_cnt <= s_cnt;
     mscnt := 0;
     keytmp <= retn;
     setf   <= '0';
    WHEN "0010" =>      --delay enough time
     IF mscnt >=  99999 THEN
      keysta <= "0110";
      mscnt := 0;
     ELSE
      keysta <= "0010";
      mscnt := mscnt + 1;
     END IF;
     setf   <= '0';
    WHEN "0110" =>      --check out whether that key changed
         IF retn = "1111" THEN   --if the key released
      keysta <= "0001";
     ELSIF keytmp /= retn THEN  --if the key changed
      keysta <= "0001";
     ELSE
      keysta <= "0111";   --the key is a valid key
     END IF;
     setf   <= '0';
     mscnt := 0;
    WHEN "0111" =>      --wait for key release
     IF retn = "1111" THEN   --normally released
      keysta <= "0101";
     ELSE
      keysta <= "0111";
     END IF;
     mscnt := 0;
     setf   <= '0';
    WHEN "0101" =>      --delay enough time
     IF mscnt >=  99999 THEN
      keysta <= "0100";
      mscnt := 0;
     ELSE
      keysta <= "0101";
      mscnt := mscnt + 1;
     END IF;
     setf   <= '0';
    WHEN "0100" =>
     IF retn = "1111" THEN   --normally released
      keysta <= "1100";
     ELSE
      keysta <= "0001";
     END IF;
     mscnt := 0;
     setf <='0';
    WHEN "1100" =>      --key decode
     keysta <= "1101";
     setf <='0';
     CASE codtmp IS
      WHEN "001110" => keycode <= CONV_STD_LOGIC_VECTOR(1,4);
      ......中间部分译码程序略


      WHEN OTHERS   => keycode <= "1111";
     END CASE;
    WHEN "1101" =>
     keysta <= "0001";
     setf   <= '1';
    WHEN OTHERS =>
     keysta <= "0000";
     setf   <= '0';
   END CASE;
  END IF;
 END IF;
END PROCESS;


PROCESS(s_cnt)
BEGIN
 CASE s_cnt IS
  WHEN  "00" => scan <= "1110";
  WHEN  "01" => scan <= "1101";
  WHEN  "10" => scan <= "1011";
  WHEN OTHERS =>scan <= "0111";
 END CASE;
END PROCESS;


PROCESS(rstn, setf, keycsn)
BEGIN
 IF rstn = '0' OR keycsn = '0' THEN
  keyoktmp <= '1';
 ELSIF setf = '1' THEN
  keyoktmp <= '0';
 ELSE
  keyoktmp <= keyoktmp;
 END IF;
END PROCESS;


 keyokn <= keyoktmp;


 keycod <= keycode WHEN keycsn = '0' ELSE (OTHERS => 'Z'); 
      
END Behavior;


其中keyokn接到单片机外部中断线上,配置为下降沿中断(或低电平中断)


可是发现一个奇怪问题:第一次按键后能正常响应,第二次按键后程序就死机了,好像是第二次按键以后,键盘中断标志没有清除。


可是从程序来看,当按键中断产生后,有把keyoktmp恢复为1啊,不应该出现上面的现象啊?


请大侠们帮忙看看程序,谢谢!


如果可以的话,回邮箱更好,因我本人实在忙,上论坛时间少


chenye_cau@163.com


谢谢

返回列表