一.实验题目名称:

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. eclipse安装lua

    单击Eclipse->Help->Install New Software… 在Work with中输入网址 Kepler - http://download.eclipse.org/re ...

  2. alwayson监控

    最近大体自己写了点alwayson相关的监控,是通过存储过程的方法,做个笔记如下: --alwayson启用状态 declare @isenabled sql_variant SELECT @isen ...

  3. 使用Reflector反编译并提取源代码

    Reflector是一个强大的.net 反编译工具,有时我们不止需要反编译源代码,更需要提取源代码. Reflector本身不自带提取源代码功能,不过可以借助插件Reflector.FileDisas ...

  4. 转: SSH框架总结(框架分析+环境搭建+实例源码下载)

    原:http://blog.csdn.net/shan9liang/article/details/8803989 首先,SSH不是一个框架,而是多个框架(struts+spring+hibernat ...

  5. windows 查看端口号,杀进程

    查看端口号: 开始--运行--cmd netstat –and 杀进程: windows任务管理器         查看--显示列-PID 相关知识: 一台机器的80端口被httpd (apache) ...

  6. Asp.net Core 2.0+EntityFrameWorkCore 2.0添加数据迁移

    Asp.net Core 由于依赖注入的广泛使用,配置数据迁移,与Asp.net大不相同,本篇介绍一下Asp.net Core添加数据迁移的过程 添加Nuget包 Install-Package Mi ...

  7. 你的ABAP程序给佛祖开过光么?来试试Jerry这个小技巧

    最近Jerry在忙一个项目,技术栈换成了nodejs平台,语言换成了JavaScript,因为赶项目进度,一直没时间更新公众号.感谢大家的支持,关注人数还是慢慢地增长到了3000. 今天我们来聊聊一个 ...

  8. U-Mail:多方面因素避免EDM邮件进垃圾箱

    有很多做邮件营销的企业客户给U-Mail来电或来函咨询一件困扰他们的事:群发邮件时,要怎么样才能降低被收件人列入垃圾邮件的概率呢?其实关于这个问题,U-Mail小编已经请资深营销专家解答过多次了,经常 ...

  9. PHP设计模式系列 - 委托模式

    委托模式 通过分配或委托其他对象,委托设计模式能够去除核心对象中的判决和复杂的功能性. 应用场景 设计了一个cd类,类中有mp3播放模式,和mp4播放模式 改进前,使用cd类的播放模式,需要在实例化的 ...

  10. 【转载】socket 的 connect、listen、accept 和全连接队列、半连接队列的原理

    转自:http://blog.csdn.net/tennysonsky/article/details/45621341 写在前面: 1. accept 只是从全连接队列拿出一个已经建立好的socke ...