FPGA按键消抖实验(源码)

合集下载

按键消抖的原理和基于fpga的消抖设计

按键消抖的原理和基于fpga的消抖设计

按键消抖1功能概述按键开关是各种电子设备不可或缺的人机接口,如电脑的键盘等。

实际应用中,按键开关通常为机械式弹性开关。

当机械点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定接通,断开时也不会马上断开,在闭合和断开的瞬间均伴随有一连串的抖动。

为保证系统及时正确识别,必须对这种情况作出相应处理。

我们称之为按键消抖。

按键消抖可分为硬件消抖和软件消抖。

硬件消抖的原理是在信号输入系统之前消除抖动干扰,在按键较少的情况下比较适宜。

如果按键较多,则使用软件消抖。

软件消抖的实质在于降低键盘输入端口的采样频率,将高频抖动略去。

需要注意的是,软件消抖需要占据一定的系统资源。

尽管硬件消抖和软件消抖能实现按键消抖功能,串行处理的方式都存在一定的局限性,显得不那么完美。

而硬件资源丰富的FPGA系统采用并行处理的模式,利用硬件来减轻软件工作量,通过硬件加速软件消抖处理,即可做到软件消抖并行化,因而在按键消抖处理方面具备非常明显的优势。

优秀的设计程序应该是用最简单的代码(架构、信号)实现功能。

在本例中,我们的只需要用4个信号界定,并用很短的代码即可。

下面我们先来看看功能要求:在系统设计中,消除按键抖动的方法五花八门,无论是硬件电路和软件设计都十分成熟。

在本项目中,我们将用Verilog语言给出具体实现过程,设计一个程序来检查键值,有效滤除按键抖动区间20 ms的毛刺脉冲。

2 设计思路一般按键所用开关为机械弹性开关,由于机械触点的弹性作用,每个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。

因而在闭合及断开的瞬间均伴随有一连串的抖动,如下图。

抖动时间的长短由按键的机械特性决定,一般为5 ms~10 ms。

1图1 按键抖动过程示意当系统检测出按键闭合后,执行一个延时程序,产生5ms~10ms的延时;前沿抖动消失后,再一次检测键的状态;如果仍保持闭合状态电平,则确认为真正有键按下。

当检测到按键释放后,也要给5ms~10ms的延时,待后沿抖动消失后才能转入该键的处理程序。

FPGA按键去抖程序

FPGA按键去抖程序

FPGA按键去抖程序代码是特权同学的,我将其理解后加上了注释。

去抖的原理和单片机是一样的,即通过延时来过滤掉按键抖动产生的毛刺信号。

不同的是判断按键按下的条件不同,单片机通常是已知按键不按时IO口的电平(如高电平),当IO口电平发生改变时(如低电平),则开启定时器进行延时,延时20ms后再次读取IO口的电平,若仍为低电平,则说明有按键按下;若为高电平,则说明是按键抖动,没有按键按下。

FPGA的采样频率很高,它可以在每个时钟周期的上升沿到来时对IO口的电平进行一次读取。

通过读取相邻2个时钟周期内IO口的电平值并进行比较,若电平值发生改变(此代码中是判断电平从0变为1),则计数器清零,若持续20ms后电平值没有发生改变,则读取按键的键值,同时将这一键值存储起来,当下一个20ms后再次读取键值,将2次键值进行比较,若键值发生改变,则说明按键有动作(要么按下,要么松手)。

此代码中是判断键值从0变为1,即松手检测。

// 按键去抖// 实现一个简单的三个按键分别控制三个发光二极管亮或暗的控制。

// 例如,按键1控制发光二极管1。

上电初始发光二极管1不亮,// 当检测到按键1被按下后,发光二极管1则点亮,// 按键1再次被按下时,发光二极管1则不亮,如此反复。

// 该实验需要把握好按键消抖检测的设计技巧。

// 注:此代码的按键操作是包括松手检测的,// 即按键按下后要等到松手才算一次按键操作module key_debounce(clk,rst_n,key1_n,key2_n,key3_n,led1_n,led2_n,led3_n);input clk;input rst_n;input key1_n,key2_n,key3_n;output led1_n,led2_n,led3_n;reg [2:0] key_rst;always @(posedge clk or negedge rst_n)beginif(!rst_n)key_rst <= 3'b111;elsekey_rst <= {key3_n,key2_n,key1_n}; // 读取当前时刻的按键值endreg [2:0] key_rst_r;always @(posedge clk or negedge rst_n)beginif(!rst_n)key_rst_r <= 3'b111;elsekey_rst_r <= key_rst; // 将上一时刻的按键值进行存储endwire [2:0]key_an = key_rst_r & (~key_rst); // 当键值从0到1时key_an改变//wire [2:0]key_an = key_rst_r ^ key_rst; // 注:也可以这样写reg [19:0] cnt; // 延时用计数器always @(posedge clk or negedge rst_n)beginif(!rst_n)cnt <= 20'd0;else if(key_an)cnt <= 20'd0;elsecnt <= cnt + 20'd1;endreg [2:0] key_value;always @(posedge clk or negedge rst_n)beginif(!rst_n)key_value <= 3'b111;else if(cnt == 20'hfffff) // 2^20*1/(50MHZ)=20ms key_value <= {key3_n,key2_n,key1_n}; // 去抖20ms 后读取当前时刻的按键值endreg [2:0] key_value_r;always @(posedge clk or negedge rst_n)beginif(!rst_n)key_value_r <= 3'b111;elsekey_value_r <= key_value; // 将去抖前一时刻的按键值进行存储endwire [2:0] key_ctrl = key_value_r & (~key_value); // 当键值从0到1时key_ctrl改变reg d1;reg d2;reg d3;always @(posedge clk or negedge rst_n)beginif(!rst_n)begin // 一个if内有多条语句时不要忘了begin end d1 <= 0;d2 <= 0;d3 <= 0;endelsebeginif(key_ctrl[0]) d1 <= ~d1;if(key_ctrl[1]) d2 <= ~d2;if(key_ctrl[2]) d3 <= ~d3;endendassign led1_n = d1? 1'b1:1'b0; // 此处只是为了将LED输出进行翻转,RTL级与下面注释代码无差别assign led2_n = d2? 1'b1:1'b0; assign led3_n = d3? 1'b1:1'b0; endmodule。

基于FPGA的LED流水灯与按键消抖实验

基于FPGA的LED流水灯与按键消抖实验

基于FPGA的LED流水灯与按键消抖实验1.实验目的(1)通过实验进一步学习Quartus II软件的使用方法。

(2)通过实验学习流水灯的设计原理。

(3)通过实验学习按键消抖(边沿检测法)的基本原理。

2.实验仪器设备(1)FPGA开发实验箱。

(2)数字万用表。

(3)电脑。

3.预习(1)复习FPGA开发有关的流程。

(2)复习Verilog HDL语言语法。

(3)复习实验所用的相关原理。

(4)按要求编写实验中要求的硬件描述语言程序。

4.实验原理(1)LED流水灯。

流水灯是一个典型的FPGA程序设计,通过控制8位led向左依次循环点亮,达到对硬件语言、软件开发平台等的初步认识。

①if语句的使用。

Verilog HDL语言中的if语句与C语言中的十分相似,其使用方法有以下三种:a.if(条件1)语句块1;b.if(条件1)语句块1;else 语句块2;c.if(条件1)语句块1;else if(条件2)语句块2;……else if(条件n)语句块n;else 语句块n+1。

在上述三种方式中,“条件”一般为逻辑表达式或关系表达式,也可以是一位的变量。

如果表达式的值出现0(假),x(未知),z(高阻),则全部按“假”来处理;若为“1”,则按“真”来处理。

语句块若为单句,直接书写即可;若为多句,则需要用“begin end”块括起来。

建议无论多句还是单句都用“begin end”括起来。

②case语句的使用。

case语句是一个多路条件分支语句,常用于多路译码、状态机和微处理机的指令译码等场合。

case语句的语法格式为:case(条件表达式)分支1:语句块1;分支2:语句块2;……default:语句块nendcase其中,“分支n”通常都是一些常量表达式。

case语句先对“条件表达式”求值,然后同时并行对各分支项求值并进行比较,这是与if语句最大不同。

比较完成后,与条件表达式值相匹配的分支中的语句被执行。

分支项需要互斥,否则会出现逻辑矛盾。

【豆丁-精品】-基于FPGA的按键消抖动设计

【豆丁-精品】-基于FPGA的按键消抖动设计

2009年11月吉林师范大学学报(自然科学版)№.4第4期Journal of Jilin Normal University (Natural Science Edition )Nov.2009收稿日期:2009209222 基金项目:吉林省信息产业厅专项发展基金项目(2007042)作者简介:许德成(19772),男,吉林省辽源市人,现为吉林师范大学信息技术学院讲师,硕士.研究方向:基础电子技术,单片机及可编程逻辑器件技术.基于FPG A 的按键消抖动设计许德成(吉林师范大学信息技术学院,吉林四平136000)摘 要:在研制测量仪表、电子仪器及电子设计的过程中,按键是常用器件,而按键的弹跳现象是数字系统设计中存在的客观问题.这就要求电路具有消抖措施,即对于由于机械弹跳产生的噪声信号经过消抖电路滤除,保证电路能够正确的响应.本文介绍了基于FPG A 的两种消除按键抖动的方法,并给出了相应的VH D L 代码以及仿真图形,从而解决了按键的机械抖动影响,保证电路稳定工作.关键词:机械抖动;仿真图形;电路中图分类号:T N912 文献标识码:A 文章编号:1674238732(2009)04201542030 引言我们通常所用的按键都为机械触点开关.由于机械触点存在弹性作用,当我们按下按键或松开按键时,都不可避免的要在触点闭合及断开的瞬间产生有一连串的键抖动.其按键信号的实际波形如图1所示.图1 按键信号的实际波形 由图1可见,在按键闭合和断开时产生了多个边沿.而在实际中每按一次键,我们只需要一组稳定的上升或下降边沿.所以对于电路中的按键信号,如果我们不滤除抖动的话,还是简单的读取信号的边沿,会引起一次按键被误读多次.这样就会引起电路的误动作.为了保证按一次键电路只有一次正确的响应,即在键闭合稳定时读取键的状态,就要求电路中必须采取滤除抖动的措施.消除案件抖动的方法一般有硬件和软件两种方式.对于硬件方式一般可用RS 触发器作为常用的消抖电路,从根本上解决按键抖动问题.但对于按键较多且从节省硬件资源和易于修改的角度考虑,我们常应用软件滤抖.1 基于计数器模式消抖电路的设计方法应用计数器实现,即采用延时的方法.先正确设定计数的时钟脉冲.当判断到按键按下时计数器开始计数,等计数器计满后再一次判断键的状态.如果仍为按下状态,则认为是按键稳定闭合.这时再针对具体按键信号做相应的处理,否则认为是抖动信号,电路不做任何处理.应用这种方法消除按键抖动,其计数器模值的确定和计数时钟的频率是按键抖动消除的关键问题,因为它们共同决定了延时的时间.如果延时时间过长,就会使正确的按键信号得不到处理;如果延时时间过短,则会将抖动误认为是输入信号,从而导致后电路做出错误处理.一般人按键的时间大于100ms ,抖动时间一般·451·为5ms ~10ms.按这种常规处理,我们一般认为接收到的按键信号持续时间如果小于40ms 则其为抖动信号,如果时间大于40ms 则为正确的按键信号.即让计数器的模值和计数时钟周期的乘积略大于40ms 即可.这样就可以把按下的时间小于40ms 的抖动信号滤掉.其VH D L 代码为:library ieee ;use ieee.std -logic -1164.all ;entity anjian is port (clk ,input :in std -logic ;output :out std -logic );end anjian ;architecture one of anjian is signal a :std -logic ;signal count :integer range 0to 9;beginprocess (clk )beginif input =′0′then count <=0;elsif clk ’event and clk =′1′thenif count =9then count <=count ;else count <=count +1;end if ;end if ;if count =8then a <=′1′;else a <=′0′;end if ;end process ;output <=a ;end one; 由上仿真图可以看出:当信号维持时间小于八个计数时钟周期的时候,认为这时的信号是短时间的抖动信号,所以电路输出不做任何反应.保持原电平不变,后续电路也无需处理.当信号维持时间超过八个计数时钟周期,认为这时定稳定的按键信号,即键稳定的闭合.所以输出一个按键脉冲,以供后续电路处理.2 基于RS 触发器模式的消抖动电路设计在设计中用时钟信号进行采样.对于按键输入信号,当两次采样信号相同时,这是判定已经稳定的按下或放开了按键.触发器相应的被置成0态或1态.如两次采样结果不相同.则触发器维持原输出信号不变.由于直接由触发器输出的信号时间宽度可能过长,所以在触发器后再接一级同步化电路,保证每次输出的信号只占有一个时钟周期的宽度.应用这种方法去滤除抖动,关键是确定采样时钟的频率.保证两次采样的时间间隔能够大于按键的抖动时间,且小于正常按键时的按键稳定闭合时间.其VH D L 代码和仿真如下:library ieee ;use ieee.std -logic -1164.all ;entity dou is port (din ,clk :in std -logic ;dout :out std -logic );end entity dou ;architecture one of dou issignal clr0,clr1,q0,q1,d1,d0:std -logic ;beginclr0<=din ;clr1<=q0;process (clk ,clr0,clr1)beginif clr0=′0′then q0<=′0′;elsif clk ′event and clk =′1′thenq0<=′1′;end if ;if clr1=′0′then q1<=′0′;elsif clk ′event and clk =′1′thenq1<=′1′;end if ;end process ;process (clk )beginif clk ′event and clk =′1′thend0<=q1;d1<=d0;end if ;end process ;dout <=d0and (not d1);end ;·551· 由上仿真图形可以看出:当两次的采样信号结果相同时,这时输出信号才可能发生变化,对应的按键的稳定闭合或断开,当两次的采样信号结果不同时,认为输入的信号定抖动信号.这时电路输出维持原状态不变,同时由于有同步化的处理,输出信号的高电平宽度只为采样时钟的一个周期.3 结束语通过以上的仿真图形可以看出,对于带有机械抖动的按键信号,当它经过消抖电路处理后其输出信号已经将抖动滤除,且输出信号只占有一个时钟信号的周期,从而能使后续电路能够正确的读取键值,做相应的响应,有效的避免了误动作.因此该设计有很大的实际应用意义.参 考 文 献[1]潘 松,黄继业.E DA 技术实用教程[M].北京:科学出版社,20051[2]谭会生,瞿遂春.E DA 技术综合应用实例与分析[M].西安:西安电子科技大学出版社,2004.[3]林明权等.VH D L 数字控制系统设计范例[M].北京:电子工业出版社,2003.[4]方 龙,肖献保,李 威.关于消除按键机械抖动的研究[J ].广西轻工业,2008,1:92.[5]潘永雄,泌河,刘向阳.电子线路CAD 实用教程[M].西安:西安电子科技大学出版社,2004.[6]杨 恒,李爱国,王辉,王新安.FPG A/CP LD 最新实用技术指南[M].北京:清华大学出版社,2005.[7][美]沃尔夫(W olr.w )基于FPG A 的系统设计(英语版)[M].北京:机械工业出版社,2005.[8]王强,曾繁泰,励娜.EPA 工程的理论与实践—S OC 系统蕊片设计[M].北京:电子工业出版社,2004.[9]李国洪,胡辉,沈阳山等.E DA 技术与实验[M].北京:电子工业出版社,2005.Shaking R elease Design on the K eys of FPGAXU De 2cheng(C ollege of In formation T echnology ,Jilin N ormal University ,S iping 136000,China )Abstract :K eys were the comm on elements during the research of measure instrument ,electronic apparatus ,and design of the electronic.The bounce phenomenon of keys was the objective problem in the digital system design.Therefore ,the shaking release measurement was necessary.That is to rem ove the noise signal at the engine bounce through the elimi 2nating the shaking circuit in order to ensure the right response of the circuit.The paper introduced tw o methods of elim 2inating shaking on FPG A and gave the relative VH D L code and the imitating picture.It res olved the in fluence of engine shaking on keys and ensurd the steady w orking of the circuit.K ey w ords :engine shaking ;imitating picture ;circuit·651·。

键盘消抖原理代码说明(Verilog)

键盘消抖原理代码说明(Verilog)

笔记2 键盘消抖(别人的笔记)老实说,这个实验的开始之前和之后,都给我蛋疼了。

时钟了解不到源码的思路,边看源码边睡着。

醒来的时候既然“惊”一下,相通了......module lesson02(CLK, RST,SW0, SW1, SW2,LED0, LED1, LED2);input CLK;input RST;input SW0, SW1, SW2;output LED0, LED1, LED2;//---------------------------------------------------------------------------//Detect the switch pressingreg [2:0] Press0;reg [2:0] Press1;wire [2:0] isPress;always @ (posedge CLK or negedge RST)if(!RST)Press0 <= 3'b111;elsePress0 <= {SW0, SW1, SW2}; //read the pin result;always @ (posedge CLK or negedge RST)if(!RST)Press1 <= 3'b111;elsePress1 <= Press0; //read the previous Press0 resultassign isPress=Press1 & (~Press0); //detect the logic with bit is changed from logic 1 to 0 //---------------------------------------------------------------------------//if pressing, counter start counting for 20msreg [19:0] Counter; //计数寄存器always @ (posedge CLK or negedge RST)if(!RST)Counter <= 20'd0;else if(isPress)Counter <= 20'd0;elseCounter <= Counter + 1'b1; //increment for counter//------------------------------------------------------------------------//After 20ms read the key pin resultreg [2:0] Press2;reg [2:0] Press3;wire [2:0] Result;always @ (posedge CLK or negedge RST)if(!RST)beginPress2 <= 3'b111;Press3 <= 3'b111;endelse if(Counter == 20'hfffff)Press2 <= {SW0, SW1, SW2}; //read the pin result after 20mselsealways @ (posedge CLK or negedge RST)if(!RST)elsePress3 <= Press2; //read the previous pin resultassign Result = Press3 & (~Press2); //detect the changing bit from logic 1 to 0//------------------------------------------------------------------------//turn on led with pin resultreg D1;reg D2;reg D3;always @ (posedge CLK or negedge RST)if(!RST)beginD1 <= 1'b0;D2 <= 1'b0;D3 <= 1'b0;endelsebeginif( Result[0] ) D1 <= ~D1;if( Result[1] ) D2 <= ~D2;if( Result[2] ) D3 <= ~D3;endassign LED0 = D1 ? 1'b1 : 1'b0;assign LED1 = D2 ? 1'b1 : 1'b0;assign LED2 = D3 ? 1'b1 : 1'b0;endmodule这个实验主要有计数器和边缘检查来实现按键消抖,按键功能。

实验23按键消抖冯冠玺

实验23按键消抖冯冠玺
wire clkout_100,key_pulse;
initial
begin
led=0;
end
Fenpin fp(clk_100m,clkout_100,reset);//分频模块,有100MHz的作为输入,输出是100Hz时钟
Xiaodou xd(reset,clkout_100,key,key_pulse);//消抖模块,接收100Hz时钟,输出是key_pulse
always@(posedge reset or posedge clk_100M)
begin
if(reset)
begin
counter<=19'd0;
clkout_100<=1'b0;
end
else if(counter==19'd500000)/*在counter为1M的一半时,反转状态,也就是每半个周期方波信号从0变为1,或从1变为0*/
第18,19个实验:郑凯
各模块示意图:
一.分频器模块
clk_100mclk_100m分频器
clk_10ms
clkout_100
resetreset
二.按键消抖模块
reset reset
按键消抖模块
clk_100 clk
key_pulse
keykey
三.计数器模块
计数器
resetreset
led
clkclk
S5:key_pulse<=key?1:0;
endcase
case(ST)
S0:ST<=key?S1:S0;
S1:ST<=key?S3:S2;
S2:ST<=key?S1:S0;

基于FPGA的抖动及消抖的方法

基于FPGA的抖动及消抖的方法

基于FPGA的抖动及消抖的方法抖动的产生通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。

因而在闭合及断开的瞬间均伴随有一连串的抖动,为了不产生这种现象而作的措施就是按键消抖。

抖动时间抖动时间的长短由按键的机械特性决定,一般为5ms~10ms。

这是一个很重要的时间参数,在很多场合都要用到按键稳定闭合时间的长短则是由操作人员的按键动作决定的,一般为零点几秒至数秒。

键抖动会引起一次按键被误读多次。

为确保FPGA对键的一次闭合仅作一次处理,必须去除键抖动。

在键闭合稳定时读取键的状态,并且必须判别到键释放稳定后再作处理。

FPGA内实现消抖的方法在FPGA内实现按键消抖的方法多种多样,但是最简单的是采用移位寄存器的方法进行消抖。

因为移位寄存器的方法不需要对时钟进行分频,也不需要进行延时等复杂操作,即可实现对按键边沿的检测。

假设未按下时键值=1.1、在无键按下时,移位寄存器samp[7:0]始终采集到高电平,即samp[7:0]=8b1111_1111;2、当键按下时,samp[7:0]将采集到低电平,数据的变化方式为samp[7:0]=8b1111_1110--8b1111_1100--8b1111_1000-- ........8b0000_0000;samp[7:0]=8b1111_ 1110即为按键下降沿。

3、当松开按键时,samp[7:0]将重新采集到高电平,数据变化方式为samp[7:0]=8b0000_0001--8b0000_0011-- ........--8b1111_1111;当samp[7:0]=8b0111_1111时,即为按键上升沿。

参考Verilog代码//模块名:EdgeDetect,边沿检测//button:按键,无键按下时为高电平//clk:10M时钟//rst:复位按钮,低电平有效//rise:检测到上升沿,高电平有效,宽度为1个clk//fall:检测到下降沿,高电平有效,宽度为1个clkmodule EdgeDetect(input clk,input rst,input button,output reg rise,output reg fall);。

Verilog的键盘源码keypad—有去抖功能

Verilog的键盘源码keypad—有去抖功能

下面是转的一个源码,俺没有细看,有兴趣的看看,讲讲如何// author: Dandy Nee// mail: dandynee@// module: HW KeyScan Module// version:0.1// **************************// all functions are provided as if okay// run at your own risk// **************************//// problem: there is one keyvalue valid// indicator signal needed////------------------------------------------------//// ^ ^ ^ ^ Pull Up// | | | |// x0 >--|--|--|--|-// x1 >--|--|--|--|-// x2 >--|--|--|--|-// x3 >--|--|--|--|-// y0 <--+ | | |// y1 <-----+ | |// y2 <--------+ |// y3 <-----------+//module m_keyscan(clk, //system clkrstb, //system a-rst, low active//clkdiv, //clock divide coef//keyvalue, //returned key//x, //x-row scan outy //y-col scan in);input clk, rstb;input [19:0] clkdiv;output [15:0] keyvalue;output [3:0] x;input [3:0] y;reg [19:0] cnt;always @(posedge clk or negedge rstb) if(~rstb)cnt<=0;elsecnt <= cnt==clkdiv ? 0 : cnt+1;reg clken;always @(posedge clk or negedge rstb) if(~rstb)clken <= 0;elseclken <= cnt==clkdiv;reg [2:0] fsm;always @(posedge clk or negedge rstb) if(~rstb)fsm <= 0;else if(clken)fsm <= fsm+1; //8 statesreg [15:0] keyvalue;reg [3:0] x;always @(posedge clk or negedge rstb) if(~rstb)keyvalue <= 0;else if(clken)case(fsm)0: beginx <= 4'b1110;end1: beginkeyvalue[3:0] <= ~y;end2: beginx <= 4'b1101;end3: beginkeyvalue[7:4] <= ~y;end4: beginx <= 4'b1011;end5: beginkeyvalue[11:8] <= ~y;end6: beginx <= 4'b0111;end7: beginkeyvalue[15:12] <= ~y;endendcaseendmodule本程序做的只是按键单纯挂在IO上,并不是行列扫描的。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

modulekey_scan(
inputclk,
inputrst_n,
input [3:0] row, // 矩阵键盘行
output reg [3:0] col, // 矩阵键盘列
output reg [7:0] key_val // 键盘值
);
//++++++++++++++++++++++++++++++++++++++
// 分频部分开始
//++++++++++++++++++++++++++++++++++++++
reg [19:0] cnt; // 计数子
always @ (posedgeclk, negedgerst_n)
if (!rst_n)
cnt<= 0;
else
cnt<= cnt + 1'b1;
wirekey_clk = cnt[19]; // (2^20/50M = 21)ms //--------------------------------------
// 分频部分结束
//--------------------------------------
//++++++++++++++++++++++++++++++++++++++
// 状态机部分开始
//++++++++++++++++++++++++++++++++++++++
// 状态数较少,独热码编码
parameter NO_KEY_PRESSED = 6'b000_001; // 没有按键按下parameter SCAN_COL0 = 6'b000_010; // 扫描第0列parameter SCAN_COL1 = 6'b000_100; // 扫描第1列parameter SCAN_COL2 = 6'b001_000; // 扫描第2列parameter SCAN_COL3 = 6'b010_000; // 扫描第3列parameter KEY_PRESSED = 6'b100_000; // 有按键按下
reg [5:0] current_state, next_state; // 现态、次态
always @ (posedgekey_clk, negedgerst_n)
if (!rst_n)
current_state<= NO_KEY_PRESSED;
else
current_state<= next_state;
// 根据条件转移状态
always @ *
case (current_state)
NO_KEY_PRESSED : // 没有按键按下if (row != 4'hF)
next_state = SCAN_COL0;
else
next_state = NO_KEY_PRESSED;
SCAN_COL0 : // 扫描第0列if (row != 4'hF)
next_state = KEY_PRESSED;
else
next_state = SCAN_COL1;
SCAN_COL1 : // 扫描第1列if (row != 4'hF)
next_state = KEY_PRESSED;
else
next_state = SCAN_COL2;
SCAN_COL2 : // 扫描第2列if (row != 4'hF)
next_state = KEY_PRESSED;
else
next_state = SCAN_COL3;
SCAN_COL3 : // 扫描第3列if (row != 4'hF)
next_state = KEY_PRESSED;
else
next_state = NO_KEY_PRESSED;
KEY_PRESSED : // 有按键按下
if (row != 4'hF)
next_state = KEY_PRESSED;
else
next_state = NO_KEY_PRESSED;
endcase
regkey_pressed_flag; // 键盘按下标志
reg [3:0] col_val, row_val; // 列值、行值
// 根据次态,给相应寄存器赋值
always @ (posedgekey_clk, negedgerst_n)
if (!rst_n)
begin
col<= 4'h0;
key_pressed_flag<= 0;
end
else
case (next_state)
NO_KEY_PRESSED : // 没有按键按下begin
col<= 4'h0;
key_pressed_flag<= 0; // 清键盘按下标志
end
SCAN_COL0 : // 扫描第0列col<= 4'b1110;
SCAN_COL1 : // 扫描第1列col<= 4'b1101;
SCAN_COL2 : // 扫描第2列col<= 4'b1011;
SCAN_COL3 : // 扫描第3列col<= 4'b0111;
KEY_PRESSED : // 有按键按下begin
col_val<= col; // 锁存列值
row_val<= row; // 锁存行值
key_pressed_flag<= 1; // 置键盘按下标志
end
endcase
//--------------------------------------
// 状态机部分结束
//--------------------------------------
//++++++++++++++++++++++++++++++++++++++
// 扫描行列值部分开始
//++++++++++++++++++++++++++++++++++++++
always @ (posedgekey_clk, negedgerst_n)
if (!rst_n)
key_val<= 4'h0;
else
if (key_pressed_flag)
case ({col_val, row_val})
8'b1110_1110 :key_val<= 8'h01;
8'b1110_1101 :key_val<= 8'h02;
8'b1110_1011 :key_val<= 8'h03;
8'b1110_0111 :key_val<= 8'h04;
8'b1101_1110 :key_val<= 8'h05;
8'b1101_1101 :key_val<= 8'h06;
8'b1101_1011 :key_val<= 8'h07;
8'b1101_0111 :key_val<= 8'h08;
8'b1011_1110 :key_val<= 8'h09;
8'b1011_1101 :key_val<= 8'h10;
8'b1011_1011 :key_val<= 8'h11;
8'b1011_0111 :key_val<= 8'h12;
8'b0111_1110 :key_val<= 8'h13;
8'b0111_1101 :key_val<= 8'h14;
8'b0111_1011 :key_val<= 8'h15;
8'b0111_0111 :key_val<= 8'h16; default: key_val=8'h00;
endcase
endmodule。

相关文档
最新文档