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

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

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

用状态机实现的4x4键扫,当有键按下时产生一个按键中断,在中断中再读按键的键值


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';有键按下时,中断标志为0
 ELSE
  keyoktmp <= keyoktmp;
 END IF;
END PROCESS;


 keyokn <= keyoktmp;有键按下时,产生一个下降沿,触发外部中断


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


 

现在出现的问题是:
第一次按下按键,程序是正常运行的,键值也正确,可是第二次按下按键,却发现程序死机了,好像是因为第二次按键以后,
中断标志没有清除,所以处理器一直响应中断的缘故,而且第二次无论按下什么按键,读出的键值都和第一次按键相同

事实上,从程序上看,我有清中断标志啊,为什么会出现上面的现象

请各位大侠帮忙,困扰多时,实在不解

如果不麻烦的话,请回邮箱:chenye_cau@163.com

最近很忙,上论坛少,见谅

谢谢
程序太长了,看了一遍,还觉得乱.
能把仿真图形贴出来吗?
看仿真波形没问题啊
中断能产生
奇怪

程序设计思路:
使用行扫描法,判断有没有键盘
当识别到有键按下时,延时消抖,即延时一段时间如10ms后再看是不是有键按下,如果是说明是一次有效按键
然后译码
在释放按键时也进行按键消抖,以避免一次长时间按键当作多次按键

如果有键按下,则产生一个下降沿中断,同时把键值锁存到寄存器
当MCU来读时,就把寄存器里的值打到数据总线上

各位朋友帮忙看看,中断老有问题。

即第一次中断能正常响应,第二次以后中断线一直为低,即好像中断一直产生

所以程序死机

谢谢先
哪位大侠耐心帮我看看,谢谢
返回列表