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

状态机实现的键扫,出现奇怪问题,恳请各位朋友帮忙

状态机实现的键扫,出现奇怪问题,恳请各位朋友帮忙


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


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


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


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


 

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

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

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

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

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

谢谢 
[em13][em13][em13]

状态机内部不可以跑计数器的

WHEN "0001" =>     --shift state
     s_cnt <= s_cnt + 1;--计数器哦
     keysta <= "0011";
     setf   <= '0';

而且你发表的地方有问题啊
返回列表