FPGA系统性学习笔记连载_Day16【状态机:一段式、二段式、三段式】 【原理及verilog仿真】篇
本系列为FPGA系统性学习学员学习笔记整理分享,如有学习或者购买开发板意向,可加交流群联系群主。
连载《叁芯智能fpga设计与研发-第16天》 【状态机:一段式、二段式、三段式】 【原理及verilog仿真】
原创作者:紫枫术河 转载请联系群主授权,否则追究责任
本篇文章描述状态机的一段式、二段式、三段式区别
一、状态机
再次给出状态机的示意图:
1.1、摩尔型,输出只与状态寄存器的输出状态有关
1.2、米粒型,输出不仅与状态寄存器的输出状态有关,还与组合逻辑的输入有关
二、一段式、二段式、三段式区别
根据状态机的结构,状态机描述方式 可分为:一段式、二段式、三段式
1.1、一段式
整个状态机写到一个 always 模块里面。在该模块中既描述状态转移,又描述状态的输入和输出 。
1.2、二段式
用两个 always 模块来描述状态机。
1.2.1、其中一个 always 模块采用同步时序描述状态转移;
1.2.2、另一个 always模块采用组合逻辑判断状态转移条件,描述状态转移规律及其输出 ,注意组合逻辑输出要用阻塞赋值。
1.3、三段式
在两个 always 模块描述方法基础上,使用三个 always 模块。
1.3.1、 一个 always 模块采用同步时序描述状态转移;
1.3.2、一个 always 采用组合逻辑判断状态转移条件,描述状态转移规律,注意组合逻辑输出要用阻塞赋值;
1.3.3、另一个 always 模块描述状态输出(可以用组合电路输出,也可以时序电路输出),注意组合逻辑输出要用阻塞赋值。
1.4、综合
可以看出两段式有限状态机与一段式有限状态机的区别是将时序部分(状态转移)和组合部分(判断状态转移条件和产生输出)分开,写为两个 always语句,即为两段式有限状态机。将组合部分中的判断状态转移条件和产生输出再分开写,则为三段式有限状态机。
三、自动售货机、一段式
代码语言:javascript复制module auto_sell(
input clk,
input rst_n,
input coin_one,
input coin_half,
output reg water,
output reg coin_back
);
parameter ZERO = 3'b000;
parameter HALF = 3'b001;
parameter ONE = 3'b010;
parameter ONE_HALF = 3'b011;
parameter TWO = 3'b100;
//一段式状态机
reg [2:0] status;
always@(posedge clk,negedge rst_n)begin
if(!rst_n)
begin
status <= ZERO;
water <= 0;
coin_back <= 0;
end
else
case(status)
ZERO :
begin
water <= 0;
coin_back <= 0;
if(coin_half)
status <= HALF;
else if(coin_one)
status <= ONE;
else
status <= status;
end
HALF :
begin
water <= 0;
coin_back <= 0;
if(coin_half)
status <= ONE;
else if(coin_one)
status <= ONE_HALF;
else
status <= status;
end
ONE :
begin
water <= 0;
coin_back <= 0;
if(coin_half)
status <= ONE_HALF;
else if(coin_one)
status <= TWO;
else
status <= status;
end
ONE_HALF :
begin
if(coin_half)
begin
status <= TWO;
water <= 1'b0;
coin_back <= 1'b0;
end
else if(coin_one)
begin
status <= ZERO;
water <= 1'b1;
coin_back <= 1'b0;
end
else
begin
status <= status;
water <= 1'b0;
coin_back <= 1'b0;
end
end
TWO :
begin
if(coin_half)
begin
status <= ZERO;
water <= 1'b1;
coin_back <= 1'b0;
end
else if(coin_one)
begin
status <= ZERO;
water <= 1'b1;
coin_back <= 1'b1;
end
else
begin
status <= status;
water <= 1'b0;
coin_back <= 1'b0;
end
end
default:
begin
status <= ZERO;
water <= 1'b0;
coin_back <= 1'b0;
end
endcase
end
endmodule
四、自动售货机、二段式
1.1、二段式,写法一
代码语言:javascript复制module auto_sell(
input clk,
input rst_n,
input coin_one,
input coin_half,
output reg water,
output reg coin_back
);
parameter ZERO = 3'b000;
parameter HALF = 3'b001;
parameter ONE = 3'b010;
parameter ONE_HALF = 3'b011;
parameter TWO = 3'b100;
//--------------------二段式 1 ok--------------------------
//二段式状态机
reg [2:0] c_status;
reg [2:0] n_status;
//状态转移
always@(posedge clk,negedge rst_n)begin
if(!rst_n)
c_status <= ZERO;
else
c_status <= n_status;
end
//描述状态转移规律以及输出
always@(posedge clk,negedge rst_n)begin
if(!rst_n)
begin
n_status <= ZERO;
water <= 1'b0;
coin_back <= 1'b0;
end
else
case(c_status)
ZERO :
begin
water <= 1'b0;
coin_back <= 1'b0;
if(coin_half)
n_status <= HALF;
else if(coin_one)
n_status <= ONE;
else
n_status <= ZERO;
end
HALF :
begin
water <= 1'b0;
coin_back <= 1'b0;
if(coin_half)
n_status <= ONE;
else if(coin_one)
n_status <= ONE_HALF;
else
n_status <= HALF;
end
ONE :
begin
water <= 1'b0;
coin_back <= 1'b0;
if(coin_half)
n_status <= ONE_HALF;
else if(coin_one)
n_status <= TWO;
else
n_status <= ONE;
end
ONE_HALF :
begin
water <= 1'b0;
coin_back <= 1'b0;
if(coin_half)
n_status <= TWO;
else if(coin_one)
begin
n_status <= ZERO;
water <= 1'b1;
coin_back <= 1'b0;
end
else
n_status <= ONE_HALF;
end
TWO :
begin
water <= 1'b0;
coin_back <= 1'b0;
if(coin_half)
begin
n_status <= ZERO;
water <= 1'b1;
coin_back <= 1'b0;
end
else if(coin_one)
begin
n_status <= ZERO;
water <= 1'b1;
coin_back <= 1'b1;
end
else
n_status <= TWO;
end
default:
n_status <= ZERO;
endcase
end
endmodule
1.2、二段式,写法二
代码语言:javascript复制module auto_sell(
input clk,
input rst_n,
input coin_one,
input coin_half,
output reg water,
output reg coin_back
);
parameter ZERO = 3'b000;
parameter HALF = 3'b001;
parameter ONE = 3'b010;
parameter ONE_HALF = 3'b011;
parameter TWO = 3'b100;
//---------------------二段式 2 ok--------------------------------------
//二段式状态机
reg [2:0] status;
//状态转移
always@(posedge clk,negedge rst_n)begin
if(!rst_n)
status <= ZERO;
else
begin
case(status)
ZERO :
begin
if(coin_half)
status <= HALF;
else if(coin_one)
status <= ONE;
else
status <= ZERO;
end
HALF :
begin
if(coin_half)
status <= ONE;
else if(coin_one)
status <= ONE_HALF;
else
status <= HALF;
end
ONE :
begin
if(coin_half)
status <= ONE_HALF;
else if(coin_one)
status <= TWO;
else
status <= ONE;
end
ONE_HALF :
begin
if(coin_half)
status <= TWO;
else if(coin_one)
begin
status <= ZERO;
end
else
status <= ONE_HALF;
end
TWO :
begin
if(coin_half)
begin
status <= ZERO;
end
else if(coin_one)
begin
status <= ZERO;
end
else
status <= TWO;
end
default:
status <= ZERO;
endcase
end
end
//输出 时序逻辑
always@(posedge clk,negedge rst_n)begin
if(!rst_n)
begin
water <= 1'b1;
coin_back <= 1'b0;
end
else
case(status)
ONE_HALF:
begin
if(coin_one)
begin
water <= 1'b1;
coin_back <= 1'b0;
end
else
begin
water <= 1'b0;
coin_back <= 1'b0;
end
end
TWO:
begin
if(coin_half)
begin
water <= 1'b1;
coin_back <= 1'b0;
end
else if(coin_one)
begin
water <= 1'b1;
coin_back <= 1'b1;
end
else
begin
water <= 1'b0;
coin_back <= 1'b0;
end
end
default:
begin
water <= 1'b0;
coin_back <= 1'b0;
end
endcase
end
endmodule
五、自动售货机、三段式
代码语言:javascript复制module auto_sell(
input clk,
input rst_n,
input coin_one,
input coin_half,
output reg water,
output reg coin_back
);
parameter ZERO = 3'b000;
parameter HALF = 3'b001;
parameter ONE = 3'b010;
parameter ONE_HALF = 3'b011;
parameter TWO = 3'b100;
//三段式状态机
reg [2:0] c_status;
reg [2:0] n_status;
//状态转移
always@(posedge clk,negedge rst_n)begin
if(!rst_n)
c_status <= ZERO;
else
c_status <= n_status;
end
//状态转移规律及状态输出,组合逻辑输出只与输入有关
//如果有n_status = n_status,电路会出错;
always@(*)begin
case(c_status)
ZERO :
begin
if(coin_half)
n_status = HALF;
else if(coin_one)
n_status = ONE;
else
n_status = ZERO;
end
HALF :
begin
if(coin_half)
n_status = ONE;
else if(coin_one)
n_status = ONE_HALF;
else
n_status = HALF;
end
ONE :
begin
if(coin_half)
n_status = ONE_HALF;
else if(coin_one)
n_status = TWO;
else
n_status = ONE;
end
ONE_HALF :
begin
if(coin_half)
n_status = TWO;
else if(coin_one)
n_status = ZERO;
else
n_status = ONE_HALF;
end
TWO :
begin
if(coin_half)
n_status = ZERO;
else if(coin_one)
n_status = ZERO;
else
n_status = TWO;
end
default:
n_status = ZERO;
endcase
end
always@(posedge clk,negedge rst_n)begin
if(!rst_n)
begin
water = 1'b1;
coin_back = 1'b0;
end
else
case(c_status)
ONE_HALF:
begin
if(coin_one)
begin
water = 1'b1;
coin_back = 1'b0;
end
else
begin
water = 1'b0;
coin_back = 1'b0;
end
end
TWO:
begin
if(coin_half)
begin
water = 1'b1;
coin_back = 1'b0;
end
else if(coin_one)
begin
water = 1'b1;
coin_back = 1'b1;
end
else
begin
water = 1'b0;
coin_back = 1'b0;
end
end
default:
begin
water = 1'b0;
coin_back = 1'b0;
end
endcase
end
endmodule
六、仿真脚本
代码语言:javascript复制`timescale 1ns/1ps
module auto_sell_tb;
reg clk;
reg rst_n;
reg coin_one;
reg coin_half;
wire water;
wire coin_back;
initial begin
clk = 0;
rst_n = 0;
coin_one = 0;
coin_half = 0;
#20;
rst_n = 1;
//延时200us
#10000
//投2.5元
coin_half = 1;
#20;
coin_half = 0;
#20;
coin_one = 1;
#20;
coin_one = 0;
#20;
coin_half = 1;
#20;
coin_half = 0;
#20;
coin_half = 1;
#20;
coin_half = 0;
#20;
//延时200us
#10000
//投3元
coin_half = 1;
#20;
coin_half = 0;
#20;
coin_one = 1;
#20;
coin_one = 0;
#20;
coin_half = 1;
#20;
coin_half = 0;
#20;
coin_one = 1;
#20;
coin_one = 0;
#20;
//延时200us
#10000
$stop;
end
auto_sell auto_sell_inst(
.clk (clk),
.rst_n (rst_n),
.coin_one (coin_one),
.coin_half (coin_half),
.water (water),
.coin_back (coin_back)
);
always #10 clk = ~clk;
endmodule
七、仿真结果
【QQ交流群】
群号:173560979,进群暗语:FPGA技术江湖粉丝。
多年的FPGA企业开发经验,各种通俗易懂的学习资料以及学习方法,浓厚的交流学习氛围,QQ群目前已有1000多名志同道合的小伙伴,无广告纯净模式,给技术交流一片净土,从初学小白到行业精英业界大佬等,从军工领域到民用企业等,从通信、图像处理到人工智能等各个方向应有尽有。
【微信交流群】
现微信交流群已建立09群,人数已达数千人,欢迎关注“FPGA技术江湖”微信公众号,可获取进群方式。
完
后续会持续更新,带来Vivado、 ISE、Quartus II 、candence等安装相关设计教程,学习资源、项目资源、好文推荐等,希望大侠持续关注。
江湖偌大,继续闯荡,愿大侠一切安好,有缘再见!