状态机finite-state machine学习笔记2——按键消抖初步(1)

状态机finite-state machine学习笔记2

现实生活中按键按下之后并不会是理想状态

这里引入按键消抖的状态机学习

状态机finite-state machine学习笔记2——按键消抖初步(1)_第1张图片

按键消抖第一种写法

状态

未按下时空闲状态(IDLE)

按下抖动滤除状态(FILTER0)

按下稳定状态(DOWN)

释放抖动滤除状态(FILTER1)

/*
Clk为50_000_000的时钟

Rst_n为复位信号

key_in为按键输入

key_flag为按键的使能状态

key_state是按键状态标志
*/

//主模块输入输出部分
module key_filter(Clk,Rst_n,key_in,key_flag,key_state);

         input Clk;
         input Rst_n;
         input key_in;
         output reg key_flag;

         output reg key_state;

         localparam        //独热码方式
                   IDEL       = 4'b0001,
                   FILTER0    = 4'b0010,
                   DOWN       = 4'b0100,
                   FILTER1    = 4'b1000;
         reg[3:0]state;
         reg[19:0]cnt;
         reg en_cnt;      //使能计数寄存器

状态机finite-state machine学习笔记2——按键消抖初步(1)_第2张图片
状态机finite-state machine学习笔记2——按键消抖初步(1)_第3张图片

电平判断和寄存部分

//对外部输入的异步信号进行同步处理
 reg key_in_sa,key_in_sb;
 reg key_tmpa,key_tmpb;
 wire pedge,nedge;
 always@(posedge Clk or negedge Rst_n)
	 if(!Rst_n)begin
		  key_in_sa <= 1'b0;
		  key_in_sb <= 1'b0;
	 end
	 else begin	//寄存两个电平变化状态
		  key_in_sa <= key_in;
		  key_in_sb <= key_in_sa; 
 end
 

//使用D触发器存储两个相邻时钟上升沿时外部输入信号
//(已经同步到系统时钟域中)的电平状态

         always@(posedge Clk or negedge Rst_n)
         if(!Rst_n)begin
                   key_tmpa <= 1'b0;
                   key_tmpb <= 1'b0;
         end
         else begin
                   key_tmpa <= key_in_sb;
                   key_tmpb <= key_tmpa; 
         end
//产生跳变沿信号 ,分别为上升沿和下降沿
         assign nedge = (!key_tmpa) & key_tmpb;
         assign pedge = key_tmpa & (!key_tmpb);

计数和计数满部分

reg cnt_full;//计数满标志信号
always@(posedge Clk or negedge Rst_n)
 if(!Rst_n)
  cnt <= 20'b0;
 else if(en_cnt)
  cnt <= cnt + 1'b1;
 else
  cnt <= 20'b0;
 
 always@(posedge Clk or negedge Rst_n)
 if(!Rst_n)
  cnt_full <= 1'b0;
 else if(cnt == 999_999)
  cnt_full <= 1'b1;
 else
  cnt_full <= 1'b0; 

这里需要说明一下,我自己的FPGA的系统晶振为50_000_000Hz,周期为20ns,但是按键的按下一般为20ms左右20_000_000ns,为晶振周期的1_000_000倍,而1_000_000的16进制为F4240,对应二进制20位,因此这里的cnt为20个位

主模块状态机部分

1.状态为IDLE时,若检测到下降沿状态,则进入FILTER0的下降沿过滤抖动状态,并且打开计数器使能信号,否则在IDLE中死等。

2.状态为FILTER0时,若20ms还没有结束就有上升沿,那么认为按键在抖动,重新回到IDLE状态(去检测到下降沿重新20ms的计时); 如果只有低电平,按键已经按下,key_state置为低电平0,key_flag为1(状态已切换)

3.进入DOWN状态之后检测状态不变化,key_flag置为0,在DOWN状态中死等;检测上升信号后,进入FILTER1的滤除抖动状态,并且将计数使能信号打开

4.类比FILTER0状态

 always@(posedge Clk or negedge Rst_n)
 if(!Rst_n)begin
  	en_cnt <= 1'b0;
  	state <= IDEL;
 	key_flag <= 1'b0;
  	key_state <= 1'b1;
 	end
 else begin
  	case(state)
  		IDEL :
    		begin
     			key_flag <= 1'b0;
     		if(nedge)begin
      			state <= FILTER0;
      			en_cnt <= 1'b1;
     			end
     		else
      			state <= IDEL;
    		end
     
   		FILTER0:
    		if(cnt_full)begin
     			key_flag <= 1'b1;
     			key_state <= 1'b0;
     			en_cnt <= 1'b0;
     			state <= DOWN;
    			end
    		else if(pedge)begin
     			state <= IDEL;
     			en_cnt <= 1'b0;
    			end
    		else
     			state <= FILTER0;
     
   		DOWN:
    		begin
     			key_flag <= 1'b0;
     		if(pedge)begin
      			state <= FILTER1;
      			en_cnt <= 1'b1;
     			end
     		else
      			state <= DOWN;
    		end
   
   		FILTER1:
    		if(cnt_full)begin
     			key_flag <= 1'b1;
     			key_state <= 1'b1;
     			en_cnt <= 1'b0;
     			state <= IDEL;
    			end
    		else if(nedge)begin
     			en_cnt <= 1'b0;
     			state <= DOWN;
    			end
    		else
     			state <= FILTER1;
   
   		default:
    		begin 
     			state <= IDEL; 
     			en_cnt <= 1'b0;  
     			key_flag <= 1'b0;
     			key_state <= 1'b1;
    		end
   
  endcase 
 end
 endmodule

状态机转移图
状态机finite-state machine学习笔记2——按键消抖初步(1)_第4张图片

状态转移条件
状态机finite-state machine学习笔记2——按键消抖初步(1)_第5张图片

你可能感兴趣的:(verilog,Altera,Xilinx)