一.实验题目名称:

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 := '';
RXD : in std_logic;
CLK : in std_logic; --Master Clock
--DBIN : in std_logic_vector ( downto ); --Data Bus in
DBOUT : out std_logic_vector ( downto ); --Data Bus out
RDA : inout std_logic; --Read Data Available
TBE : inout std_logic := ''; --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 := ''); --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 clock cycles
strGetData, --Shifts in the 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( downto ) := "";
--Baud Rate dividor, set now for a rate of .
--Found by dividing 50MHz by and .
signal rdReg : std_logic_vector( downto ) := "";
--Receive holding register
signal rdSReg : std_logic_vector( downto ) := "";
--Receive shift register
signal tfReg : std_logic_vector( downto ); --Transfer holding register
signal tfSReg : std_logic_vector( downto ) := "";
--Transfer shift register
signal clkDiv : std_logic_vector( downto ) := ""; --used for rClk
signal rClkDiv : std_logic_vector( downto ) := ""; --used for tClk
signal ctr : std_logic_vector( downto ) := ""; --used for delay times
signal tfCtr : std_logic_vector( downto ) := ""; --used to delay in transfer
signal rClk : std_logic := ''; --Receiving Clock
signal tClk : std_logic; --Transfering Clock
signal dataCtr : std_logic_vector( downto ) := ""
--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 := '';
signal load : std_logic := '';
signal shift : std_logic := '';
signal par : std_logic;
signal tClkRST : std_logic := '';
signal rShift : std_logic := '';
signal dataRST : std_logic := '';
signal dataIncr: std_logic := '';
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();
parError <= not ( rdSReg() xor (((rdSReg() xor rdSReg()) xor (rdSReg() xor rdSReg())) xor ((rdSReg() xor rdSReg()) xor (rdSReg() xor rdSReg()))) );
DBOUT <= rdReg;
--tfReg <= DBIN;
par <= not ( ((tfReg() xor tfReg()) xor (tfReg() xor tfReg())) xor ((tfReg() xor tfReg()) xor (tfReg() xor tfReg())) ); --Clock Dividing Functions--
process (CLK, clkDiv) --set up clock divide for rClk
begin
if (Clk = '' and Clk'event) then
if (clkDiv = baudDivide) then
clkDiv <= "";
else
clkDiv <= clkDiv +;
end if;
end if;
end process; process (clkDiv, rClk, CLK) --Define rClk
begin
if CLK = '' 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 = '' and rClk'event) then
rClkDiv <= rClkDiv +;
end if;
end process; tClk <= rClkDiv(); --define tClk process (rClk, ctRst) --set up a counter based on rClk
begin
if rClk = '' and rClk'Event then
if ctRst = '' then
ctr <= "";
else
ctr <= ctr +;
end if;
end if;
end process; process (tClk, tClkRST) --set up a counter based on tClk
begin
if (tClk = '' and tClk'event) then
if tClkRST = '' then
tfCtr <= "";
else
tfCtr <= tfCtr +;
end if;
end if;
end process; --This process controls the error flags--
process (rClk, RST, RD, CE)
begin
if RD = '' or RST = '' then
FE <= '';
OE <= '';
RDA <= '';
PE <= '';
elsif rClk = '' and rClk'event then
if CE = '' then
FE <= frameError;
OE <= RDA;
RDA <= '';
PE <= parError;
rdReg( downto ) <= rdSReg ( downto );
end if;
end if;
end process; --This process controls the receiving shift register--
process (rClk, rShift)
begin
if rClk = '' and rClk'Event then
if rShift = '' then
rdSReg <= (RXD & rdSReg( downto ));
end if;
end if;
end process; --This process controls the dataCtr to keep track of shifted values--
process (rClk, dataRST)
begin
if (rClk = '' and rClk'event) then
if dataRST = '' then
dataCtr <= "";
elsif dataIncr = '' then
dataCtr <= dataCtr +;
end if;
end if;
end process;
--Receiving State Machine--
process (rClk, RST)
begin
if rClk = '' and rClk'Event then
if RST = '' 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 <= '';
rShift <= '';
dataRst <= ''; CE <= '';
if RXD = '' then
ctRst <= '';
strNext <= strEightDelay;
else
ctRst <= '';
strNext <= strIdle;
end if; when strEightDelay =>
dataIncr <= '';
rShift <= '';
CE <= ''; if ctr( downto ) = "" then
ctRst <= '';
dataRST <= '';
strNext <= strGetData;
else
ctRst <= '';
dataRST <= '';
strNext <= strEightDelay;
end if; when strGetData =>
CE <= '';
dataRst <= '';
if ctr( downto ) = "" then
ctRst <= '';
dataIncr <= '';
rShift <= '';
else
ctRst <= '';
dataIncr <= '';
rShift <= '';
end if; if dataCtr = "" then
strNext <= strCheckStop;
else
strNext <= strGetData;
end if; when strCheckStop =>
dataIncr <= '';
rShift <= '';
dataRst <= '';
ctRst <= '';
CE <= '';
strNext <= strIdle;
end case;
end process;
end rtl;

 eq \o\ac(○,2)

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

一:设置控制字

如图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

基于VHDL的8255可编程并行接口电路设计的更多相关文章

  1. 微型计算机系统实验总结(学习性实验:IO地址译码,可编程并行接口8255,交通灯控制实验 + 自主设计实验:汽车信号灯控制系统,电风扇控制器,洗衣机控制系统,霓虹灯,电梯控制系统)

    实验配套软件: https://download.csdn.net/download/qq_39932172/11221584 实验指导用书: 教师版: https://download.csdn.n ...

  2. [芯片] 3、接口技术·实验三·可编程并行接口8255A

    目录 一.实验目的和要求 二.实验原理与背景 2-1.8255A简介 2-2.8255A编程 三.实验具体的内容 3-1.8255方式0实验1 3-2.8255方式0实验2 3-3.8255方式1输出 ...

  3. 基于VHDL利用PS2键盘控制的电子密码锁设计

    基于VHDL利用PS2键盘控制的密码锁设计 附件:下载地址 中文摘要 摘 要:现代社会,人们的安全意识正在不断提升.按键密码锁由于其具有方便性.低成本等特征,还是大有用武之地的.但是通常的按键密码锁开 ...

  4. .Net Core WebAPI 基于Task的同步&异步编程快速入门

    .Net Core WebAPI 基于Task的同步&异步编程快速入门 Task.Result async & await 总结 并行任务(Task)以及基于Task的异步编程(asy ...

  5. 网络编程——基于TCP协议的Socket编程,基于UDP协议的Socket编程

    Socket编程 目前较为流行的网络编程模型是客户机/服务器通信模式 客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求.如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服 ...

  6. SQL Server 2008空间数据应用系列六:基于SQLCRL的空间数据可编程性

    原文:SQL Server 2008空间数据应用系列六:基于SQLCRL的空间数据可编程性 友情提示,您阅读本篇博文的先决条件如下: 1.本文示例基于Microsoft SQL Server 2008 ...

  7. Matlab与.NET基于类型安全的接口混合编程入门

    原文:[原创]Matlab与.NET基于类型安全的接口混合编程入门 如果这些文章对你有用,有帮助,期待更多开源组件介绍,请不要吝啬手中的鼠标. [原创分享]Matlab.NET混编调用Figure窗体 ...

  8. 基于TCP(面向连接)的Socket编程

    基于TCP(面向连接)的Socket编程 一.客户端: 1.打开一个套接字(Socket); 2.发起连接请求(connect); 3.如果连接成功,则进行数据交换(read.write.send.r ...

  9. 基于TCP/UDP的socket编程

    基于TCP(面向连接)的socket编程服务器端顺序: 1. 创建套接字(socket) 2. 将套接字绑定到一个本地地址和端口上(bind) 3. 将套接字设为监听模式,准备接收客户请求(liste ...

随机推荐

  1. mysql 存储引擎 配置文件my.ini 的配置方式

    如果想使修改后的参数生效,须重新启动MySQL服务器. #存储引擎设置 default-storage-engine = INNODB

  2. INFO: Font Metrics and the Use of Negative lfHeight

    INFO: Font Metrics and the Use of Negative lfHeight  Print  Email   Article translations  Article ID ...

  3. Automate the Sizing of your SGA in Oracle 10g

    How much memory does each of the individual components of the SGA need? Oracle now has methods to de ...

  4. javascript 关于new()继承的笔记

    近期的一些学习总结,如有错误不严谨地方,希望指正! 使用new操作符会有如下操作: 1.创建一个对象temp = {}, 2. temp.__proto__ = A.prototype, 3. A.c ...

  5. Android组件系列----Activity的生命周期

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/3 ...

  6. 命令模式-实现undo和redo

    这次实验主要是实现多次redo和undo,即程序的撤回和恢复,这里只实现加法的撤回和恢复. 程序的撤回和恢复就是由所使用的软件来记录操作步骤,可以将数据恢复到某个操作状态. 撤回这个指令很常见,Win ...

  7. 监控SQLServer 数据库表每天的空间变化情况

    阅读完桦仔的<分享一个SQLSERVER脚本(计算数据库中各个表的数据量和每行记录所占用空间)>后,我想使用文中提供的代码做一个统计表每天的新增行数及新增存储空间的功能 实现步骤如下: 1 ...

  8. 如何在 Azure 中均衡 Linux 虚拟机负载以创建高可用性应用程序

    负载均衡通过将传入请求分布到多个虚拟机来提供更高级别的可用性. 本教程介绍了 Azure 负载均衡器的不同组件,这些组件用于分发流量和提供高可用性. 你将学习如何执行以下操作: 创建 Azure 负载 ...

  9. Spring Security自定义GrantedAuthority前缀

    如果我们正使用Spring Security提供默认的基于方法的权限认证注解如下: @PreAuthorize("hasAnyRole('ADMIN', 'USER')") pub ...

  10. if a in range(len(lst)): print(a,lst[a]) #获取索引和对应元素, 背下来~~

    经典的"获取元素的索引和元素", 背下来! if a in range(len(lst)): print(a, lst[a])