基于FPGA的UART接口实现

串行通讯是指外部设备与计算机间只使用一根数据线(另外须要地线,还可能须要控制线)进行数据传送的方式。数据在一根数据线上按位依次传送。因为CPU与接口之间按并行方式传输,接口与外设之间按串行方式传输,所以串行通讯的基本功能是:在发送时,把CPU送来的并行数据转换为串行数据,逐位依次发送出去;在接受时,把外部设备发送过来的的串行数据逐位地接受,组装成并行数据,并行地送给CPU去处理。异步

异步通讯是以一个字符做为传输方式,通讯中两个字符间的时间间隔多少不固定,但同一个字符的两个相邻位的时间间隔固定。通讯过程当中没有时钟线。code

UART使用的是串行异步通讯。blog

基本的UART通讯协议:接口

波特率:表示每秒钟传输字符数的多少input

起始位:通常为逻辑“0”it

数据位:通常位6~8位之间可变,数据低位在前,高位在后class

校验位:能够为无校验位,奇校验,偶校验,常“0”或常“1”之间可选module

中止位:必须为逻辑“1”sed

空闲位:处于逻辑“1”状态并行

 

UART发送功能模块:

`define     NONE    0       //无校验位
`define     ODD     1       //奇校验
`define     EVEN    2       //偶校验
`define     MARK    3       //常“1”
`define     SPACE   4       //常“0”

`define     STOPBITS_ONE     0      //1位中止位
`define     STOPBITS_ONEHALF 1      //1.5位中止位
`define     STOPBITS_TWO     2      //2位中止位
module uart_tx  #(
parameter   CLK_FREQ = 50_000_000,          //时钟频率
parameter   BPS = 9600,                     //波特率
parameter   PARITY = `NONE,                 //数据位宽
parameter   DATA_BITS = 8,                  //校验位
parameter   STOP_BITS = `STOPBITS_ONE       //中止位位宽
)
(
input                       clk,
input                       rst_n,
input       [DATA_BITS-1:0]  data,
input                       enable,     //定义一个发送使能信号

output      reg             tx,
output      wire            free        //定义一个发送端空闲状态
    );
reg     [DATA_BITS-1:0]  data_2 = 0;
reg     flag = 0;                           //定义一个flag信号来锁住enable
wire    stop_flag;                          //定义一个传输中止脉冲
reg     [31:0]  cnt = 0;
localparam  [31:0]  CNT_MAX =  CLK_FREQ/BPS;
reg     [2:0]   cstate = 0;
localparam  [2:0]
            FSM_IDEL    = 0,                //空闲位
            FSM_START   = 1,                //开始位
            FSM_DATA    = 2,                //数据位
            FSM_PARITY  = 3,                //校验位
            FSM_STOP    = 4;                //中止位
reg     ifparity = 0;                       //有无校验位
reg     parity_value = 0;                   //校验位的值 
reg     [3:0]   num = 0;                    //定义一个计数num
           
assign  free = ~flag;                       
assign  stop_flag = (cstate == FSM_STOP && ((STOP_BITS == `STOPBITS_ONE && cnt == CNT_MAX-1) || (STOP_BITS == `STOPBITS_ONEHALF && num == 1 && cnt == CNT_MAX>>1) || (STOP_BITS == `STOPBITS_TWO && num == 1 && cnt == CNT_MAX-1))) ? 1'b1 : 1'b0;

always  @(posedge   clk or  negedge rst_n)
    if  (!rst_n)
        data_2 <= 0;
    else    if  (enable && flag == 0)
        data_2 <= data;
    else    data_2 <= data_2;


always  @(posedge   clk or  negedge rst_n)
    if  (!rst_n)       
        flag <= 0;
    else    if  (enable)
        flag <= 1;
    else    if  (stop_flag)
        flag <= 0;
    else    flag <= flag;
    
   
always  @(posedge   clk or  negedge rst_n)
    if  (!rst_n)
        cnt <= 0;
    else    if  (cnt == CNT_MAX-1 || flag == 0 )
        cnt <= 0;
    else    if  (flag)
        cnt <= cnt + 1;
    else    cnt <= cnt;
    
    
always  @(posedge   clk or  negedge rst_n)
    if  (!rst_n)
        cstate <= FSM_IDEL; 
    else    case    (cstate)
                FSM_IDEL    :   begin
                                    tx <= 1;
                                    if  (flag)
                                        cstate <= FSM_START;
                                    else    cstate <= FSM_IDEL;
                                end
                FSM_START   :   begin
                                    tx <= 0;
                                    if  (cnt == CNT_MAX-1)
                                        cstate <= FSM_DATA;
                                    else    cstate <= FSM_START;      
                                end
                FSM_DATA    :   begin
                                    tx <= data_2 [num];
                                    if  (cnt == CNT_MAX-1 && num == DATA_BITS-1)
                                        begin
                                            num <= 0;
                                            cstate <= ifparity ? FSM_PARITY : FSM_STOP;
                                        end
                                    else    if  (cnt == CNT_MAX-1)
                                        num <= num + 1;
                                    else    num <= num;
                                end
                FSM_PARITY  :   begin
                                    tx <=  parity_value;
                                    if  (cnt == CNT_MAX-1)
                                         cstate <= FSM_STOP;
                                    else    cstate <= FSM_PARITY;
                                end
                FSM_STOP    :   begin
                                    tx <= 1;
                                    if  (STOP_BITS == `STOPBITS_ONE && cnt == CNT_MAX-1)
                                          cstate <= FSM_IDEL;
                                    else    if  (STOP_BITS == `STOPBITS_ONEHALF)  begin  
                                        if  (num == 1 && cnt == CNT_MAX>>1)
                                            begin   cstate <= FSM_IDEL; num <= 0; end
                                        else    if  (cnt == CNT_MAX-1)
                                            num <=1;
                                        else  cstate <= FSM_STOP;
                                    end
                                    else    if  (STOP_BITS == `STOPBITS_TWO)  begin
                                        if   (num == 1 && cnt == CNT_MAX-1)
                                            begin   cstate <= FSM_IDEL; num <= 0; end
                                        else    if  (cnt == CNT_MAX-1)
                                            num <=1;
                                        else  cstate <= FSM_STOP;
                                    end                                      
                                end
            default         :   cstate <= FSM_IDEL; 
            endcase
            
                
                
always  @(*)
    if  (!rst_n)
        begin
           ifparity = 0;    
           parity_value = 0; 
        end
    else    case    (PARITY)
            `NONE    :   begin
                            ifparity = 0;     
                            parity_value = 0;  
                         end
            `ODD     :   begin
                            ifparity = 1;     
                            parity_value = ~(^data_2);   
                         end  
            `EVEN    :   begin
                            ifparity = 1;     
                            parity_value = ^data_2;  
                         end  
            `MARK    :   begin
                            ifparity = 1;     
                            parity_value = 1; 
                         end  
            `SPACE   :   begin
                            ifparity = 1;     
                            parity_value = 0;
                         end
            default :    begin
                            ifparity = 0;    
                            parity_value = 0; 
                         end  
            endcase

UART接收功能模块:

`define     NONE    0       //无校验位
`define     ODD     1       //奇校验
`define     EVEN    2       //偶校验
`define     MARK    3       //常"1"
`define     SPACE   4       //常"0"

`define     STOPBITS_ONE        0       //1位中止位
`define     STOPBITS_ONEHALF    1       //1.5位中止位
`define     STOPBITS_TWO        2       //2位中止位
module uart_rx  #(
parameter   BPS = 9600,                 //波特率
parameter   CLK_FREQ = 50_000_000,      //时钟频率
parameter   DATA_BITS = 8,              //数据位宽
parameter   PARITY = `NONE,             //校验位
parameter   STOP_BITS = `STOPBITS_ONE   //中止位位宽
)
(
input       clk,
input       rst_n,
input       rx,

output      reg    [DATA_BITS-1:0] data,
output      reg     done,
output      reg     err
    );

    
reg     [1:0]   in;
always  @(posedge   clk or  negedge rst_n)
    if  (!rst_n)
        in <= 0;
    else    in <= {in[0],rx};
    
wire    en;
assign  en = (in[1] == 1 && in[0] == 0) ? 1 : 0;

reg     flag = 0;                               //定义一个接收信号标志位  
always  @(posedge   clk or  negedge rst_n)
    if  (!rst_n)
        flag <= 0;
    else    if  (en)
        flag <= 1;
    else    if  (cstate == FSM_STOP && sampling)
        flag <= 0;
    else    flag <= flag;
    
reg     [31:0]  cnt = 0;
localparam  [31:0]  CNT_MAX = CLK_FREQ/BPS;
always  @(posedge   clk or  negedge rst_n)
    if  (!rst_n)
        cnt <= 0;
    else    if  (cnt == CNT_MAX-1 || flag == 0)
        cnt <= 0;
    else    if  (flag)
        cnt <= cnt + 1;
    else    cnt <= cnt;
    
reg     sampling = 0;                               //定义一个采样脉冲信号     
always  @(posedge   clk or  negedge rst_n)
    if  (!rst_n)
        sampling = 0;
    else    if  (cnt == CNT_MAX>>1)
        sampling = 1;
    else     sampling = 0;
    
    
reg     [3:0]   num = 0;                                //定位计数num
reg     ifparity = 0;                                   //有无校验位
reg     parity_value = 0;                               //定义校验位的值
reg     parity_rx = 0;                                  //定义接受信号中校验位的值
reg     [2:0]   cstate = 0;
localparam  [2:0]
            FSM_IDEL    = 0,                            //空闲位
            FSM_START   = 1,                            //开始位
            FSM_DATA    = 2,                            //数据位
            FSM_PARITY  = 3,                            //校验位
            FSM_STOP    = 4;                            //中止位
            
always  @(posedge   clk or  negedge rst_n)
    if  (!rst_n)    begin
        cstate <= FSM_IDEL;
        parity_rx <= 0;
        done <= 0;
        err <= 0;
        data <= 0;       
        num <= 0;
    end
    else    case    (cstate)
                FSM_IDEL    :   if  (flag)
                                    cstate <= FSM_START;
                                else    cstate <= FSM_IDEL;           
                FSM_START   :   begin
                                    done <= 0;
                                    if  (sampling)
                                        cstate <= FSM_DATA;
                                    else    cstate <= FSM_START;
                                end          
                FSM_DATA    :   if  (sampling && num <= DATA_BITS-1)
                                    begin
                                        data[num] <= rx;
                                        num <= num + 1;    
                                    end
                                else    if  (num == DATA_BITS)    begin
                                    num <= 0;
                                    cstate <= ifparity ? FSM_PARITY : FSM_STOP ;
                                end
                FSM_PARITY  :   if  (sampling)
                                    begin
                                        parity_rx <= rx;
                                        cstate <= FSM_STOP;
                                    end
                                else    cstate <= FSM_PARITY;
                FSM_STOP    :   if  (sampling)
                                    begin
                                        done <= 1;
                                        cstate <= FSM_IDEL;
                                        err <= ifparity ? (parity_rx == parity_value ? 0 : 1) : 0;
                                    end
                                else    cstate <= FSM_STOP;
            default         :   begin
                                    cstate <= FSM_IDEL;
                                    parity_rx <= 0;
                                    done <= 0;
                                    err <= 0;       
                                end
            endcase
                
    
always  @(*)
    if  (!rst_n)    begin
        ifparity = 0;
        parity_value = 0;
    end
    else    case    (PARITY)
                `NONE    :  begin   ifparity = 0; parity_value = 0; end         
                `ODD     :  begin   ifparity = 1; parity_value = ~(^data);  end  
                `EVEN    :  begin   ifparity = 1; parity_value = ^data;  end
                `MARK    :  begin   ifparity = 1; parity_value = 1;  end 
                `SPACE   :  begin   ifparity = 1; parity_value = 0;  end
             default     :  begin   ifparity = 0; parity_value = 0; end
             endcase
    
endmodule
相关文章
相关标签/搜索