重拾FPGA-单按键(按键消抖)
前言
1、只是简单的单按键检测功能;未上板仿真,学习笔记。
2、按键抖动20ms;
3、消抖,直接是每当检测到下降沿,就计时20ms,若20ms结束后,输入依然为低电平,就认为是一次有效的按下动作;后面改为:每当下降沿时,开始计数,计数未满来了上升沿,状态回到【检测按下】,直到一次数值记满。
准备工作:
1、状态机
2、计数值

3、模块

4、代码
a、计数器
1 `timescale 1ns/10ps 2 module JiShuQi_module( 3 clk, 4 rst_n, 5 KaiShi, 6 JieShu 7 ); 8 input clk; 9 input rst_n; 10 input KaiShi; 11 output reg JieShu; 12 13 parameter JiShuZhi = 20'd200; //计数值 14 15 reg JiShu_ZhuangTai; 16 reg [19:0]JiShuQi; 17 wire JiMan; //计数器记满 18 19 always@(posedge clk or negedge rst_n) 20 if(!rst_n) 21 #1 JiShu_ZhuangTai <= 1'b0; 22 else if(KaiShi) 23 #1 JiShu_ZhuangTai <= 1'b1; 24 else if(JiMan) 25 #1 JiShu_ZhuangTai <= 1'b0; 26 else 27 #1 JiShu_ZhuangTai <= JiShu_ZhuangTai; 28 //计数器计数 29 always@(posedge clk or negedge rst_n) 30 if(!rst_n) 31 #1 JiShuQi <= 20'd0; 32 else if(JiMan) 33 #1 JiShuQi <= 20'd0; 34 else if(JiShu_ZhuangTai) 35 #1 JiShuQi <= JiShuQi + 1'b1; 36 else 37 #1 JiShuQi <= 20'd0; 38 // 39 assign JiMan = (JiShuQi == JiShuZhi)?1'b1:1'b0; 40 // 41 always@(posedge clk or negedge rst_n) 42 if(!rst_n) 43 #1 JieShu <= 1'b0; 44 else if(JiMan) 45 #1 JieShu <= 1'b1; 46 else 47 #1 JieShu <= 1'b0; 48 endmodule
b、按键检测模块
1 `timescale 1ns/10ps 2 module DanAnJianJianCe_module( 3 clk, 4 rst_n, 5 JianCe_En, 6 AnJian_ShuRu, 7 AnJian_YouXiao, 8 AnJian_ZhuangTai 9 ); 10 input clk; 11 input rst_n; 12 input JianCe_En; //按键检测开关 可控制,上级系统可给一个持续的信号 13 input AnJian_ShuRu; //物理接口 14 output reg AnJian_YouXiao; //按键按下有效 与按下持续时间无关,一次动作只给一个有效 15 output AnJian_ZhuangTai; //按下时为1,松开为0 16 // 17 reg KaiShi; 18 wire JieShu; 19 // 20 reg AnJian_ShuRu_JiCun_a; //按键输入信号同步 21 reg AnJian_ShuRu_JiCun_b; //按键输入信号同步 22 wire AnJian_AnXia; //按键按下有效 23 wire AnJian_SongKai; //按键松开 24 // 25 reg [3:0]NS; 26 reg [3:0]CS; 27 localparam 28 KongXian = 4'b0000, 29 JianCe_AnXia = 4'b0001, 30 AnXia_XiaoDou = 4'b0010, 31 JianCe_SongKai = 4'b0100, 32 SongKai_XiaoDou = 4'b1000; 33 34 //按键同步及状态检测 35 always@(posedge clk or negedge rst_n) 36 if(!rst_n)begin 37 #1 AnJian_ShuRu_JiCun_a <= 1'b0; 38 #1 AnJian_ShuRu_JiCun_b <= 1'b0; 39 end 40 else begin 41 #1 AnJian_ShuRu_JiCun_a <= AnJian_ShuRu; 42 AnJian_ShuRu_JiCun_b <= AnJian_ShuRu_JiCun_a; 43 end 44 assign AnJian_AnXia = (!AnJian_ShuRu_JiCun_a & AnJian_ShuRu_JiCun_b)?1'b1:1'b0; 45 assign AnJian_SongKai = (AnJian_ShuRu_JiCun_a & !AnJian_ShuRu_JiCun_b)?1'b1:1'b0; 46 47 48 //状态机1 49 always@(posedge clk or negedge rst_n) 50 if(!rst_n) 51 #1 CS <= KongXian; 52 else 53 #1 CS <= NS; 54 //状态机2 55 always@(CS,JianCe_En,AnJian_AnXia,AnJian_SongKai,JieShu,AnJian_ShuRu_JiCun_b)begin 56 NS = 4'bxxxx; 57 case(CS) 58 KongXian :begin 59 if(JianCe_En) 60 NS = JianCe_AnXia; 61 else 62 NS = KongXian; 63 end 64 JianCe_AnXia :begin 65 if(AnJian_AnXia) 66 NS = AnXia_XiaoDou; 67 else 68 NS = JianCe_AnXia; 69 end 70 AnXia_XiaoDou :begin 71 if(JieShu)begin 72 if(!AnJian_ShuRu_JiCun_b) 73 NS = JianCe_SongKai; 74 else 75 NS = JianCe_AnXia; 76 end 77 else 78 NS = AnXia_XiaoDou; 79 end 80 JianCe_SongKai :begin 81 if(AnJian_SongKai) 82 NS = SongKai_XiaoDou; 83 else 84 NS = JianCe_SongKai; 85 end 86 SongKai_XiaoDou :begin 87 if(JieShu)begin 88 if(AnJian_ShuRu_JiCun_b) 89 NS = KongXian; 90 else 91 NS = JianCe_SongKai; 92 end 93 else 94 NS = SongKai_XiaoDou; 95 end 96 default:NS = KongXian; 97 endcase 98 end 99 //状态机3 100 always@(posedge clk or negedge rst_n) 101 if(!rst_n)begin 102 #1 AnJian_YouXiao <= 1'b0; 103 #1 KaiShi <= 1'b0; 104 end 105 else begin 106 case(CS) 107 KongXian :; 108 JianCe_AnXia : 109 if(AnJian_AnXia) 110 #1 KaiShi <= 1'b1; 111 AnXia_XiaoDou :begin 112 #1 KaiShi <= 1'b0; 113 if(JieShu && !AnJian_ShuRu_JiCun_b) 114 #1 AnJian_YouXiao <= 1'b1; 115 end 116 JianCe_SongKai :begin 117 #1 AnJian_YouXiao <= 1'b0; 118 if(AnJian_SongKai) 119 #1 KaiShi <= 1'b1; 120 end 121 SongKai_XiaoDou: 122 #1 KaiShi <= 1'b0; 123 default : begin 124 #1 KaiShi <= 1'b0; 125 #1 AnJian_YouXiao <= 1'b0; 126 end 127 endcase 128 end 129 assign AnJian_ZhuangTai = ~AnJian_ShuRu_JiCun_b; 130 JiShuQi_module JiShuQi( 131 .clk(clk), 132 .rst_n(rst_n), 133 .KaiShi(KaiShi), 134 .JieShu(JieShu) 135 ); 136 endmodule
c、顶层模块
1 `timescale 1ns/10ps 2 module top_module( 3 clk, 4 rst_n, 5 AnJian_ShuRu 6 ); 7 input clk; 8 input rst_n; 9 input AnJian_ShuRu; //物理接口 10 11 DanAnJianJianCe_module tt( 12 .clk(clk), 13 .rst_n(rst_n), 14 .JianCe_En(1'b1), 15 .AnJian_ShuRu(AnJian_ShuRu), 16 .AnJian_YouXiao(), 17 .AnJian_ZhuangTai() 18 ); 19 endmodule
d、仿真
1 `timescale 1ns/10ps 2 `define clk_period 20 3 4 module top_module_tb( 5 ); 6 reg clk; 7 reg rst_n; 8 reg AnJian_ShuRu; 9 10 initial clk = 0; 11 always#(`clk_period/2) clk = ~clk; 12 13 initial begin 14 rst_n = 0; 15 AnJian_ShuRu = 1; 16 #(`clk_period*5); 17 rst_n = 1; 18 #(`clk_period*5); 19 DouDong; 20 end 21 22 reg [15:0]randnum; 23 task DouDong;begin 24 repeat(30)begin 25 randnum = {$random}%200; 26 #randnum AnJian_ShuRu = ~AnJian_ShuRu; 27 end 28 #(`clk_period*5); 29 AnJian_ShuRu = 0; 30 #(`clk_period*100); 31 32 repeat(30)begin 33 randnum = {$random}%200; 34 #randnum AnJian_ShuRu = ~AnJian_ShuRu; 35 end 36 #(`clk_period*5); 37 AnJian_ShuRu = 1; 38 #(`clk_period*100); 39 $stop; 40 end 41 endtask 42 43 top_module top_module( 44 .clk(clk), 45 .rst_n(rst_n), 46 .AnJian_ShuRu(AnJian_ShuRu) 47 ); 48 endmodule
仿真图

状态机


浙公网安备 33010602011771号