接下来我们结合Verilog描述状态机的代码来探讨一下有限状态机FSM。前面我们讲过,在FPGA中设计硬件电路的本质是Verilog代码综合出的配置文件控制0、1开关矩阵,开关矩阵来控制第二层硬件电路,满足我们的功能需求。状态机的目的就是在不同时间段切换不同的电路功能来满足算法需求。
1、状态不多并且跳转条件不复杂时,可以优先考虑计数器,计数器本身也是一种状态机。
2、以控制脉冲信号为条件,在有限步内完成一定的算法操作,不同的脉冲时刻到来,处理不同不同的算法。
以上两种控制状态机的方式如图1所示,按照一定的时间顺序控制电路。
图 1
3、就是最常见的状态,状态机的基本概念我们就不做太多的讲解了,可以百度。接下来我们结合代码谈论一下实际工程上如何用状态机设计电路。
状态机的编写模板如下所示。
//同步时序always模块,描述次态寄存器迁移到现态寄存器reg [3:0] state_c;//寄存器的位宽根据状态的个数来定reg [3:0] state_n;always@(posedge clk or negedge rst_n)begin if(!rst_n)begin state_c <= IDLE; end else begin state_c <= state_n; endend//组合逻辑always模块,描述状态跳转方式always@(*)begin case(state_c) IDLE:begin if(idle2s1_start)begin state_n = S1; end else begin state_n = state_c; end end S1:begin if(s12s2_start)begin state_n = S2; end else begin state_n = state_c; end end S2:begin if(s22s3_start)begin state_n = S3; end else begin state_n = state_c; end end default:begin state_n = IDLE; end endcaseend//状态转移条件assign idle2s1_start = state_c ==IDLE && ;assign s12s2_start = state_c ==S1 && ;assign s22s3_start = state_c ==S2 && ;//同步时序always模块,描述寄存器输出always @(posedge clk or negedge rst_n)begin if(!rst_n)begin out1 <=1'b0; end else if(state_c==S1)begin out1 <= 1'b1; end else begin out1 <= 1'b0; endend
状态机中的状态需要用寄存器保存,如图2所示,图中有两个状态,当前状态和次状态,状态的位宽由状态机状态的个数决定,根据实际工程修改。每个时钟的上升沿都会把次态寄存器中的数据迁移到现态的寄存器中。至于什么时候跳转,我们在这个always模块中不考虑。本模块只考虑现态state_c如何变化。
图 2
图1中我们知道次态如何转移到现态,那么在什么条件跳转到次态state_n呢。图3中描述的组合逻辑就为了解决这个问题。例如,当前状态state_c在IDLE状态下,当IDLE状态跳转到S1状态的条件满足时,就将S1状态赋给次态state_n寄存器,如果跳转条件不满足保持当前状态。
该模块使用组合逻辑电路建模,只要条件满足,次态state_n的值立刻变化,状态真正跳转是在时钟的上升沿到来,可以结合图1理解。
注意:在使用组合逻辑建模时特别注意避免综合出锁存器,具体方法是使用if...else语句时条件补全,即 if...else成对出现;或者case选择语句要用default语句补全逻辑。
图 3
图4是状态转移的条件,设计状态机的核心就在于状态跳转条件的描述。要确保状态跳转逻辑完整,不会跳到未知状态的的情况。
图 4
设计状态机的目的是要输出我们需要的信号(包括结果或其他模块控制信号),在状态机的分类上有Mealy型和Moore型,两个的区别就在于输出与输入是否有关系,与输入有关系就是Mealy型状态机,否则就是Moore型状态机。我的理解是没必要区分那么清楚,我们只要确保工程中输出数据的条件正确即可。如图5的输出只与状态有关,所以是Moore型状态机。
图 5
在后续的电机控制算法中我们会详细探讨,FSM设计时注意的细节问题。
得到金句: 热爱,不等于称职。把热爱转化成持续的行动,才是称职的开始。--罗翔 得到APP 得到金句产品