本帖最后由 hhxdianzi 于 2016-9-10 22:56 编辑
这是上周帖子的链接:https://bbs.elecfans.com/forum.ph ... d&tid=936046&extra=里面提到了锆石A4自带按键消抖的例程存在一点问题,这里用Modelsim Altera进行了验证一下。首先贴上例程源码方便大家查看。
- //---------------------------------------------------------------------------
- //-- 文件名 : A4_Ked2.v
- //-- 作者 : ZIRCON
- //-- 描述 : 按键消抖
- //-- 修订历史 : 2014-1-1
- //---------------------------------------------------------------------------
- module A4_Key2
- (
- //输入端口
- CLK_50M,RST_N,KEY,
- //输出端口
- LED
- );
-
- //---------------------------------------------------------------------------
- //-- 外部端口声明
- //---------------------------------------------------------------------------
- input CLK_50M; //时钟的端口,开发板用的50MHz晶振
- input RST_N; //复位的端口,低电平复位
- input [ 7:0] KEY; //对应开发板上的KEY
- output [ 7:0] LED; //对应开发板上的LED
- //---------------------------------------------------------------------------
- //-- 内部端口声明
- //---------------------------------------------------------------------------
- reg [20:0] time_cnt; //用来计数按键延迟的定时计数器
- reg [20:0] time_cnt_n; //time_cnt的下一个状态
- reg [ 7:0] key_in_r; //用来接收按键信号的寄存器
- reg [ 7:0] key_out; //消抖完成输出按键
- reg [ 7:0] key_out_n; //key_out的下一个状态
- wire key_press; //检测按键有没有变化
- //设置定时器的时间为20ms,计算方法为 (20*10^3)us / (1/50)us 50MHz为开发板晶振
- parameter SET_TIME_20MS = 21'd1_000_000;
- //---------------------------------------------------------------------------
- //-- 逻辑功能实现
- //---------------------------------------------------------------------------
- //时序电路,用来key_in_r寄存器赋值
- always @ (posedge CLK_50M, negedge RST_N)
- begin
- if(!RST_N) //判断复位
- key_in_r <= 8'h00; //初始化key_in_r值
- else
- key_in_r <= KEY; //将按键的值赋值给key_in_r
- end
- assign key_press = key_in_r ^ KEY; //检测按键有没有变化
- //时序电路,用来给time_cnt寄存器赋值
- always @ (posedge CLK_50M, negedge RST_N)
- begin
- if(!RST_N) //判断复位
- time_cnt <= 21'h0; //初始化time_cnt值
- else
- time_cnt <= time_cnt_n; //用来给time_cnt赋值
- end
- //组合电路,实现20ms的定时计数器
- always @ (*)
- begin
- if(time_cnt == SET_TIME_20MS || key_press) //判断按键有没有变化、时间有没有到
- time_cnt_n = 21'h0; //如果到达20ms或者按键有了变化,那么定时计数器将会被清零
- else
- time_cnt_n = time_cnt + 1'b1; //如果未到20ms或者按键没有变化,那么定时计数器将会继续累加
- end
- //时序电路,用来key_out寄存器赋值
- always @ (posedge CLK_50M, negedge RST_N)
- begin
- if(!RST_N) //判断复位
- key_out <= 8'h00; //初始化key_out值
- else
- key_out <= key_out_n; //用来给key_out赋值
- end
- //组合电路,每20ms接收一次按键的值
- always @ (*)
- begin
- if(time_cnt == SET_TIME_20MS) //判断20ms时间
- key_out_n = key_in_r; //如果到达20ms,接收一次按键的值
- else
- key_out_n = key_out; //如果未到20ms,保持原状态不变
- end
- assign LED = key_out; //将消抖的按键值赋值给LED
- endmodule
复制代码
仔细查看以上代码,难免会有疑问,8个按键共用一个消抖延时计数器,如果不同按键接连按下,优先级怎么排?按下一个按键,消抖还未完成,是否允许第二个按键按下?如果第二个按键按下会不会刷新定时器重新计数?带着这些问题,编写了一个简单的仿真文件对按键进行测试,以下代码为单个按键测试文件:
- `timescale 1ns/1ns
- `define clk_period 20
- module Key_TB;
- reg CLK_50M;
- reg RST_N;
- reg [7:0]KEY;
- wire [7:0]LED;
- A4_Key2 Key
- (
- .CLK_50M(CLK_50M),
- .RST_N(RST_N),
- .KEY(KEY),
- .LED(LED)
- );
- initial CLK_50M = 1;
- always#(`clk_period/2)CLK_50M = ~CLK_50M;
- initial
- begin
- RST_N = 1'b0;
- KEY = 8'b0000_0000;
- #(`clk_period*10) RST_N = 1'b1;
- #(`clk_period*10+1);
- KEY = 8'b0000_0000;#10000000;
- KEY = 8'b0000_0001;#1000;
- KEY = 8'b0000_0000;#1200;
- KEY = 8'b0000_0001;#1300;
- KEY = 8'b0000_0000;#800;
- KEY = 8'b0000_0001;#1000;
- KEY = 8'b0000_0000;#1000;
- KEY = 8'b0000_0001;#20000100;
-
- #60000000;
-
- KEY = 8'b0000_0000;#1200;
- KEY = 8'b0000_0001;#1300;
- KEY = 8'b0000_0000;#800;
- KEY = 8'b0000_0001;#1000;
- KEY = 8'b0000_0000;#1000;
- KEY = 8'b0000_0001;#1200;
- KEY = 8'b0000_0000;#20000100;
- #30000000;
-
- $stop;
- end
- endmodule
复制代码
下面是模拟单个按键按下的波形:
单个按键的没有问题,下面进行多个按键接连按下的测试,以下是测试文件:
- `timescale 1ns/1ns
- `define clk_period 20
- module Key_TB;
- reg CLK_50M;
- reg RST_N;
- reg [7:0]KEY;
- wire [7:0]LED;
- A4_Key2 Key
- (
- .CLK_50M(CLK_50M),
- .RST_N(RST_N),
- .KEY(KEY),
- .LED(LED)
- );
- initial CLK_50M = 1;
- always#(`clk_period/2)CLK_50M = ~CLK_50M;
- initial
- begin
- RST_N = 1'b0;
- KEY = 8'b0000_0000;
- #(`clk_period*10) RST_N = 1'b1;
- #(`clk_period*10+1);
- KEY = 8'b0000_0000;#30000000;
- KEY = 8'b0000_0001;#10000000;
- KEY = 8'b0000_0011;#10000000;
- KEY = 8'b0000_0111;#10000000;
- KEY = 8'b0000_1111;#60000000;
- KEY = 8'b0000_0111;#10000000;
- KEY = 8'b0000_0011;#10000000;
- KEY = 8'b0000_0001;#10000000;
- KEY = 8'b0000_0000;#30000000;
-
- $stop;
- end
- endmodule
复制代码
从下面的波形,可以明显看出,多个按键按下,如果定时器被占用的时候,后按下的按键并没有完成消抖时间就输出了,因此这里存在一些问题,个人目前的解决办法就是每个按键使用一个计数器。如果大家有好的解决办法,欢迎指导。
Quartus II可以按列删除或修改的功能,批量修改比其他编译器方便很多,方法是ctrl + 鼠标左键,下面贴张图:
0
|
|
|
|