UART:Universal Asynchronous Receiver/Transmitter,通用异步接收/发送装置。笼统的说就是串口传输,学习这个非常有用,因为现在很多电子设计中都是用串行传输数据的,在学习FPGA中,先弄一下串是有必要的,因为,假如想写个读写SDRAM的代码,那么怎么才能知道是否读写成功的呢,也许方法很多,不过,我觉得用串口调试助手调试还是比较方便的,可以先把想写入的数据通过串口发送出去,然后再写入SDRAM,然后再把SDRAM中的某个地址的数据读出来,然后通过串口发送出来,这样很直观。好了,还是不费话了,还是弄俺这串口吧。
这个代码包括顶层映射文件,波特率发生器,接收器,发送器。
一、波特率发生器
波特率发生器的代码如下:
--------------------------------------------------------------------------------------------
-- 每天进步一点点,开心一大点^_^
--文件名称:baud.vhd
--函数功能:将外部输入的32MHz的信号分成频率为153600Hz的信号
--作 者:萤火虫II号
--创建日期:2010.04.24
--------------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity baud is
port(
clk,resetb : in std_logic;
bclk : out std_logic
);
end baud;
architecture beha of baud is
begin
process(clk,resetb)
variable cnt : integer;
begin
if resetb='1' then cnt:=0;bclk<='0'; --reset
elsif rising_edge(clk) then
if cnt>=208 then cnt:=0;bclk<='1'; --320000000/208=1538461.54
else cnt:=cnt+1;bclk<='0';
end if;
end if;
end process;
end beha;
主要是应用到分频,产生相应的频率,分频的多少要看外部晶振和发送速率决定,原理不是太难,就像是加法进位一样,等 到一定时钟周期才触发一次,就达到了分频的目的。
二、接收器代码
--------------------------------------------------------------------------------------------
-- 每天进步一点点,开心一大点^_^
--文件名称:reciever.vhd
--函数功能:UART接受器,系统由五个状态(r_start,r_center,r_wait,r_sample,r_stop)和两个进程构成
--作 者:萤火虫II号
--创建日期:2010.04.24
--版 本:Quartus II 7.2
--------------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity reciever is
generic(framlent : integer:=8); --transfer paramater
port(
bclkr,resetr,rxdr : in std_logic; --define the input signals
r_ready : out std_logic;
rbuf : out std_logic_vector(7 downto 0)
);
end reciever;
architecture beha of reciever is
type states is(r_star,r_center,r_wait,r_sample,r_stop); --define substate
signal state : states:=r_star;
signal rxd_sync : std_logic;
begin
pro1:process(rxdr)
begin
if rxdr='0' then rxd_sync<='0';
else rxd_sync<='1';
end if;
end process;
pro2:process(bclkr,resetr,rxdr) --master control time sequence,combination course
variable count : std_logic_vector(3 downto 0); --define the middle variable
variable rcnt : integer:=0;
variable rbufs : std_logic_vector(7 downto 0);
begin
if resetr='1' then state<=r_star;count:="0000"; --reset
elsif rising_edge(bclkr) then
case state is
when r_star=>
if rxd_sync='0' then state<=r_center;r_ready<='0';rcnt:=0; --the first state:wait for the start bit
else state<=r_star;r_ready<='0';
end if;
when r_center=> --the secont state:figure out the center of every bit
if rxd_sync='0' then
if count="0100" then state<=r_wait;count:="0000";
else count:=count+1;state<=r_center;
end if;
else state<=r_star;
end if;
when r_wait=> --the third state: wait state
if count>="1110" then
if rcnt="framlent" then state<=r_stop; --if the recieve data is equivalent to 8 bit,enter stop state
else state<=r_sample;
end if;
count:="0000";
else count:=count+1;state<=r_wait;
end if;
when r_sample=>rbufs(rcnt):=rxd_sync;rcnt:=rcnt+1;state<=r_wait;--the fourth state:detect the data bit
when r_stop=>r_ready<='1';rbuf<=rbufs;state<=r_star; --over signal;
when others=>state<=r_star;
end case;
end if;
end process;
end beha;
用的是状态机,由五个状态(r_start,r_center,r_wait,r_sample,r_stop)和两个进程构成,主要是控制时序。由于用的是Quartus II7.2的版本,不支持中文注释,所以就用英文注释,鉴于本的英语比较憋足,所以可能表达的不太准确,但若当作“中式英文”,应该还是可以理解的……
三、发送器代码
--------------------------------------------------------------------------------------------
-- 每天进步一点点,开心一大点^_^
--文件名称:transfer.vhd
--函数功能:UART发送器,系统由五个状态(x_idle,x_start,x_wait,x_shift,x_stop)和一个进程构成
--作 者:萤火虫II号
--创建日期:2010.04.24
--版 本:Quartus II 7.2
--------------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity transfer is
generic(framlent : integer:=8); --transfer paramater
port(
bclkt : in std_logic;
resett : in std_logic;
xmit_cmd_p : in std_logic;
txdbuf : in std_logic_vector(7 downto 0):="11001010";
txd : out std_logic;
txd_done : out std_logic
);
end transfer;
architecture beha of transfer is
type states is(x_idle,x_star,x_wait,x_shift,x_stop); --define Sub state
signal state : states := x_idle;
signal tcnt : integer:=0;
begin
process(bclkt,resett,xmit_cmd_p,txdbuf) --master control time sequence,combination course
variable xcnt16 : std_logic_vector(4 downto 0):="00000"; --define the middle variable
variable xbitcnt : integer:=0;
variable txds : std_logic;
begin
if resett='1' then state<=x_idle;txd_done<='0';txds:='1'; --reset
elsif rising_edge(bclkt) then
case state is
when x_idle=> --the first state :wait for send data command
if xmit_cmd_p='1' then state<=x_star;txd_done<='0';
else state<=x_idle;
end if;
when x_star=> -- the second state: send the start bit of signal
if xcnt16>="01111" then state<=x_wait;xcnt16:="00000";
else xcnt16:=xcnt16+1;txds:='0';state<=x_star;
end if;
when x_wait=> --the thrid state:wait state
if xcnt16>="01110" then
if xbitcnt="framlent" then state<=x_stop;xbitcnt:=0; --here parameter framlent is used,restraint the Bit of send data
else state<=x_shift;
end if;
xcnt16:="00000";
else xcnt16:=xcnt16+1;state<=x_wait;
end if;
when x_shift=>txds:=txdbuf(xbitcnt);xbitcnt:=xbitcnt+1;state<=x_wait; --the fourth state: serialized data
when x_stop=> --the fifith state: stop sending data
if xcnt16>="01111" then
if xmit_cmd_p='0' then state<=x_idle;xcnt16:="00000";
else xcnt16:=xcnt16;state<=x_stop;
end if;
txd_done<='1';
else xcnt16:=xcnt16+1;txds:='1';state<=x_stop;
end if;
when others=>state<=x_idle;
end case;
end if;
txd<=txds;
end process;
end beha;
--because the Version of Quartus II 7.2 does not support annotation in Chinese,so I tryto ---annotate some words in English,for my poor English,
--I can't annotate exactly,but as mark I can understand it ^_^ ,and you?
和接收器类似,也是用的状态机,哦,对它和接收器都用到的了参数传递generic,这个俺以关没有用过,见到时才临时翻语法的,真是惭愧。
四、顶层映射文件
--------------------------------------------------------------------------------------------
-- 每天进步一点点,开心一大点^_^
--文件名称:top.vhd
--函数功能:实现USART顶层映射
--作 者:萤火虫II号
--创建日期:2010.04.23
--------------------------------------------------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY top IS
PORT(
clk32mhz : IN STD_LOGIC; --总的输入输出信号的定义
reset : IN STD_LOGIC; --复位信号
rxd : IN STD_LOGIC;
xmit_cmd_p_in : IN STD_LOGIC;
rec_ready : OUT STD_LOGIC;
txd_out : OUT STD_LOGIC;
txd_done_out : OUT STD_LOGIC;
txd_buf_in : IN STD_LOGIC_VECTOR(7 DOWNTO 0); --待发送数据输入
rec_buf : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)--接收数据缓冲
);
END top;
ARCHITECTURE beha OF top IS
component reciever
port(
bclkr : in std_logic; --接收时钟
resetr : in std_logic; --复位
rxdr : in std_logic;
r_ready: out std_logic;
rbuf : out std_logic_vector(7 downto 0)
);
end component;
component transfer
port(
bclkt : in std_logic;
resett : in std_logic;
xmit_cmd_p : in std_logic;
txdbuf : in std_logic_vector(7 downto 0);
txd : out std_logic;
txd_done : out std_logic
);
end component;
component baud
port(
clk,resetb : in std_logic;
bclk : out std_logic
);
end component;
signal b : std_logic;
begin
u1 : baud port map(clk=>clk32mhz, resetb=>reset, bclk=>b); --顶层映射
u2 : reciever port map(bclkr=>b, resetr=>reset, rxdr=>rxd, r_ready=>rec_ready, rbuf=>rec_buf);
u3 : transfer port map(bclkt=>b, resett=>reset, xmit_cmd_p=>xmit_cmd_p_in,txdbuf=>txd_buf_in, txd=>txd_out,
txd_done=>txd_done_out);
end beha;
这是顶层映射文件,就是把各个模块连起来,组成一个真正的“东西”,用到的关键词就是MAP,这就像生产汽车 一样,把轮子了,发动机了组装起来。关键就是声明正确,不要映射错了。
这个UART没有在硬件上测试(惭愧,没有弄开发板,但最近在自己画),只是软件仿真了一下,时序正确,所以哪位要想在实际中运用,注意再验证一下,我在这里只是学习之用,这也只是验证书上的例子,不过代码全是自己敲上去的,也好好研究了一下原理,才写下的学习日志。
每天进步一点点,开心多一点^_^
文章评论(0条评论)
登录后参与讨论