基于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+字)的主要内容,如果未能解决你的问题,请参考以下文章