UART的VHDL实现

串口原理

标准的串口是接触到的RSR232串口,工业上用的比较多,而我们实际中使用的串口则是在这基础上的简化,只用其中三根线TXD,RXD和地线。

串口通信是单线通信,数据在一根线上进行传输,而传输协议为:

一帧数据的开始拉低电平,表示开始传输数据;随后串行发送8位bit位,随后紧跟1到2个码元的高电平停止位,此时一帧数据传输完毕,等待下一帧数据传输。

数据的传输时间与码元宽度直接相关,而码元宽度由传输的波特率决定。

实现步骤

一个串口可以分为三个部分:波特率发生器,接受模块,发送模块

1.波特率发生器

该模块直接就是一个分频模块,直接对总时钟进行分频,我们预先规定一个码元的宽度为16个波特时钟,则波特率模块所要产生的波特时钟分频系数为sys_clk/波特率再乘以16,实际工程中系统时钟为50Mhz,所以分频系数为27.

2.接受模块

该模块实现依赖有限状态机,状态机共分为5个状态,分别为R_START,R_CENTER,R_WAIT,R_SAMPLE,R_STOP。

R_START:等待RX信号变为低电平,发生转变则说明数据开始准备接受,进入R_CENTER状态。

R_CENTER:计数8个时钟到达第一个bit中间位置,跳转到R_WAIT状态(码元宽度为16个波特时钟,8为半个码元,开始信号0的持续时间也为一个码元宽度,所以一共8个波特时钟进入)。

R_WAIT:等待16个波特时钟开始采样,进入R_SAMPLE状态,采样时刻对应到每一个数据的中点位置(中点位置判断最准确)。

R_SAMPLE:进行取值,输入到串并转换。取样8次则进入R_STOP状态。

R_STOP:不做具体检测,直接跳转R_START.

3.发送模块

该模块也分为5个状态,T_NONE,T_START,T_WAIT,T_SHIFT,T_STOP。具体的实现方法以及状态机的转换与接受相类似,这里就不再重复。

最后将三个模块进行整合就形成完整的串口模块,可以数据口共用,也可分开,由于是直接实现的,自由性比较大。

VHDL程序

废话不多说,直接上代码:

波特率模块

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity baud is
    generic(b_temp:integer:=27);
    port(clk:in std_logic;
          bclk:out std_logic);
end baud;
architecture behavior of baud is
begin
    process(clk)
    variable cnt:integer range 0 to b_temp;
    begin
        if clk'event and clk='1' then
            if cnt=b_temp then cnt:=0;bclk<='1';
            else cnt:=cnt+1;bclk<='0';
            end if;
        end if;
    end process;
end behavior;

接受模块

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity rxd is
    generic(data_bits:integer:=8);
    port(bclk_in,rxd_in:in std_logic;
          rx_ready:out std_logic;
          rx_buffer:out std_logic_vector(7 downto 0));
end rxd;
architecture beheavior of rxd is
type states is(r_start,r_center,r_wait,r_sample,r_stop);
signal state:states:=r_start;
signal rxd_sync:std_logic;
begin
    process(rxd_in)
    begin
        if rxd_in='0' then rxd_sync<='0';
        else rxd_sync<='1';
        end if;
    end process;

    process(bclk_in,rxd_sync)
    variable count:std_logic_vector(3 downto 0);
    variable r_cnt:integer:=0;
    variable buf:std_logic_vector(7 downto 0);
    begin
        if bclk_in'event and bclk_in='1' then
            case state is
                when r_start=>
                    if rxd_sync='0' then 
                        state<=r_center;
                        rx_ready<='0';
                        r_cnt:=0;
                    else state<=r_start;rx_ready<='0';
                    end if;
                when r_center=>
                    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_start;
                    end if;
                when r_wait=>
                    if count="1110" then
                        if r_cnt=data_bits then
                            state<=r_stop;
                        else
                           state<=r_sample;
                        end if;
                        count:="0000";
                    else
                        count:=count+'1';
                        state<=r_wait;
                    end if;
                when r_sample=>
                    buf(r_cnt):=rxd_sync;
                    r_cnt:=r_cnt+1;
                    state<=r_wait;
                when r_stop=>
                    rx_ready<='1';
                    rx_buffer<=buf;
                    state<=r_start;
                when others=>
                    state<=r_start;
            end case;               
        end if;
    end process;
end beheavior;

发送模块

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity txd is
    generic(data_bits:integer:=8);
    port(bclk_in:in std_logic;
         tx_cmd:in std_logic;
          txd_out:out std_logic;
          txd_done:out std_logic;
          tx_buffer:in std_logic_vector(7 downto 0));
end txd;
architecture beheavior of txd is
type states is(t_none,t_start,t_wait,t_shift,t_stop);
signal state:states:=t_none;
signal t_cnt:integer:=0;
begin
    process(bclk_in,tx_cmd,tx_buffer)
    variable count:std_logic_vector(4 downto 0);
    variable t_bitcnt:integer:=0;
    variable txds:std_logic;
    begin
        if bclk_in'event and bclk_in='1' then
            case state is
                when t_none=>
                    if tx_cmd='1' then
                        state<=t_start;
                        txd_done<='0';
                    else
                        state<=t_none;
                    end if;
                when t_start=>
                    if count="01111" then 
                        state<=t_shift;
                        count:="00000";
                    else
                        count:=count+'1';
                        txds:='0';
                        state<=t_start;
                    end if;
                when t_wait=>
                    if count="01110" then
                        if t_bitcnt=data_bits then
                            state<=t_stop;
                            t_bitcnt:=0;
                            count:="00000";
                        else
                            state<=t_shift;
                        end if;
                        count:="00000";
                    else
                        count:=count+'1';
                        state<=t_wait;
                    end if;
                when t_shift=>
                    txds:=tx_buffer(t_bitcnt);
                    t_bitcnt:=t_bitcnt+1;
                    state<=t_wait;
                when t_stop=>
                    if count="01111" then
                        if tx_cmd='0' then
                            state<=t_none;
                            count:="00000";
                        else
                            count:=count;
                            state<=t_stop;
                        end if;
                        txd_done<='1';
                    else
                        count:=count+'1';
                        txds:='1';
                        state<=t_stop;
                    end if;
                when others=>state<=t_none;
            end case;
        end if;
        txd_out<=txds;
    end process;
end beheavior;

顶层模块

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity my_uart is
port(clk_in:in std_logic;
      rx:in std_logic;
      tx:out std_logic;
      tcmd:in std_logic;
      tx_done:out std_logic;
      rx_ready:out std_logic;
      t_data:in std_logic_vector(7 downto 0);
      r_data:out std_logic_vector(7 downto 0));
end my_uart;
architecture beheavior of my_uart is
component baud is
port(clk:in std_logic;
     bclk:out std_logic);
end component;

component rxd is
port(bclk_in,rxd_in:in std_logic;
      rx_ready:out std_logic;
      rx_buffer:out std_logic_vector(7 downto 0));
end component;

component txd is
port(bclk_in:in std_logic;
      tx_cmd:in std_logic;
      txd_out:out std_logic;
      txd_done:out std_logic;
      tx_buffer:in std_logic_vector(7 downto 0));
end component;

signal baud_clk:std_logic;
begin
B:baud 
port map(clk_in,baud_clk);
R:rxd
port map(baud_clk,rx,rx_ready,r_data);
T:txd
port map(baud_clk,tcmd,tx,tx_done,t_data);
end beheavior;

代码没有注释,凑合看吧,嘻嘻

你可能感兴趣的:(fpga)