实战训练2 基于verilog按键消抖设计.docx
-
资源ID:3435458
资源大小:38.18KB
全文页数:4页
- 资源格式: DOCX
下载积分:6.99金币
友情提示
2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
|
实战训练2 基于verilog按键消抖设计.docx
实战训练2 基于verilog按键消抖设计实战训练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; 周期 wire 2:0 led_ctrl = low_sw_r2:0 & ( low_sw2:0); reg d1; reg d2; reg d3; /当寄存器low_sw由1变为0时,led_ctrl的值变为高,维持一个时钟 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_ctrl0 ) d1 <= d1; if ( led_ctrl1 ) d2 <= d2; if ( led_ctrl2 ) d3 <= d3; end assign led_d5 = d1 ? 1'b1 : 1'b0; assign led_d3 = d2 ? 1'b1 : 1'b0; assign led_d4 = d3 ? 1'b1 : 1'b0; endmodule /LED翻转输出 也许初看起来这段代码似乎有点吃力,好多的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_r2:0 & ( low_sw2:0); 仔细分析,你会发现当没有键按下时,low_sw=low_sw_r=3b111,此时的led_ctrl=3b000;只有当low_sw和low_sw_r的某一位分别为0和1时,才可能使led_ctrl的值改变。那么这意味着当键值由1跳变到0时才可能把led_ctrl拉高。回顾前面的20ms赋键值,也就是说每20ms内如果出现按键被按下,那么有一个时钟周期里led_ctrl是会被拉高的,而再看后面的程序,led_ctrl的置高就使得相应的LED灯的亮灭做一次改变,这就达到了目的。