实战训练2 基于verilog按键消抖设计

合集下载

FPGA按键消抖实验(源码)

FPGA按键消抖实验(源码)

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;elsecnt<= 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;elsecurrent_state<= next_state;// 根据条件转移状态always @ *case (current_state)NO_KEY_PRESSED : // 没有按键按下if (row != 4'hF)next_state = SCAN_COL0;elsenext_state = NO_KEY_PRESSED;SCAN_COL0 : // 扫描第0列if (row != 4'hF)next_state = KEY_PRESSED;elsenext_state = SCAN_COL1;SCAN_COL1 : // 扫描第1列if (row != 4'hF)next_state = KEY_PRESSED;elsenext_state = SCAN_COL2;SCAN_COL2 : // 扫描第2列if (row != 4'hF)next_state = KEY_PRESSED;elsenext_state = SCAN_COL3;SCAN_COL3 : // 扫描第3列if (row != 4'hF)next_state = KEY_PRESSED;elsenext_state = NO_KEY_PRESSED;KEY_PRESSED : // 有按键按下if (row != 4'hF)next_state = KEY_PRESSED;elsenext_state = NO_KEY_PRESSED;endcaseregkey_pressed_flag; // 键盘按下标志reg [3:0] col_val, row_val; // 列值、行值// 根据次态,给相应寄存器赋值always @ (posedgekey_clk, negedgerst_n)if (!rst_n)begincol<= 4'h0;key_pressed_flag<= 0;endelsecase (next_state)NO_KEY_PRESSED : // 没有按键按下begincol<= 4'h0;key_pressed_flag<= 0; // 清键盘按下标志endSCAN_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 : // 有按键按下begincol_val<= col; // 锁存列值row_val<= row; // 锁存行值key_pressed_flag<= 1; // 置键盘按下标志endendcase//--------------------------------------// 状态机部分结束//--------------------------------------//++++++++++++++++++++++++++++++++++++++// 扫描行列值部分开始//++++++++++++++++++++++++++++++++++++++always @ (posedgekey_clk, negedgerst_n)if (!rst_n)key_val<= 4'h0;elseif (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;endcaseendmodule。

fpgaVeriloghdl按键消抖部分程序讲解

fpgaVeriloghdl按键消抖部分程序讲解

fpgaVeriloghdl按键消抖部分程序讲解module debounce(clk_in,rst_in,key_in,key_pulse,key_state);input clk_in;//system clockinput rst_in;//system resetinput key_in;//button inputoutput key_pulse;//debounce pulse outoutput reg key_state;//debounce state outreg key_reg;//register key_rst,lock key_in to next clk//定义⼀个寄存器对输⼊信号进⾏锁存always @(posedge clk_in or negedge rst_in)beginif(!rst_in) key_reg<=1;else key_reg<=key_in;endwire key_an=(key_reg==key_in)?0:1;reg[18:0] cnt;/******* 计数器count the number of clk when a dege of key_in if occured*******/always @(posedge clk_in or negedge rst_in)beginif(!rst_in) cnt<=0;else if(key_an) cnt<=0;//由此可见当按键按下信号变化key_an变为1,计数cnt清零,然后重新计数,else cnt<=cnt+1; //由此可见这个程序是⼀直计数(相当于⼀直查询,key_an为1或者复位时cnt清零,重新计数)end/*******延时采样******/reg low_sw;//lock the status to register low_sw when cnt count to 19'd500000(即20ms)always @(posedge clk_in or negedge rst_in)beginif(!rst_in) low_sw<=1'b1;//直接写low_sw<=1;⼀样else if(cnt==500000) low_sw<=key_in;end/********下降沿检测********************/reg low_sw_reg;//register low_sw_reg,lock low_sw to next clkalways @(posedge clk_in or negedge rst_in)beginif(!rst_in) low_sw_reg<=1;else low_sw_reg<=low_sw;endwire key_pulse;//detect the negedge of low,generate pulseassign key_pulse=low_sw_reg&(~low_sw);/******脉冲状态输出*****/always @(posedge clk_in or negedge rst_in)beginif(!rst_in)key_state<=1;else if(key_pulse)key_state<=~key_state;else key_state<=key_state;endendmodule。

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

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

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

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

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

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

我们称之为按键消抖。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Verilog写的按键消抖程序

Verilog写的按键消抖程序

前几天看了特权同学用Verilog写的按键消抖程序,感觉很经典。

在这里将程序贴出来分享一下。

module lcd_button2(clk,rst,seg,wei,sw1,sw2,sw3,sw4);//按键按下,数码管依次显示0-9input clk;input rst;input sw1,sw2,sw3,sw4;output [3:0] wei;output[7:0] seg;reg [7:0] seg;reg [3:0] wei;integer num;initial beginnum = 0;endreg[3:0] key_rst;always @(posedge clk or negedge rst)if(!rst)key_rst <= 4'b1111;elsekey_rst <= {sw4,sw3,sw2,sw1};reg[3:0] key_rst_r;always @(posedge clk or negedge rst)if(!rst)key_rst_r <= 4'b111;elsekey_rst_r <= key_rst;wire[3:0] key_an = key_rst_r & (~key_rst);reg[19:0] cnt;always @(posedge clk or negedge rst)if(!rst)cnt <= 0;else if(key_an) cnt <= 0;else cnt <= cnt+1'b1;reg [3:0] low_sw;always @(posedge clk or negedge rst)if(!rst)low_sw <= 4'b1111;else if(cnt==10'hfffff)low_sw <= {sw4,sw3,sw2,sw1};reg[3:0] low_sw_r;always @(posedge clk or negedge rst)if(!rst)low_sw_r <= 4'b1111;elselow_sw_r <= low_sw;wire [3:0] led_ctrl = low_sw_r[3:0] & (~low_sw[3:0]);reg d1,d2,d3,d4;always @(posedge clk or negedge rst)if(!rst) begind1 <= 0;d2 <= 0;d3 <= 0;d4 <= 0;endelse beginif(led_ctrl[0]) beginnum <= num+1;if(num==9)num <= 0;endendalways @(posedge clk ) beginwei <= 4'b1111;case(num)0: seg <= 8'hfc;1: seg <= 8'h60;2: seg <= 8'hda;3: seg <= 8'hf2;4: seg <= 8'h66;5: seg <= 8'hb6;6: seg <= 8'hbe;7: seg <= 8'he0;8: seg <= 8'hfe;9: seg <= 8'hf6;default: seg <= 8'h02;endcaseendendmodule参考了特权的代码。

基于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语句最大不同。

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

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

verilog按键消抖

verilog按键消抖

module mybut(rst_n,clk,key_in,wei,duan);input rst_n,clk;input key_in;output wei;output[7:0]duan;wire key_edge;reg[7:0]duan;wire wei;reg[3:0]out;reg clkdiv;reg[25:0]cnt;reg key1,key2,key3,buff;////------------------------------------------------------------------------------------分频模块------------------------------------------------------------------------------////always@(posedge clk)beginif(!rst_n)cnt <=0;else if(cnt==2500000)begincnt <=0;clkdiv <=1'b1;endelse begincnt <=cnt+1;clkdiv <=1'b0;endend////------------------------------------------------------------------------在分频时钟下多次采样,消抖--------------------------------------------------------////always@(posedge clkdiv)beginif(!rst_n)beginkey1<=0;key2<=0;key3<=0;endelse beginkey1<=key_in;key2<=key1;key3<=key2;endend////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////buff 与(key1,key2,key3)之间有寄存器【熟悉边沿检测电路】//------------------------------------------在上升沿作用------------------------------------------//先有buff==0,后有key1&key2&key3==1上升沿//always@(posedge clk)begin//buff<=key1&key2&key3;//end//edge=~buff&(key1&key2&key3);//检测按键上升沿key_edge//assign key_//-------------------------------------------在下降沿作用----------------------------------------//先有buff==1,后有key1|key2|key3==0下降沿always@(posedge clk)beginbuff<=key1|key2|key3;endedge=~(key1|key2|key3)&buff;//检测按键下降沿key_edgeassign key_/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// always@(posedge clk)beginif(!rst_n)out<=0;else if(key_edge)beginif(out==9)out<=0;elseout<=out+1;endend////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// assign wei=1'b0;always@(*)case(out)0:duan=8'b11111100;//0duan1:duan=8'b01100000;//1【7】1342:duan=8'b11011010;//2【6】1353:duan=8'b11110010;//3【5】1364:duan=8'b01100110;//4【4】1375:duan=8'b10110110;//5【3】1266:duan=8'b10111110;//6【2】1297:duan=8'b11100000;//7【1】1328:duan=8'b11111110;//8【0】1339:duan=8'b11110110;//9default:duan=8'b11111100;//0endcaseendmodule。

【豆丁-精品】-基于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这个实验主要有计数器和边缘检查来实现按键消抖,按键功能。

Verilog按键消抖的理解

Verilog按键消抖的理解

Verilog按键消抖的理解按键在按下时会产生抖动,释放时也会产生抖动,所以在设计键盘扫描程序时必须考虑按键的消抖,我们一般只考虑按下时的抖动,而放弃对释放时抖动的消抖。

抖动时间一般为20ms左右。

按下的最终结果是低电平'在单片机设计的的按键去抖思路是:检测到按下时延时20ms,再检测,如果状态仍为按下,贝U确认是按下的;如果状态为弹起的,则确认是干扰,无按键按下。

图1 按键抖动特性有一个概念要理一下,按键按下时会有抖动,也就是说我们其实只按一次,但是实际产生的&ldquo; 按下&rdquo; 却是许多次的,这些许多次集中在这20ms 里。

我们按的只是一次,而实际却产生了许多次,那么就必须滤除其他的次数。

单片机为了得到真正的&ldquo; 按下&rdquo;,通过延时20ms,把其他的&ldquo;按下&rdquo; (也就是抖动)给滤除了。

然后再次判断是否有按下,因为有的时候干扰很大。

而在FPGA中,基于下面的程序,理解如下:在这个程序里检测按键是否按下的方法是脉冲边沿检法。

而在单片机里是判断是否为低电平的方法(那么在FPGA中可不可以也用这个方法呢?)第一次检测到后,启动20ms 计数器,时间到后再检测。

这里的检测方法跟脉冲边沿检测法有异曲同工之处,FPGA过20ms检测按键是否按下,存储检测到的值,并且按位取反与前一个20ms检测的值相与,得到一个值,如果为1,则判断按键按下,否则则无按下。

所以跟单片机按键扫描的原理是一样的,不同的是检测方法不一样。

图2 FPGA 按键的理解示意图其中key_an 寄存器的功能是检测第一次的 &ldquo;按 下&rdquo;,是ent 的启动标志位。

通过也能滤除干扰信 号。

led_etrl是确实有按键按下的信号,维持一个时钟周期。

特权同学的Verilog 键盘扫描程序// 说明:当三个独立按键的某一个被按下后,相应的LED 被点亮;//再次按下后,LED 熄灭,按键控制 LED 亮灭 modulesw_debounce( clk,rst_n, sw1_n,sw2_n,sw3_n,下的JS生 谨产汞 按时彼伺隔勿吧时间轴110 UCi 111] 边沿唸迴注检测到"m 零汁数器并启动⑷矶的 时间计数 tn in no 110led_d1,led_d2,led_d3);input clk; // 主时钟信号,50MHzinput rst_n; // 复位信号,低有效input sw1_n,sw2_n,sw3_n; // 三个独立按键,低表示按下output led_d1,led_d2,led_d3; // 发光二极管,分别由按键控制// ----------------------------------------------reg[2:0] key_rst;always @(posedge clk or negedge rst_n)if (!rst_n) key_rst。

用Verilog HDL实现按键消抖

用Verilog HDL实现按键消抖

按键消抖用按键控制一个数字,按键每按一次,这个数字加1,并通过数码管将这个数字显示出来(以16进制)。

可能是悟性比较低,按键消抖都搞了1天才搞出来,下面这个程序是我经过参考别人的(有些地方没想明白),然后自己领会,写的一个程序,经过在开发板上实验,还是有一点小问题,但是我觉得,按键消抖的原理应该是这样的。

希望本文能帮到需要的人,我也是一个初学者,可能程序中也有很多不足,还请能提出来,相互交流。

QQ:1664619265module SW_debounce(rst_n,sy_clk,key,HEX0_D);input rst_n;/低电平复位input sy_clk;//系统时钟50Mhzinput key; 按键output [6:0]HEX0_D;数码管//*************************/reg key_rst;always@(posedge sy_clk or negedge rst_n) beginif(!rst_n)key_rst<=1'b1;else每个时钟周期读一次按键的值key_rst<=key;end 将按键的值存在key_rst中//*************************/reg key_rst_r;always@(posedge sy_clk or negedge rst_n) beginif(!rst_n)key_rst_r<=1'b1;else 每个时钟周期将key_rst中的值存入key_rst_r中。

key_rst_r<=key_rst;这样key_rst和key_rst_r中存放的是前后两个时钟周期,按键的值end//*************************/wire key_en,key_an;重点1:抖动时期的标志量,这两个标志量是用来给后面的计数器清零的assign key_en=key_rst&(~key_rst_r);当按键由0变1时,key_en为1 assign key_an=key_rst_r&(~key_rst);当按键由1变0时,key_an为1;看下面的按键波形,俺觉得,抖动期间,这两个标志量都有可能为1 //**************************/reg[18:0] count; 计数,是为了延时10ms左右always@(posedge sy_clk or negedge rst_n) beginif(!rst_n)count<=19'd0;else if(key_en | key_an)count<=19'd0;出现抖动就将count清零,使其计不满,因为后面是每10ms读一次按键的值else if(count==19'h7ffff)//10mscount<=19'd0;elsecount<=count+1'b1;end//************************/reg low_sw;always@(posedge sy_clk or negedge rst_n) beginif(!rst_n)low_sw<=1'b1;else if(count==19'h7ffff)low_sw<=key;每10ms读一次按键的值,因为抖动期间,count的值是到不了7ffff的,所以抖动期间是不会读按键的值的,因此能消除抖动。

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

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

按键消抖的原理和基于verilog的消抖设计按键开关是各种电子设备不可或缺的人机接口。

在实际应用中,很大一部分的按键是机械按键。

在机械按键的触点闭合和断开时,都会产生抖动,为了保证系统能正确识别按键的开关,就必须对按键的抖动进行处理。

在系统设计中,有各种各样的消除按键抖动的设计方法,硬件电路和软件设计都很成熟。

不过我们这里要从另外一个角度来讨论按键的消抖,并给出一个用verilog给出一个具体的实现。

首先,看一个普通的机械按键的触点在闭合与断开时的波形(用示波器抓取)。

下面的四张图都是按键在闭合的时候抓到的波形。

可以看到两个明显的趋势:1. 按键在几个us之内就可以达到稳定状态,从高电平转换到底电平;2. 在高电平转换到低电平的过程中,触点有非常明显的抖动。

下面的两张图是按键在断开的时候抓到的波形。

也可以看到两个明显的趋势:1. 按键的变化趋势比较缓慢,从低电平变为高电平需要大概10~20ms的时间;2. 按键断开时没有闭合时那么大的抖动下面两张图是用手迅速闭合按键然后就断开时,按键的输出波形。

在处理按键抖动的程序中,必须同时考虑消除闭合和断开两种情况下的抖动。

所以,对于按键消抖的处理,必须按最差的情况来考虑。

我们从上面的图上可以看到,按键输出的信号的跳变时间(上升沿和下降沿)最大是在20ms左右。

按键一次闭合最短的时间大概是120ms 左右。

如果我们把按键的输出做为一个时钟域(时钟频率未知,但信号的slow rate是已知的,既最大20ms左右)的信号,用另外一个时钟来采集这个按键的输出,则就可以把按键的消抖归结为一个最基本的CDC问题来处理。

而问题的核心是如何确定采集时钟的频率。

假设采集时钟的周期小于20ms,那么,采集时钟就有可能两次采到按键断开时的不。

verilog按键消抖原理

verilog按键消抖原理

verilog按键消抖原理(原创版)目录1.Verilog 简介2.按键消抖的概念3.按键消抖的实现原理4.实际应用中的按键消抖设计5.总结正文【1.Verilog 简介】Verilog 是一种硬件描述语言,主要用于数字系统硬件的描述、模拟和验证。

在数字电路设计和 FPGA 开发领域,Verilog 被广泛应用。

通过Verilog,设计人员可以对硬件电路进行建模、模拟和验证,以确保设计满足性能要求。

【2.按键消抖的概念】按键消抖,又称按键去抖,是一种在按键输入过程中消除误触发的技术。

在实际应用中,按键输入可能会受到噪声、抖动等因素的影响,导致误触发。

按键消抖的目的就是消除这些干扰,确保按键输入的准确性。

【3.按键消抖的实现原理】按键消抖的实现原理主要有两种:软件消抖和硬件消抖。

(1)软件消抖:软件消抖是通过程序算法实现的。

在按键触发时,程序会检测按键触发信号是否满足一定的条件,例如连续触发次数、触发时间间隔等。

如果满足条件,则认为这是一个有效的按键触发,否则不予响应。

(2)硬件消抖:硬件消抖是通过硬件电路实现的。

硬件消抖电路通常包括滤波器、延迟器等组件。

当按键触发信号输入时,滤波器会滤除噪声,延迟器会消除触发信号的抖动,从而保证输出信号的稳定性。

【4.实际应用中的按键消抖设计】在实际应用中,按键消抖设计需要考虑多种因素,如按键触发信号的噪声、抖动特性,系统的响应速度等。

为了实现高效、可靠的按键消抖,设计人员需要对这些因素进行综合考虑,选择合适的消抖方案。

【5.总结】按键消抖是一种重要的技术,可以有效消除按键输入中的误触发,提高系统的稳定性和可靠性。

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上,并不是行列扫描的。

阐述基于FPGA的按键抖动的消除方法

阐述基于FPGA的按键抖动的消除方法

阐述基于FPGA的按键抖动的消除方法我们在进行数字电路的设计的过程中,经常会碰到信号抖动相关的问题。

抖动信号大致分为两类:一类是时间极短的干扰信号(比如毛刺);另一类是时间较长的干扰信号(如本文所研究的按键抖动问题)。

对于第一类干扰信号——毛刺,它的时间极短,通常只有几纳秒,不能满足触发器的建立时间与保持时间,因此我们可以用一个D触发器去读带毛刺的信号,由于D触发器具有对毛刺不敏感的特点,可以去除信号中的毛刺,达到消除抖动的效果(消除毛刺的方法很多,在这里不做讨论,本文重点说明按键抖动的消除及其代码设计)。

在数字电路设计中,按键通常为一个个具有弹性的机械触点开关,其开启或者闭合的瞬间都会产生按键抖动,实际波形如图1所示:由图1可知,在按键闭合和断开的瞬间,我们往往只需要一组稳定的上升边沿和下降边沿,但实际上却产生了若干个边沿。

所以,在实际电路中,我们仅仅按动按键,简单地读取信号的边沿,却不滤除抖动,会导致一次按键操作被误读多次,从而引起电路的误动作。

为了达到一次按键操作得到一次正确的响应的目的(在按键闭合或者断开),信号稳定的状态下读取此时按键的状态,就必须在电路中采取消除抖动的措施。

在纯数字电路设计中,下面介绍几种消除按键抖动的常用实现方法。

1 设计硬件消抖电路(硬件方法)设计一个具有延时作用的滤波电路或者经常用到的单稳态电路等硬件电路,来消除按键的抖动(避免抖动时间)。

图2所示的电路,即为典型的滤波延时消抖电路,S为按键,Di为CPU数据线。

当按键S未闭合时,与非门的输入电压Vi(即电容的端电压)为0,从而输出电压Vo为1。

我们按下按键S,电容C的端电压不会发生突变,充电延迟时间取决于R1、R2和C值的大小,当电容端电压在充电时间内未达到与非门的开启电压,将不会改变门的输出电压;当电容端电压大于门的开启电压时,与非门的输出Vo发生改变,即输出为0(我们在数字电路的设计过程中,为了避开按键抖动的影响,需要使充电延时大于或等于100ms)。

FPGA入门系列实验教程——按键消抖控制LED亮灭

FPGA入门系列实验教程——按键消抖控制LED亮灭

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。

实验2:按键消抖

实验2:按键消抖

基于verilog按键消抖设计关于键盘的基础知识,我就以下面的一点资料带过,因为这个实在是再基础不过的东西了。

然后我引两篇我自己的博文,都是关于按键消抖的,代码也正是同目录下project里的。

这两篇博文都是ednchina的博客精华,并且在其blog 首页置顶多日,我想对大家会很有帮助的。

键盘的分类键盘分编码键盘和非编码键盘。

键盘上闭合键的识别由专用的硬件编码器实现,并产生键编码号或键值的称为编码键盘,如计算机键盘。

而靠软件编程来识别的称为非编码键盘。

在单片机组成的各种系统中,用的最多的是非编码键盘。

也有用到编码键盘的。

非编码键盘有分为:独立键盘和行列式(又称为矩阵式)键盘。

按键在闭合和断开时,触点会存在抖动现象:从上面的图形我们知道,在按键按下或者是释放的时候都会出现一个不稳定的抖动时间的,那么如果不处理好这个抖动时间,我们就无法处理好按键编码,所以如何才能有效的消除按键抖动呢?让下面的两篇博文日志给你答案吧。

经典的verilog键盘扫描程序拿到威百仕( VibesIC )的板子后就迫不及待的开始我的学习计划,从最基础的分频程序开始,但看到这个键盘扫描程序后,直呼经典,有相见恨晚的感觉,还想说一句:威百仕( VibesIC ),我很看好你!WHY?待我慢慢道来,这个程序的综合后是0error,0warning。

想想自己编码的时候那个warning是满天飞,现在才明白HDL设计有那么讲究了,代码所设计的不仅仅是简单的逻辑以及时序的关系,更重要的是你要在代码中不仅要表现出每一个寄存器,甚至每一个走线。

想想我写过的代码,只注意到了前者,从没有注意过后者,还洋洋自得以为自己也算是个高手了,现在想来,实在惭愧啊!学习学习在学习,这也重新激发了我对HDL设计的激情,威百仕给了我一个方向,那我可要开始努力喽!废话说了一大堆,看程序吧:(本代码经过ise7.1i综合并下载到SP306板上验证通过)//当三个独立按键的某一个被按下后,相应的LED被点亮;再次按下后,LED 熄灭,按键控制LED亮灭`TImescale 1ns/1nsmodule keyscan(clk,rst_n,sw1_n,sw2_n,sw3_n,//outputled_d3,led_d4,led_d5);input clk; //主时钟信号,48MHzinput rst_n; //复位信号,低有效input sw1_n,sw2_n,sw3_n; //三个独立按键,低表示按下output led_d3,led_d4,led_d5; //发光二极管,分别由按键控制// ---------------------------------------------------------------------------reg [19:0] cnt; //计数寄存器always @ (posedge clk or negedge rst_n)if (!rst_n) //异步复位cnt <= 20'd0;elsecnt <= cnt + 1'b1;reg [2:0] low_sw;always @(posedge clk or negedge rst_n)if (!rst_n)low_sw <= 3'b111;else if (cnt == 20'hfffff) //满20ms,将按键值锁存到寄存器low_sw中low_sw <= {sw3_n,sw2_n,sw1_n};// ---------------------------------------------------------------------------reg [2:0] low_sw_r; //每个时钟周期的上升沿将low_sw信号锁存到lo w_sw_r中always @ ( posedge clk or negedge rst_n )if (!rst_n)low_sw_r <= 3'b111;elselow_sw_r <= low_sw;//当寄存器low_sw由1变为0时,led_ctrl的值变为高,维持一个时钟周期wire [2:0] led_ctrl = low_sw_r[2:0] & ( ~low_sw[2:0]);reg d1;reg d2;reg d3;always @ (posedge clk or negedge rst_n)if (!rst_n)begind1 <= 1'b0;d2 <= 1'b0;d3 <= 1'b0;endelsebegin //某个按键值变化时,LED将做亮灭翻转if ( led_ctrl[0] ) d1 <= ~d1;if ( led_ctrl[1] ) d2 <= ~d2;if ( led_ctrl[2] ) d3 <= ~d3;endassign led_d5 = d1 ? 1'b1 : 1'b0; //LED翻转输出assign led_d3 = d2 ? 1'b1 : 1'b0;assign led_d4 = d3 ? 1'b1 : 1'b0;endmodule也许初看起来这段代码似乎有点吃力,好多的always好多的wire啊,而我们通常用得最多的判断转移好像不是主流。

fpga按键消抖的原理和方法

fpga按键消抖的原理和方法

FPGA(现场可编程门阵列)是一种可按照用户需求重新配置其硬件资源的可编程硅芯片。

在数字电路中,按键消抖 (Debounce) 是一个非常常见但重要的问题,因为机械按钮在按下和释放时会产生不稳定的信号。

为了解决这个问题,我们需要消除机械按键所产生的抖动信号。

消抖的原理是为输入信号添加处理和判断逻辑,将抖动视为一个单位的无效信号,从而过滤有问题的输入信号。

针对 FPGA,常用的按键消抖方法有以下两种:1. **计数器方法 (Counter Method)**这种方法检测按键输入是否持续一定时间内(假设我们使用n 个时钟周期)保持稳定。

如果输入持续稳定,则将其作为有效输入信号。

通过计数器实现的消抖具备可配置的消抖时间,从而适应各种不同类型的按键。

以下是计数器消抖方法的大致步骤:1. 初始化一个 n 位计数器。

2. 如果按键输入保持稳定(按下或释放),计数器增加,否则计数器清零。

3. 当计数器达到预定的阈值时,改变按键的状态(按下或释放)。

4. **移位寄存器方法 (Shift Register Method)**其实现原理是将多个连续的抖动信号视为一个有效输入,适用于按键抖动时间较短的场景。

以下是移位寄存器消抖方法的大致步骤:1. 初始化一个 n 位移位寄存器。

2. 每个时钟周期将输入信号添加到移位寄存器的低位(或高位),同时向右(或左)移动一位。

3. 当移位寄存器中所有位的值都相同(全为 0 或全为 1)时,认为信号稳定,将其视为有效输入信号。

在消抖方法的选择上,实际应用要考虑系统性能、消抖精度、按键抖动时间等因素。

简单的消抖算法可能只跟踪按键的状态改变,而更高级的算法可以检测按键被按下并保持的持续时间,从而在功能上更灵活。

verilog按键消抖原理

verilog按键消抖原理

verilog按键消抖原理
摘要:
1.按键消抖的原理
2.按键消抖的方法
3.基于Verilog 的按键消抖设计
4.结论
正文:
一、按键消抖的原理
按键消抖是指在按键输入过程中,由于按键机械特性和电路特性的影响,导致按键在按下或松开时,信号电平会在一段时间内发生抖动。

为了消除这种抖动,需要采用一定的方法来确认按键输入的稳定性,这就是按键消抖。

二、按键消抖的方法
常见的按键消抖方法有以下几种:
1.硬件消抖:通过硬件电路实现消抖,如使用滤波器、RC 电路等。

2.软件消抖:通过软件算法实现消抖,如使用计数器、计时器等。

3.结合硬件和软件消抖:既使用硬件电路,也使用软件算法来实现消抖。

三、基于Verilog 的按键消抖设计
基于Verilog 的按键消抖设计可以分为以下几个步骤:
1.输入信号处理:对输入的按键信号进行采样,并转化为数字信号。

2.计数器:使用计数器来统计按键信号的持续时间,以判断按键是否稳定。

3.状态判断:根据计数器的计数值来判断按键是按下还是松开。

4.输出信号处理:将判断结果输出,以控制其他电路或设备。

四、结论
按键消抖是电子设备中常见的一种技术,它可以有效地消除按键输入过程中的抖动,提高系统的稳定性和可靠性。

【黑金原创教程】【FPGA那些事儿-驱动篇I】实验二:按键模块①-消抖

【黑金原创教程】【FPGA那些事儿-驱动篇I】实验二:按键模块①-消抖

【⿊⾦原创教程】【FPGA那些事⼉-驱动篇I】实验⼆:按键模块①-消抖实验⼆:按键模块① - 消抖按键消抖实验可谓是经典中的经典,按键消抖实验虽曾在《建模篇》出现过,⽽且还惹来⼀堆⿇烦。

事实上,笔者这是在刁难各位同学,好让对⽅的惯性思维短路⼀下,但是惨遭⼝⽔攻击 ... ⾯对它,笔者宛如被甩的男⼈,对它⼜爱⼜恨。

不管怎么样,如今 I’ll be back,笔者再也不会重复⼀样的悲剧。

按键消抖说傻不傻说难不难。

所谓傻,它因为原理不仅简单(就是延迟⼏下下⽽已),⽽且顺序语⾔(C语⾔)也有⽆数不尽的例⼦。

所谓难,那是因为⼈们很难从单⽚机的思维跳出来 ... 此外,按键消抖也有许多细节未曾被⼈重视,真是让⼈伤⼼。

按键消抖⼀般有3段操作:l 检测电平变化;l 过滤抖动(延迟);l 产⽣有效按键。

假设C语⾔与单⽚机的组合想要检测电平变化,它们⼀般是利⽤if查询或者外部中断。

事后,如果这对组合想要过滤抖动,那么可以借⽤for 延迟的⼒量,⼜或者依赖定时中断产⽣精明的延迟效果。

反观有效案件的产⽣,这对组合视乎⽽外钟情“按下有效”似的 ... 不管怎么样,C语⾔与单⽚机这对组合在处理按键的时候,它们往往会错过⼀些黄⾦。

“黄⾦?”,读者震撼道。

所谓黄⾦时间就是电平发⽣变化那⼀瞬间,还有消抖(延迟)以后那⼀瞬间。

按键按下期间,按键的输⼊电平故会发⽣变化,如果使⽤if查询去检测,结果很容易浪费单⽚机的处理资源,因为单⽚机必须⼀直等待 ... 换之,如果反⽤外部中断,中断寻址也会耽误诺⼲时间。

假设C语⾔与单⽚机这对组合挨过电平检测这起难关,余下的困难却是消抖动作。

如果利⽤for循环实现去消抖,例如 Delay_ms(10) 之类的函数。

For循环不仅计数不紧密,⽽且还会⽩⽩浪费单⽚机的处理资源。

定时中断虽然计数紧密,但是中断触发依然也会产⽣诺⼲的寻址延迟。

补上,所谓寻址延迟是处理器处理中断触发的时候,它要事先保护现场之余,也要寻址中断处理⼊⼝,然后执⾏中断函数,完后回复现场,最后再返回当前的⼯作。

Verilog-按键消抖程序

Verilog-按键消抖程序

按键消抖一、程序(50mhz)modulexiaodou(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 valuebeginif(!clr)begin key_rst<=5'b11111;endelsebegin key_rst<={key5,key4,key3,key2,key1};endend//---------------------------------------always @(posedge clk or negedge clr) beginif(!clr)begin key_rst_n<=5'b11111;endelsebegin key_rst_n<=key_rst;endend//---------------------------------------- assign key_flag=key_rst_n&(~key_rst); //--------------jishu------------------- always @(posedge clk or negedge clr) beginif(!clr)begin cnt<=20'd0;endelse if(key_flag)begin cnt<=20'b0;endelsebegin cnt<=cnt+1'b1;endend//-----------------20ms after ------------- always @(posedge clk or negedge clr) beginif(!clr)begin key_next<=5'b11111;endelse if(cnt==20'hfffff)beginkey_next<={key5,key4,key3,key2,key1};endend//----------------------------------always @(posedge clk or negedge clr)beginif(!clr)begin key_next_n<=5'b11111;endelsebegin key_next_n<=key_next;endend//-------------------------------------------assign key_out_n=key_next_n&(~key_next);//--------------------------------------always @(posedge clk or negedge clr)beginif(!clr)begin d1<=1'b1;d2<=1'b1;d3<=1'b1;d4<=1'b1;d5<=1'b1;count_flag<=1;endelse //应led止显示一个时钟周期,我们观测不到,begin //此处有个计数延时,目的是led灯显示能够持续一段时间if(key_out_n[0])begin d1<=1'b0;count_flag<=1'b0;endelseif(count1==24'hffffff)begin d1<=1'b1;count_flag<=1;endif(key_out_n[1])begin d2<=1'b0;count_flag<=1'b0;endelseif(count1==24'hffffff)begin d2<=1'b1;count_flag<=1;endif(key_out_n[2])begin d3<=1'b0;count_flag<=1'b0;endelseif(count1==24'hffffff)begin d3<=1'b1;count_flag<=1;endif(key_out_n[3])begin d4<=1'b0;count_flag<=1'b0;endelseif(count1==24'hffffff)begin d4<=1'b1;count_flag<=1;endif(key_out_n[4])begin d5<=1'b0;count_flag<=1'b0;endelseif(count1==24'hffffff)begin d5<=1'b1;count_flag<=1;endendendassign 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) //计数延时,具体时间没有计算beginif(!clr)begin count1<=0;endelseif(count_flag==1'b0)begin count1<=count1+1'b1;endelsebegincount1<=0;endendendmodule二、框图。

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

实战训练2 基于verilog按键消抖设计
键盘的分类
键盘分编码键盘和非编码键盘。

键盘上闭合键的识别由专用的硬件编码器实现,并产生键编码号或键值的称为编码键盘,如计算机键盘。

而靠软件编程来识别的称为非编码键盘。

在单片机组成的各种系统中,用的最多的是非编码键盘。

也有用到编码键盘的。

非编码键盘有分为:独立键盘和行列式(又称为矩阵式)键盘。

按键在闭合和断开时,触点会存在抖动现象:
从上面的图形我们知道,在按键按下或者是释放的时候都会出现一个不稳定的抖动时间的,那么如果不处理好这个抖动时间,我们就无法处理好按键编码,所以如何才能有效的消除按键抖动呢?
经典的verilog键盘扫描程序
//当三个独立按键的某一个被按下后,相应的LED被点亮;再次按下后,LED 熄灭,按键控制LED亮灭
`timescale 1ns/1ns
module keyscan(
clk,
rst_n,
sw1_n,
sw2_n,
sw3_n,
//output
led_d3,
led_d4,
led_d5
);
input clk; //主时钟信号,48MHz
input rst_n; //复位信号,低有效
input sw1_n,sw2_n,sw3_n; //三个独立按键,低表示按下
output led_d3,led_d4,led_d5; //发光二极管,分别由按键控制 // ---------------------------------------------------------------------------
reg [19:0] cnt; //计数寄存器
always @ (posedge clk or negedge rst_n)
if (!rst_n) //异步复位
cnt <= 20'd0;
else
cnt <= cnt + 1'b1;
reg [2:0] low_sw;
always @(posedge clk or negedge rst_n)
if (!rst_n)
low_sw <= 3'b111;
else if (cnt == 20'hfffff) //满20ms,将按键值锁存到寄存器low_sw中
low_sw <= {sw3_n,sw2_n,sw1_n};
// ---------------------------------------------------------------------------
reg [2:0] low_sw_r; //每个时钟周期的上升沿将low_sw信号锁存到low_sw_ r中
always @ ( posedge clk or negedge rst_n )
if (!rst_n)
low_sw_r <= 3'b111;
else
low_sw_r <= low_sw;
//当寄存器low_sw由1变为0时,led_ctrl的值变为高,维持一个时钟周期
wire [2:0] led_ctrl = low_sw_r[2:0] & ( ~low_sw[2:0]);
reg d1;
reg d2;
reg d3;
always @ (posedge clk or negedge rst_n)
if (!rst_n)
begin
d1 <= 1'b0;
d2 <= 1'b0;
d3 <= 1'b0;
end
else
begin //某个按键值变化时,LED将做亮灭翻转
if ( led_ctrl[0] ) d1 <= ~d1;
if ( led_ctrl[1] ) d2 <= ~d2;
if ( led_ctrl[2] ) d3 <= ~d3;
end
assign led_d5 = d1 ? 1'b1 : 1'b0; //LED翻转输出
assign led_d3 = d2 ? 1'b1 : 1'b0;
assign led_d4 = d3 ? 1'b1 : 1'b0;
endmodule
也许初看起来这段代码似乎有点吃力,好多的always好多的wire啊,而我们通常用得最多的判断转移好像不是主流。

的确是这样,一个好的verilog代码,用多个always语句来分摊一个大的always来执行,会使得综合起来更快,这也是接前两篇日志说到代码优化的一个值得学习的方面。

其次是wire连线很多,你要是仔细研究代码,不难发现所有的锁存器的连线关系编程者都考虑到
了,这样就不会平白无故的生成意想不到的寄存器了,这也是一个优秀代码的必备要素。

上面说的是代码风格,下面就看程序的编程思想吧。

前两个always语句里其实是做了一个20ms的计数,每隔20ms就会读取键值,把这个键值放到寄存器low_sw中,接下来的一个always语句就是把low_sw的值锁存到low_sw_r 里,这样以来,low_sw和low_sw_r就是前后两个时钟周期里的键值了,为什么要这样呢?看下一个语句吧:
wire [2:0] led_ctrl = low_sw_r[2:0] & ( ~low_sw[2:0]);
仔细分析,你会发现当没有键按下时,low_sw=low_sw_r=3’b111,此时的led_ctrl=3’b000;只有当low_sw和low_sw_r的某一位分别为0和1时,才可能使led_ctrl的值改变(也就是把led_ctrl的某一位拉高)。

那么这意味着当键值由1跳变到0时才可能把led_ctrl拉高。

回顾前面的20ms赋键值,也就是说每20ms内如果出现按键被按下,那么有一个时钟周期里led_ctrl是会被拉高的,而再看后面的程序,led_ctrl的置高就使得相应的LED灯的亮灭做一次改变,这就达到了目的。

相关文档
最新文档