赞
踩
写的第一篇博客,只是用作个人学习的简单记录,如有错误还请大家指出。
按键消抖的部分参考了《勇敢的芯 伴你玩转Altera FPGA》。
按键 | 功能 |
---|---|
复位键 | 小灯全灭 |
key[0] | 小灯向左依次点亮 |
key[1] | 小灯向右依次点亮 |
key[2] | 1,3位的小灯闪烁 |
key[3] | 2,4位的小灯闪烁 |
按键消抖原理:采用打拍的方式,与原按键信号组合得到下降沿标志,设置一个计时20ms的计数器,当下降沿有效时(即存在抖动时),计数器的值会清零,这样设置就可以避免采到抖动时错误的键值。一旦计数器的值达到了最大值,就对当前所有的按键值做一次锁存。最后可以通过获得的键值来选择流水灯的变化模式。
- //---------按键消抖--------------//
- module key_debounce(
- input wire clk,
- input wire rst_n,
- input wire [3:0] key_in,
- output reg [3:0] key_flag,
- output reg [3:0] key_value
- );
-
- parameter CNT_MAX = 1_000_000; //1000_000
-
-
- wire key;
- reg key_reg;
- wire key_neg;
-
- reg [19:0] cnt_20ms;
- reg cnt_flag;
- reg [3:0] key_value_reg;
-
-
- //按键触发判断 按键在未按下时,为高电平
- assign key = (key_in[0] & key_in[1] & key_in[2] & key_in[3]);
-
- //检测下降沿
- always @(posedge clk or negedge rst_n) begin
- if(!rst_n) begin
- key_reg <= 1'b1;
- end
- else begin
- key_reg <= key;
- end
- end
-
- assign key_neg = ~key & key_reg;
-
- //20ms计数器
- always @(posedge clk or negedge rst_n) begin
- if(!rst_n) begin
- cnt_20ms <= 20'b0;
- end
- else if(key_neg) begin
- cnt_20ms <= 20'b0;
- end
- else begin
- cnt_20ms <= (cnt_20ms == CNT_MAX-1) ? 20'b0 : cnt_20ms + 1'b1;
- end
- end
-
- //完成20ms计数标志
- always @(posedge clk or negedge rst_n) begin
- if(!rst_n) begin
- cnt_flag <= 1'b0;
- end
- else if(cnt_20ms == CNT_MAX-1) begin
- cnt_flag <= 1'b1;
- end
- else begin
- cnt_flag <= 1'b0;
- end
- end
-
- //采集按键数据
- always @(posedge clk or negedge rst_n) begin
- if(!rst_n) begin
- key_value <= 4'b1111;
- end
- else if(cnt_flag) begin
- key_value <= key_in;
- end
- end
-
- always @(posedge clk or negedge rst_n) begin
- if(!rst_n) begin
- key_value_reg <= 4'b1111;
- end
- else begin
- key_value_reg <= key_value;
- end
- end
-
- //输出对应的按键控制值
- always @(posedge clk or negedge rst_n) begin
- if(!rst_n) begin
- key_flag <= 4'b0;
- end
- else begin
- key_flag <= ~key_value & key_value_reg;
- end
- end
-
- endmodule
流水灯原理:采用的开发板晶振是50MHz,所对应的时钟周期也就是20ns,我想让小灯每隔200ms发生变化,因此需要定义一个从0记到(10000000-1)的24位计数器,以及一个控制小灯状态变化的2位状态计数器。当没有按键按下时,计数器会归零,当计数记到最大值时,状态计数器加一,当状态计数器记到最大值3时,会自动归零,以实现小灯在四个状态内的循环变化。
- //--------------状态转换----------------//
- reg [23:0] cnt;
- reg [1:0] interval_flag;
-
- always @(posedge clk or negedge rst_n) begin
- if(!rst_n) begin
- cnt <= 24'b0;
- end
- else if(key_value == 4'b1111) begin
- cnt <= 24'b0;
- end
- else begin
- cnt <= (cnt == INTERVAL - 1'b1) ? 24'b0 : cnt + 1'b1;
- end
- end
-
- always @(posedge clk or negedge rst_n) begin
- if(!rst_n) begin
- interval_flag <= 1'b0;
- end
- else if(cnt == INTERVAL - 1'b1) begin
- interval_flag <= interval_flag + 1'b1;
- end
- else if(key_value == 4'b1111) begin
- interval_flag <= 2'b0;
- end
- else begin
- interval_flag <= interval_flag;
- end
- end
小灯的四种模式
- //---------------模式选择-------------------//
- always @(posedge clk or negedge rst_n) begin
- if(!rst_n) begin
- led_out <= 4'b0000;
- end
- else begin
- if(key_value[0] ==1'b0) begin
- case(interval_flag)
- 2'd0: led_out <= 4'b0001;
- 2'd1: led_out <= 4'b0010;
- 2'd2: led_out <= 4'b0100;
- 2'd3: led_out <= 4'b1000;
- endcase
- end
- else if(key_value[1] ==1'b0) begin
- case(interval_flag)
- 2'd0: led_out <= 4'b1000;
- 2'd1: led_out <= 4'b0100;
- 2'd2: led_out <= 4'b0010;
- 2'd3: led_out <= 4'b0001;
- endcase
- end
- else if(key_value[2] ==1'b0) begin
- led_out <= (interval_flag < 2'd2) ? 4'b1010 : 4'b0000;
- end
- else if(key_value[3] ==1'b0) begin
- led_out <= (interval_flag < 2'd2) ? 4'b0101 : 4'b0000;
- end
- else if(key_value == 4'b1111)begin
- led_out <= 4'b0000;
- end
- end
- end
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。