• 基于VHDL的8255可编程并行接口电路设计


    一.实验题目名称:

    8255可编程并行接口电路设计

    二.实验目的、任务和要求:

    实验目的:学习掌握基本的数字系统设计方法,建立自顶向下的设计思维,能够使用VHDL语言编写简单的应用IP核,掌握基本的FPGA编译、烧写步骤。

    任务:使用VHDL语言编写一个IP核,实现8255并行接口的功能,能通过仿真并在Spartan-3E Starter Kit开发板上实现

    要求:所编写的IP核要能实现8255的全部三种工作方式。由于8255接口众多,应尽可能多得使用板上其他资源,例如串口、LCD、LED等。

    三.实验系统结构设计分析

    1.模块划分思想和方法;

    针对8255端口多,逻辑判断复杂,需要分时应用的特点。我们自顶向下设计了两层文件,顶层文件为8255的端口声明及各个模块的端口声明,然后用map将各个模块连接起来

    底层是8个子模块的元件定义。我们首先用串口模块将一个从PC机发来的串行数据转换成并行数据存放到数据输出选择模块的DOUT口,至于这个八位数据是输入到控制寄存器还是从PA/PB/PC口输出,就由另一个输入输出逻辑判断模块来控制。逻辑判断模块根据A0-A1,WR,RD,还有控制字来判断三个端口处于什么工作方式,并将数据发送(接收)至A口、B口、C口的缓冲区。最后,我们通过PA输出模块、PA输入模块、PB输出模块、PB输入模块、PC输出模块将缓存区中的数据根据不同的工作方式进行输入输出。

     

    2.模块框图和作用;

    8个模块的作用:

    串口通信模块(Rs232RefComp):由于8255端口众多,而fpga板载I/O口不够用,所以采用串口输入的方式来给8255提供所需的数据(D0-D7)。

    数据输出选择模块(dout_mux):8255A有3个8位数据端口,即端口A、端口B和端口C,通过数据输出选择模块来最终判断选择哪个端口输出。

    数据输入输出逻辑判断模块(cntl_log):8255A的三个端口,还有一个控制寄存器,通过数据输出输入逻辑判断模块来判断8255处于何种工作方式。

    PA口输出模块(portaout):用来控制PA的缓存区的八位数据输出到PA口。

    PA口输入模块(portain):用来控制PA口读到的数据放到PA的缓存区。

    PB口输出模块(portbout):用来控制PB的缓存区的八位数据输出到PB口。

    PB口输入模块(portbin):用来控制PB口读到的数据放到PB的缓存区。

    PC口输出模块(portcout):用来控制PC口的位输出。

    3.各模块引脚定义和作用.

     1 串口通信模块

    CLK: 时钟(50MHZ),配合波特率接收PC端发来的串行数据

    RD: 读信号,始终置0,一直读来自串口的信号

    RST:复位端

    RXD:接收端,接收来自PC机传出的串行数据

    DBIN:并行数据输入端,接收来自PB口的8位输出数据

    TXD: 串行输出端,将PB口发出的8位并行数据转换成串行数据发送到上位机

    DBOUT: 并行数据输出端,将来自PC机的串行数据转化成8位并行数据输出

    2 逻辑判断模块

    CLK:时钟(50MHZ)

    RESET:复位

    nCS:片选端

    nRD:读寄存器

    nWR:写寄存器

    A[1-0]:选择端,选择PA/PB/PC/控制寄存器

    DIN[7-0]:数据输入端

    PCIN[7-0]:PC输入端(用于方式三)

    PAEN:PA使能

    PBEN:PB使能

    Portaoutld:PA口允许输出                                    

    Portaread:读PA口            Portbread:读PB口         PCEN:PC使能

    Portawrite:写PA口           Portbwrite:写PB口        DOUTSelect:输出选择

    Portboutld:PB口允许输出      Controlreg:控制寄存器    

    Portcoutld:PC口允许输出

    3 数据输出选择模块

    DOUTSelect:数据输出选择位

    Controlreg:控制寄存器

    PortAInReg:PA口输入缓存器

    PAIN:PA口输入寄存器

    PortBInReg:PB口输入缓存器

    PBIN:PB口输入寄存器

    Portcstatus:PC口状态寄存器

    DOUT:数据输出寄存器

    4 PA口输出模块

    CLK:时钟

    PortAoutld:PA口允许输出

    Reset:复位

    DIN:数据输入寄存器

    PAOUT:PA口输出寄存器

    5 PA口输入模块

    CLK:时钟

    PortAInLd:PA口允许输入

    RESET:复位

    PAIN:PA口输入寄存器

    PortAInReg:PA口输入缓存器

    6 PB口输出模块

    CLK:时钟

    PortBoutld:PB口允许输出

    Reset:复位

    DIN:数据输入寄存器

    PBOUT:PA口输出寄存器

    7 PB口输入模块

    CLK:时钟

    PortBInLd:PB口允许输入

    RESET:复位

    PBIN:PB口输入寄存器

    PortBInReg:PB口输入缓存器

    8 PC口输出模块

    CLK:时钟

    PortARead:读PA口

    PortAWrite:写PA口

    PortBRead:读PB口

    PortBWrite:写PB口

    PortCOverride:PC口重载

    RESET:复位

    DIN:数据输入寄存器

    PCIN:PC口输入寄存器

    Controlreg:控制寄存器              Portcstatus:PC口状态寄存器

    PortCoutld:PC口允许输出           PCOUT:PC口输出寄存器

    四.实验代码设计以及分析:

    1.给出模块层次图;

    2.按模块完成的代码及注释.

    完整源代码下载地址:

    http://files.cnblogs.com/yuzeren48/8255%E6%BA%90%E7%A0%81%E5%8A%A0%E6%B5%8B%E8%AF%95%E6%96%87%E4%BB%B6.rar

     1串口通信模块

    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    use IEEE.STD_LOGIC_ARITH.ALL;
    use IEEE.STD_LOGIC_UNSIGNED.ALL;
    
    entity Rs232RefComp is
        Port ( 
            --TXD     : out std_logic      := '1';
            RXD     : in  std_logic;                    
            CLK         : in  std_logic;                            --Master Clock
            --DBIN     : in  std_logic_vector (7 downto 0);                --Data Bus in
            DBOUT  : out std_logic_vector (7 downto 0);                --Data Bus out
            RDA        : inout std_logic;                            --Read Data Available
            TBE        : inout std_logic     := '1';                        --Transfer Bus Empty
            RD        : in  std_logic;                                --Read Strobe
            --WR    : in  std_logic;                                --Write Strobe
            PE        : out std_logic;                                   --Parity Error Flag
            FE        : out std_logic;                                --Frame Error Flag
            OE        : out std_logic;                                --Overwrite Error Flag
            RST        : in  std_logic    := '0');                           --Master Reset
    end Rs232RefComp;
    
    architecture rtl of Rs232RefComp is
    ------------------------------------------------------------------------
    -- Component Declarations
    ------------------------------------------------------------------------
    ------------------------------------------------------------------------
    --  Local Type Declarations
    ------------------------------------------------------------------------
        --Receive state machine
        type rstate is (                      
            strIdle,            --Idle state
            strEightDelay,      --Delays for 8 clock cycles
            strGetData,        --Shifts in the 8 data bits, and checks parity
            strCheckStop        --Sets framing error flag if Stop bit is wrong
        );
    
        type tstate is (
            sttIdle,            --Idle state
            sttTransfer,        --Move data into shift register
            sttShift            --Shift out data
            );
    
        type TBEstate is (
            stbeIdle,
            stbeSetTBE,
            stbeWaitLoad,
            stbeWaitWrite
            );
            
    ------------------------------------------------------------------------
    -- Signal Declarations
    ------------------------------------------------------------------------
        constant baudDivide : std_logic_vector(7 downto 0) := "10100011";     
    --Baud Rate dividor, set now for a rate of 9600. 
    --Found by dividing 50MHz by 9600 and 16.
        signal rdReg    :  std_logic_vector(7 downto 0) := "00000000";            
    --Receive holding register
        signal rdSReg    :  std_logic_vector(9 downto 0) := "1111111111";        
    --Receive shift register
        signal tfReg    :  std_logic_vector(7 downto 0);                                --Transfer holding register
        signal tfSReg  :  std_logic_vector(10 downto 0)     := "11111111111";    
    --Transfer shift register
        signal clkDiv    :  std_logic_vector(8 downto 0)    := "000000000";        --used for rClk
        signal rClkDiv :  std_logic_vector(3 downto 0)    := "0000";            --used for tClk
        signal ctr    :  std_logic_vector(3 downto 0)    := "0000";            --used for delay times
        signal tfCtr    :  std_logic_vector(3 downto 0)    := "0000";    --used to delay in transfer
        signal rClk    :  std_logic := '0';                                   --Receiving Clock
        signal tClk    :  std_logic;                                      --Transfering Clock
        signal dataCtr :  std_logic_vector(3 downto 0)    := "0000"
    --Counts the number of read data bits
        signal parError:  std_logic;                                        --Parity error bit
        signal frameError: std_logic;                                        --Frame error bit
        signal CE        :  std_logic;                                --Clock enable for the latch
        signal ctRst    :  std_logic := '0';
        signal load    :  std_logic := '0';
        signal shift    :  std_logic := '0';
        signal par    :  std_logic;
    signal tClkRST    :  std_logic := '0';
        signal rShift    :  std_logic := '0';
        signal dataRST :  std_logic := '0';
        signal dataIncr:  std_logic := '0';
        signal strCur    :  rstate    := strIdle;            --Current state in the Receive state machine
        signal strNext    :  rstate;                           --Next state in the Receive state machine
        signal sttCur  :  tstate := sttIdle;              --Current state in the Transfer state machine
        signal sttNext :  tstate;                        --Next state in the Transfer staet machine
        signal stbeCur :  TBEstate := stbeIdle;
        signal stbeNext:  TBEstate;
        
    ------------------------------------------------------------------------
    -- Module Implementation
    ------------------------------------------------------------------------
    begin
        frameError <= not rdSReg(9);
        parError <= not ( rdSReg(8) xor (((rdSReg(0) xor rdSReg(1)) xor (rdSReg(2) xor rdSReg(3))) xor ((rdSReg(4) xor rdSReg(5)) xor (rdSReg(6) xor rdSReg(7)))) );
        DBOUT <= rdReg;
        --tfReg <= DBIN;
        par <=  not ( ((tfReg(0) xor tfReg(1)) xor (tfReg(2) xor tfReg(3))) xor ((tfReg(4) xor tfReg(5)) xor (tfReg(6) xor tfReg(7))) );
    
    --Clock Dividing Functions--
        process (CLK, clkDiv)                                --set up clock divide for rClk
            begin
                if (Clk = '1' and Clk'event) then
                    if (clkDiv = baudDivide) then
                        clkDiv <= "000000000";
                    else
                        clkDiv <= clkDiv +1;
                    end if;
                end if;
            end process;
    
        process (clkDiv, rClk, CLK)                         --Define rClk
        begin
            if CLK = '1' and CLK'Event then
                if clkDiv = baudDivide then
                    rClk <= not rClk;
                else
                    rClk <= rClk;
                end if;
            end if;
        end process;    
    
        process (rClk)                                  --set up clock divide for tClk
            begin
                if (rClk = '1' and rClk'event) then
                    rClkDiv <= rClkDiv +1;
                end if;
            end process;
    
        tClk <= rClkDiv(3);                            --define tClk
    
        process (rClk, ctRst)                           --set up a counter based on rClk
            begin
                if rClk = '1' and rClk'Event then
                    if ctRst = '1' then
                        ctr <= "0000";
                    else
                        ctr <= ctr +1;
                    end if;
                end if;
            end process;
    
        process (tClk, tClkRST)                        --set up a counter based on tClk
            begin
                if (tClk = '1' and tClk'event) then
                    if tClkRST = '1' then
                        tfCtr <= "0000";
                    else
                        tfCtr <= tfCtr +1;
                    end if;
                end if;
            end process;
    
         --This process controls the error flags--
        process (rClk, RST, RD, CE)
            begin
                if RD = '1' or RST = '1' then
                    FE <= '0';
                    OE <= '0';
                    RDA <= '0';
                    PE <= '0';
                elsif rClk = '1' and rClk'event then
                    if CE = '1' then
                        FE <= frameError;
                        OE <= RDA;
                        RDA <= '1';     
                        PE <= parError;
                        rdReg(7 downto 0) <= rdSReg (7 downto 0);
                    end if;                
                end if;
            end process;
    
        --This process controls the receiving shift register--
        process (rClk, rShift)
            begin
                if rClk = '1' and rClk'Event then
                    if rShift = '1' then
                        rdSReg <= (RXD & rdSReg(9 downto 1));
                    end if;
                end if;
            end process;
    
        --This process controls the dataCtr to keep track of shifted values--
         process (rClk, dataRST)
            begin
                if (rClk = '1' and rClk'event) then
                    if dataRST = '1' then
                        dataCtr <= "0000";
                    elsif dataIncr = '1' then
                        dataCtr <= dataCtr +1;
                    end if;
                end if;
            end process;
          --Receiving State Machine--
        process (rClk, RST)
            begin
                if rClk = '1' and rClk'Event then
                    if RST = '1' then
                        strCur <= strIdle;
                    else
                        strCur <= strNext;
                    end if;
                end if;
            end process;
                
        --This process generates the sequence of steps needed receive the data
        
        process (strCur, ctr, RXD, dataCtr, rdSReg, rdReg, RDA)
            begin   
                case strCur is
    
                    when strIdle =>
                        dataIncr <= '0';
                        rShift <= '0';
                        dataRst <= '0';
                    
                        CE <= '0';
                        if RXD = '0' then
                            ctRst <= '1';
                            strNext <= strEightDelay;
                        else
                            ctRst <= '0';
                            strNext <= strIdle;
                        end if;
                    
                    when strEightDelay => 
                        dataIncr <= '0';
                        rShift <= '0';
                        CE <= '0';
    
                        if ctr(2 downto 0) = "111" then
                            ctRst <= '1';
                                dataRST <= '1';
                            strNext <= strGetData;
                        else
                            ctRst <= '0';
                            dataRST <= '0';
                            strNext <= strEightDelay;
                        end if;
                    
                    when strGetData =>    
                        CE <= '0';
                        dataRst <= '0';
                        if ctr(3 downto 0) = "1111" then
                            ctRst <= '1';
                            dataIncr <= '1';
                            rShift <= '1';
                        else
                            ctRst <= '0';
                            dataIncr <= '0';
                            rShift <= '0';        
                        end if;
    
                        if dataCtr = "1010" then
                            strNext <= strCheckStop;
                        else
                            strNext <= strGetData;
                        end if;
    
                    when strCheckStop =>
                        dataIncr <= '0';
                        rShift <= '0';
                        dataRst <= '0';
                        ctRst <= '0';
                        CE <= '1';
                        strNext <= strIdle;
                end case;
            end process;
    end rtl;


    .仿真图(输入输出波形)以及分析:

    一:设置控制字

    如图1所示:

    首先将寄存器选择位a[1:0]设置为“11”,在复位信号(reset)到来时,往数据输出寄存器(dout)放入控制字9B,使PA、PB、PC口工作在方式0下

    当读取信号(nrd)到来时,将控制字读入控制寄存器

    二:选择端口输出

    如图2所示:

    首先串行数据接收端(uart)接收来自PC机的串行数据(0xCB)并通过串口模块将串行数据转化为8位并行数据

    然后将寄存器选择位a[1:0]设置为“00”,表示由PA口输出

    当写信号(nwr)到来时,将8位并行数据发送到PA口

    若要使用PB口输出,就将将寄存器选择位a[1:0]设置为“01”

    当写信号(nwr)到来时,将8位并行数据发送到PB口

                                             图1 设置控制字

                                            图2 选择端口输出

    六.实验问题分析和经验总结:

    问题一:8255端口众多,而FPGA的板载I/O口有特别少,因而产生两个问题:1、如何将数据输入8255的数据段(D0-D7)。2、如何安排PA、PB、PC口。

    解决第一个问题可以有两个办法:1、分时传送,使用四个开关分两次将8为数据传送到数据端。优点:设计简单。缺点:不直观,在开发板上始终只能看到最后四位输入。2、使用串口。优点:界面直观,可以在PC端清楚显示所传送的每一个数据。缺点:设计复杂。

    解决第二个问题也有三个办法:1、用LED灯显示8位输出数据。优点:设计简单。缺点:无。2、用LCD显示8位输出数据。优点:界面直观。缺点:编程复杂。3、使用串口输出数据到PC机上显示。优点:界面直观。缺点:编程复杂。

    问题二:状态机编写困难,由于串口模块需要与PC机通讯,所以要编写相应的状态机来完成接收和转换的时序,这个是难点

    问题三:测试文件难编写。编写测试文件对时序要求很高,8255内部逻辑复杂,时序一点有错结果就不对。

    经验总结:

    1、采用了VHDL语言作为输入方式并结合FPGA/CPLD,大大缩短了设计周期,提高了设计的可靠性、灵活性,使用户可根据自己的需求,方便、高效地设计出适合的IP核。

    2、要善于查阅网上资料。很多模块都有相应的IP核,可以利用网上资源将IP核适当修改然后应用到自己的设计中。

    3、要学会自顶向下的设计方法,首先构建一个结构体系,编写一个顶层文件,然后对各个模块分别编写程序,进行仿真,最后编写顶层测试文件,实现全部功能。

    4、对开发板的I/O口要尽可能得有效利用。比如按钮的分时复用,对LED的刷新显示

    5、充分利用板载资源。如串口、LCD等

    6、将FPGA与上位机通讯,能够更加方便对数据的操作,并且直观的显示数据的收发过程

    七.参考资料:

    [1] 郑群星. Xilinx FPGA 数字电路设计. 科学出版社,2011

    [2] 董兰荣. Xilinx FPGA电路设计与实习. 沧海书局,2001

    [3] 林国良. VHDL硬件设计语言. 全华图书公司,1996

    [4] 萧如宣. VHDL数位系统电路设计. 儒林书局,2000

  • 相关阅读:
    layui的table使用,二
    将字符串中的以某个字符间隔放到数组中
    oracle中的 函数应用
    spring 的3种常用的注入方式
    写一个方法,输入两个正整数,输出在两个正整数范围内即被3整除,又被7整除的正整数
    Myeclipse 10.7配置egit及导入项目
    Plsqi安装
    web项目引入js包时,报syntax error on token
    java笔试面试题总结
    web.xml中的配置
  • 原文地址:https://www.cnblogs.com/yuzeren48/p/C_8255.html
Copyright © 2020-2023  润新知