1. 理论
FPGA 是并行执行的,如果我们想要处理具有前后顺序的事件,就需要引入状态机。举个例子,将人看成 FPGA ,我们可以在散步的时候听歌和聊天这是并行执行的,但一天的行程安排却是以时间段前后执行的。
状态机简写为 FSM( Finite State Machine),称为同步有限状态机,简称为状态机,之所以说“同步”是因为状态机中所有的状态跳转都是在时钟的作用下进行的,而“有限”则是说状态的个数是有限的。状态机根据影响输出的原因分为两大类,即Moore 型状态机和 Mealy 型状态机,其共同点是:状态的跳转都只和输入有关。区别主要是在输出的时候:若最后的输出只和当前状态有关而与输入无关则称为 Moore 型状态机;若最后的输出不仅和当前状态有关还和输入有关则称为 Mealy 型状态机(使用较多)。
状态机的每一个状态代表一个事件,从执行当前事件到执行另一事件我们称之为状态的跳转或状态的转移,我们需要做的就是执行该事件然后跳转到一下事件。
2. 实操
实验目标:可乐机每次只能投入 1 枚 1 元硬币,且每瓶可乐卖 3 元钱,即投入 3 个硬币就可以让可乐机出可乐,如果投币不够 3 元想放弃投币需要按复位键,否则之前投入的钱不能退回。
2.1 模块框图
2.2 状态转换图和波形图
2.3 RTL代码
`timescale 1ns/1ns
module simple_fsm
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire pi_money ,
output reg po_cola
);
//状态编码
parameter IDLE = 4'b0001 ;
parameter ONE = 4'b0010 ;
parameter TWO = 4'b0100 ;
parameter THREE = 4'b1000;
reg [3:0] state;
//第一段状态机,描述当前状态state如何根据输入跳转到下一状态
always@(posedge sys_clk or negedge sys_rst_n)
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)
state <= THREE;
else
state <= TWO;
THREE: if(pi_money == 1'b1)
state <= ONE;
else
state <= IDLE;
default : state <= IDLE;
endcase
//第二段状态机,描述当前状态state和输入pi_money如何影响po_cola输出
always@(posedge sys_clk or negedge sys_rst_n)
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;
endmodule
总结一下套用的格式有哪些主要部分构成:第一部份端口列表部分; 第二部份状态编码部; 第三部份是定义的状态变量; 第四部份分为第一段状态机和第二段状态机。一共有四部分,我们写状态机代码的时候根据这种格式依次编写,非常容易的就可以实现。
2.4 验证
仿真代码:
`timescale 1ns/1ns
module tb_simple_fsm();
reg sys_clk;
reg sys_rst_n;
reg pi_money;
wire po_cola;
initial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
#20
sys_rst_n <= 1'b1;
end
always #10 sys_clk = ~sys_clk;
always #20 pi_money <= {$random} % 2;
//将 RTL 模块中的内部信号引入到 Testbench 模块中进行观察,我是自己在仿真中单独添加的
//wire [2:0] state = simple_fsm_inst.state;
simple_fsm simple_fsm_inst(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.pi_money (pi_money ),
.po_cola (po_cola )
);
endmodule
上板验证:
可以选择按键作一元硬币,小灯表示可乐模拟结果。
重点:熟练掌握状态机编写的设计流程、方法和格式特点。
练习题:
以可乐机为背景,一瓶可乐的价格还是 2.5 元。用按键控制投币(加入按键消抖功能),可以投 0.5 元硬币和 1 元硬币,投入 0.5 元后亮一个灯,投入 1 元后亮 2 个灯,投入 1.5 元后亮 3 个灯,投入 2 元后亮 4 个灯,如果投币后 10s 不再继续进行投币操作则可乐机回到初始状态。投入 2.5 元后出可乐不找零,此时 led 灯实现单向流水操作,流水 10s后自动停止;投入 3 元后出可乐找零,此时 led 灯实现双向流水操作,流水 10s 后自动停止。这里也有复位键,其功能是终止本次投币操作,使可乐机立刻回到初始状态。
参考答案见另一篇博客: FPGA—可乐机拓展训练题(状态机)_咖啡0糖的博客-CSDN博客
说明:
本人使用的是野火家Xilinx Spartan6系列开发板及配套教程,以上内容如有疑惑或错误欢迎评论区指出,或者移步B站观看野火家视频教程。
开发软件:ise14.7 仿真:modelsim 10.5
如需上述资料私信或留下邮箱。