数电实验 按键防抖设计(状态机)

数电实验 按键防抖设计(状态机)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
主程序:

module yyc2018113559_6_1(

input clk,rst,key_in,

output reg key_state, //按键状态,低电平为未按下,高电平为按下状态

output reg [3:0] key_count,  //用于数码管输出的数字

output reg [6:0] codeout

);

parameter IDLE=2'b00; //定义4种状态

parameter FILTER0=2'b01;

parameter DOWN=2'b10;

parameter FILTER1=2'b11;

//内部信号声明

reg key_tmp0;

reg key_tmp1;

wire pose_edge;

wire nege_edge;


//边沿检测模块

always@(posedge clk or negedge rst)

begin 

	if(~rst)

	begin     //复位

		key_tmp0<=0; 

		key_tmp1<=0;

	end

	else

	begin 

		key_tmp0<=key_in;  //tmp0等于输入,tmp0表示当前状态

		key_tmp1<=key_tmp0; //tmp1表示前一个状态

	end

end

assign pose_edge=(~key_tmp1)&(key_tmp0);  //上升沿,当前与前一个状态比,由低到高

assign nege_edge=(key_tmp1)&(~key_tmp0);  //下降沿,当前与前一个状态比,由高到低

reg [9:0] cnt;

reg en;       //使能信号

reg cnt_full;


//计数器,实际用于延时,计数器记满
//即是在规定时间内抖动,即认为是一次按下按键,记录。若没有记满,则不认为是一次按下,不记录

always@(posedge clk or negedge rst)

begin 

if(~rst) cnt<=10'd0;

else if(en) cnt<=cnt+1;

else cnt<=10'd0; 

end


//计数满信号

always@(posedge clk or negedge rst)

begin 

	 if(~rst)

		cnt_full<=1'b0;

	 else if(cnt==10'd999)  //cnt记满999,cnt_full标志置1

		cnt_full<=1'b1;

	 else cnt_full<=1'b0;

 end

 //状态机

reg [1:0] current_state;

always@(posedge clk or negedge rst)  //敏感触发为clk上升沿,复位信号rst下降沿

 begin 

	if(~rst)

		begin   //复位
			en<=1'b0;current_state<=IDLE;

			key_state<=1'b0;key_count<=4'b0000;
		end

	else

   begin 

		case (current_state)    //4中状态
		

		IDLE: //未按下空闲状态

		begin

			key_state<=1'b0;

			if(pose_edge) //检测到上升沿,进入下一个状态,计数器开始计数

				begin current_state<=FILTER0; en<=1'b1;end

			else //否则仍处于未按下空闲状态

				current_state<=IDLE;
      end
		

		FILTER0: //按下抖动滤除状态

		begin

			if(cnt_full)//计数器记满,达到稳定状态,计数停止

			begin

				key_state<=1'b1; //key_state为1表示按键按下

				key_count<=key_count+1'b1; //按下输出就得加一

				if(key_count==4'b1001)  //超过9归0

					 key_count<=4'b0000;

				en<=1'b0;

				current_state=DOWN;  //下一状态

			end

			else if(nege_edge)  //若计数没有记满,即在延时前结束了抖动,那么认为不是按下操作,回到前一状态

			begin

				current_state<=IDLE;

				en<=1'b0;

			end

			else  //维持当前状态

				current_state<=FILTER0;
		end	
		

		DOWN: //按下稳定状态

		begin

			key_state<=1'b1;

			if(nege_edge)

			begin

				current_state<=FILTER1;	//下一状态

				en<=1'b1;

			end

			else    //保持当前状态

				current_state<=DOWN;

		end
			

		FILTER1: //释放抖动滤除状态

		begin

			if(cnt_full)  //计数记满了,即超过规定延时,认为为一次按下操作

			 begin

				key_state<=1'b0;

				en<=1'b0;

				current_state<=IDLE;

			 end

			 else if(pose_edge)  //若计数没有满,不认为有按下操作,保持当前状态

         begin

				current_state<=DOWN;

				en<=1'b0;

			end

		end	
		

		default:

			begin

				en<=1'b0;

				current_state<=IDLE;

				key_state<=1'b0;

			end

		endcase

	end

 end
 


always@(key_count)     //数码管输出
begin

	case(key_count)

	4'd0:codeout=7'b0111111;

   4'd1:codeout=7'b0000110;

   4'd2:codeout=7'b1011011;

   4'd3:codeout=7'b1001111;

   4'd4:codeout=7'b1100110;

   4'd5:codeout=7'b1101101;

   4'd6:codeout=7'b1111101;

   4'd7:codeout=7'b0000111;

   4'd8:codeout=7'b1111111;

   4'd9:codeout=7'b1101111;

default:codeout=7'b0000000;  //说明其他输入情况的输出取值

endcase

end

endmodule 

modelsim仿真

`timescale 10 ns/1 ns

module yyc2018113559_6_1_test;

reg clk; 

reg rst;

reg key_in;

wire key_state;

wire [3:0] key_count;

wire [6:0] codeout;

yyc2018113559_6_1 test(

.clk(clk),

.rst(rst),

.key_in(key_in),

.key_state(key_state),

.key_count(key_count),

.codeout(codeout)

);



initial begin

clk=1'b0;

rst=1'b1;

key_in=1'b0;

#100000

rst=1'b0;

#100000

rst=1'b1;

end

 

always

begin

	key_in=1'b0;

	repeat(20)

	begin

		#50000 key_in=~key_in;//抖动时间20*10*50000ns=10ms

	end

	#3000000//按下时长30ms

	key_in=1'b1;

	repeat(20)//抖动时间10ms

	begin

		#50000 key_in=~key_in;

	end

	#3000000;

end

always #500 clk=~clk; //时钟周期为10us



endmodule

猜你喜欢

转载自blog.csdn.net/weixin_44026026/article/details/110687173