VHDL RS-232接收器

时间:2014-11-23 07:44:55

标签: serial-port vhdl fsm

我一直在尝试设计采用FSM方法的RS-232接收器。我承认我对VHDL没有非常全面的了解,所以我一直在研究代码并随时学习。但是,我相信此时我已经碰到了一堵砖墙。

我的问题是我的代码中有两个进程,一个用于触发下一个状态,另一个用于执行组合逻辑。我的代码如下:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity ASyncReceiverV4 is
Port ( DataIn : in  STD_LOGIC;
              Enable : in STD_LOGIC;
           CLK : in  STD_LOGIC;
              BadData : out STD_LOGIC;
           DataOut : out  STD_LOGIC_VECTOR (7 downto 0));
end ASyncReceiverV4;

architecture Behavioral of ASyncReceiverV4 is

type states is (StartBitCheck, ReadData, StopBitCheck);
signal currentState, nextState : states;

begin

    process(CLK)
    begin
        if rising_edge(CLK) then
            currentState <= nextState;
        end if;
    end process;

    process(CLK)
    variable counter : integer := 0;
    variable dataIndex : integer := 0;
    begin
            case currentState is

                when StartBitCheck =>
                    if Enable = '1' then
                        if (DataIn = '0' and counter < 8)  then
                            counter := counter + 1;
                        elsif (DataIn = '0' and counter = 8) then
                            BadData <= '0';
                            nextState <= ReadData;
                            counter := 0;
                        else 
                            nextState <= StartBitCheck;
                        end if;
                    end if;

                when ReadData =>
                    if Enable = '1' then
                        if counter < 16 then
                            counter := counter + 1;
                        elsif (counter = 16 and dataIndex < 8) then
                            DataOut(dataIndex) <= DataIn;
                            counter := 0;
                            dataIndex := dataIndex + 1;
                        elsif dataIndex = 8 then
                            dataIndex := 0;
                            nextState <= StopBitCheck;
                        else
                            nextState <= ReadData;
                        end if;
                    end if;

                when StopBitCheck =>
                    if Enable = '1' then
                        if DataIn = '1' then
                            if counter < 16  then
                                counter := counter + 1;
                                nextState <= StopBitCheck;                          
                            elsif counter = 16 then
                                counter := 0;
                                nextState <= StartBitCheck;                         
                            end if;
                        else
                            DataOut <= "11111111";
                            BadData <= '1';
                            nextState <= StartBitCheck;
                        end if;
                    end if;

            end case;

    end process;


end Behavioral;

无论出于何种原因,根据我的模拟,似乎我的流程不同步。虽然事情只发生在时钟的上升沿,但我在下降沿发生了转换。而且,似乎事情并没有根据反击的价值而改变。

我的所有模拟中的启用输入都很高。但是,这只是为了保持现在的简单,最终将输出153,600波特率发生器的输出(波特率发生器将连接到使能输入)。因此,当波特发生器很高时,我只想改变一些事情。否则,什么也不做。我用我的代码采取了正确的方法吗?

如果有帮助,我可以提供模拟的屏幕截图。我也不确定我是否在我的过程敏感性列表中包含了正确的变量。另外,我是否采用了我的计数器和dataIndex变量的正确方法?如果我在任何进程之前将它们作为我的架构的一部分发出信号怎么办?

对此的任何帮助都非常感激!

2 个答案:

答案 0 :(得分:1)

修复此问题的最简单方法是生成最容易读取的代码,这样就可以转移到1进程状态机(警告:未编译可能包含语法错误):

entity ASyncReceiverV4 is
Port ( DataIn  : in  STD_LOGIC;
       Enable  : in  STD_LOGIC;
       CLK     : in  STD_LOGIC;
       BadData : out STD_LOGIC;
       DataOut : out STD_LOGIC_VECTOR (7 downto 0));
end ASyncReceiverV4;

architecture Behavioral of ASyncReceiverV4 is
    type states is (StartBitCheck, ReadData, StopBitCheck);
    signal state     : states  := StartBitCheck;
    signal counter   : integer := 0;
    signal dataIndex : integer := 0;
begin
    process(CLK)
    begin
        if rising_edge(CLK) then
            case state is
                when StartBitCheck =>
                    if Enable = '1' then
                        if (DataIn = '0' and counter < 8)  then
                            counter <= counter + 1;
                        elsif (DataIn = '0' and counter = 8) then
                            BadData <= '0';
                            state <= ReadData;
                            counter <= 0;
                        end if;
                    end if;
                when ReadData =>
                    if Enable = '1' then
                        if counter < 16 then
                            counter <= counter + 1;
                        elsif (counter = 16 and dataIndex < 8) then
                            DataOut(dataIndex) <= DataIn;
                            counter <= 0;
                            dataIndex <= dataIndex + 1;
                        elsif dataIndex = 8 then
                            dataIndex <= 0;
                            state <= StopBitCheck;
                        end if;
                    end if;
                when StopBitCheck =>
                    if Enable = '1' then
                        if DataIn = '1' then
                            if counter < 16  then
                                counter <= counter + 1;                        
                            elsif counter = 16 then
                                counter <= 0;
                                state <= StartBitCheck;                         
                            end if;
                        else
                            DataOut <= "11111111";
                            BadData <= '1';
                            state <= StartBitCheck;
                        end if;
                    end if;
            end case;
        end if;
    end process;
end Behavioral;

请注意,虽然这不再包含语言问题,但逻辑中仍有一些奇怪的事情。

StopBitCheck为16之前,您无法输入状态counter,因为状态转换位于counter < 16的elsif中。因此,if counter < 16中的StopBitCheck无法访问。

另请注意,状态转换为StopBitCheck的时间与您通常采样数据的周期相同,因此DataInStopBitCheck的采样时间较晚。更糟糕的是,你是否曾经得到错误的数据(DataIn/='1'中的StopBitCheck),counter仍然是16,StartBitCheck总是会转到else子句,而州机器会锁定。


之前对错误的更多解释:

您的模拟在负时钟边沿上发生了变化,因为组合过程只有灵敏度列表上的时钟。组合过程的正确敏感度列表仅包括DataInEnablecurrentState以及您的两个变量counterdataIndex。变量不能成为灵敏度列表的一部分,因为它们超出了灵敏度列表的范围(你也不想触发你自己的过程,稍后会更多地介绍它)。

然而,灵敏度列表主要只是模拟器的拐杖。当转换为真实硬件时,过程在LUT和触发器中实现。您当前的实现将永远不会合成,因为您在非时钟逻辑中包含反馈(信号或变量,这些信号或变量被赋予新值作为其旧值的函数),从而产生组合循环。

counterdataIndex是您的州数据的一部分。状态机更容易理解,因为它们与显式状态分离,但它们仍然是状态数据的一部分。当您创建一个双进程状态机(同样,我建议使用1个进程状态机,而不是2个)时,必须将所有状态数据拆分为用于存储它的触发器(例如currentState)以及生成下一个值的LUT的输出(例如nextState)。这意味着对于您的两台流程计算机,变量counterdataIndex必须改为currentCounternextCountercurrentDataIndexnextDataIndex以及对待你的州任务。请注意,如果您选择实施更改以保留2进程状态机,则该行上方​​提到的逻辑错误仍将适用。


编辑:

是的,在进入counter之前将StopBitCheck重置为0可能是一个好主意,但您还需要考虑在对最后一个数据位进行采样之后等待全部16个计数你甚至过渡到StopBitCheck。只是因为counter 重置,示例只关闭一个时钟而不是16个。您可能希望修改ReadData操作以转换为{{1在dataIndex = 7(以及将StopBitCheck重置为0)时最后一位采样,如下所示:

counter

纯状态机仅存储状态。它仅从状态或从状态和输入的组合生成其输出。由于存储了 elsif (counter = 16) then DataOut(dataIndex) <= DataIn; counter <= 0; if (dataIndex < 7) then dataIndex <= dataIndex + 1; else dataIndex <= 0; state <= StopBitCheck; end if; end if; counter,因此它们是州的一部分。如果你想枚举每个州,你会有类似的东西:

dataIndex

并且你最终会得到8 * 16 * 3 = 384个状态(实际上有点少,因为只有 type states is (StartBitCheck_Counter0, StartBitCheck_counter1... 使用ReadData,所以384中的一些是完全冗余状态)。毫无疑问,由于状态数据的不同部分的使用方式不同,因此简单地声明3个单独的信号要简单得多。在双进程状态机中,人们经常忘记实际命名为dataIndex的信号不是需要存储在时钟进程中的唯一状态数据。

当然,在单过程机器中,这不是问题,因为分配的所有内容必然存储在触发器中(中间组合逻辑不在信号中列举)。此外,请注意,1进程状态机和2进程状态机将合成相同的东西(假设它们都正确实现),尽管我认为相对容易阅读并且更难以弄乱了1工艺机器。

我还删除了在我提供的1进程示例中维护当前状态分配的else子句;它们在分配组合state时非常重要,但只要未给出新的分配而没有推断锁存器,时钟信号nextState将保留其旧值。

答案 1 :(得分:-1)

第一个过程仅在CLK上升沿运行,而第二个过程在CLK边沿运行(因为每次CLK变化都会运行)。

你使用2个进程,“内存状态”和“下一个状态构建器”,第一个必须是同步的(正如你所做的那样),第二个通常是组合的,能够及时产生下一个状态下一个CLK有效边沿。

但是在你的情况下,第二个过程也需要在每个CLK脉冲上运行(因为变量计数器和索引),因此解决方案可以是在上升沿运行第一个,在下降沿运行第二个(如果你的硬件支持这个)。

以下是您的代码,我希望它有用。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity ASyncReceiverV4 is
   Port ( DataIn :  in  STD_LOGIC;
          Enable :  in  STD_LOGIC;
          CLK :     in  STD_LOGIC;
          BadData : out STD_LOGIC := '0';
          DataOut : out STD_LOGIC_VECTOR (7 downto 0) := "00000000");
end ASyncReceiverV4;

architecture Behavioral of ASyncReceiverV4 is

   type states is (StartBitCheck, ReadData, StopBitCheck);
   signal currentState : states := StartBitCheck;
   signal nextState : states    := StartBitCheck;

begin

   process(CLK)
   begin
      if rising_edge(CLK) then
         currentState <= nextState;
      end if;
   end process;

   process(CLK)
      variable counter : integer := 0;
      variable dataIndex : integer := 0;
   begin
      if falling_edge(CLK) then
         case currentState is
            when StartBitCheck =>
               if Enable = '1' then
                  if (DataIn = '0' and counter < 8)  then
                     counter := counter + 1;
                  elsif (DataIn = '0' and counter = 8) then
                     BadData <= '0';
                     nextState <= ReadData;
                     counter := 0;
                  else
                     nextState <= StartBitCheck;
                  end if;
               end if;

            when ReadData =>
               if Enable = '1' then
                  if counter < 15 then
                     counter := counter + 1;
                  elsif (counter = 15 and dataIndex < 8) then
                     DataOut(dataIndex) <= DataIn;
                     counter := 0;
                     dataIndex := dataIndex + 1;
                  elsif dataIndex = 8 then
                     dataIndex := 0;
                     nextState <= StopBitCheck;
                  else
                     nextState <= ReadData;
                  end if;
               end if;

            when StopBitCheck =>
               if Enable = '1' then
                  if DataIn = '1' then
                     if counter < 15  then
                        counter := counter + 1;
                        nextState <= StopBitCheck;
                     elsif counter = 15 then
                        counter := 0;
                        nextState <= StartBitCheck;
                     end if;
                  else
                     DataOut <= "11111111";
                     BadData <= '1';
                     nextState <= StartBitCheck;
                  end if;
               end if;

         end case;
      end if;
   end process;

end Behavioral;

这是一个错误的停止位接收数据模拟的0x55

enter image description here