按键消抖实验
作者:互联网
当按键被按下在到被释放,期间产生的输入信号会发生抖动,如果不进行消抖处理,直接使用可能就会误触发。
按键消抖实验设计思路,当按键被按下,隔20ms取数据,也就是说20ms的前后各取一次数据进行边沿检测:
(1)、需要一个计数器cnt,因为按键随时都可能会被按下,所以计数器需一直启动在计数,需一直在检测。
1 always @(posedge clk or negedge rst_n)begin 2 if(!rst_n)begin 3 cnt <= 0; 4 end 5 else if(add_cnt)begin 6 if(end_cnt)begin 7 cnt <= 0; 8 end 9 else begin 10 cnt <= cnt + 1; 11 end 12 end 13 end 14 15 assign add_cnt = 1; 16 assign end_cnt = add_cnt && cnt == T_20MS -1 || key_en;
(2)、需要一个边沿检测器,需要对输入pin 上的信号进行边沿检测,检测到下降沿之后,立刻马上将计数器cnt 清0 ,cnt从0开始计数,数到20ms 取一次数据
1 always @(posedge clk or negedge rst_n)begin 2 if(!rst_n)begin 3 key_rst <= 1; 4 key_rst_r <= 1; 5 end 6 else begin 7 key_rst <= wr_en; 8 key_rst_r <= key_rst; 9 end 10 end 11 //当key_en = 1时,说明有检测到下降沿,但这个并不能当做一个真正有效的信号去启动cnt0, 12 //在按键按下到释放期间可能会多次产生key_en = 1 13 assign key_en = key_rst_r & (~key_rst);
1 //每隔20ms就取按键上的值 2 always @(posedge clk or negedge rst_n)begin 3 if(!rst_n) begin 4 pin_status <= 1; 5 end 6 else if(end_cnt) begin //隔20ms 取一次数据 7 pin_status <= wr_en; 8 end 9 end 10 11 always @(posedge clk or negedge rst_n)begin 12 if(!rst_n)begin 13 pin_status_r <= 1; 14 end 15 else begin 16 pin_status_r <= pin_status; 17 end 18 end 19 20 //前20MS的值与后20MS的值 21 assign pin_status_ctrl = pin_status_r & (~pin_status);//这个信号才比较稳定信号,可以当做启动计数器cnt0
完整代码:该代码是基于spi flash 一个读ID操作
1 module spi_flash( 2 clk, 3 rst_n, 4 wr_en, 5 spi_miso, 6 7 spi_sclk, 8 spi_mosi, 9 spi_cs, 10 rec_buf 11 ); 12 parameter SCLK_CLK = 3'd04; 13 parameter T_20MS = 20'd1_000_000; 14 parameter CMD_ID = 8'h9f; 15 16 input clk ; 17 input rst_n ; 18 input wr_en ; 19 input spi_miso; 20 21 output spi_sclk; 22 output spi_mosi; 23 output spi_cs ; 24 output[24-1:0] rec_buf ; 25 26 wire add_cnt0; 27 wire end_cnt0; 28 wire add_cnt1; 29 wire end_cnt1; 30 wire add_cnt/*synthesis keep=1*/; 31 wire end_cnt/*synthesis keep=1*/; 32 wire key_en/*synthesis keep=1*/; 33 34 wire key_h_2_l; 35 wire pin_status_ctrl/*synthesis keep=1*/; 36 37 reg[3-1:0] cnt0; 38 reg[6-1:0] cnt1; 39 reg[20-1:0] cnt/*synthesis preserve=1*/; 40 reg wr_vld; 41 reg key_rst; 42 reg key_rst_r; 43 reg pin_status; 44 reg pin_status_r; 45 46 47 /************************************************/ 48 //按键消抖动 49 always @(posedge clk or negedge rst_n)begin 50 if(!rst_n)begin 51 key_rst <= 1; 52 key_rst_r <= 1; 53 end 54 else begin 55 key_rst <= wr_en; 56 key_rst_r <= key_rst; 57 end 58 end 59 60 assign key_en = key_rst_r & (~key_rst); 61 62 //每隔20ms就取按键上的值 63 always @(posedge clk or negedge rst_n)begin 64 if(!rst_n) begin 65 pin_status <= 1; 66 end 67 else if(end_cnt) begin 68 pin_status <= wr_en; 69 end 70 end 71 72 always @(posedge clk or negedge rst_n)begin 73 if(!rst_n)begin 74 pin_status_r <= 1; 75 end 76 else begin 77 pin_status_r <= pin_status; 78 end 79 end 80 81 //前20MS的值与后20MS的值 82 assign pin_status_ctrl = pin_status_r & (~pin_status); 83 84 always @(posedge clk or negedge rst_n)begin 85 if(!rst_n)begin 86 cnt <= 0; 87 end 88 else if(add_cnt)begin 89 if(end_cnt)begin 90 cnt <= 0; 91 end 92 else begin 93 cnt <= cnt + 1; 94 end 95 end 96 end 97 98 assign add_cnt = 1; 99 assign end_cnt = add_cnt && cnt == T_20MS -1 || key_en; 100 101 102 always @(posedge clk or negedge rst_n)begin 103 if(!rst_n)begin 104 wr_vld <= 0; 105 end 106 else if(pin_status_ctrl)begin 107 wr_vld <= 1; 108 end 109 else if(end_cnt1)begin 110 wr_vld <= 0; 111 end 112 end 113 114 always @(posedge clk or negedge rst_n)begin 115 if(!rst_n)begin 116 cnt0 <= 0; 117 end 118 else if(add_cnt0)begin 119 if(end_cnt0)begin 120 cnt0 <= 0; 121 end 122 else begin 123 cnt0 <= cnt0 + 1; 124 end 125 end 126 end 127 128 assign add_cnt0 = wr_vld; 129 assign end_cnt0 = add_cnt0 && cnt0 == SCLK_CLK -1; 130 131 always @(posedge clk or negedge rst_n)begin 132 if(!rst_n)begin 133 cnt1 <= 0; 134 end 135 else if(add_cnt1)begin 136 if(end_cnt1)begin 137 cnt1 <= 0; 138 end 139 else begin 140 cnt1 <= cnt1 + 1; 141 end 142 end 143 end 144 145 assign add_cnt1 = end_cnt0; 146 assign end_cnt1 = add_cnt1 && cnt1 == 33 -1; 147 148 reg spi_sclk; 149 always @(posedge clk or negedge rst_n)begin 150 if(!rst_n)begin 151 spi_sclk <= 1; 152 end 153 else if(end_cnt0 && cnt1 != 32)begin 154 spi_sclk <= 0; 155 end 156 else if(add_cnt0 && cnt0 == ((SCLK_CLK>>1) -1))begin 157 spi_sclk <= 1; 158 end 159 end 160 161 reg spi_cs; 162 always @(posedge clk or negedge rst_n)begin 163 if(!rst_n)begin 164 spi_cs <= 1; 165 end 166 else if(add_cnt0 && cnt0 == ((SCLK_CLK>>1) -1) && cnt1 == 0)begin 167 spi_cs <= 0; 168 end 169 else if(end_cnt1)begin 170 spi_cs <= 1; 171 end 172 end 173 174 reg spi_mosi; 175 always @(posedge clk or negedge rst_n)begin 176 if(!rst_n)begin 177 spi_mosi <= 1; 178 end 179 else if(end_cnt0 && cnt1 >= 0 && cnt1 < 8)begin 180 spi_mosi <= CMD_ID[7-cnt1]; 181 end 182 end 183 184 reg[24-1:0] rec_buf_temp; 185 always @(posedge clk or negedge rst_n)begin 186 if(!rst_n)begin 187 rec_buf_temp <= 0; 188 end 189 else if(add_cnt0 && cnt0 == ((SCLK_CLK>>1)-1) && cnt1 >= 9 && cnt1 < 33)begin 190 rec_buf_temp[32-cnt1] <= spi_miso; 191 end 192 end 193 194 reg dout_vld; 195 always @(posedge clk or negedge rst_n)begin 196 if(!rst_n)begin 197 dout_vld <= 0; 198 end 199 else begin 200 dout_vld <= end_cnt1; 201 end 202 end 203 204 reg[24-1:0] rec_buf; 205 always @(posedge clk or negedge rst_n)begin 206 if(!rst_n)begin 207 rec_buf <= 0; 208 end 209 else if(end_cnt1)begin 210 rec_buf <= rec_buf_temp; 211 end 212 end 213 214 endmoduleView Code
用quartus II 的SignalTab抓取的波形:
如果pin_status_ctl 检测到多次,可以将间隔时间适当的加长点。一般的轻触按键20~50ms。
触发条件可以多开几个窗口进行捕获观察 。
标签:begin,wire,消抖,spi,实验,cnt1,按键,rst,reg 来源: https://www.cnblogs.com/wen2376/p/16171571.html