可乐售卖状态机 verilog FPGA 基础练习9.1
发现问题,用技术解决问题。兴趣是自己的源动力 !
前言
状态机其核心就是状态的转换,由以下几个要点。在理解一下几个要素之后就明白状态机设计的核心思维了
- 输入
- 输入后得到的状态
- 该状态对应的输出
一、可乐机-状态机实现
状态机简写为FSM(Finite State Machine),也称为同步有限状态机,我们一般简称为状态机,之所以说“同步”是因为状态机中所有的状态跳转都是在时钟的作用下进行的,而“有限”则是说状态的个数是有限的。状态机根据影响输出的原因分为两大类,即Moore型状态机和Mealy型状态机,其共同点 是:状态的跳转都只和输入有关。区别主要是在输出的时候:
- 若最后的输出只和当前状态有关而与输入无关则称为Moore型状态机;也就说当前如数会决定输出的
- 若最后的输出不仅和当前状态有关还和输入有关则称为Mealy型状态机。会延迟
1.1 问题
可乐机每次只能投入1枚1元硬币,且每瓶可乐卖3元钱,即投入3个硬币就可以让可乐机出可乐,如果投币不够3元想放弃投币需要按复位键,否则之前投入的钱不能退回。
下面是状态机跳转图:其中1/0,表示为:输入/输出 ; IDLE、ONE、TWO表示状态
1.1.1 功能代码
module simple_fsm
(
input wire sys_clk , //系统时钟50MHz
input wire sys_rst_n , //全局复位
input wire pi_money , //投币方式可以为:不投币(0)、投1元(1)
output reg po_cola //po_cola为1时出可乐,po_cola为0时不出可乐
);
// 状态机三要素:输入、状态、输出,这里使用新二段式来写状态机(Mealy状态机更节省资源)
// 输入:是投币,每次1元
// 状态:是当前有多少钱
// 输出:是最终的结果,是否要输出可乐
// 使用独热码定义参数
parameter IDLE = 3'b000;
parameter ONE = 3'b010;
parameter TWO = 3'b100;
reg [2:0]state;
// 用时序逻辑写输入和状态跳转的关系
always@(posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n == 1'b0)
state <= IDLE;
else case(state) // 根据当前状态和输入这两个要素来进行状态的跳转
IDLE: if(pi_money == 1'b1)
state <= ONE;
else
state <= IDLE;
ONE: if(pi_money == 1'b1)
state <= TWO;
else
state <= ONE;
TWO: if(pi_money == 1'b1) // 因为是Mealy状态机,所以最后一个状态直接跳转,而不写最后一个状态THREE
state <= IDLE;
else
state <= TWO;
default: state <= IDLE; // 注意要写default
endcase
end
// 用时序逻辑写输出
always@(posedge sys_clk or negedge sys_rst_n) begin
if(sys_rst_n ==1'b0)
po_cola <= 1'b0;
else if(state == TWO & pi_money == 1'b1)
po_cola <= 1'b1;
else
po_cola <= 1'b0;
end
endmodule
1.1.2 仿真代码
`timescale 1ns/1ns
module tb_top();
//\* Parameter and Internal Signal \//
//wire define
//reg define
reg sys_clk ;
reg sys_rst_n ;
// **********begin:u0_simple_fsm 参数定义**********
reg pi_money;
wire po_cola ;
// **********end:u0_simple_fsm 参数定义**********
///
//\* Main Code \//
//初始化系统时钟、全局复位
initial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
#20
sys_rst_n <= 1'b1;
end
//sys_clk:模拟系统时钟,每10ns电平翻转一次,周期为20ns,频率为50MHz
always #10 sys_clk = ~sys_clk;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
pi_money <= 1'b0;
else
pi_money <= {$random} % 2; //取模求余数,产生非负随机数0、1
simple_fsm u0_simple_fsm
(
.sys_clk (sys_clk ), //系统时钟50MHz
.sys_rst_n (sys_rst_n ), //全局复位
.pi_money (pi_money ), //投币方式可以为:不投币(0)、投1元(1)
.po_cola (po_cola )//po_cola为1时出可乐,po_cola为0时不出可乐
);
endmodule
1.1.3 仿真结果
总结
以上就是简单状态机的实现,后续实现一个相对复杂的状态机。
- 吃透输入、状态、输出之间的关系
- 欢迎一起交流学习,如有错误之处,还请各位指正。
参考资料
[1] FPGA系列教学