一、摩尔状态机和米利状态机
1.1 相关例子
1.1.1检测"H" "E" "L" "L" "O''
(输入)检测到"H"+下一个状态的组合逻辑,产生激励信号state<=CHECK_e,给到状态寄存器CHECK_e,产生输出组合逻辑led <= led
输出仅仅由当前状态机(CHECK_e)组合逻辑;
/***************************************************
* Module Name : Hello
* Engineer : 小梅哥
* Target Device : EP4CE10F17C8
* Tool versions : Quartus II 13.0
* Create Date : 2017-3-31
* Revision : v1.0
* Description : 实现字符串检测,每检测成功一次 LED状态便翻转一次
**************************************************/
module Hello(
Clk,
Rst_n,
data,
led
);
input Clk;//50M
input Rst_n;//低电平复位
input [7:0]data;
output reg led;
localparam
CHECK_H = 5'b0_0001,
CHECK_e = 5'b0_0010,
CHECK_la = 5'b0_0100,
CHECK_lb = 5'b0_1000,
CHECK_o = 5'b1_0000;
reg[4:0]state;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
led <= 1'b1;
state <= CHECK_H;
end
else begin
case(state)
CHECK_H:
if(data == "H") state <= CHECK_e;
else state <= CHECK_H;
CHECK_e:
if(data == "e") state <= CHECK_la;
else if(data == "H") state <= CHECK_e;
else state <= CHECK_H;
CHECK_la:
if(data == "l") state <= CHECK_lb;
else if(data == "H") state <= CHECK_e;
else state <= CHECK_H;
CHECK_lb:
if(data == "l") state <= CHECK_o;
else if(data == "H") state <= CHECK_e;
else state <= CHECK_H;
CHECK_o:
if(data == "H") state <= CHECK_e;
else begin
state <= CHECK_H;
if(data == "o")
led <= ~led;
else
led <= led;
end
default:state <= CHECK_H;
endcase
end
endmodule
1.1.2 fsm 按键消抖
米利有限状态机的输出不止与其输入有关还于它的当前状态相关,这也是与摩尔有限状态
机的不同之处。这句话的理解,在检测按下后检测上升沿的状态时,如果当前状态是检测按下时间到达,则输出就是判断已按下再松开,如果当前状态是正在检测按下时间是否足够,未足够,就检测到上升沿,则输出就是判断未正确按下。所以此时输入就是会影响产生输出的组合逻辑。
/***************************************************
* Module Name : key_filter
* Engineer : 小梅哥
* Target Device : EP4CE10F17C8
* Tool versions : Quartus II 13.0
* Create Date : 2017-3-31
* Revision : v1.0
* Description : 单按键消抖设计
**************************************************/
module key_filter(
Clk, //50M时钟输入
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; //使能计数寄存器
//对外部输入的异步信号进行同步处理
reg key_in_sa,key_in_sb;
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
reg key_tmpa,key_tmpb;
wire pedge,nedge;
reg cnt_full;//计数满标志信号
//使用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);
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;
state <= IDEL;
en_cnt <= 1'b0;
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
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt <= 20'd0;
else if(en_cnt)
cnt <= cnt + 1'b1;
else
cnt <= 20'd0;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt_full <= 1'b0;
else if(cnt == 20'd999_999)
cnt_full <= 1'b1;
else
cnt_full <= 1'b0;
endmodule