vhdl按键消抖程序
- 格式:docx
- 大小:21.46 KB
- 文档页数:6
基于VHDL的开关消抖电路的研究王彩君;周开邻;黄智进【摘要】介绍了3种开关消抖方案的工作原理,给出了基于VHDL的相关实现程序和测试结果,并就结构、抗干扰、时序配合等方面对电路性能进行分析讨论.电路实用性强,对学生设计电路有一定的启发引导.【期刊名称】《实验科学与技术》【年(卷),期】2010(008)002【总页数】3页(P1-2,11)【关键词】开关;消抖;VHDL语言【作者】王彩君;周开邻;黄智进【作者单位】云南大学物理科学技术学院,昆明,650091;云南大学物理科学技术学院,昆明,650091;云南大学物理科学技术学院,昆明,650091【正文语种】中文【中图分类】TN79;TP39机械式开关、按钮或键盘由于其低成本、高可靠性作为输入控制器件而被广泛应用于电子设备中。
但是,由于此类开关机械弹性的作用,在开关闭合或断开的瞬间会伴随着一连串的随机抖动,使某些电路误动作,造成整个系统工作的异常。
因此,在开关信号送入此类电路前,必须对其进行预处理,以消除开关的抖动。
本文归纳了 3种基于VHDL(VHSI C Hardware Description Langaage)的实用开关消抖方案的工作原理、实体结构以及各自特点,希望对本科学生进行电子设备类的毕业设计起到一定的启发引导作用。
基于VHDL的开关消抖方案有很多,但按工作原理,可将它们归纳为“电平检测消抖法”、“定时检测消抖法”和“脉宽检测消抖法”3大类。
2.1 电平检测消抖法电平检测消抖法是对开关信号电平值的多次检测比较来判断开关状态的。
如图 1所示,其中 k为模拟 2次按键时的输入开关抖动信号;clk为检测时钟;y为消抖后的输出信号。
在 clk上升沿时刻检测,若连续检测到 2个输入高电平 (依次寄存在tmep2、tmep1中)时才可认为开关稳定闭合[1-2], y输出高电平;只要检测到低电平,即认为开关断开,y即回 0。
因此 2次按键对应 2个正脉冲输出。
这学期的EDA课程设计有涉及到一个按键信号稳定的问题,虽然就算没有这块处理,最后成绩只会扣3分,但自己觉得像LED亮度变化,数字钟设置这些功能,如果没有加进一个稳定按键信号的模块,根本不能算是已实现的功能。
按键消抖的程序在网上有几种可供选择,但这里只讨论一种,本人觉得简单得来又比较强大的一种。
其实消抖的原理就是把一个按键周期内所输入的所有有效信号,包括那些毛刺,处理成一个脉冲输入。
能达到这点,就可以实现消抖功能了。
功能的源代码:代码中的 key 是按键输入,count 是自定义的计数器,N的值可以根据需要结合时钟频率设置,如果只是想达到按键一次输入一个脉冲的效果,建议 count 的时长设为 5ms,key_en 是处理完后输出的单个脉冲,至于有效信号是 '0' 还是'1' ,这要看板上的电路设计了。
此代码中是 '0' 为有效信号。
不要怀疑这段代码有错,理清逻辑后再套用,如果弄不明白什么原理,建议还是别用,用了可能会更糟糕。
要注意的是一个 process 中只能有一个时钟信号,否则很容易出错,就算编译通过,实际操作还是不行。
所以如果要对多个按键消抖,一定要在 "if clk'event and clk='1' then" 语句的内部增加,别重新设置一个 clk'event 。
还有就是按键的消抖功能块最好用单独的 process 运行,将 key_en 设置成新的按键输入信号,而实际的输入信号 key 只在按键消抖的process 中读入。
之所以说这种消抖方法简单得来又比较强大,是因为这方法不需要用到什么状态机、component 之类较高级点的东西,只需要多个 process 即可;另外这种方法还有其他的拓展用途,比如可以利用这个 count 延时周期设置一个短按键和长按键的识别,实现长按此键切换或者 reset 等等的功能,这里不详细解释。
--------------------------------------------------------------------------------------- --LED灯花样闪烁程序library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;entity led_change isport(clk:in std_logic;led:out std_logic_vector(7 downto 0));end led_change;architecture fun of led_change issignal cnt: std_logic_vector(31 downto 0);signal flip_led: std_logic_vector(4 downto 0);beginprocess(clk)beginif(clk'event and clk='1')thencnt<=cnt+1;if(cnt=25000000)thenflip_led<=flip_led+1;cnt<=(others=>'0');end if;end if;case flip_led iswhen "00000"=>led<="11111111";when "00001"=>led<="00000000";when "00010"=>led<="11111111";when "00011"=>led<="00000000";when "00100"=>led<="10000000";when "00101"=>led<="11000000";when "00110"=>led<="11100000";when "00111"=>led<="11110000";when "01000"=>led<="11111000";when "01001"=>led<="11111100";when "01010"=>led<="11111110";when "01011"=>led<="11111111";when "01100"=>led<="00000001";when "01101"=>led<="00000011";when "01110"=>led<="00000111";when "01111"=>led<="00001111";when "10000"=>led<="00011111";when "10001"=>led<="00111111";when "10010"=>led<="01111111";when "10011"=>led<="11111111";when "10100"=>led<="00000000";when others =>led<="ZZZZZZZZ";end case;if(flip_led>"10100")thenflip_led<="00000";end if;end process;end fun;--拨码开关控制LED程序library ieee;use ieee.std_logic_1164.all;entity switch_led isport(key : in std_logic_vector(1 downto 0);led : out std_logic_vector(7 downto 0)); --八个led灯end switch_led;architecture fun of switch_led isbeginprocess(key)begincase key iswhen "00" => led <="00000000"; -- // "0"when "01" => led <="00001111"; -- // "1"when "10" => led <="11110000"; -- // "2"when "11" => led <="11111111"; -- // "3"when others => led <="ZZZZZZZZ";end case;end process;end;--按键消抖控制LED程序library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_arith.all;use ieee.std_logic_unsigned.all;entity stable_key isport(clk :in std_logic;key_in:in std_logic;key_out: out std_logic);end ;architecture fun of stable_key issignal cnt : integer range 0 to 1999999;signal key ,key_d : std_logic;beginprocess(clk)beginif clk'event and clk='1' thenif key /= key_in then -----键值变化开始计时10ms key_d <= key_in;cnt <= 0;elsif cnt=1999999 then ---10mskey_out <= not key_d;cnt <= 0;elsecnt <= cnt + 1 ;end if ;key<= key_in;end if ;end process;end ;--蜂鸣器电子琴程序library ieee;use ieee.std_logic_1164.all;entity digital_piano isport(key : in std_logic_vector(7 downto 0); --定义8个按键key1~key8clk : in std_logic; --时钟输入端50Mhzbeep: out std_logic); --蜂鸣器输出端end digital_piano;architecture fun of digital_piano issignal freq : integer range 0 to 50000;signal beep_reg: std_logic;beginbeep_process: process(clk,freq) --分频进程--本工程内核心进程,计数器的大小由counter决定variable cnt : integer range 0 to 50000;beginif clk'event and clk='1' thenif cnt < freq thencnt := cnt + 1;elsecnt := 0 ;beep_reg <=not beep_reg;end if;end if;end process beep_process;freq_process: process(key)begincase key iswhen "11111110" => freq <= 47774; ---------------------------------counter 计算公式:中音do的频率为523.3hz,为了在上个beep_pro进程中得到523的频率counter= 50*1000000/(523*2)when "11111101" => freq <= 42568; --中音re的频率为587.3hzwhen "11111011" => freq <= 37919; --中音mi的频率为659.3hzwhen "11110111" => freq <= 35791; --中音fa的频率为698.5hzwhen "11101111" => freq <= 31888; --中音sol的频率为784hzwhen "11011111" => freq <= 28409; --中音la的频率为880hzwhen "10111111" => freq <= 25309; --中音si的频率为987.8hzwhen "01111111" => freq <= 23912; --高音do的频率为1045.5hzwhen "01111101" => freq <= 21282; --高音re的频率为1174.7hzwhen "01111011" => freq <= 18961; --高音mi的频率为1318.5hzwhen "01110111" => freq <= 17897; --高音fa的频率为1396.9hzwhen "01101111" => freq <= 15944; --高音sol的频率为1568hzwhen "01011111" => freq <= 14205; --高音la的频率为1760hzwhen "00111111" => freq <= 12605; --高音si的频率为1975.5hzwhen others => freq <= 0;end case;end process freq_process;beep <= beep_reg;end;--数码管静态扫描library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_arith.all;use ieee.std_logic_unsigned.all;entity static_segled isport(clk : in std_logic;data:out std_logic_vector(7 downto 0);sel:out std_logic_vector(7 downto 0));end ;architecture fun of static_segled issignal num : std_logic_vector(3 downto 0);signal cnt : integer range 0 to 12499999 ;beginsel <= "00000000"; --静态显示,全部位选中process(clk)beginif clk'event and clk='1' then --每四秒改变一次数字if cnt=12499999 thencnt<=0;num<= num + 1;elsecnt<= cnt + 1 ;end if ;end if ;end process;process(num)begincase num iswhen "0000" => data<=x"c0"; -- // "0"when "0001" => data<=x"f9"; -- // "1"when "0010" => data<=x"a4"; -- // "2"when "0011" => data<=x"b0"; -- // "3"when "0100" => data<=x"99"; -- // "4"when "0101" => data<=x"92"; -- // "5"when "0110" => data<=x"82"; -- // "6"when "0111" => data<=x"f8"; -- // "7"when "1000" => data<=x"80"; -- // "8"when "1001" => data<=x"90"; -- // "9"when "1010" => data<=x"88"; -- // "a"when "1011" => data<=x"83"; -- // "b"when "1100" => data<=x"c6"; -- // "c"when "1101" => data<=x"a1"; -- // "d"when "1110" => data<=x"86"; -- // "e"when "1111" => data<=x"8e"; -- // "f"when others => data<=x"ff";end case;end process;end ;--数码管动态扫描library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_arith.all;use ieee.std_logic_unsigned.all;entity dynamic_segled isport(clk : in std_logic;data: out std_logic_vector(7 downto 0);sel:out std_logic_vector(7 downto 0) );end ;architecture fun of dynamic_segled issignal cnt: integer range 0 to 62449;signal flip_led: integer range 0 to 7;beginprocess(clk)beginif clk'event and clk='1' then ----- 动态扫描if cnt=62499 thencnt<=0;flip_led<=flip_led+1; -- 数据改变elsecnt<=cnt + 1;end if ;end if ;end process;process(flip_led)begincase flip_led is ---译码显示when 0 =>sel<="01111111";data<=x"c0";when 1 =>sel<="10111111";data<=x"f9";when 2 =>sel<="11011111";data<=x"a4";when 3 =>sel<="11101111";data<=x"b0";when 4 =>sel<="11110111";data<=x"99";when 5 =>sel<="11111011";data<=x"92";when 6 =>sel<="11111101";data<=x"82";when 7 =>sel<="11111110";data<=x"f8";when others=>sel<="11111111";data<=x"ff"; end case;end process;end ;。
2.2系统的输入、输出端口以及寄存器清单及说明:CLK 输入时钟方波信号端口KIN 键盘按键输入端口KOUT 键盘完整编码码值输出端口(七位二进制数)KOUT1 扫描信号输出端口(三位二进制数)SIN 键盘消抖输入端口(七位二进制数)SOUT 键盘消抖输出端口(七位二进制数)LIN 键盘按键编码模块输入端口(七位二进制数)DF 数字按键标志寄存器FF 功能按键标志寄存器ND 数字按键识别编码寄存器NF 功能按键识别编码寄存器LOCK 电子密码锁上锁状态标志寄存器LOCK1 电子密码锁报警状态标志寄存器UNLOCK 电子密码锁开锁状态标志寄存器NULL1 电子密码锁无密码状态标志寄存器DATA 电子密码锁数码显示数据寄存器CAT 电子密码锁数码显示位选寄存器DISPLAY 电子密码锁数码显示段选寄存器(十七位二进制数)NUM0、NUM1、NUM2、NUM3数码显示中分位显示数据寄存器DISNUM 数码显示段选数据寄存器I1 数码显示计数器SCANS 键盘扫描中按键完整编码寄存器SCAN 键盘扫描寄存器CNT 键盘消抖计数器SIN1 键盘按键键值寄存器I 键盘扫描计数器DF1 数字按键状态标志寄存器ACC 键盘数字输入暂存器T 报警计数器REG 电子密码锁密码存储器NC 计数器1键盘输入扫描部分源程序LIBRARY IEEE;USE IEEE.STD_LOGIC_ARITH.ALL;USE IEEE.STD_LOGIC_UNSIGNED.ALL;USE IEEE.STD_LOGIC_1164.ALL;ENTITY kbscan1 isPORT(clk:in STD_LOGIC;kin:in STD_LOGIC_VECTOR(3 DOWNTO 0);---PC7-PC4 kout:out STD_LOGIC_VECTOR(7 downto 0);--PC3--PCkout1: out STD_LOGIC_VECTOR(3 downto 0));end kbscan1;architecture a of kbscan1 issignal scans: std_logic_vector(7 downto 0);--PC7--PC0signal scan : std_logic_vector(3 downto 0);--PC3--PC0signalt :integer range 0 to 140;signal sin1:std_logic_vector(3 downto 0);signal i:integer range 0 to 3;beginscans<=scan& kin;kout<=scans;kout1<=scan;process(clk)beginif(falling_edge(clk))thenif(i=3)theni<=0;elsei<=i+1;end if;case i iswhen 0=>scan<="0001";when 1=>scan<="0010";when 2=>scan<="0100";when 3=>scan<="1000";end case;end if;end process;End a;2键盘输入消抖部分源程序LIBRARY IEEE;USE IEEE.STD_LOGIC_1164.ALL;ENTITY xiaodou isPort(clk :in STD_LOGIC;sin:in std_logic_vector(7 downto 0);sout:out std_logic_vector(7 downto 0));end xiaodou;architecture behavioral of xiaodou issignalt :integer range 0 to 120;signal sin1:std_logic_vector(7 downto 0);beginprocess(clk)beginsin1<=sin;if (rising_edge(clk))thenif(sin1=sin)thent<=cnt+1;elsesin1<=sin;t<=0;end if;if(cnt=120)thensout<=sin;t<=0;end if;end if;end process;end behavioral;3键盘输入编码部分源程序LIBRARY IEEE;USE IEEE.STD_LOGIC_ARITH.ALL;USE IEEE.STD_LOGIC_UNSIGNED.ALL;USE IEEE.STD_LOGIC_1164.ALL;ENTITY bianma isPORT(clk:in STD_LOGIC;lin:in STD_LOGIC_VECTOR(7 DOWNTO 0);---PC7-PC4DF,FF: out std_logic;nd,nf:BUFFER std_logic_vector(3 downto 0));end bianma;architecture b of bianma isbeginprocess(clk)beginif clk'event and clk='1' thencase lin iswhen"10000001"=>ND<="0000";--0when"00010001"=>ND<="0001";--1when"00010010"=>ND<="0010";--2when"00010100"=>ND<="0011";--3when"00100001"=>ND<="0100";--4when"00100010"=>ND<="0101";--5when"00100100"=>ND<="0110";--6when"01000001"=>ND<="0111";--7when"01000010"=>ND<="1000";--8when"01000100"=>ND<="1001";--9when others =>ND<="1111";END CASE;END IF;IF CLK'EVENT AND CLK='1' THENCASE LIN ISwhen"00011000"=>NF<="0001";--qingchuwhen"00101000"=>NF<="0010";--querenwhen"01001000"=>NF<="0011";--shangsuowhen"10001000"=>NF<="0100";--kaisuowhen"10000100"=>NF<="0101";--wangjimimawhen"10000010"=>NF<="0111";--genggaimimaWhen others =>NF<="1000";END CASE;END IF;END PROCESS;DF<=NOT(ND(3) AND ND(2) AND ND(1) AND ND(0));FF<=NF(2) OR NF(1) OR NF(0);end b;4 电子密码锁的控制部分程序DF 数字按键标志寄存器FF 功能按键标志寄存器ND 数字按键识别编码寄存器NF 功能按键识别编码寄存器LOCK 电子密码锁上锁状态标志寄存器LOCK1 电子密码锁报警状态标志寄存器UNLOCK 电子密码锁开锁状态标志寄存器NULL1 电子密码锁无密码状态标志寄存器DATA 电子密码锁数码显示数据寄存器LIBRARY IEEE;USE IEEE.STD_LOGIC_1164.ALL;ENTITY kongzhi ISPORT(CLK: IN STD_LOGIC;DF,FF: in STD_LOGIC;ND,NF:in STD_LOGIC_VECTOR(3 downTO 0);LOCK,LOCK1,UNLOCK:buffer STD_LOGIC;NULL1: buffer STD_LOGIC;DA TA: out STD_LOGIC_VECTOR(15 downTO 0) );END kongzhi;ARCHITECTURE V1 OF kongzhi ISsignal i1:integer range 0 to 3;signal df1:std_logic;signal ACC: STD_LOGIC_VECTOR(15 DOWNTO 0);signal t: INTEGER RANGE 0 TO 2;signal REG:STD_LOGIC_VECTOR(15 downTO 0);signal NC,A:INTEGER RANGE 0 TO 3;beginPROCESS(FF,DF)ISBEGINif rising_edge(clk) thenIF FF='1'THENIF NF="0001"THENACC<="0000000000000000";NC<=0;END IF;ELSEdf1<=df;IF df1='0'and DF='1' THENIF NC<4 THENACC<=ACC(11 DOWNTO 0)&ND;NC<=NC+1;END IF;END IF;END IF;IF FF='1' THENIF NF="0011" THENREG<=ACC;LOCK<='0';UNLOCK<='1';LOCK1<='1';NULL1<='1';elseIF NF="0100" THENIF REG=ACC THENLOCK<='1';UNLOCK<='0';LOCK1<='1';NULL1<='1';ELSELOCK<='0';UNLOCK<='1';IF t=2 THENREG<="1000100010001000";LOCK1<='0';lock<='1';unlock<='1';null1<='1';t<=0;ELSEt<=t+1;END IF;END IF;elseIF NF="0101" THENREG<="1000100010001000";LOCK<='0';UNLOCK<='1';LOCK1<='1';NULL1<='1';elseIF NF="0111" THENIF UNLOCK='1' THENIF REG=ACC THENREG<="0000000000000000";NULL1<='0';LOCK<='1';LOCK1<='1';UNLOCK<='1';END IF;END IF;elseIF NF="0010" THENREG<=ACC;NULL1<='1';LOCK<='0';LOCK1<='1';UNLOCK<='1';END IF;end if;end if;end if;end if;end if;end if;END PROCESS;DA TA<=ACC;END ARCHITECTURE V1;CAT 电子密码锁数码显示位选寄存器DISPLAY 电子密码锁数码显示段选寄存器(十七位二进制数)DISPLAY 电子密码锁数码显示段选寄存器(十七位二进制数)NUM0、NUM1、NUM2、NUM3数码显示中分位显示数据寄存器DISNUM 数码显示段选数据寄存器I1 数码显示计数器5电子密码锁的数码显示模块源程序LIBRARY IEEE;USE IEEE.STD_LOGIC_1164.ALL;ENTITY LEDXIANSHI ISPORT(CLK :IN STD_LOGIC;DA TA: in STD_LOGIC_VECTOR (15 DOWNTO 0);CA T:OUT STD_LOGIC_VECTOR(0 TO 3);DISPLAY:OUT STD_LOGIC_VECTOR(16 DOWNTO 0));END LEDXIANSHI;ARCHITECTURE BEHA VIORAL OF LEDXIANSHI ISSignal NUM0,NUM1,NUM2,NUM3: STD_LOGIC_VECTOR(3 DOWNTO 0);SIGNAL DISNUM:STD_LOGIC_VECTOR(16 DOWNTO 0);SIGNAL I1:INTEGER RANGE 0 TO 3;BEGINNUM0<=DATA(3 DOWNTO 0);NUM1<=DATA(7 DOWNTO 4);NUM2<=DATA(11 DOWNTO 8);NUM3<=DA TA(15 DOWNTO 12);DISPLAY<=DISNUM;PROCESS(CLK)BEGINIF(RISING_EDGE(CLK))THENIF(I1=3)THENI1<=0;ELSEI1<=I1+1;END IF;END IF;END PROCESS;PROCESS(I1)BEGINCASE I1 ISWHEN 0=>CA T<="1110";CASE NUM0 ISWHEN "0000"=>DISNUM<="00000000011111111";WHEN "0001"=>DISNUM<="00000000000001100";WHEN "0010"=>DISNUM<="00001000101110111";WHEN "0011"=>DISNUM<="00001000100111111";WHEN "0100"=>DISNUM<="01001010110000000";WHEN "0101"=>DISNUM<="00001100110111011";WHEN "0110"=>DISNUM<="00001000111111011";WHEN "0111"=>DISNUM<="00000000000001111";WHEN "1000"=>DISNUM<="00001000111111111";WHEN "1001"=>DISNUM<="00001000110111111";WHEN OTHERS=>DISNUM<=NULL;END CASE;WHEN 1 => CAT<="1101";CASE NUM1 ISWHEN "0000"=>DISNUM<="00000000011111111";WHEN "0001"=>DISNUM<="00000000000001100";WHEN "0010"=>DISNUM<="00001000101110111";WHEN "0011"=>DISNUM<="00001000100111111";WHEN "0100"=>DISNUM<="01001010110000000";WHEN "0101"=>DISNUM<="00001100110111011";WHEN "0110"=>DISNUM<="00001000111111011";WHEN "0111"=>DISNUM<="00000000000001111"; WHEN "1000"=>DISNUM<="00001000111111111"; WHEN "1001"=>DISNUM<="00001000110111111"; WHEN OTHERS=>DISNUM<=NULL;END CASE;WHEN 2=>CAT<="1011";CASE NUM2 ISWHEN "0000"=>DISNUM<="00000000011111111"; WHEN "0001"=>DISNUM<="00000000000001100"; WHEN "0010"=>DISNUM<="00001000101110111"; WHEN "0011"=>DISNUM<="00001000100111111"; WHEN "0100"=>DISNUM<="01001010110000000"; WHEN "0101"=>DISNUM<="00001100110111011"; WHEN "0110"=>DISNUM<="00001000111111011"; WHEN "0111"=>DISNUM<="00000000000001111"; WHEN "1000"=>DISNUM<="00001000111111111"; WHEN "1001"=>DISNUM<="00001000110111111"; WHEN OTHERS=>DISNUM<=NULL;END CASE;WHEN 3=>CAT<="0111";CASE NUM3 ISWHEN "0000"=>DISNUM<="00000000011111111"; WHEN "0001"=>DISNUM<="00000000000001100"; WHEN "0010"=>DISNUM<="00001000101110111";WHEN "0011"=>DISNUM<="00001000100111111";WHEN "0100"=>DISNUM<="01001010110000000";WHEN "0101"=>DISNUM<="00001100110111011";WHEN "0110"=>DISNUM<="00001000111111011";WHEN "0111"=>DISNUM<="00000000000001111";WHEN "1000"=>DISNUM<="00001000111111111";WHEN "1001"=>DISNUM<="00001000110111111";WHEN OTHERS=>DISNUM<=NULL;END CASE;END CASE;END PROCESS;END BEHA VIORAL;6电子密码锁的数码显示部分(附加)LIBRARY IEEE;USE IEEE.STD_LOGIC_1164.ALL;ENTITY LEDXIANSHI ISPORT(CLK :IN STD_LOGIC;DATA: in STD_LOGIC_VECTOR (15 DOWNTO 0);CA T:OUT STD_LOGIC_VECTOR(0 TO 3);DISPLAY:OUT STD_LOGIC_VECTOR(16 DOWNTO 0));END LEDXIANSHI;ARCHITECTURE BEHA VIORAL OF LEDXIANSHI ISsignal NUM0,NUM1,NUM2,NUM3: STD_LOGIC_VECTOR(3 DOWNTO 0);SIGNAL DISNUM:STD_LOGIC_VECTOR(16 DOWNTO 0);SIGNAL I1:INTEGER RANGE 0 TO 3;BEGINNUM0<=DATA(3 DOWNTO 0);NUM1<=DATA(7 DOWNTO 4);NUM2<=DATA(11 DOWNTO 8);NUM3<=DA TA(15 DOWNTO 12); DISPLAY<=DISNUM;PROCESS(CLK)BEGINIF(RISING_EDGE(CLK))THENIF(I1=3)THENI1<=0;ELSEI1<=I1+1;END IF;END IF;END PROCESS;PROCESS(I1)BEGINCASE I1 ISWHEN 0=>CAT<="1110";CASE NUM0 ISWHEN "0000"=>DISNUM<="00000000011111111";WHEN OTHERS=>DISNUM<="01111111100000000";END CASE;WHEN 1=>CAT<="1101";CASE NUM1 ISWHEN "0000"=>DISNUM<="00000000011111111";WHEN OTHERS=>DISNUM<="01111111100000000";END CASE;WHEN 2=>CAT<="1011";CASE NUM2 ISWHEN "0000"=>DISNUM<="00000000011111111"; WHEN OTHERS=>DISNUM<="01111111100000000"; END CASE;WHEN 3=>CAT<="0111";CASE NUM3 ISWHEN "0000"=>DISNUM<="00000000011111111"; WHEN OTHERS=>DISNUM<="01111111100000000"; END CASE;END CASE;END PROCESS;END BEHA VIORAL;数码管显示library IEEE;use IEEE.STD_LOGIC_1164.ALL;use IEEE.STD_LOGIC_ARITH.ALL;use IEEE.STD_LOGIC_UNSIGNED.ALL;entity KeyScan isport(RESET : in std_logic;CLK : in std_logic; --基本时钟源6MHzKeyIn : in std_logic_vector(3 downto 0); --column列KeyOut : out std_logic_vector(3 downto 0); --row行LED_A : out std_logic; --4位数码管引脚LED_B : out std_logic;LED_C : out std_logic;LED_D : out std_logic;LED_E : out std_logic;LED_F : out std_logic;LED_G : out std_logic;LED_VCC1 : out std_logic; --时十位LED_VCC2 : out std_logic; --时个位LED_VCC3 : out std_logic; --分十位LED_VCC4 : out std_logic; --分个位LED_TimePoint:out std_logic; --冒号LED_Point :out std_logic; --小数点LED_EN1 :out std_logic --小数点);end KeyScan;architecture Behavioral of KeyScan issignal timecnt : integer range 0 to 100000 ; --分频计数器,用来得到10ms时钟signal time10ms : std_logic ; --10ms时钟signal scanvalue : std_logic_vector(3 downto 0);--记录扫描数据signal combvalue : std_logic_vector(7 downto 0);--KeyIn、KeyOut组合值signal cpy_scanvalue : std_logic_vector(3 downto 0);--备份扫描数据signal count : integer range 0 to 60000 ; --分频器,产生毫秒时钟基准signal scancnt : integer range 0 to 3 ; --LED扫描轮转signal Data0: integer range 0 to 9 ;beginLED_EN1<='0';--进程1:产生20ms时钟process( CLK,RESET)beginif RESET='0' then time10ms<='0'; --初始化elsif CLK'event and CLK='1' thentimecnt<=timecnt+1;if timecnt=100000then time10ms<=not time10ms; timecnt<=0;end if;end if;end process;--进程2:键盘扫描输出process( time10ms,RESET)beginif RESET='0' then scanvalue<="0001";combvalue<="00000000";Data0<=0; --初始化elsif time10ms'event and time10ms='1' then --每10ms进行一次键盘扫描KeyOut<=scanvalue; --输出扫描值cpy_scanvalue<=scanvalue; --备份扫描值,为了进程3对扫描结果进行比较case scanvalue is --扫描值移位when "0001" => scanvalue<="0010";when "0010" => scanvalue<="0100";when "0100" => scanvalue<="1000";when "1000" => scanvalue<="0001";when others => scanvalue<="0001";end case;combvalue<= (KeyIn & cpy_scanvalue); --组合键盘扫描的输入和输出case combvalue is --翻译扫描结果when "00010001" => Data0<=1; --对应键盘“1”when "00100001" => Data0<=2; --对应键盘“2”when "01000001" => Data0<=3; --对应键盘“3”when "00010010" => Data0<=4; --对应键盘“4”when "00100010" => Data0<=5; --对应键盘“5”when "01000010" => Data0<=6; --对应键盘“6”when "00010100" => Data0<=7; --对应键盘“7”when "00100100" => Data0<=8; --对应键盘“8”when "01000100" => Data0<=9; --对应键盘“9”when "00011000" => Data0<=0; --对应键盘“0”when others => null; --无键盘按下end case;end if;end process;--数码管扫描process(CLK,RESET) --时钟进程,产生各种时钟信号beginif RESET='0' then NULL;elsif CLK'event and CLK='1' thencount<=count+1;if count=60000 thencount<=0;if scancnt>3 then scancnt<=0;else scancnt<=scancnt+1;end if;end if;end if;end process;--数码管扫描process(CLK, RESET)begin--LED_VCC信号是‘1’有效,其余信号均为‘0’有效,中间的冒号两个点分别由VCC2和VCC3控制if RESET='0' then LED_A<='1';LED_B<='1';LED_C<='1';LED_D<='1';LED_E<='1';LED_F<='1';LED_G<='1';LED_VCC1<='0';LED_VCC2<='0';LED_VCC3<='0';LED_VCC4<='0';LED_TimePoint<='1'; LED_Point<='1';elseif scancnt=0 thencase Data0 is --分个位when 0 => LED_A<='0';LED_B<='0';LED_C<='0';LED_D<='0';LED_E<='0';LED_F<='0';LED_G<='1';LED_VCC1<='0';LED_VCC2<='0'; LED_VCC3<='0';LED_VCC4<='1';LED_Point<='1';when 1 => LED_A<='1';LED_B<='0';LED_C<='0';LED_D<='1';LED_E<='1';LED_F<='1';LED_G<='1';LED_VCC1<='0';LED_VCC2<='0'; LED_VCC3<='0';LED_VCC4<='1';LED_Point<='1';when 2 => LED_A<='0';LED_B<='0';LED_C<='1';LED_D<='0';LED_E<='0';LED_F<='1';LED_G<='0';LED_VCC1<='0';LED_VCC2<='0'; LED_VCC3<='0';LED_VCC4<='1';LED_Point<='1';when 3 => LED_A<='0';LED_B<='0';LED_C<='0';LED_D<='0';LED_E<='1';LED_F<='1';LED_G<='0';LED_VCC1<='0';LED_VCC2<='0'; LED_VCC3<='0';LED_VCC4<='1';LED_Point<='1';when 4 => LED_A<='1';LED_B<='0';LED_C<='0';LED_D<='1';LED_E<='1';LED_F<='0';LED_G<='0';LED_VCC1<='0';LED_VCC2<='0'; LED_VCC3<='0';LED_VCC4<='1';LED_Point<='1';when 5 => LED_A<='0';LED_B<='1';LED_C<='0';LED_D<='0';LED_E<='1';LED_F<='0';LED_G<='0';LED_VCC1<='0';LED_VCC2<='0'; LED_VCC3<='0';LED_VCC4<='1';LED_Point<='1';when 6 => LED_A<='0';LED_B<='1';LED_C<='0';LED_D<='0';LED_E<='0';LED_F<='0';LED_G<='0';LED_VCC1<='0';LED_VCC2<='0'; LED_VCC3<='0';LED_VCC4<='1';LED_Point<='1';when 7 => LED_A<='0';LED_B<='0';LED_C<='0';LED_D<='1';LED_E<='1';LED_F<='1';LED_G<='1';LED_VCC1<='0';LED_VCC2<='0'; LED_VCC3<='0';LED_VCC4<='1';LED_Point<='1';when 8 => LED_A<='0';LED_B<='0';LED_C<='0';LED_D<='0';LED_E<='0';LED_F<='0';LED_G<='0';LED_VCC1<='0';LED_VCC2<='0'; LED_VCC3<='0';LED_VCC4<='1';LED_Point<='1';when 9 => LED_A<='0';LED_B<='0';LED_C<='0';LED_D<='0';LED_E<='1';LED_F<='0';LED_G<='0';LED_VCC1<='0';LED_VCC2<='0'; LED_VCC3<='0';LED_VCC4<='1';LED_Point<='1';when others => null;end case;end if;end if;end process;end Behavioral;控制电路的软件仿真图(1)图2-11 控制电路的软件仿真图(2)控制电路的软件仿真图(3)控制电路的软件仿真图(4)控制电路的软件仿真图(5)5电子密码锁的数码显示模块源程序(改七段)LIBRARY IEEE;USE IEEE.STD_LOGIC_1164.ALL;ENTITY LEDXIANSHI ISPORT(CLK :IN STD_LOGIC;LED_TimePoint:out std_logic; --冒号LED_Point :out std_logic; --小数点LED_EN1 :out std_logic; --选择数码管显示DA TA: in STD_LOGIC_VECTOR (15 DOWNTO 0);CA T:OUT STD_LOGIC_VECTOR(0 TO 3);DISPLAY:OUT STD_LOGIC_VECTOR(6 DOWNTO 0));END LEDXIANSHI;ARCHITECTURE BEHA VIORAL OF LEDXIANSHI ISSignal NUM0,NUM1,NUM2,NUM3: STD_LOGIC_VECTOR(3 DOWNTO 0);SIGNAL DISNUM:STD_LOGIC_VECTOR(6 DOWNTO 0);SIGNAL I1:INTEGER RANGE 0 TO 3;BEGINNUM0<=DATA(3 DOWNTO 0);NUM1<=DATA(7 DOWNTO 4);NUM2<=DATA(11 DOWNTO 8);NUM3<=DA TA(15 DOWNTO 12);DISPLAY<=DISNUM;PROCESS(CLK)BEGINIF(RISING_EDGE(CLK))THENIF(I1=3)THENI1<=0;ELSEI1<=I1+1;END IF;END IF;END PROCESS;PROCESS(I1)BEGINCASE I1 ISWHEN 0=>CA T<="0001";CASE NUM0 ISWHEN "0000"=>DISNUM<="1000000";WHEN "0001"=>DISNUM<="1111001";WHEN "0010"=>DISNUM<="0100100";WHEN "0011"=>DISNUM<="0110000";WHEN "0100"=>DISNUM<="0011001";WHEN "0101"=>DISNUM<="0010010";WHEN "0110"=>DISNUM<="0000010";WHEN "0111"=>DISNUM<="1111000";WHEN "1000"=>DISNUM<="0000000";WHEN "1001"=>DISNUM<="0010000";WHEN OTHERS=>DISNUM<=NULL;END CASE;WHEN 1 => CAT<="0010";CASE NUM1 ISWHEN "0000"=>DISNUM<="1000000";WHEN "0001"=>DISNUM<="1111001";WHEN "0010"=>DISNUM<="0100100";WHEN "0011"=>DISNUM<="0110000";WHEN "0100"=>DISNUM<="0011001"; WHEN "0101"=>DISNUM<="0010010"; WHEN "0110"=>DISNUM<="0000010"; WHEN "0111"=>DISNUM<="1111000"; WHEN "1000"=>DISNUM<="0000000"; WHEN "1001"=>DISNUM<="0010000";WHEN OTHERS=>DISNUM<=NULL; END CASE;WHEN 2=>CAT<="0100";CASE NUM2 ISWHEN "0000"=>DISNUM<="1000000"; WHEN "0001"=>DISNUM<="1111001"; WHEN "0010"=>DISNUM<="0100100"; WHEN "0011"=>DISNUM<="0110000"; WHEN "0100"=>DISNUM<="0011001"; WHEN "0101"=>DISNUM<="0010010"; WHEN "0110"=>DISNUM<="0000010"; WHEN "0111"=>DISNUM<="1111000"; WHEN "1000"=>DISNUM<="0000000"; WHEN "1001"=>DISNUM<="0010000";WHEN OTHERS=>DISNUM<=NULL; END CASE;WHEN 3=>CAT<="1000";CASE NUM3 ISWHEN "0000"=>DISNUM<="1000000"; WHEN "0001"=>DISNUM<="1111001"; WHEN "0010"=>DISNUM<="0100100"; WHEN "0011"=>DISNUM<="0110000"; WHEN "0100"=>DISNUM<="0011001"; WHEN "0101"=>DISNUM<="0010010"; WHEN "0110"=>DISNUM<="0000010"; WHEN "0111"=>DISNUM<="1111000"; WHEN "1000"=>DISNUM<="0000000"; WHEN "1001"=>DISNUM<="0010000";WHEN OTHERS=>DISNUM<=NULL; END CASE;END CASE;END PROCESS;END BEHA VIORAL;。
VHDL专题--------电子密码锁一、设计要求:设计一个简单的数字电子密码锁,密码为4位。
功能:1、密码输入:每按下一个键,要求在数码管上显示,并依次左移;2、密码清除:清除密码输入,并将输入置为”0000”;3、密码修改:将当前输入设为新的密码;4、上锁和开锁。
二、电路组成:为达到以上功能,可将电子密码锁分为以下几个模块:1、键盘接口电路:键盘矩阵、键盘扫描、键盘消抖、键盘译码及按键存储。
2、电锁控制电路:数字按键输入、存储及清除。
功能按键的设计。
密码清除、修改与存储。
电锁的激活与解除。
3、输出显示电路BCD译码、动态扫描电路。
三、功能电路的设计:1、键盘接口电路:矩阵式键盘工作原理:矩阵式键盘是一种常见的输入装置,在计算机、电话、手机、微波炉等各工电子产品中被广泛应用。
如图所示为一3×4矩阵式键盘。
矩阵式键盘以行、列形式排列,图中为4行3列,键盘上的每一个按键盘其实是一个开关电路,当某键被按下时,该按键所对应的位置就呈现逻辑0的状态,键盘的扫描可以以行扫或列扫方式进行,图中为行扫方式,KEYR3—KEYR0为扫描信号,其中的某一位为0即扫描其中的一行,具体见表1-1.12键盘扫描信号KEYR3与第一行相连,KEYR2与第二行相连,依此类推。
很显然,扫描信号的变化顺序为:0111、1011、1101、1110,周而复始。
在扫描的过程中,当有键按下时,对应的键位就为逻辑0状态,从而从KEYC2..0读出的键值相应列为0.具体情况如表1-2所示:若从KEYC2..0读出的值全为1时,表示没有键被按下,则不进行按键的处理。
如果的键被按下,则将KEYC2..0读出的送至键盘译码电路进行译码。
表1-2 键盘扫描与其对应的键值的关系时序产生电路:在一个系统的设计中,往往需要多种时钟信号,最为方便的方法是利用一个自由计数器来产生各种需要的频率。
本电路需要:系统主时钟、消抖取样时钟和动态扫描时钟。
VHDL——按键消抖按键检测需要消抖,一般有硬件和软件两种方式。
硬件就是加去抖动电路,这样从根本上解决按键抖动问题。
除了用专用电路以外,用可编程FPGA或者CPLD设计相应的逻辑和时序电路,对按键信号进行处理,同样可以达到去抖动的目的。
本例中用状态机实现了消抖电路:端口描述:clk输入检测时钟;reset复位信号;din原始按键信号输入;dout去抖动输出信号。
VHDL源码如下:LIBRARY ieee;USE ieee.std_logic_1164.all;USE ieee.std_logic_unsigned.all;ENTITY xiaod ISPORT(clk:IN STD_LOGIC ;reset:IN STD_LOGIC ;din:IN STD_LOGIC ;dout:OUT STD_LOGIC);END ENTITY; ARCHITECTURE RTL OF xiaod IS TYPE state IS( s0,s1,s2,s3); SIGNAL pre_s, next_s:state;BEGINP0:PROCESS( reset, clk ) BEGINif reset = '0' thenpre_s <= s0;elsif rising_edge( clk ) thenpre_s <= next_s;elsenull;end if;END PROCESS P0;P1:PROCESS( pre_s, next_s, din ) BEGINcase pre_s isdout <= '1';if din = '1' then next_s <= s0; elsenext_s <= s1; end if;when s1 => dout <= '1';if din = '1' then next_s <= s0; elsenext_s <= s2; end if;when s2 => dout <= '1';if din = '1' then next_s <= s0; elsenext_s <= s3; end if;dout <= '0';if din = '1' thennext_s <= s0;elsenext_s <= s1;end if;end case;END PROCESS P1;END RTL;多按键去抖动电路VHDL源码,按键个数参数化,每个按键处理调用了上面的模块:LIBRARY ieee;USE ieee.std_logic_1164.all;USE ieee.std_logic_arith.all;USE ieee.std_logic_unsigned.all;ENTITY Nxiaod ISGENERIC( width:positive:= 5 );PORT(clk:IN STD_LOGIC ;reset:IN STD_LOGIC ;din:IN STD_LOGIC_VECTOR( width - 1 DOWNTO 0); dout:OUT STD_LOGIC_VECTOR( width - 1 DOWNTO 0) );END ENTITY;ARCHITECTURE RTL OF Nxiaod IS COMPONENT xiaod ISPORT(clk:IN STD_LOGIC ;reset:IN STD_LOGIC ;din:IN STD_LOGIC ;dout:OUT STD_LOGIC);END COMPONENT;BEGINg1: FOR i IN 0 to width - 1 GENERATEux:xiaod port map( clk => clk, reset => reset, din => din(i), dout =>dout(i)); END GENERATE;END RTL;。
实 验 报 告实验日期: 学 号:姓 名:实验名称:消抖电路总 分:一、实验概述运用LPM 原件定制DFF 触发器,并调用LPM 定制的DFF 触发器,用VHDL 语言的元件例化实现消抖电路并了解其工作原理。
二、实验原理 1、触发器原理触发器是一种可存储1位二进制码的逻辑电路,是构成各种时序电路的最基本逻辑单元。
触发器有一对互补输出端,输出状态不仅与当前输入有关,还与前一输出状态有关。
触发器有两个稳定状态,在一定的外界信号作用下会发生状态翻转。
2、消抖电路原理脉冲按键与电平按键通常采用机械式开关结构,其核心部件为弹性金属簧片。
按键信号在开关拨片与触电接触后经多次弹跳才会稳定,而在按键过程中,可能出现了多个脉冲。
因此需要根据实际情况进行按键消抖处理以提取稳定脉冲,在按键过程中提取稳定的电平状态,通过对抖动脉冲多次检测信号按键电平值,并提取一前一后两个信号按键电平值来进行比较,以此来获取开关状态。
输出一个周期的脉冲时,要求前一次检测到的电平信号为低电平,后一次检测到的电平信号为高电平时。
3、结构图:三、实验设计时钟信号 元件记忆当前的按键信号电平 元件记忆上一次按键信号电平 两次按键的电平进行比较 脉冲信号1、LPM元件定制DFF触发器(1)设置lpm_ff元件选择Installed Plug-Ins→Storage→lpm_ff项。
(2)LPM元件定制步骤,设置输入data为1位,clock为时钟信号,类型为D 型。
(3)添加异步清零和异步置1。
(4)aclr异步清零且高电平有效,aset异步置1且高电平有效,二者无效时,q输出由clock上升沿触发更新为data。
(5)调出其vhd文件添加至消抖电路的工程中。
(6)仿真验证并下载。
功能仿真波形分析参数:end time 为2.0ns,grid size为100ns;信号:alcr 异步清零且高电平有效,二进制;aset异步置1且高电平有效,二进制;二者无效,q(二进制)输出由clock(二进制)上升沿触发更新为data(二进制)。
FPGA入门系列实验教程——按键消抖控制LED亮灭1.实验任务实现按键控制LED亮灭。
通过这个实验,掌握采用Verilog HDL语言编程实现按键控制LED亮灭及按键消抖方法。
2.实验环境硬件实验环境为艾米电子工作室型号EP2C8Q208C8增强版开发套件。
软件实验环境为Quartus II8.1开发软件。
3.实验原理当独立按键key1按下后,相应的LED被点亮;再次按下后,LED做翻转输出,即LED熄灭,从而实现按键控制LED亮灭。
本实验对按键进行了消抖处理。
作为机械开关的按键,操作时,机械触点的弹性及电压突跳等原因,在触点闭合或开启的瞬间会出现电压抖动,实际应用中如果不进行处理将会造成误触发。
按键去抖动的关键在于提取稳定的低电平状态,滤除前沿、后沿抖动毛刺。
按键消抖处理一般有硬件和软件两种方法。
软件消抖是检测到有触发后,延时一段时间后再检测触发状态,如果与之前检测到的状态相同,则认为有按键按下;如果没有则认为是误触发。
硬件就是加去抖电路。
4.实验程序module key_debounce(rst_n,clk,key,led);input rst_n;input clk;input key;output led;//通过降采样对key的输入做低通滤波,将其高频分量滤除,得到low_sw值reg[17:0]cnt;always@(posedge clk)if(!rst_n)cnt<=18'd0;elsecnt<=cnt+1'b1;wire sample_pulse=cnt==18'h3ffff;reg low_sw;always@(posedge clk)if(!rst_n)low_sw<=1'b1;else if(sample_pulse)low_sw<=key;//在整个low_sw(active_low)有效过程中取一个控制量作为led的控制信号//本实例中使用low_sw的下降沿reg low_sw_r;//将low_sw信号锁存一个时钟周期,延时不是真的“锁存”always@(posedge clk)low_sw_r<=low_sw;wire led_ctrl=low_sw_r&(!low_sw);reg led;always@(posedge clk or negedge rst_n)if(!rst_n)led<=1'b0;else if(led_ctrl)led<=~led;endmodule5.实验步骤(1)建立新工程项目:打开Quartus II软件,进入集成开发环境,点击File→New project wizard建立一个工程项目key_debounce。
1.vhdl按键消抖程序一:延时性消抖在本例子中,input是按键的输入,output是消抖之后的按键输出是clk经历8个上升沿之后就让output输出一个CLK周期的高电平library ieee;use ieee.std_logic_1164.all;entity PWlock isport(clk:in std_logic;input:in std_logic;output:out std_logic);end PWlock;architecture one of PWlock issignal a:std_logic;signal count:integer range 0 to 9;beginprocess(clk)beginif input=‘0’ thencount<=0;elsif (clk‘event and clk=’1‘)thenif count=9 thencount<=count;elsecount<=count+1;end if;end if; -if count=8 thena<=’0‘;elsea<=’1‘;end if;end process;output<=a;end one;2.vhdl按键消抖程序二一般按键延时在20ms左右,根据时钟频率决定你的计数范围。
程序非常简单,但经常用到,对于FPGA初学者要好好学习这部分。
library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;entity reseter isport(clk,reset_in:in std_logic; --按键按下时为0reset_out:out std_logic:=‘0’);end reseter;architecture behav of reseter isbeginPROCESS(clk,reset_in)VARIABLE COUNT1 :INTEGER RANGE 0 TO 100000;BEGINIF reset_in=‘0’ THENIF RISING_EDGE(clk)THENIF COUNT1<10000 THEN COUNT1:=COUNT1+1;ELSE COUNT1:=COUNT1; END IF;IF COUNT1<=9999 THEN reset_out<=‘1’;ELSE reset_out<=‘0’; END IF;END IF;ELSE COUNT1:=0;reset_out<=‘1’;END IF;END PROCESS ;end behav;3.vhdl按键消抖程序三:计数器型消抖电路(一)计数器型消抖电路是设置一个模值为(N+1)的控制计数器,clk在上升沿时,如果按键开关key_in=‘1’,计数器加1,key_in=‘0’时,计数器清零。
当计数器值为2时,key_out输出才为1,其他值为0时。
计数器值为N时处于保持状态。
因此按键key_in持续时间大于N 个clk时钟周期时,计数器输出一个单脉冲,否则没有脉冲输出。
如果按键开关抖动产生的毛刺宽度小于N个时钟周期,因而毛刺作用不可能使计数器有输出,防抖动目的得以实现。
clk的时钟周期与N的值可以根据按键抖动时间由设计者自行设定。
主要程序结构如下:if(clk’event and clk=’1’)thenif(key_in=’1’)thenif count=N thencount<=count;else count<=count+1;end if;end if;else count<=0;end if;4.vhdl按键消抖程序四:计数器型消抖电路(二)计数器型消抖电路(二)是控制计数器工作一个循环周期(N+1个状态),且仅在计数器为0时输出为“1”。
电路设计了连锁控制设施。
在计数器处于状态0时,此时若有按键操作,则计数器进入状态1,同时输出单脉冲(其宽度等于时钟周期)。
计数器处于其他状态,都没有单脉冲输出。
计数器处于状态N时,控制en=‘0’,导致计数器退出状态N,进入状态0。
计数器能否保持状态0,取决于人工按键操作,若按键key_in=‘1’,控制en=‘1’(计数器能正常工作),key_in=‘0’,计数器状态保持。
显见计数器处于状态0,人工不按键,则计数器保持状态0。
主要程序结构如下:if count=N thencount<=0;else count<=count+1;end if;if count=0 thenkey_out<=’0’;end if;end ifend process;B:process(clk)beginif(clk’event and clk=’1’)thenif count<N thenif key_in=’1’ thenen<=’1’;else en<=en;end if;end if;end process;5.vhdl按键消抖程序五:D触发器型消抖电路D触发器型消抖电路设计了三个D触发器与一个三输入与门。
三个D触发器串行连接,其Q输出端分别与三输入与门的输入端连接.主要程序结构如下:key_out<=d1 or d2 or d3;process(clock)beginif(clk’event and clk=’1’)thend1<=key_in; d2<=d1; d3<=d2;end if;end process;补充:改进型D触发器(正负双输出端,本次实验被多次引用)library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_arith.all;use ieee.std_logic_unsigned.all;entity qdd isport(key,clk:in std_logic;up:out std_logic);end qdd;architecture a of qdd issignal q0,q1:std_logic;beginprocess(clk)beginif (clk'event and clk='1')thenq0<=key;q1<=q0;end if;end process;up<=(q1 and (not q0));end a;6.vhdl按键消抖程序六:状态机型消抖电路状态机型消抖电路采用有限状态机的设计方法来描述与实现,状态机有S0,S1,S2三种状态,在S0状态下key_out输出为低电平,并以clk时钟信号的频率采样按键输入信号,如果key_in=‘0’,则保持在S0状态,并继续采样按键输入信号的状态,如果key_in=‘1’,则转入S1状态;在S1状态下key_out输出仍为低电平,继续采样按键输入信号的状态,如果key_in=‘1’,则转入S2状态,如果key_in=‘0’则转入S0状态;在S2状态下继续采样按键输入信号的状态,如果key_in=‘1’,则保持在S2状态,key_out输出正脉冲,如果key_in=‘0’,则转入S0状态,key_out输出低电平。
主要程序结构如下:if clk’event and clk=’1’ thencase sta iswhen s0=>key_out<=’0’;if key_in=’1’thens<=s1;else s<=s0;end if;when s2=>if key_in=’1’thenkey_out<=’1’;s<=s2;else s<=s0;end if;when s2=>if key_in=’1’ thenkey_out<=’1’;s<=s2;elsekey_out<=’0’;s<=s0;end if;end case;end if;7.vhdl按键消抖程序七end程序中所用的方法是不断检测按键值。
每当Count[17]上升沿到来,就进行检测输入信号。
其中dout1,dout2,dout3分别为当前、上个Count[17]上升沿、上上个Count [17]上升沿输入数值。
正常情况下为1,假如连续三次为0,三个信号作或运算,使得key_done信号为0,出现下降沿,这样就认为是有按键。
assign key_done = (dout1 | dout2 | dout3); //按键消抖输出always @(posedge count[17])begindout1 <= key_in;dout2 <= dout1;dout3 <= dout2;endalways @(negedge key_done[0])beginkeyen = ~keyen;。