1 状态机的基本结构和功能 状态机是一类很重要的时序电路,是许多数字电路的核心部件。状态机的一般形式如图1所示。除了输入信号、输出信号外,状态机还包括一组寄存器,它用于记忆状态机的内部状态。状态机寄存器的下一个状态及输出,不仅同输入信号有关,而且还于寄存器当前状态有关。寄存器可以认为是组合逻辑和寄存器逻辑的特殊组合。 图1状态机的结构示意图 状态机的基本操作有两种: (1) 状态机内部状态转换。状态机的下一状态由状态译码器根据当前状态和输入条件决定。 (2) 产生输出信号系列。输出信号由输出译码器根据当前状态和输入条件决定。 状态机的分类: (1) 从状态机的输出方式分:Mealy型和Moore型。在摩尔状态机中,其输出只是当前状态值的函数,并且仅在时钟边沿到来时才发生变化。 (2) 从结构上分:有单进程状态机和多进程状态机。 (3) 从状态表达方式上分:有符号状态机和确定状态编码的状态机。 2用状态机实现A/D采样控制 对A/D器件进行采样控制,传统的方法多数是有CPU或单片机完成的。编程简单,控制灵活,但缺点是控制周期长,速度慢。特别是当A/D本身的采样速度比较快时,CPU的慢速极大地限制了A/D高速性能的利用。整个采样周期需要4~6个状态即可以完成。若FPGA的时钟频率为100MHz,从一 个状态向另一状态转移的时间为一个时钟周期,即10ns,那么一个采样周期为50ns,不到单片机60us采样周期的千万分之一。由此可见利用状态机对A/D进行采样控制是一种行之有效的方法。
2.1用状态机对0809采样控制 为了便于说明,以下以更为常见的、大家熟悉的ADC0809为例。图2、3分别是0809的引脚图、A/D转换时序图和采样状态控制图,时序图中,START为转换控制信号,高电平有效;ALE为模拟信号输入选通端口地址琐序信号,上升沿有效;一旦START有效后,状态信号EOC即变为低电平,表示进入转化状态,转换时间大概100us。转换结束后,EOC将变为高电平。此后外部控制可以使OE由低电平变为高电平(输出有效),此时,0809的输出数据总线D[0``7]从原来的高阻状态变为输出数据有效。由状态图可以看到,在状态st2中需要对0809工作状态信号EOC进行测试,如果为低电平,表示转换没有结束,仍需要停留在st2 状态中等待,直到变成高电平后才说明转换结束,在下一时钟脉冲到来时转向状态st3。在状态st3,由状态机向0809发出转换好的8位数据输出命令,这一状态周期同时可作为数据输出稳定周期,以便能在下一状态中向锁存器中锁入可靠的数据。在状态st4,由状态机向FPGA中的锁存信号(LOCK的上升沿),将0809输出的数据进行锁存。 图2 ADC0809工作时序和引脚图 3 ADC0809采样控制程序VHDL的设计 在对0809的工作时序了解后,再根据图3写出相应的VHDL代码。以下程序含三个进程。REG进程是时序进程,它在时钟信号CLK的驱动下,不断将next_state中的内容赋给current_state,并由此信号将状态变量传输给组合进程COM。组合进程COM有两个主要的功能: ①状态译码功能,即从current_state信号中获得的状态变量,加上来自0809的状态线信号EOC,决定下一个状态的转移方向,即确定次态的状态变量; ②采样控制功能,即根据current_state中的状态变量确定对0809的控制信号线ALE、START、OE等输出相应的控制信号,当采样结束后还要通过LOCK向锁存器件进程LATACH1发出锁存信号,以便将0809的D[7..0]数据输出口输出的8位数据锁存起来。 图3控制ADC0809采样状态图
3.1 VHDL的实现 在一完整的采样周期中,状态机中最先被启动的是CLK为敏感信号的进程,接着是组合进程COM被启动,因为它以信号current_state为敏感信号。最后被启动的是琐序器进程(LATCH1),将本采样周期的输出8位数据琐序到寄序器中,以便外部电路从Q端口读到稳定正确的数据。采用上三个进程,层次清晰,各进程分工明确。 程序如下: LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; ENTITY ADCINT IS PORT (D : IN STD_LOGIC_VECTOR(7 DOWNTO 0); CLK,EOC : IN STD_LOGIC; ALE,START,OE,ADDA,LOCK0 : OUT STD_LOGIC;--ADDA,ADDB,ADDC用于选择模拟信号输入通道,但是--此处只有ADDA??? Q : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)); END ADCINT; ARCHITECTURE behav OF ADINT IS TYPE states IS (st0,st1,st2,st3,st4); SIGNAL current_state,next_state: states: =st0; SIGNAL REGL :STD_LOGIC_VECTOR(7 DOWNTO 0); SIGNAL LOCK :STD_LOGIC; BEGIN ADDA<='1'; Q<=REGL;; LOCK0<=LOCK; COM: PROCESS(current_tate,EOC) BEGIN CASE current_state IS WHEN st0=>ALE<='0';START<='0';LOCK<='0';OE<='0'; next_state<=st1; WHEN st1=>ALE<='1';START<='1';LOCK<='0';OE<='0'; next_state<=st2; WHEN st2=>ALE<='0';START<='0';LOCK<='0';OE<='0'; IF (EOC='1')THEN next_state <=st3;--这是一个查询EOC值的状态 ELSE next_state<=st2; END IF; WHEN st3=>ALE<='0';START<='0';LOCK<='0';OE<='1'; next_state<=st4; WHEN st4=>ALE<='0';START<='0';LOCK<='1';OE<='1'; next_state<=st0; WHEN OTHERS=>next_state<=st0; END CASE; END PROCESS COM; REG: PROCESS (CLK) --这是最先启动的process,因为这是clk敏感的。 BEGIN IF(CLK'EVENT AND CLK'1')THEN current_state<=next_state; END IF; END PROCESS REG; LATCH1: PROCESS (LOCK) BEGIN IF LOCK='1' AND LOCK'EVENT THEN REGL<=D; END IF; END PROCESS LATCH1; END behav;
|