三段式状态机实现按键消抖
状态机
状态机分类:
Moore型状态机:
状态机的变化只与当前的状态有关
Mearly型状态机:
状态机的变化不仅与当前的状态有关,还与输入有关
状态机编写方法:
一段式:
主要是讲所有的状态变化以及导致的输出变化都写在了一个always块中。
两段式:
将一些复位信号,clk信号单独写在一个always块中,其他的状态变化,输出值得变化写在一个always块中。
三段式:
将一些复位信号,clk信号单独写在一个always块中,其他的状态迁移变化写在一个always块中,对应状态的输出值得变化写在一个always块中
一、题目分析
本次设计需要用到状态机进行按键消抖的编写,同时使用按键控制led灯实现每按下一次按键使led灯以二进制顺序亮起,按键消抖的原理图如下:
原理图说明:
前沿抖动与后沿抖动持续时间均约为5-10ms,键稳定状态持续时间约为20ms-40ms
二、设计分析
当前沿抖动时将高低电平切换的状态分为高低电平两个状态两个状态来回切换,当按键稳定时进入下一个状态并将标志信号拉高一个时钟周期,当按键长时间保持时标志信号并不一直保持高电平状态,所以在按键松开时重新回到空闲状态。
三、状态图
四、三段式状态机编写步骤
1.确定输入输出
输入:系统时钟,复位信号,按键信号
输出:标志信号
代码实现:
`timescale 1ns / 1ps
module KeyAndLed(
input clk ,
input rst_n ,
input key ,
output reg flag
);
2.状态编码
编码类型简介:
例:编写八个状态
编码类型代码如下:
二进制编码:
s0 = 4'b0001;
s1 = 4'b0010;
s2 = 4'b0011;
s3 = 4'b0100;
s4 = 4'b0101;
s5 = 4'b0110;
s6 = 4'b0111;
s7 = 4'b1000;
格雷码:
s0 = 5'b00001;
s1 = 5'b00011;
s2 = 5'b00010;
s3 = 5'b00110;
s4 = 5'b00100;
s5 = 5'b01100;
s6 = 5'b01000;
s7 = 5'b11000;
独热码:
s0 = 8'b00000001;
s1 = 8'b00000010;
s2 = 8'b00000100;
s3 = 8'b00001000;
s4 = 8'b00010000;
s5 = 8'b00100000;
s6 = 8'b01000000;
s7 = 8'b10000000;
3.状态机编写
第一段:
状态切换,使用时序逻辑进行实现。
代码如下(示例):
always@(posedge clk)
if(!rst_n)
cur_state <= IDLE;
else
cur_state <= next_state;
第二段:
根据当前状态确定下一个状态,使用组合逻辑实现。
代码如下:
always@(*)
case(cur_state)
IDLE :begin
if(key == 0)
next_state = s0;
else
next_state = cur_state;
end
s0 :begin
if(key == 1)
next_state = IDLE;
else if(cnt == DELAY - 1)
next_state = s1;
else
next_state = cur_state;
end
s1 :begin
next_state = s2;
end
s2 :begin
if(key == 0)
next_state = s2;
else
next_state = IDLE;
end
default:begin
next_state = IDLE;
end
endcase
第三段:
确定输出状态,使用时序逻辑进行实现。
代码如下:
always@(posedge clk)
if(!rst_n)begin
flag2 <= 0;
cnt <= 0;
end
else
case(cur_state)
IDLE :begin
flag <= 0;
cnt <= 0;
end
s0 :begin
if(cnt == DELAY - 1)
cnt <= 32'b0;
else
cnt <= cnt + 32'b1;
end
s1 :begin
flag <= 1;
cnt <= 0;
end
s2 :begin
flag <= 0;
cnt <= 0;
end
default:begin
flag <= 0;
cnt <= 0;
end
endcase
五、顶层模块编写
1.确定输入输出
输入:系统时钟,复位信号,按键
输出:4个led灯
2.顶层模块编写
将按键消抖模块例化到顶层模块。
代码实现:
`timescale 1ns / 1ps
module TOP(
input clk ,
input rst_n ,
input key ,
output reg [3:0] led
);
wire flag;
Key2 key_1(
.clk (clk ) ,
.rst_n (rst_n ) ,
.key (key ) ,
.flag (flag )
);
always@(posedge clk)
if(!rst_n)
led <= 0;
else if(flag == 1)
led <= led + 1;
else
led <= led;
endmodule
六、实验结果
1.仿真文件编写
代码实现:
`timescale 1ns / 1ps
module test();
reg clk;
reg rst_n;
reg key;
TOP top(
.clk (clk ),
.rst_n (rst_n ),
.key (key ),
.led (led )
);
initial
begin
clk = 1;
rst_n = 0;
#100 rst_n = 1;
end
always #1 clk = ~clk;
initial
begin
key = 1;
#200 key = 0;
end
endmodule
2.仿真结果
仿真截图:
七、总结
1.了解按键消抖原理
2.了解状态机编写方法
3.学会描述并绘画状态图
重点:
状态机编写逻辑