按键使用方法(二)------verilog
这里我们要验证一键两用的情况:点击与长击,单击与双击
代码:
/********************************Copyright************************************** **----------------------------File information-------------------------- ** File name :key_function_2.v ** CreateDate :2015.03 ** Funtions :按键的用法(二):点击和长击,单击和双击 ** Operate on :M5C06N3L114C7 ** Copyright :All rights reserved. ** Version :V1.0 **---------------------------Modify the file information---------------- ** Modified by : ** Modified data : ** Modify Content: *******************************************************************************/ 001 module key_function_2 ( 002 clk, 003 rst_n, 004 005 key_4, 006 key_5, 007 008 led_d41, 009 led_d42, 010 led_d51, 011 led_d52 012 013 ); 014 input clk; 015 input rst_n; 016 017 input key_4; //按键的点击与长击:按下按键后,2S内松开按键则为点击,2s后松开按键为长击,默认未按下为高。 018 input key_5; /*按键的单击和双击,完成第一次按键后100ms之内第二次按下按键则为双击,否则为单击 */ 019 020 output led_d41; 021 output led_d42; 022 output led_d51; 023 output led_d52; 024 025 //--------------------------- 026 //定时2s 027 reg cnt_en; 028 localparam t_1s = 25'd23999999; /* //实际使用 */ 029 // localparam t_1s = 25'd239; /* //测试使用 */ 030 031 localparam t_2s = 2'd2; 032 reg [24:0] cnt; 033 always @(posedge clk or negedge rst_n) 034 begin 035 if(!rst_n) 036 begin 037 cnt <= 0; 038 end 039 else if(cnt_en) 040 begin 041 if(cnt == t_1s) 042 cnt <= 0; 043 else 044 cnt <= cnt + 1; 045 end 046 else 047 cnt <= 0; 048 end 049 050 reg [1:0] cnt1; 051 always @(posedge clk or negedge rst_n) 052 begin 053 if(!rst_n) 054 begin 055 cnt1 <= 0; 056 end 057 else if(cnt_en) 058 begin 059 if(cnt1 == 2'd2) 060 cnt1 <= 2'd2; 061 else if(cnt == t_1s) 062 cnt1 <= cnt1 + 1; 063 end 064 else 065 cnt1 <= 0; 066 end 067 068 //------------------------------- 069 /* 取key_4的上升沿和下降沿 */ 070 reg [2:0] key_4_reg; 071 wire key_4_pos; 072 wire key_4_neg; 073 always @(posedge clk or negedge rst_n) 074 begin 075 if(!rst_n) 076 begin 077 key_4_reg <= 3'b111; 078 end 079 else 080 begin 081 key_4_reg <= {key_4_reg[1:0],key_4}; 082 end 083 end 084 assign key_4_pos = (key_4_reg[2:1] == 2'b01); 085 assign key_4_neg = (key_4_reg[2:1] == 2'b10); 086 087 //------------------------------ 088 /* 状态机 */ 089 reg [2:0] state1; 090 reg key_S; 091 reg key_L; 092 always @(posedge clk or negedge rst_n) 093 begin 094 if(!rst_n) 095 begin 096 state1 <= 'd0; 097 cnt_en <= 0; 098 key_S <= 0; 099 key_L <= 0; 100 end 101 else 102 begin 103 case(state1) 104 'd0: 105 begin 106 cnt_en <= 0; 107 key_S <= 0; 108 key_L <= 0; 109 if(key_4_neg) /* 按键按下 */ 110 state1 <= 'd1; 111 else 112 state1 <= 'd0; 113 end 114 'd1: 115 begin 116 if(key_4_pos) /* 按键释放 */ 117 begin 118 cnt_en <= 0; 119 state1 <= 'd2; 120 key_S <= 1; 121 end 122 else if((key_4_reg==3'b000)&&(cnt1 == 2'd2)) /* 按键一直为低,延时2s之后 */ 123 begin 124 cnt_en <= 0; 125 state1 <= 'd3; 126 key_L <= 1; 127 end 128 else 129 cnt_en <= 1; 130 end 131 'd2: /* 点击 */ 132 begin 133 key_S <= 0; 134 state1 <= 'd5; 135 end 136 'd3: 137 begin 138 key_L <= 0; 139 state1 <= 'd4; 140 end 141 'd4: 142 begin 143 if(key_4_pos) 144 state1 <= 'd5; 145 else 146 state1 <= 'd4; 147 end 148 'd5: 149 begin 150 state1 <= 'd0; 151 end 152 default:state1 <= 'd0; 153 endcase 154 155 end 156 end 157 158 reg led_s; 159 reg led_l; 160 always @(posedge clk or negedge rst_n) 161 begin 162 if(!rst_n) 163 begin 164 led_s <= 0; 165 end 166 else if(key_S) 167 begin 168 led_s <= ~led_s; 169 end 170 end 171 172 always @(posedge clk or negedge rst_n) 173 begin 174 if(!rst_n) 175 begin 176 led_l <= 0; 177 end 178 else if(key_L) 179 begin 180 led_l <= ~led_l; 181 end 182 end 183 184 //------------------------------------ 185 localparam t_100ms = 22'd2399999; /* //实际使用 */ 186 // localparam t_100ms = 22'd23; /* //测试使用 */ 187 reg [21:0] cnnt; 188 reg cnnt_en; 189 always @(posedge clk or negedge rst_n) 190 begin 191 if(!rst_n) 192 begin 193 cnnt <= 0; 194 end 195 else if(cnnt_en) 196 begin 197 if(cnnt == t_100ms ) 198 cnnt <= t_100ms; 199 else 200 cnnt <= cnnt + 1; 201 end 202 else 203 cnnt <= 0; 204 end 205 //------------------------------- 206 /* 取key_5的上升沿和下降沿 */ 207 reg [2:0] key_5_reg; 208 wire key_5_pos; 209 wire key_5_neg; 210 always @(posedge clk or negedge rst_n) 211 begin 212 if(!rst_n) 213 begin 214 key_5_reg <= 3'b111; 215 end 216 else 217 begin 218 key_5_reg <= {key_5_reg[1:0],key_5}; 219 end 220 end 221 assign key_5_pos = (key_5_reg[2:1] == 2'b01); 222 assign key_5_neg = (key_5_reg[2:1] == 2'b10); 223 224 //------------------------------ 225 /* 状态机 */ 226 reg [2:0] state2; 227 reg key_SS; 228 reg key_D; 229 always @(posedge clk or negedge rst_n) 230 begin 231 if(!rst_n) 232 begin 233 state2 <= 'd0; 234 cnnt_en <= 0; 235 key_SS <= 0; 236 key_D <= 0; 237 end 238 else 239 begin 240 case(state2) 241 'd0: 242 begin 243 cnnt_en <= 0; 244 key_SS <= 0; 245 key_D <= 0; 246 if(key_5_neg) /*第一次 按键按下 */ 247 state2 <= 'd1; 248 else 249 state2 <= 'd0; 250 end 251 'd1: 252 begin 253 if(key_5_pos) /*第一次 按键释放 */ 254 begin 255 state2 <= 'd2; 256 end 257 else 258 state2 <= 'd1; 259 end 260 'd2: 261 begin 262 if((key_5_neg)&&(cnnt < t_100ms)) 263 begin 264 cnnt_en <= 0; 265 state2 <= 'd3; 266 key_D <= 1; 267 end 268 else if(cnnt ==t_100ms) 269 begin 270 cnnt_en <= 0; 271 state2 <= 'd4; 272 key_SS <= 1; 273 end 274 else 275 cnnt_en <= 1; 276 end 277 'd3: 278 begin 279 key_D <= 0; 280 if(key_5_pos) 281 state2 <= 'd5; 282 end 283 'd4: 284 begin 285 key_SS <= 0; 286 state2 <= 'd5; 287 end 288 'd5: 289 begin 290 state2 <= 'd0; 291 end 292 default:state2 <= 'd0; 293 endcase 294 295 end 296 end 297 298 reg led_signal; 299 reg led_double; 300 always @(posedge clk or negedge rst_n) 301 begin 302 if(!rst_n) 303 begin 304 led_signal <= 0; 305 end 306 else if(key_SS) 307 begin 308 led_signal <= ~led_signal; 309 end 310 end 311 312 always @(posedge clk or negedge rst_n) 313 begin 314 if(!rst_n) 315 begin 316 led_double <= 0; 317 end 318 else if(key_D) 319 begin 320 led_double <= ~led_double; 321 end 322 end 323 324 //------------------------ 325 assign led_d41 = led_s; 326 assign led_d42 = led_l; 327 assign led_d51 = led_signal; 328 assign led_d52 = led_double; 329 330 endmodule 331 332 333
仿真代码:
/********************************Copyright************************************** **----------------------------File information-------------------------- ** File name :key_function_testbench.v ** CreateDate :2015.03 ** Funtions :按键功能的测试文件 ** Operate on :M5C06N3L114C7 ** Copyright :All rights reserved. ** Version :V1.0 **---------------------------Modify the file information---------------- ** Modified by : ** Modified data : ** Modify Content: *******************************************************************************/ 001 `timescale 1 ns/1 ns 002 003 module key_function_2_tb; 004 reg clk; 005 reg rst_n; 006 007 reg key_4; //按键的点击与长击:按下按键后,2S内松开按键则为点击,2s后松开按键为长击,默认未按下为高。 008 reg key_5; /*按键的单击和双击,完成第一次按键后100ms之内第二次按下按键则为双击,否则为单击 */ 009 010 wire led_d41; 011 wire led_d42; 012 wire led_d51; 013 wire led_d52; 014 015 016 key_function_2 key_function_2( 017 .clk, 018 .rst_n, 019 020 .key_4, 021 .key_5, 022 023 .led_d41, 024 .led_d42, 025 .led_d51, 026 .led_d52 027 028 ); 029 030 parameter tck = 24; 031 parameter t = 1000/tck; 032 033 always #(t/2) clk = ~clk; 034 035 initial 036 begin 037 clk = 0; 038 rst_n = 0; 039 key_4 = 1; 040 key_5 = 1; 041 042 #(100*t) rst_n = 1; 043 /* 点击 */ 044 #(100*t) key_4 = 1; 045 #(60*t) key_4 = 0; 046 #(100*t) key_4 = 1; 047 048 /* 长击 */ 049 #(100*t); 050 #(100*t) key_4 = 1; 051 #(60*t) key_4 = 0; 052 #(1000*t); 053 #(100*t) key_4 = 1; 054 055 /* 单击 */ 056 #(2000*t); 057 #(100*t) key_5 = 1; 058 #(300*t) key_5 = 0; 059 #(100*t) key_5 = 1; 060 061 062 /* 双击 */ 063 #(2000*t); 064 #(100*t) key_5 = 1; 065 #(300*t) key_5 = 0; 066 #(300*t) key_5 = 1; 067 #(10*t) key_5 = 1; 068 #(10*t) key_5 = 0; 069 #(300*t) key_5 = 1; 070 071 072 end 073 074 endmodule 075 076
仿真波形:
1、点击与长击
2、单击与双击
注:参考资料来自网络。