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