当前位置:文档之家› 按键消抖

按键消抖

一、按键消抖1.1 计数器型消抖电路(一)计数器型消抖电路(一)是设置一个模值为(N+1)的控制计数器,clk在上升沿时,如果按键开关key_in='1',计数器加1,key_in='0' 时,计数器清零。

当计数器值为2时,key_out 输出才为1,其他值为0时。

计数器值为N时处于保持状态。

因此按键key_in持续时间大于N个clk时钟周期时,计数器输出一个单脉冲,否则没有脉冲输出。

如果按键开关抖动产生的毛刺宽度小于N个时钟周期,因而毛刺作用不可能使计数器有输出,防抖动目的得以实现。

clk的时钟周期与N的值可以根据按键抖动时间由设计者自行设定。

主要程序结构如下:图1是N为3的波形仿真图,当按键持续时间大于3个时钟周期,计数器输出一个单脉冲,其宽度为1个时钟周期,小于3个时钟周期的窄脉冲用作模拟抖动干扰,从图1可以看出,抖动不能干扰正常的单脉冲输出。

1 按键抖动产生原因分析绝大多数按键都是机械式开关结构,由于机械式开关的核心部件为弹性金属簧片,因而在开关切换的瞬间会在接触点出现来回弹跳的现象。

虽然只是进行了一次按键,结果在按键信号稳定的前后出现了多个脉冲,如图1所示。

如果将这样的信号直接送给微处理器扫描采集的话,将可能把按键稳定前后出现的脉冲信号当作按键信号,这就出现人为的一次按键但微处理器以为多次按键现象。

为了确保按键识别的准确性,在按键信号抖动的情况下不能进入状态输入,为此就必须对按键进行消抖处理,消除抖动时不稳定、随机的电压信号。

机械式按键的抖动次数、抖动时间、抖动波形都是随机的。

不同类型的按键其最长抖动时间也有差别,抖动时间的长短和按键的机械特性有关,一般为5~10 ms,但是,有些按键的抖动时间可达到20 ms,甚至更长。

所以,在具体设计中要具体分析,根据实际情况来调整设计。

2 按键消抖电路的设计按键消抖一般采用硬件和软件消抖两种方法。

硬件消抖是利用电路滤波的原理实现,软件消抖是通过按键延时来实现。

在微机系统中一般都采用软件延时的消抖方法。

在用可编程逻辑器件FPGA/CPLD设计数字系统中,也可以用VHDL语言设计相应的时序和逻辑电路,对按键信号进行处理,同样可以达到消抖目的。

本文利用Altera公司的可编程逻辑器件CPLD和QuartusⅡ,设计性能可靠的按键消抖电路。

2.1 按键消抖电路设计原理按键消抖的关键是提取稳定的低电平(或高电平)状态,滤除按键稳定前后的抖动脉冲。

在用基于VHDL 语言的时序逻辑电路设计按键消抖电路时,可以用一个时钟脉冲信号对按键状态进行取样,当第一次采样到低电平时,启动延时电路,延时结束后,再对按键信号进行连续三次取样,如果三次取样都为低电平,则可以认为按键已经处在稳定状态,这时输出一个低电平的按键确认信号,如果连续三次的取样中,至少有一次是高电平,则认为按键仍处在抖动状态,此时不进行按键确认,按键输出信号为高电平。

2.2 按键消抖电路设计该控制电路采用VHDL语言的有限状态机的设计方法来描述和实现,其状态转换图如图2所示。

电路的复位信号Reset有效时,电路进入复位状态S0,在S0状态下时钟信号CLK以一定的频率采样按键输入信号Key_in,如果采样到Key_in=‘1’则停留在S0状态,并继续采样按键输入信号的状态,一旦采样到输入信号是低电平,即Key_in=‘0’,则转入S1延时状态,进行消抖延时,当延时结束时Delay_end=‘1’,则转入在S2状态,在此状态下时钟信号CLK以一定频率采样按键输入Key_in的状态,如果采样到Key_in为高电平即Key_in=‘1’则转回状态S0,表示按键仍处在抖动状态,如果采样到Key_in=‘O’,则转入状态S3;状态S3,S4的转换过程和条件跟S2相同,在S4状态下,如果Key_in=‘0’则转入S5状态,当到达状态S5时.表示经过S2,S3,S4三个连续状态检测按键输入Key_in的状态都为‘0’,则认为按键处在稳定状态,并在S5输出按键确认信号Key_confirm=‘1’。

同时在状态S5下时钟信号CLK检测按键输入状态,当检测到按键输入Key_in=‘0’,表示按键仍未释放,则停留在S5继续检测按键输入信号状态,如果检测到Key_in=‘1’,表示按键已经释放,则转回状态S0,等待下一次按键操作。

3 按键消抖电路的仿真分析消抖电路的仿真图如图3所示。

当复位信号Reset=‘0’时,状态机Key处在S0状态,同时以CLK的时钟频率采样按键输入信号Din的状态,当CLK第一次采样到Din为低电平时,此时可能发生了按键操作,随即状态机Key进入S1消抖延时状态,当延时结束时delay_end=‘1’(延时结束信号),跟接着状态机KEY 的S2,S3,S4连续三个状态对按键输入信号Din进行采样,当三个状态下采样到Din信号都是低电平,则转入S5状态,并产生按键确认信号Key_confirm=‘1’,同时在S5状态下等待按键释放,在此状态下当CLK时钟信号检测到Din为高电平时转回状态S0。

因按键释放瞬间也会发生抖动,所以由波形图可以看出,当按键释放瞬间由状态S5转回状态S0,在S0状态下,因按键抖动CLK时钟又检测到Din为低电平,随即转入S1进行消抖延时,经过S1的消抖延时后,按键已经稳定,Din为稳定的高电平,所以在状态S2检测到Din为高电平,则转入S0状态,到此时完成一次按键的操作,等待下一次按键操作,如果没有按键操作,即按键没按下,则一直保持在状态S0。

4 结语采用有限状态机方法设计按键消抖电路,再根据按键的特性设定合适的延时时间(一般10 ms)后,通过仿真分析及实验验证,能够起到很好的消抖效果,而且性能稳定,能确保每一次按键操作,产生一次按键确认,可广泛应用于可编程逻辑器件的键盘扫描设计中。

基于CPLD 的VHDL 语言数字钟设计基于CPLD 的VHDL 语言数字钟()设计利用一块芯片完成除时钟源、按键、扬声器和显示器(数码管)之外的所有数字电路功能。

所有数字逻辑功能都在CPLD 器件上用VHDL 语言实现。

这样设计具有体积小、设计周期短(设计过程中即可实现时序仿真)、调试方便、故障率低、修改升级容易等特点。

本设计采用自顶向下、混合输入方式(原理图输入—顶层文件连接和VHDL 语言输入—各模块程序设计)实现数字钟的设计、下载和调试。

一、功能说明已完成功能1. 完成秒/分/时的依次显示并正确计数;2. 秒/分/时各段个位满10 正确进位,秒/分能做到满60 向前进位;3. 定时闹钟:实现整点报时,又扬声器发出报时声音;4. 时间设置,也就是手动调时功能:当认为时钟不准确时,可以分别对分/时钟进行调整;5. 利用多余两位数码管完成秒表显示:A、精度达10ms;B、可以清零;C、完成暂停可以随时记时、暂停后记录数据。

待改进功能:1.闹钟只是整点报时,不能手动设置报时时间,遗憾之一;2.秒表不能向秒进位,也就是最多只能记时100ms;3.秒表暂停记录数据后不能在原有基础上继续计时,而是复位重新开始。

【注意】秒表为后来添加功能,所以有很多功能不成熟!二、设计方案1. 数字钟顶层设计外部输入要求:输入信号有1kHz/1Hz 时钟信号、低电平有效的秒/微秒清零信号CLR、低电平有效的调分信号SETmin、低电平有效的调时信号SEThour;外部输出要求:整点报时信号SOUND(59 分51/3/5/7 秒时未500Hz 低频声,59 分59 秒时为1kHz 高频声)、时十位显示信号h1(a,b,c,d,e,f,g)、时个位显示信号h0(a ,b,c,d,e,f,g)、分十位显示信号m1 及分个位m0、秒十位s1 及秒个位s0、微秒十位ms1 及微秒个位ms0;数码管显示位选信号SEL0/1/2 等三个信号。

2. 内部功能模块主要有:Fenp 分频模块:主要是整点报时用的1kH 与500Hz 的脉冲信号,这里的输入信号是1KHz 信号,所以只要一个二分频即可;时间基准采用1Hz 输入信号直接提供(当然也可以分频取得,这里先用的是分频取得的信号,后考虑到精度问题而采用硬件频率信号。

实现带有100 进制进位和清零功能,暂定等功能的微秒模块MINSECONDB 输入为1Hz 脉冲和低电平的清零信号CLR 与暂定信号STOP,输出微秒个位、十位及进位信号CO(虽然没有实现进位功能,但还是编写了这个端口,只是在连线时悬空)。

实现60 进制带有进位和清零功能的秒计数模块SECOND,输入为1Hz 脉冲和低电平有效的清零信号CLR,输出秒个位、时位及进位信号CO。

实现60 进制带有进位和置数功能的分计数模块MINUTE,输入为1Hz 脉冲和高 1 基于CPLD 的VHDL 语言数字钟设计电平有效的使能信号EN,输出分个位、时位及进位信号CO。

实现24 进制的时计数模块HOUR,输入为1Hz 脉冲和高电平有效的使能信号EN,输出分个位、时位。

实现分时复用功能模块SELTIME,输入为秒(含个/十位)、分、时、扫描时钟CLK1K,输出为D 和显示控制信号SEL。

实现整点报时功能模块ALERT,输入为分/秒信号,输出为高频声控Q1K 和Q500。

实现译码显示功能模块DISPLAY,输入为D,输出为Q三、设计框图高/低电平频率信号输入分频进进进微秒模块位秒模块位分模块位时模块置数/位选显示模块四、模块说明(含程序代码)1. 分频模块 2 基于CPLD 的VHDL 语言数字钟设计采用原理图输入方式实现 2 分频与1000 分频,但这里并没有用到1000 分频,因为后来考虑到精度问题,将千分频用直接输入了。

程序如图:利用三个7490 进行硬件分频!2. 微秒模块采用VHDL 语言输入方式,以时钟clk,清零信号clr 以及暂停信号STOP 为进程敏感变量,程序如下:library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;entity MINSECONDb isport(clk,clrm,stop:in std_logic;----时钟/清零信号secm1,secm0:out std_logic_vector(3 downto 0);----秒高位/低位co:out std_logic);-------输出/进位信号end MINSECONDb;architecture SEC of MINSECONDb issignal clk1,DOUT2:std_logic;beginprocess(clk,clrm)variable cnt1,cnt0:std_logic_vector(3 downto 0);---计数V ARIABLE COUNT2 :INTEGER RANGE 0 TO 10 ;beginIF CLK'EVENT AND CLK='1'THENIF COUNT2>=0 AND COUNT2<10 THENCOUNT2:=COUNT2+1;ELSE COUNT2:=0;DOUT2<= NOT DOUT2;END IF; 3 基于CPLD 的VHDL 语言数字钟END IF;if clrm='1' then----当clr 为1 时,高低位均为0cnt1:="0000";cnt0:="0000";elsif clk'event and clk='1' thenif stop='1' thencnt0:=cnt0;cnt1:=cnt1;end if;if cnt1="1001" and cnt0="1000" then----当记数为98(实际是经过59 个记时脉冲)co<='1';----进位cnt0:="1001";----低位为9elsif cnt0<"1001" then----小于9 时cnt0:=cnt0+1;----计数--elsif cnt0="1001" then--clk1<=not clk1;Elsecnt0:="0000";if cnt1<"1001" then----高位小于9 时cnt1:=cnt1+1;elsecnt1:="0000";co<='0';end if;end if;end if;secm1<=cnt1;secm0<=cnt0;end process;end SEC;3. 秒模块程序清单library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;entity SECOND is port(clk,clr:in std_logic;----时钟/清零信号sec1,sec0:out std_logic_vector(3 downto 0);----秒高位/低位co:out std_logic);-------输出/进位信号4 基于CPLD 的VHDL 语言数字钟end SECOND;architecture SEC of SECOND isbeginprocess(clk,clr)variable cnt1,cnt0:std_logic_vector(3 downto 0);---计数beginif clr='1' then----当ckr 为1 时,高低位均为0cnt1:="0000";cnt0:="0000";elsif clk'event and clk='1' thenif cnt1="0101" and cnt0="1000" then----当记数为58(实际是经过59 个记时脉冲)co<='1';----进位cnt0:="1001";----低位为9elsif cnt0<"1001" then----小于9 时cnt0:=cnt0+1;----计数elsecnt0:="0000";if cnt1<"0101" then----高位小于5 时cnt1:=cnt1+1;elsecnt1:="0000";co<='0';end if;end if;end if;sec1<=cnt1;sec0<=cnt0;end process;end SEC;4. 分模块程序清单library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;entity MINUTE isport(clk,en:in std_logic; min1,min0:out std_logic_vector(3 downto 0); co:out std_logic); end MINUTE; 5 基于CPLD 的VHDL 语言数字钟architecture MIN of MINUTE isbeginprocess(clk)variable cnt1,cnt0:std_logic_vector(3 downto 0);beginif clk'event and clk='1' thenif en='1' thenif cnt1="0101" and cnt0="1000" thenco<='1';cnt0:="1001";elsif cnt0<"1001" thencnt0:=cnt0+1;elsecnt0:="0000";if cnt1<"0101" thencnt1:=cnt1+1;elsecnt1:="0000";co<='0';end if;end if;end if;end if;min1<=cnt1;min0<=cnt0;end process;end MIN;5. 时模块程序清单library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;entity HOUR isport(clk,en:in std_logic;----输入时钟/高电平有效的使能信号h1,h0:out std_logic_vector(3 downto 0));----时高位/低位end HOUR;architecture hour_arc of HOUR isbeginprocess(clk)variable cnt1,cnt0:std_logic_vector(3 downto 0);----记数6 基于CPLD 的VHDL 语言数字钟beginif clk'event and clk='1' then---上升沿触发if en='1' then---同时“使能”为1if cnt1="0010" and cnt0="0011" thencnt1:="0000";----高位/低位同时为0 时cnt0:="0000";elsif cnt0<"1001" then----低位小于9 时,低位记数累加cnt0:=cnt0+1;elsecnt0:="0000";cnt1:=cnt1+1;-----高位记数累加end if;end if;end if;h1<=cnt1;h0<=cnt0;end process;end hour_arc;6. 动态扫描模块library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;use ieee.std_logic_arith.all;entity SELTIME isport( clk:in std_logic;------扫描时钟secm1,secm0,sec1,sec0,min1,min0,h1,h0:in std_logic_vector(3 downto 0);-----分别为秒个位/时位;分个位/ daout:out std_logic_vector(3 downto 0);----------------输出sel:out std_logic_vector(2 downto 0));-----位选信号end SELTIME;architecture fun of SELTIME issignal count:std_logic_vector(2 downto 0);----计数信号beginsel<=count;process(clk)beginif(clk'event and clk='1') thenif(count>="111") thencount<="000";elsecount<=count+1;end if; 7 基于CPLD 的VHDL 语言数字钟end if;case count iswhen"111"=>daout<= secm0;----秒个位when"110"=>daout<= secm1;----秒十位when"101"=>daout<= sec0;----分个位when"100"=>daout<= sec1;----分十位when"011"=>daout<=min0; ----时个位when"010"=>daout<=min1;----时十位when"001"=>daout<=h0;when others =>daout<=h1; end case;end process;end fun;7. 报时模块library ieee;use ieee.std_logic_1164.all;entity ALERT isport(m1,m0,s1,s0:in std_logic_vector(3 downto 0);------输入秒、分高/低位信号clk:in std_logic;------高频声控制q500,qlk:out std_logic);----低频声控制end ALERT;architecture sss_arc of ALERT isbeginprocess(clk)beginif clk'event and clk='1' thenif m1="0101" and m0="1001" and s1="0101" then----当秒高位为5,低位为9 时且分高位为5if s0="0001" or s0="0011" or s0="0101" or s0="0111" then---当分的低位为1 或3 或5或7时q500<='1';----低频输出为1else q500<='0';----否则输出为0end if;end if;if m1="0101" and m0="1001" and s1="0101" and s0="1001" then---当秒高位为5,低位为9 时且分高位为5,----分低位为9 时,也就是“59 分59 秒”的时候“报时” qlk<='1';-----高频输出为1elseqlk<='0'; 8 基于CPLD 的VHDL 语言数字钟end if;end if;end process;end sss_arc;8. 显示模块library ieee;use ieee.std_logic_1164.all;entity DISPLAY isport(d:in std_logic_vector(3 downto 0);----连接seltime 扫描部分 d 信号q:out std_logic_vector(6 downto 0));----输出段选信号(电平)end DISPLAY;architecture disp_are of DISPLAY isbeginprocess(d)begincase d iswhen"0000" =>q<="0111111";--显示0when"0001" =>q<="0000110";--显示1when"0010" =>q<="1011011";--显示2when"0011" =>q<="1001111";--显示3when"0100" =>q<="1100110";--显示4when"0101" =>q<="1101101";--显示5when"0110" =>q<="1111101";--显示6when"0111" =>q<="0100111";--显示7when"1000" =>q<="1111111";--显示8when others =>q<="1101111";--显示9end case; end process; end disp_are;9. 顶层文件(原理图输入)9 基于CPLD 的VHDL 语言数字钟******************************************************************** 数字钟模块与程序(不)*********************************************************************。

相关主题