基于FPGA的通用8251串行异步收发器(6600+字)

Posted fpga&matlab

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于FPGA的通用8251串行异步收发器(6600+字)相关的知识,希望对你有一定的参考价值。

1.简介与仿真结论

       随着集成电路技术的发展,电子设计自动化(EDA)逐渐成为重要的设计手段,已经广泛应用于模拟与数字电路系统等许多领域。电子设计自动化是一种实现电子系统或电子产品自动化设计的技术,它与电子技术,微电子技术的发展密切相关,它吸收了计算机科学领域的大多数最新研究成果,以高性能的计算机作为工作平台,促进了工程发展。EDA的一个重要特征就是使用硬件描述语言(HDL)来完成的设计文件,VHDL语言是经IEEE确认的标准硬件语言,在电子设计领域受到了广泛的接受。本文介绍了串行通信的基本理论;综述了EDA技术的发展概况,介绍了MAX+PLUSll软件;熟悉Intel8251基本结构和工作原理.

发送段的说明:

当发送01000110,发出去的是01100010——010,后面的010是校验位和停止位,注意每次发送的后三位是校验位。

paritycycle <= tsr(1) AND NOT (tag2 OR tag1 OR tsr(7) OR tsr(6) OR tsr(5) OR tsr(4) OR tsr(3) OR tsr(2));

txdone <= NOT (tag2 OR tag1 OR tsr(7) OR tsr(6) OR tsr(5) OR tsr(4) OR tsr(3) OR tsr(2) OR tsr(1) OR tsr(0));

txrdy <= NOT txdatardy;

接收段的说明:

发送01101010,接收也为01101010

2.理论分析

发送模块的设计

    首先来设计URAT的发送模块,根据系统的要求我们首先定义如下的管脚:

mclkx16 : IN std_logic;                    --系统时钟

      write   : IN std_logic;                    --写时钟

      reset   : IN std_logic;                     --复位,0工作,1复位

      data    : IN std_logic_vector(7 downto 0);  --8位并行数据输入

      tx      : OUT std_logic ;                   --串行输出

      txrdy   : OUT std_logic                     --标志位

该模块的仿真波形图如下图所示:

图1

      当信号发送的01000110的时候,将并行信号变为串行信号,data[0]=0, data[1]=1, data[2]=1, data[3]=0, data[4]=0, data[5]=0, data[6]=1, data[7]=0,后3位的010为该数据的校验信号位。由此我们验证了系统发送部分的正确性。

      下面来具体介绍发送部分的工作流程:

图2

       上图中状态的转移是靠一个内部变量(Variable)来实现的,该变量在进行完当前状态的处理后指向下一个将处理的状态,进程(Process)的每一次处理都根据变量的内容进行相应状态的处理,由于其功能就像一个指针,因此我们称之为接收或发送指针。

       其中的信号的转换过程如下:

            tsr <= '0'&tsr(7 downto 1);

            tsr(7) <= tag1;

            tag1 <= tag2;

                      tag2 <= '0';

            txparity <= txparity XOR tsr(0);

            IF (txdone = '1') THEN

               tx <= '1';

               ELSIF (paritycycle = '1') THEN

                  tx <= txparity;              

               ELSE

                  tx <= tsr(0);

            END IF;

通过这个代码可以将并型信号转为串型信号,将串行信号发送出去。

其中信号的校验公式如下:

paritycycle <= tsr(1) AND NOT (tag2 OR tag1 OR tsr(7) OR tsr(6) OR tsr(5) OR tsr(4) OR tsr(3) OR tsr(2));

2 接收模块的设计

    首先来设计URAT的发送模块,根据系统的要求我们首先定义如下的管脚:

mclkx16     :  IN std_logic;    -- 输入时钟

     read        :  IN std_logic;    -- 读取信号

     rx          :  IN std_logic;    -- 接收到的信号

     reset       :  IN std_logic;    -- 复位

     rxrdy       :  OUT  std_logic;  -- 接收的数据准备读取

     parityerr   :  OUT  std_logic;  -- 接收校验标志

     framingerr  :  OUT  std_logic; 

     overrun     :  OUT  std_logic; 

     data        :  OUT  std_logic_vector(7 downto 0)); -- 8 bit 数据输出该模块的仿真波形图如下图所示:

图3

     当信号接收串型信号01101010的时候,将串行信号变为并行信号,data[0]=0, data[1]=1, data[2]=1, data[3]=0, data[4]=1, data[5]=0, data[6]=1, data[7]=0。由此我们验证了系统发送部分的正确性。

     下面来具体介绍发送部分的工作流程:

图4

接收处理首先完成起始位的检测,并自己产生接收时序控制信号,在控制信号的控制下,逐位接收串行输入数据,并根据控制字判断接收数据位数,完成数据的接收后,进行奇偶校验位的判断,最后判断停止位。在接收的过程中设置接收状态输出信号。

其中的信号的转换过程如下:

   sample_data : PROCESS (rxclk, reset)

   BEGIN

      IF (reset = '1') THEN

      -- idle_reset  

         rsr        <= "11111111";             

      rxparity   <= '1';                       

      paritygen  <= paritymode;     

      rxstop     <= '0';    

      ELSIF (rxclk='1') AND (rxclk'EVENT) THEN

         IF (idle='1') THEN

            -- idle_reset  

            rsr        <= "11111111";       

         rxparity   <= '1';                        

         paritygen  <= paritymode;             

         rxstop     <= '0';

         ELSE

              -- shift_data

              rsr         <= '0'&rsr(7 downto 1);   

            rsr(7)      <= rxparity;           

            rxparity    <= rxstop;            

            rxstop      <= rx;                

            paritygen   <= paritygen XOR rxstop; 

         END IF;

      END IF;

   END PROCESS;

通过这个程序,我们可以讲接收端的串行信号变为原始的串行信号。

3.部分核心代码

·发送模块:

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.ALL;
ENTITY txmit IS
PORT (
      mclkx16 : IN std_logic;                    --系统时钟
      write   : IN std_logic;                    --写时钟
      reset   : IN std_logic;                    --复位,0工作,1复位
	  data    : IN std_logic_vector(7 downto 0); --8位并行数据输入
	  tx      : OUT std_logic ;                  --串行输出
      txrdy   : OUT std_logic                    --标志位
     );
END txmit;
--以下定义一些中间变量,具体使用在以下模块中介绍
ARCHITECTURE behave OF txmit IS
   SIGNAL write1, write2 : std_logic;
   SIGNAL txdone1, txdone : std_logic;
   SIGNAL thr, tsr : std_logic_vector(7 downto 0);
   SIGNAL tag1, tag2 : std_logic;
   CONSTANT paritymode : std_logic :='1';
   SIGNAL txparity : std_logic;
   SIGNAL txclk : std_logic;
   SIGNAL paritycycle : std_logic;
   SIGNAL txdatardy : std_logic;
   SIGNAL cnt : std_logic_vector(2 downto 0);
BEGIN
--校验公式
paritycycle <= tsr(1) AND NOT (tag2 OR tag1 OR tsr(7) OR tsr(6) OR tsr(5) OR tsr(4) OR tsr(3) OR tsr(2));
txdone <= NOT (tag2 OR tag1 OR tsr(7) OR tsr(6) OR tsr(5) OR tsr(4) OR tsr(3) OR tsr(2) OR tsr(1) OR tsr(0));
txrdy <= NOT txdatardy;
--当写信号为0的时候讲数据打入寄存器THR中,THR是一个中间变量
  thr_write : PROCESS (write, data)
  BEGIN
     IF (write = '0') THEN
        thr <= data;
     END IF;
  END PROCESS;
--生成一个分频后的时钟,16分频
   baud_clock_gen : PROCESS (mclkx16, reset)
   BEGIN
      IF (reset ='1') THEN
         txclk <= '0';
         cnt <= "000";
      ELSIF (mclkx16='1') AND mclkx16'EVENT THEN
         IF (cnt = "000") THEN
            txclk <= NOT txclk;
         END IF;
      cnt <= cnt + 1;
      END IF;
   END PROCESS;
--转换过程。
   shift_out : PROCESS (txclk, reset)
   BEGIN
      IF (reset = '1') THEN
      	 tsr <= (OTHERS => '0');
         tag2 <= '0';
         tag1 <= '0';
         txparity <= paritymode;
         tx <= '1';
         --idle_reset;
      ELSIF txclk = '1' AND txclk'EVENT THEN
         IF (txdone='1' AND txdatardy = '1') THEN
--          load_data;
            tsr <= thr;
            tag2 <= '1';
            tag1 <= '1';
            txparity <= paritymode;
            tx <= '0';
         ELSE
--          shift_data;                    --一下几行就是并-》串的过程。
            tsr <= '0'&tsr(7 downto 1);
            tsr(7) <= tag1;
            tag1 <= tag2;
				tag2 <= '0';
            txparity <= txparity XOR tsr(0);
            IF (txdone = '1') THEN
               tx <= '1';
               ELSIF (paritycycle = '1') THEN
                  tx <= txparity;             --输出校验位
               ELSE
                  tx <= tsr(0);
            END IF;
         END IF;
      END IF;
   END PROCESS;          
--几个控制信号的生成
   PROCESS (mclkx16, reset)
   BEGIN
      IF (reset='1') THEN
         txdatardy <= '0';
         write2 <= '1';
         write1 <= '1';
         txdone1 <= '1';
      ELSIF mclkx16 = '1' AND mclkx16'EVENT THEN
         IF (write1 = '1' AND write2 = '0') THEN
            txdatardy <= '1';
         ELSIF (txdone = '0' AND txdone1 = '1') THEN
            txdatardy <= '0';
         END IF;
         write2 <= write1;
         write1 <= write;
         txdone1 <= txdone;
      END IF;
   END PROCESS;
END behave;

·接收模块:

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.ALL;
ENTITY rxcver IS
PORT (mclkx16     :  IN std_logic;    -- 输入时钟
      read        :  IN std_logic;    -- 读取信号
      rx          :  IN std_logic;    -- 接收到的信号
      reset       :  IN std_logic;    -- 复位
	  rxrdy       :  OUT  std_logic;  -- 接收的数据准备读取
	  parityerr   :  OUT  std_logic;  -- 接收校验标志
	  framingerr  :  OUT  std_logic;  
	  overrun     :  OUT  std_logic;  
	  data        :  OUT  std_logic_vector(7 downto 0));  -- 8 bit 数据输出
END rxcver;
--定义的中间变量
ARCHITECTURE behave OF rxcver IS
SIGNAL rxcnt : std_logic_vector(3 downto 0);  
SIGNAL rx1, read1, read2, idle1 : std_logic;  
SIGNAL hunt  : std_logic;  
SIGNAL rhr : std_logic_vector(7 downto 0);  
SIGNAL rsr : std_logic_vector(7 downto 0);  
SIGNAL rxparity  :  std_logic;  
SIGNAL paritygen :  std_logic; 
SIGNAL rxstop : std_logic;   
CONSTANT paritymode : std_logic := '1'; 
SIGNAL rxclk  : std_logic;   
SIGNAL idle  :  std_logic;  
SIGNAL rxdatardy : std_logic;  
BEGIN
	idle_preset : PROCESS (rxclk, reset)
	BEGIN
		IF reset = '1' THEN
			idle <= '1';
		ELSIF rxclk'EVENT AND rxclk='1' THEN
			idle <= (NOT idle) AND (NOT rsr(0));
		END IF;
	END PROCESS;
--时钟分频
	rxclk_sync : PROCESS (mclkx16, reset)
	BEGIN
		IF reset='1' THEN
			hunt <= '0';
			rxcnt <= "0001";
			rx1 <= '1';
			rxclk <= '0';
		ELSIF (mclkx16='1') AND mclkx16'EVENT THEN
			IF (idle='1' AND rx='0' AND rx1='1') THEN
				hunt <= '1';
			ELSE
			   IF (idle='0' OR rx='1') THEN
			      hunt <= '0';
            END IF;
            IF (idle ='0' OR hunt='1') THEN
               rxcnt <= rxcnt + 1;
            ELSE
               rxcnt <= "0001";
            END IF;
         END IF;
         rx1 <= rx;
         rxclk <= rxcnt(3);		
		END IF;
	END PROCESS;		
--校验位判断过程和数据转换
   sample_data : PROCESS (rxclk, reset)
   BEGIN
      IF (reset = '1') THEN
      -- idle_reset   
         rsr        <= "11111111";		
   	   rxparity   <= '1';        	         
   	   paritygen  <= paritymode;	
   	   rxstop     <= '0';     
      ELSIF (rxclk='1') AND (rxclk'EVENT) THEN
         IF (idle='1') THEN
            -- idle_reset   
            rsr        <= "11111111";		
   	      rxparity   <= '1';        	         
   	      paritygen  <= paritymode;		
   	      rxstop     <= '0';
         ELSE
  	         -- shift_data
  	         rsr         <= '0'&rsr(7 downto 1);    
            rsr(7)      <= rxparity;            
            rxparity    <= rxstop;             
            rxstop      <= rx;                 
            paritygen   <= paritygen XOR rxstop;  
         END IF;
      END IF;
   END PROCESS;
--标志信号的生成
   generate_flag : PROCESS (mclkx16, reset)
   BEGIN
      IF (reset='1') THEN
      	rhr         <= "00000000";
	      rxdatardy 	<= '0';
	      overrun		<= '0';
	      parityerr   <= '0';
	      framingerr	<= '0';
	      idle1       <= '1'; 
	      read2       <= '1'; 
	      read1       <= '1'; 
      ELSIF (mclkx16='1') AND (mclkx16'EVENT) THEN
         IF (idle='1' AND idle1='0') THEN
            IF (rxdatardy='1') THEN
               overrun <= '1';
            ELSE
               overrun <= '0';				
			      rhr <= rsr;					  
			      parityerr <= paritygen;   
			      framingerr <= NOT rxstop;	
			      rxdatardy <= '1'; 			
			   END IF;
		   END IF;
		   IF (read2 = '0' AND read1='1') THEN
      	   rxdatardy  <= '0';
	         parityerr  <= '0';
	         framingerr <= '0';
	         overrun    <= '0';
		   END IF;
	      idle1 <= idle;				        
	      read2 <= read1;	   				 
	      read1 <= read;							
	   END IF;
   END PROCESS;
   rxrdy <= rxdatardy;
   latch_data : PROCESS (read, rhr)
   BEGIN
      IF (read = '1') THEN
         data <= rhr;
      END IF;
   END PROCESS;
END behave;

A38-01

以上是关于基于FPGA的通用8251串行异步收发器(6600+字)的主要内容,如果未能解决你的问题,请参考以下文章

可编程串行通信接口芯片8251A

基于FPGA的RS232串口收发系统开发

EDA课设 FPGA开发板 VHDL实现串口通信

EDA课设 FPGA开发板 VHDL实现串口通信

Xilinx FPGA高速串行收发器简介

JZ2440 裸机驱动 第11章 通用异步收发器UART