原创 VHDL学习日志(八)--实现简单URAT

2010-4-25 17:14 4340 7 7 分类: FPGA/CPLD

         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没有在硬件上测试(惭愧,没有弄开发板,但最近在自己画),只是软件仿真了一下,时序正确,所以哪位要想在实际中运用,注意再验证一下,我在这里只是学习之用,这也只是验证书上的例子,不过代码全是自己敲上去的,也好好研究了一下原理,才写下的学习日志。
  
  
  
 每天进步一点点,开心多一点^_^
  
  
  
  
 

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
7
关闭 站长推荐上一条 /3 下一条