首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >VHDL RS-232接收机

VHDL RS-232接收机
EN

Stack Overflow用户
提问于 2014-11-23 07:44:55
回答 2查看 2.3K关注 0票数 1

我一直在尝试设计一个RS-232接收机采用FSM方法.我承认我对VHDL的理解还不够全面,所以我一直在忙着编写代码,并且一直在学习。然而,我相信我在这一点上碰到了一堵砖墙。

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

代码语言:javascript
复制
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变量采取了正确的方法?如果我在任何流程之前将它们作为架构的一部分来发出信号呢?

在这方面的任何帮助都是非常感谢的!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-11-24 15:35:16

解决这一问题的最简单方法,同时也是生成最容易阅读的代码的方法,是移动到像这样的单进程状态机(警告:未被遵守可能包含语法错误):

代码语言:javascript
复制
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 < 16StopBitCheck是无法到达的。

还要注意的是,到StopBitCheck的状态转换发生在与通常采样数据相同的周期上,因此StopBitCheck中的DataIn采样将是一个周期延迟。更糟糕的是,如果您得到坏数据(DataIn/='1' in StopBitCheck),counter将仍然在16岁,StartBitCheck将始终转到StartBitCheck子句,状态机将被锁定。

再解释一下之前是怎么回事:

您的模拟会在负时钟边缘发生变化,因为组合过程中只有灵敏度列表中的时钟。组合过程的正确灵敏度列表将只包括DataInEnablecurrentState以及您的两个变量counterdataIndex。变量不能成为敏感列表的一部分,因为它们超出了敏感列表的范围(另外,您也不希望触发进程本身,稍后会详细介绍)。

然而,灵敏度列表基本上只是模拟器的一根拐杖。当转换到实际硬件时,进程用LUTs和触发器实现。您当前的实现永远不会合成,因为您将反馈(作为旧值的函数分配给新值的信号或变量)合并到不锁定逻辑中,从而产生组合循环。

counterdataIndex是状态数据的一部分。状态机更容易理解,因为它们与显式状态分离,但它们仍然是状态数据的一部分。当您创建两个进程状态机(同样,我建议使用一个进程状态机,而不是两个)时,您必须将所有状态数据拆分为用于存储它的触发器(例如currentState)和生成下一个值的LUT输出(例如nextState)。这意味着对于两台进程机器,变量counterdataIndex必须改为currentCounternextCountercurrentDataIndexnextDataIndex,并将其视为状态分配。请注意,如果您选择实现更改以保持一个2进程状态机,那么上面提到的逻辑错误仍然适用。

编辑:

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

代码语言:javascript
复制
                    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;

纯状态机只存储状态。它的输出完全来自状态,或者是状态和输入的组合。因为counterdataIndex是存储的,所以它们是状态的一部分。如果您想要枚举每个状态,您将得到如下内容:

代码语言:javascript
复制
    type states is (StartBitCheck_Counter0, StartBitCheck_counter1...

最后您将得到8*16*3 = 384状态(实际上稍微少了一点,因为只有ReadData使用dataIndex,所以384中的某些状态完全是冗余状态)。毫无疑问,您可以看到,仅仅声明3个独立的信号要简单得多,因为状态数据的不同部分被不同的使用。在两个进程状态机中,人们常常忘记实际上命名为state的信号并不是唯一需要存储在时钟进程中的状态数据。

当然,在一个进程机器中,这不是一个问题,因为所有分配的东西都必须存储在触发器中(中间的组合逻辑没有在信号中列举)。另外,请注意,1-进程状态机和2-进程状态机将合成为相同的东西(假设它们都正确地实现),尽管我认为这是比较容易阅读和更难搞乱一进程机器。

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

票数 1
EN

Stack Overflow用户

发布于 2014-11-23 20:54:00

第一个进程只运行在CLK上升边缘上,而第二个进程运行在两个CLK边缘上(因为每个CLK更改都运行)。

您使用两个进程,“内存状态”和“下一个状态生成器”,第一个进程必须是同步的(正如您所做的那样),而第二个进程通常是组合的,以便能够为下一个CLK活动边缘及时生成下一个状态。

但是在您的例子中,第二个进程也需要在每个CLK脉冲上运行(因为可变计数器和索引),所以解决方案可以是在上升边缘上运行第一个进程,在下降边缘运行第二个进程(如果您的硬件支持这样的话)。

下面是您的代码,希望能有所帮助。

代码语言:javascript
复制
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错误的停止位接收数据模拟。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27086712

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档