Verilog-按键消抖程序
- 格式:doc
- 大小:43.46 KB
- 文档页数:6
这学期的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 等等的功能,这里不详细解释。
FPGA上电复位和按键复位当初开始学FPGA的时候,总是疑惑:FPGA不是没有复位管教么,但总在always看到有复位信号。
这个复位信号(我们暂且称为rst_n)从哪里来?从我们自己搭建的外部复位信号产生电路里来。
一个简易的复位电路(既可以实现上电复位又可以实现按键复位)如下:上电复位:这个电路在系统接电后由3.3V经过R21给C10充电,此时复位管脚上得到低电平.经过一段时间后,C10被充满,复位管脚电平升高.最后稳定在高电平.这是上电时的情况,即上电复位.按键复位:当按下B1时,C10经过R22放电到地,复位管脚被瞬间拉到低电平,当按键放开后,C10再次通过R21充电,经过一段时间后稳定到高电平.完成手动复位.这个电路上电复位还行,但按键复位是不够的.由于FPGA是高速电路,在按键复位开关按键的时候会产生抖动,生成很多毛刺方波,这对于我们的电路来说是很有害的.可以通过verilog编写防抖程序来消除可能的误动作。
/*************************************** 功能:上电复位模块(未加消抖程序)* 输入参数:* clk: 50M 时钟输入* rst_n:外部按键全局复位信号* 输出参数:* sys_rst_n:系统全局同步复位信号***************************************/ module reset(input clk,input rst_n,output sys_rst_n);//------------------------------------------ // Delay 100ms for steady statereg [22:0] cnt;always@(posedge clk or negedge rst_n)beginif(!rst_n)cnt <= 0;elsebeginif(cnt < 23'd50_00000) //100mscnt <= cnt+1'b1;elsecnt <= cnt;endend//------------------------------------------ //rst_n synchronismreg rst_nr0;reg rst_nr1;always@(posedge clk or negedge rst_n)beginif(!rst_n)beginrst_nr0 <= 0;rst_nr1 <= 0;endelse if(cnt == 23'd50_00000) beginrst_nr0 <= 1;rst_nr1 <= rst_nr0;endelsebeginrst_nr0 <= 0;rst_nr1 <= 0;endendassign sys_rst_n = rst_nr1;endmodule消抖程序可如下设计:module fangdou(in,clk,out);input in,clk;output out;reg i,out;initial out=0;always @(posedge clk) //clk可以是系统时钟分频得到的,其的周期约100msbeginif(in==1)if(i==1)out<=1; //如果相邻的两个时钟上升沿都是都有in==1,那就说明是按键动作而非干扰,那么把out置1.elsei<=1;elsebegini<=0;out<=0; endend endmodule。
Verilog基本电路设计(包括:时钟域同步、无缝切换、异步FIFO、去抖滤波))Verilog基本电路设计共包括四部分:单bit跨时钟域同步时钟无缝切换异步FIFO去抖滤波Verilog基本电路设计之一: 单bit跨时钟域同步(帖子链接:/thread-605419-1-1.html)看到坛子里不少朋友,对于基本数字电路存在这样那样的疑惑,本人决定开贴,介绍数字电路最常见的模块单元,希望给初学者带来帮助,也欢迎大佬们前来拍砖。
如果想要做数字设计,下面这些电路是一定会碰到的,也是所有大型IP,SOC设计必不可少的基础,主要包括异步信号的同步处理,同步FIFO,异步FIFO,时钟无缝切换,信号滤波debounce等等,后面会根据大家反馈情况再介绍新电路。
首先介绍异步信号的跨时钟域同步问题。
一般分为单bit的控制信号同步,以及多bit的数据信号同步。
多bit的信号同步会使用异步FIFO完成,而单bit的信号同步,又是时钟无缝切换电路以及异步FIFO电路的设计基础,这里先介绍单bit信号同步处理。
clka域下的信号signal_a,向异步的clkb域传递时,会产生亚稳态问题。
所有的亚稳态,归根结底就是setup/hold时间不满足导致。
在同一个时钟域下的信号,综合以及布线工具可以在data路径或者clock路径上插入buffer使得每一个DFF的setup/hold时间都满足;但是当signal_a在clkb域下使用时,由于clka与clkb异步,它们的相位关系不确定,那么在clkb的时钟沿到来时,无法确定signal_a此时是否处于稳定无变化状态,也即setup/hold时间无法确定,从而产生亚稳态。
这种异步信号在前后端流程里面是无法做时序分析的,也就是静态时序分析里常说的false_path。
消除亚稳态,就是采用多级DFF来采样来自另一个时钟域的信号,级数越多,同步过来的信号越稳定。
对于频率很高的设计,建议至少用三级DFF,而两级DFF同步则是所有异步信号处理的最基本要求。
verilog mode使用方法要使用Verilog模式,您必须首先安装Emacs。
安装后,您需要将以下代码添加到您的Emacs配置文件中(通常是~/.emacs或~/.emacs.d/init.el):emacs-lisp;; 首先添加MELPA存储库(require 'package)(add-to-list 'package-archives '("melpa" . " t)(package-initialize);; 安装verilog-mode(unless (package-installed-p 'verilog-mode)(package-refresh-contents)(package-install 'verilog-mode));; 设置.verilog文件使用Verilog模式(add-to-list 'auto-mode-alist '("\\.v\\'" . verilog-mode))保存配置文件并重新启动Emacs。
现在,当您打开一个具有.verilog扩展名的Verilog文件时,Emacs将自动使用Verilog模式。
在Verilog模式中,您可以使用以下快捷键:- `C-c C-c`:编译当前Verilog文件。
- `C-c C-v`:运行Verilog模拟器(例如VCS,ModelSim)以运行当前文件。
- `C-c C-s`:在当前行处设置一个断点。
- `C-c C-k`:从当前点开始编译并运行直到下一个断点。
- `C-c C-r`:重新运行上次运行的模拟器命令。
您还可以使用Tab键自动缩进Verilog代码,并使用其他诸如代码折叠、自动补全等功能。
这只是Verilog模式的一些基本用法,有更多功能可以查看官方文档或使用`C-h m`查看模式帮助。
毕业论文--数字电路课程设计报告--基于1602液晶屏的数字万年历Verilog版基于1602液晶屏的数字万年历(Verilog版)课程名称:数字电路课程设计专业:集成电路设计与集成系统基于1602液晶屏的数字万年历(Verilog版)一.设计要求1.基本功能设计一个数字钟,能够显示当前时间,分别用6个数码管显示小时、分钟、秒钟的时间,秒针的计数频率为1Hz,可由系统脉冲分频得到。
在整点进行提示,可通过LED闪烁实现,闪烁频率及花型可自己设计。
能够调整小时和分钟的时间,调整的形式为通过按键进行累加。
具有闹钟功能,闹钟时间可以任意设定(设定的形式同样为通过按键累加),并且在设定的时间能够进行提示,提示同样可以由LED闪烁实现。
2.扩展功能设计模式选择计数器,通过计数器来控制各个功能之间转换。
调整当前时间以及闹钟时间,在按键累加的功能不变的基础上,增加一个功能,即当按住累加键超过3秒,时间能够以4Hz的频率累加。
用LCD液晶屏来显示当前时间及功能模式。
二.设计分析及系统方案设计1.要求分析:基于FPGA实际并发处理的特点,对于实现数字万历年系统,相比于任何嵌入式处理器而言,其特点和优势将得以更加全面体现。
数字万年历中所有模块都将基于基准时钟源进行处理,结合FPGA本身的特点,在时钟源下可进行精确计数,可轻易而产生十分精确的万年历时间。
基础部分:万年历可包括以下时间处理模块:基于秒时钟计数器进行判断处理。
①秒,分,时。
②星期,上/下午。
③日,月,年。
④闹钟功能部分:①时间设定:使用四个按键进行控制,分别是:设置复位按键,设置移位键,功能“加”键,功能“减”键。
②整点报时部分:使用7个绿色LED作为提示灯。
③闹钟提示部分:使用16个红色LED作为闹钟报时提示。
显示部分:使用LCD1602液晶显示屏作为万年历的主显示屏,闹钟显示部分使用6个7段数码管。
2.方案设计基于FPGA的特点以及本万年历系统自身功能特点的实现方式。
基于DE2-115开发板的FPGA入门设计实验1、Lab1: 4位加法器、减法器的设计1.1 摘要在文件add_sub里面的工程文件operation_4.v为顶层文件,该顶层文件包含了三个子模块,分别为数码管显示模块,4位带进位的二进制加法器模块和4位带借位的二进制减法器模块,最后通过DE2-115开发板显示实验结果。
1.2 程序1)add_4bits.v 加法器module adder_4bits(input clk,input rst_n,input [3:0] x,input [3:0] y,output reg [3:0] sum,output reg carry_out //溢出位);always@(posedge clk or negedge rst_n)beginif(!rst_n){carry_out, sum} <= 0;else{carry_out, sum} = x + y;endendmodule2)substractor_4bits.v减法器module subtractor_4bits(input clk,input rst_n,input [3:0] x,input [3:0] y,output r eg [3:0] sub,output r eg borrow_out);always@(posedge clk or negedge rst_n) beginif(!rst_n){borrow_out, sub} <= 0;elsebeginif(x >= y){borrow_out, sub} = {1'b0, x - y};else{borrow_out, sub} = {1'b1, x - y};endendendmodule3)seg7_lut.v 数码管显示译码模块module Seg7_lut(input [3:0] iDIG,output r eg [6:0] oSEG);always @(iDIG)begincase(iDIG)4'h1: oSEG = 7'b1111001; // ---t----4'h2: oSEG = 7'b0100100; // | |4'h3: oSEG = 7'b0110000; // lt rt4'h4: oSEG = 7'b0011001; // | |4'h5: oSEG = 7'b0010010; // ---m----4'h6: oSEG = 7'b0000010; // | |4'h7: oSEG = 7'b1111000; // lb rb4'h8: oSEG = 7'b0000000; // | |4'h9: oSEG = 7'b0011000; // ---b----4'ha: oSEG = 7'b0001000;4'hb: oSEG = 7'b0000011;4'hc: oSEG = 7'b1000110;4'hd: oSEG = 7'b0100001;4'he: oSEG = 7'b0000110;4'hf: oSEG = 7'b0001110;4'h0: oSEG = 7'b1000000;endcaseendendmodule1.3 结果本设计通过Verilog HDL硬件描述语言。
带置位和复位的d触发器veriloga代码Verilog-A 是一种用于建模和仿真模拟电路的硅级模型语言,其中包括Verilog-AMS(模拟与数字混合)和Verilog-HDL(硬件描述语言)。
在Verilog-A 中,描述D 触发器(D Flip-Flop)时,我们可以通过引入带有置位和复位功能的模块,实现具体的功能。
以下是一个简单的Verilog-A 代码示例,描述了一个带置位和复位的D 触发器。
// 带置位和复位的D 触发器Verilog-A 代码`include "disciplines.vams"module DFF_with_SetReset (input D,// 数据输入input CLK,// 时钟输入input SET,// 置位输入input RST,// 复位输入output Q,// 输出output Qn // 反相输出);// 参数定义parameter real t_setup =1.0;// 设置时间parameter real t_hold =1.0;// 保持时间parameter real t_delay =0.1;// 延迟时间// 内部变量real Q_int;// 定义行为initial beginQ_int =0.0;endalways@(D,CLK,SET,RST)begin// 时钟沿触发if(posedge(CLK))begin// 延迟一定时间后的操作#t_delay Q_int =D;// 置位和复位逻辑if(SET)beginQ_int =1.0;end else if(RST)beginQ_int =0.0;endendend// 输出逻辑assign Q =Q_int;assign Qn =~Q_int;endmodule这个Verilog-A 代码描述了一个带有置位(SET)和复位(RST)功能的D 触发器。
基于FPGA的自动打铃器的设计目录第一章绪论 (4)1.1选题目的 (4)1.2 FPGA的发展历程 (4)1.2.1 FPGA的优点 (5)1.3器件及工具介绍 (5)1.3.1 QuartusⅡ设计步骤 (5)第二章系统方案设计 (5)2.1设计方案分析与选择 (5)2.2自动打铃器总体构成 (6)2.3分频模块设计 (7)2.4消抖模块设计 (8)2.5时钟模块设计 (8)2.5.1秒计数模块 (9)2.5.2分计数模块 (9)2.5.3时计数模块 (10)2.5.4调时模块 (11)2.6闹钟模块设计 (12)2.6.1定时模块 (12)2.6.2比较模块 (13)2.7打铃模块设计 (15)2.8报警模块设计 (17)2.8.1报警时长设定模块 (17)2.8.2蜂鸣器发声模块 (17)2.9显示模块设计 (18)2.9.1时间切换模块 (18)2.9.2动态扫描模块 (20)2.10按键电路设计 (22)第三章实验结果分析 (22)3.1测试过程 (22)3.2结果分析 (23)参考文献 (25)附录 (26)摘要自动打铃器为学校上下课时间的准确控制提供了很大的便利,并且在工厂、办公室等场合也起到了提醒人们时间的作用,因此打铃器的设计有一定的实用意义。
本设计的学校打铃器采用基于现场可编程门阵列(FPGA)的方法,底层模块采用硬件描述语言(HDL)设计,不仅能对时、分、秒正常计时和显示,而且还可进行闹铃时间的设定,上下课时间报警,报警时间1-15秒设置。
系统主芯片采用美国Altera 公司的EP3C40F484I7器件,由时钟模块、控制模块、闹钟模块、定时模块、数据译码模块、显示以及报时等模块组成,由按键进行时钟的校时、清零、启停等。
本文在介绍FPGA器件的基础上,着重阐述了如何使用FPGA器件进行系统的开发,以及如何实现学校打铃系统。
通过仿真验证及实际测试,打铃器具有正常计时、定时报警、报警时长设定等功能,可为日常作息提供准确、便捷的提醒。
按键消抖
一、程序(50mhz)
module
xiaodou(clk,clr,key1,key2,key3,key4,key5,key_out1,key_out2,key_out3,key_out4,key_ out5);
input clk,clr;
input key1,key2,key3,key4,key5;
output key_out1,key_out2,key_out3,key_out4,key_out5;
//-------------------------------------------------
reg [4:0] key_rst;
reg [4:0] key_rst_n;
reg [19:0] cnt;
reg [4:0] key_next;
reg [4:0] key_next_n;
reg d1,d2,d3,d4,d5;
wire[4:0] key_flag;
wire [4:0] key_out_n;
reg [23:0] count1;
reg count_flag;
always @(posedge clk or negedge clr) //get the fist value
begin
if(!clr)
begin key_rst<=5'b11111;
end
else
begin key_rst<={key5,key4,key3,key2,key1};
end
end
//---------------------------------------
always @(posedge clk or negedge clr) begin
if(!clr)
begin key_rst_n<=5'b11111;
end
else
begin key_rst_n<=key_rst;
end
end
//---------------------------------------- assign key_flag=key_rst_n&(~key_rst); //--------------jishu------------------- always @(posedge clk or negedge clr) begin
if(!clr)
begin cnt<=20'd0;
end
else if(key_flag)
begin cnt<=20'b0;
end
else
begin cnt<=cnt+1'b1;
end
end
//-----------------20ms after ------------- always @(posedge clk or negedge clr) begin
if(!clr)
begin key_next<=5'b11111;
end
else if(cnt==20'hfffff)
begin
key_next<={key5,key4,key3,key2,key1};
end
end
//----------------------------------
always @(posedge clk or negedge clr)
begin
if(!clr)
begin key_next_n<=5'b11111;
end
else
begin key_next_n<=key_next;
end
end
//-------------------------------------------
assign key_out_n=key_next_n&(~key_next);
//--------------------------------------
always @(posedge clk or negedge clr)
begin
if(!clr)
begin d1<=1'b1;
d2<=1'b1;
d3<=1'b1;
d4<=1'b1;
d5<=1'b1;
count_flag<=1;
end
else //应led止显示一个时钟周期,我们观测不到,
begin //此处有个计数延时,目的是led灯显示能够持续一段时间if(key_out_n[0])
begin d1<=1'b0;count_flag<=1'b0;end
else
if(count1==24'hffffff)
begin d1<=1'b1;count_flag<=1;end
if(key_out_n[1])
begin d2<=1'b0;count_flag<=1'b0;end
else
if(count1==24'hffffff)
begin d2<=1'b1;count_flag<=1;end
if(key_out_n[2])
begin d3<=1'b0;count_flag<=1'b0;end
else
if(count1==24'hffffff)
begin d3<=1'b1;count_flag<=1;end
if(key_out_n[3])
begin d4<=1'b0;count_flag<=1'b0;end
else
if(count1==24'hffffff)
begin d4<=1'b1;count_flag<=1;end
if(key_out_n[4])
begin d5<=1'b0;count_flag<=1'b0;end
else
if(count1==24'hffffff)
begin d5<=1'b1;count_flag<=1;end
end
end
assign key_out1=d1?1'b1:1'b0;
assign key_out2=d2?1'b1:1'b0;
assign key_out3=d3?1'b1:1'b0;
assign key_out4=d4?1'b1:1'b0;
assign key_out5=d5?1'b1:1'b0;
always @(posedge clk or negedge clr) //计数延时,具体时间没有计算begin
if(!clr)
begin count1<=0;end
else
if(count_flag==1'b0)
begin count1<=count1+1'b1;
end
else
begin
count1<=0;
end
end
endmodule
二、框图。