用VHDL设计有限状态机的方法
现代数字系统的设计一般都采用自顶向下的模块化设计方法。即从整个系统的功能出发,将系统分割成若干功能模块。在自顶向下划分的过程中,最重要的是将系统或子系统按计算机组成结构那样划分成控制器和若干个受控制的功能模块。受控部分通常是设计者们所熟悉的各种功能电路,设计较为容易。主要任务是设计控制器,而其控制功能可以用有限状态机来实现。因而有必要深入探讨有限状态机的设计方法。
1 状态机设计的一般方法
传统的设计方法是首先绘制出控制器的状态图,并由此列出状态表,再合并消除状态表中的等价状态项。在完成状态寄存器的分配之后,根据状态表求出次态及输出方程,最后画出设计原理图。采用这种方法设计复杂状态机将会十分繁杂。
利用VHDL设计状态机,不需要进行繁琐的状态分配、绘制状态表和化简次态方程。设计者不必使用卡诺图进行逻辑化简,不必画电路原理图,也不必搭试硬件电路进行逻辑功能的测试,所有这些工作都可以通过EDA工具自动完成。应用VHDL设计状态机的具体步骤如下:
(1)根据系统要求确定状态数量、状态转移的条件和各状态输出信号的赋值,并画出状态转移图;
(2)按照状态转移图编写状态机的VHDL设计程序;
(3)利用EDA工具对状态机的功能进行仿真验证。
下面以离心机定时顺序控制器的设计为例,说明状态机的设计方法。
2 定时顺序控制状态机的设计
在化工生产中,离心机用于固、液分离的工艺流程,如图1所示。
加料至刮刀回程循环N次之后,进入大洗网工序,随后又开始进入新一轮顺序循环工作。该系统控制器的框图如图2所示。
图2中计数模块是由三个带异步复位和并行预置的计数器组成。其中COUNTER1是2位加/减法计数器,用于控制从加料至刮刀回程的各工序时间,其中加料和卸料工序为加计时,其余工序为减计时;COUNTER2是3位减法计数器,用于控制大洗网的时间;COUNTER3是2位加法计数器,用于控制循环工作次数。译码器用于选通与各工序相对应的预置数。图2中K1、K2分别是加料和卸料限位开关信号,R{R1、R2、R3}为计数器减为零(或循环次数等于预置数)时发出的信号,它们都可作为状态转移的控制信号。LD(LD1、LD2、LD3)为并行置数控制信号,CLR(CLR1、CLR2、CLR3)为异步清零信号,ENA(ENA1、ENA2)为计数使能信号,J为加/减计数控制信号,G(G1、A、B、C)为译码器控制信号,FO为各工序电磁阀和指示灯控制信号。
系统工作方式如下:当系统处于初始状态或复位信号reset有效时,系统处于复位状态。按下自动工作键C0,系统进入加料工序并开始自动控制离心机的运行。以加水工序为例,首先在加水预置数状态(water_ld)时,状态机输出信号FO,开启加水电磁阀及指示灯,同时输出信号G控制选通加水时间预置数,在LD1信号的控制下,将预置数送入COUNTER1。此时ENA1=1,J=1,使计数器为减计数状态。然后,在下一个时钟周期进入加水工作状态(water),并开始减计时。当计时为零时,计数器发出借位信号R1作为此工序结束的信号送入状态机,使其转入下一个工作状态。根据系统要求可画出状态转移图如图3所示。其中图3表示各状态转移的顺序和转移条件,表1列出了与各状态相应的输出信号值。
按照状态转移图可编写状态机的VHDL源程序。采用双进程描述法设计的离心机控制器源程序如下:
library ieee;
use ieee.std_logic_1164.all;
entity controller is
port (c0,reset: in std_logic;
clk1,k1,k2,r1,r2,r3: in std_logic;
clr1,clr2,clr3,j,enal,ena2: out std_logic;
ld1,ld2,ld3,g1,a,b,c: out std_logic;
fo: out std_logic_vector(6 downto 0));
end controller;
architecture state_machine of controller is
type statetype is (system_reset,load,one_dry,water_ld, water,
two_dry_ld,two_dry,unload_reset,unload,return_trip,decision,
wash,cycle_ld);
signal present_state,next_state : statetype;
begin
state_comb:process (present_state,c0,reset,k1,k2,r1,r2,r3)
begin
if reset='1' then
clr1='1';clr2='1';clr3='1';j='0';ena1='0';
ena2='0';
g1='0';c='0';b='0';a='0';
fo=″0000000″;ld1='0';ld2='0';ld3='0';
next_state = system_reset;
else
case present_state is
when system_reset =>
clr1='1';clr2='1';clr3='0';j='0';
ena1='0';ena2='0';
g1='1';c='1';b='0';a='1';
fo=″0000000″;ld1='0';ld2='0';ld3='1'
- 基于FPGA的DSP设计方法(08-26)
- 专家指导:Linux操作系统密码恢复方法(05-16)
- 基于多核DSP Bootload代码加载方法研究(01-16)
- 基于DSP 的大容量无线传输技术中高性能的启动方法(03-16)
- 多核调试新方法探讨(10-22)
- 有备无患Linux操作系统备份方法介绍(06-06)