附录
end if; else disp<='0'; end if; end if; end process;
stop_sec<=a_sec; stop_min<=a_min; stop_hour<=a_hour; end behave;
(4) 按键消抖
本模块用于当有按键按下时,采用软件消抖的办法去除按键抖动。模块的实现方法是先判断是否有按键按下,如有按键按下则延时一段时间,待抖动过去之后再读行线状态,如果仍有低电平行线,则确定有按键按下,然后产生一个有按键按下的信号。该模块有一个时钟输入端口,输入时钟信号是分频出来的1KHZ的时钟;有一个输入端口与行线相连,用于输入行线状态;一个输出端口,用于输出有按键按下的信号。该模块的逻辑框图如图4-6所示。
图4-6 去抖逻辑框图
该电路的VHDL程序如下: library ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity qudou is
port(clk1:in std_logic;
row:in std_logic_vector(3 downto 0); key_pre:out std_logic); end qudou;
architecture behav of qudou is
signal sig1,counter:std_logic_vector(3 downto 0); signal tmp1,sig2:std_logic; begin
sig1<=row;
tmp1<=sig1(0)and sig1(1)and sig1(2)and sig1(3);
key_pre<=counter(0)and counter(1)and counter(2)and counter(3); process(clk1) begin
if(clk1'event and clk1='1')then if(tmp1='0')then if(sig2='0')then
27
附 录
sig2<='1'; end if; end if;
if(sig2='1')then
if(counter=\ sig2<='0';
counter<=\ else
counter<=counter+'1'; end if; end if; end if;
end process; end behav;
(5) 键扫描模块
键扫描模块的框图如图4-7所示。
图4-7 按键扫描模块
CLKY为输入时钟,该时钟是分频模块分出的4MHZ的时钟信号,之所以在这里采用频率高的时钟信号就是因为键扫描是一个快过程,不需要太慢的时钟。Key_pre是由去抖模块输出的有键按下的信号,这个信号引发按键扫描模块内部信号的变化,在该状态信号的作用下,模块可以键盘扫描。
ROW[3..0]是行输入信号,与键盘的行线相连,COM[3..0]是列输出信号,与键盘的列线相连。
SCAN_CODE[7..0]是扫描的键码输出端口。
键扫描的基本方法是将列线逐一置成低电平,然后读行线输入端口,如果行线中有低电平出现,说明按键已经确定,将行向量和列向量读入键码中即可。键盘扫描程序如下:
library ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity ajsm is
port(clky,key_pre:in std_logic;
row:in std_logic_vector(3 downto 0); com:out std_logic_vector(3 downto 0);
scan_code:out std_logic_vector(7 downto 0)); end ajsm;
architecture behav of ajsm is
signal sig_com:std_logic_vector(3 downto 0);
28
附录
signal counter:std_logic_vector(1 downto 0); signal tmp,sig1,sig2:std_logic; begin
sig2<=key_pre;
tmp<=row(0) and row(1) and row(2) and row(3); process(clky) begin
if(clky'event and clky='1')then --计数进程 if(sig2='1')then
if(counter=\ sig1<='0';
counter<=\ else
sig1<='1';
counter<=counter+'1'; end if; else
sig1<=’0’;
counter<=”00”; end if; end if;
end process;
process(clky) variable jt :std_logic; begin
if(clky'event and clky='1')then if(sig1='1')then jt:=sig_com(3);
for i in 3 downto 1 loop
sig_com(i)<=sig_com(i-1); end loop;
sig_com(0)<=jt; else
sig_com<=\ end if; end if;
end process; process(clky) begin
if(clky'event and clky='1')then if(sig1='1')then com<=sig_com; else
com<=\ end if; end if;
end process;
process(clky) begin
if(clky'event and clky='1')then
--列线逐位输出低电平 --键码信号赋值 29
附 录
if(sig1='1')then if(tmp='0')then
scan_code<=row & sig_com; else
scan_code<=\ end if; else
scan_code<=\ end if; end if;
end process; end behav;
(6)顶层电路设计
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL; ENTITY clock IS
PORT ( CLK12MHZ : IN STD_LOGIC; CLK8HZ : IN STD_LOGIC; SPKOUT : OUT STD_LOGIC; CLK : IN STD_LOGIC; KEY1 : IN STD_LOGIC;
KEY2 : IN STD_LOGIC_VECTOR(1 DOWNTO 0); H1,H2,M1,M2,S1,S2: OUT STD_LOGIC_VECTOR(3 DOWNTO 0)); END;
ARCHITECTURE one OF clock IS COMPONENT shizhong
PORT (clk : in std_logic; md1 : in std_logic;
md2 : in std_logic_vector(1 downto 0); clken : out std_logic;
h1,h2,m1,m2,s1,s2: out std_logic_vector(3 downto 0)); END COMPONENT; COMPONENT NoteTabs
PORT ( clk : IN STD_LOGIC;
ToneIndex : OUT STD_LOGIC_VECTOR (3 DOWNTO 0) ); END COMPONENT; COMPONENT ToneTaba
PORT ( Index : IN STD_LOGIC_VECTOR (3 DOWNTO 0) ; Tone : OUT STD_LOGIC_VECTOR (10 DOWNTO 0); en : in std_logic); END COMPONENT; COMPONENT Speakera
PORT ( clk : IN STD_LOGIC;
Tone : IN STD_LOGIC_VECTOR (10 DOWNTO 0); SpkS : OUT STD_LOGIC ); END COMPONENT;
SIGNAL Tone :STD_LOGIC_VECTOR (10 DOWNTO 0); SIGNAL ToneIndex :STD_LOGIC_VECTOR (3 DOWNTO 0); SIGNAL clken :STD_LOGIC;
30
附录
SIGNAL en :STD_LOGIC; BEGIN
u1 : Shizhong PORT MAP (clk=>CLK,md1=>KEY1,md2=>KEY2,clken=>en,
h1=>h1,h2=>h2,m1=>m1,m2=>m2,s1=>s1,s2=>s2);
u2 : NoteTabs PORT MAP (clk=>CLK8HZ, ToneIndex=>ToneIndex); u3 : ToneTaba PORT MAP (Index=>ToneIndex,Tone=>Tone,en=>en);
u4 : Speakera PORT MAP (clk=>CLK12MHZ,Tone=>Tone, SpkS=>SPKOUT ); END;
31