【接口协议】FPGA实现UART协议进行数据的发送与接收

0.序言

使用vivado联合modelsim实现UART协议进行数据发送与接收。

1.UART协议简介

(1)定义

通用异步收发传输器,是一种异步全双工串行接口协议,是异步串行通信的总称。存在多种通信接口和总线标准,包括RS232/RS449/RS422等。

(2)结构

在这里插入图片描述

RXD:数据接收引脚;
TXD:数据发送引脚;
GND:公共地,通讯时设备需要同时接地;

(3)接口协议

在这里插入图片描述
起始位:一般以逻辑0表示;
有效数据位:通常有效数据位的长度有5/6/7/8位;
校验位:校验传输的正确性,奇校验/偶校验等;
停止位:可有0.5,1,1.5,2个逻辑1表示;
波特率:单位时间内传输的码元个数,常用的波特率为9600/19200/38400/15200,通信双方的波特率要一致

2.实例

(1)结构框图及时序图

(A)结构框图

测试模块提供需要传输的数据和数据有效标志,通过发送模块(MCU1_send)进行编码成UART协议格式数据进行发送,并在接收模块(MCU2_receive)还原数据,最后输出还原好的数据。
在这里插入图片描述

(B)发送模块时序图

在这里插入图片描述
Data_in:首先给发送模块一个需要发送的数据,首先会将数据缓存;
Data_valid:数据有效标志,也标志着一个数据传输的开始;
Tx_flag:发送过程有效标志,在整个传输帧拉高,传输结束拉低,拉低标志是uart_done_flag的下降沿;
Clk_cnt:波特率周期计数器,波特率使用的是9600,系统时钟位52MHz,每个数据发送的周期是52M /9600=5208;
Tx_cnt:UART发送数据状态计数,共有10个状态;
Txd:发送数据线上的数据;
Uart_done_flag:发送结束标志信号;
注意:tx_cnt/txd和uart_done_flag每个状态对应5208个时钟周期

(C)接收数据时序图

在这里插入图片描述
rxd:接收数据线接收到的数据;
Rx_flag:接收过程有效标志,开始于rxd空闲状态开始的下降沿,结束于rx_done_flag的下降沿;
Clk_cnt:波特率周期计数器,同发送一致,要与rxd每个数据对齐;
Tx_cnt:UART接收数据状态计数,共有10个状态;
rx_done_flag:接收结束标志信号;
data_out[7:0]:接收的数据进行输出
注意:
rx_cnt/rxd和uart_done_flag每个状态对应5208个时钟周期

为了保证数据的稳定性,我们一般取值在数据周期的中间,即clk_cnt计数到2603时将传输的数据取出

(2)代码

(A)test_bench

说明:例化了顶层模块,并间隔一段时间产生一个数据和数据有效标志,这里连续发送两个数据

`timescale 1ns / 1ps
module tb_UART_interface;
    reg             clk         ;     
    reg             rst_n       ;   
    reg     [7:0]   data_in     ; 
    reg             data_valid  ;
    wire    [7:0]   data_out    ;

    parameter T = 20;

    always#(T/2)clk = ~clk;


    UART_interface u_UART_interface(
        .clk            (clk       ),
        .rst_n          (rst_n     ),
        .data_in        (data_in   ),
        .data_valid     (data_valid),
        .data_out       (data_out  )
    );

    initial begin
        clk = 1'b1;
        rst_n = 1'b0;
        data_in = 8'd0;
        data_valid <= 1'b0;
        #T;
        rst_n = 1'b1;
        #T;
        data_in = 8'b0011_0101;
        data_valid = 1;
        #T;
        data_in = 8'b0;
        data_valid = 0;
        #(T*60000);
        data_in = 8'b1110_0001;
        data_valid = 1;
        #T;
        data_in = 8'b0;
        data_valid = 0;

    end
endmodule

(B)顶层模块

说明:例化了发送数据模块和接收数据模块

module UART_interface(
    input                   clk         ,
    input                   rst_n       ,
    input       [7:0]       data_in     ,
    input                   data_valid  ,
    output      [7:0]       data_out
    );
    wire UART_txd;
    UART_send u_UART_send(
        .clk         (clk),
        .rst_n       (rst_n),
        .data_in     (data_in),
        .data_valid  (data_valid),
        .UART_txd(UART_txd)
    );
    UART_receive u_UART_receive(
        .clk        (clk),
        .rst_n      (rst_n),
        .UART_rxd   (UART_txd),
        .data_out   (data_out) 
    );
endmodule

(C)发送数据模块

module UART_send(
    input                   clk         ,
    input                   rst_n       ,
    input       [7:0]       data_in     ,
    input                   data_valid  ,
    output reg              UART_txd
    );
    
    //输入数据暂存
    reg [7:0] data_in_r;
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            data_in_r <= 8'd0;
        else if(data_valid)
            data_in_r <= data_in;
        else
            data_in_r <= data_in_r;
    end


    //发送过程有效标志
    reg tx_done_flag;
    reg tx_done_flag_r;
    reg tx_flag;
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            tx_flag <= 1'b0;
        else if(data_valid == 1'b1)
            tx_flag <= 1'b1; 
        else if(tx_done_flag_r&(~tx_done_flag))
            tx_flag <= 1'b0;
        else
            tx_flag <=tx_flag;
    end


    //波特率周期计数器,在发送过程有效标志有效时计数
    reg [12:0] clk_cnt;
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            clk_cnt <= 13'd0;
        else if(tx_flag == 1'b1)begin
            if(clk_cnt == 13'd5207)
                clk_cnt <= 13'd0;
            else
                clk_cnt <= clk_cnt + 1'b1;
        end
        else
            clk_cnt <= 13'd0;
    end


    //UART发送数据状态计数,共有10个状态
    reg [3:0] tx_cnt;
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            tx_cnt <= 4'd0;
        else if(tx_flag == 1'b1)begin
            if(clk_cnt == 13'd5207)begin
                if(tx_cnt < 4'd9)
                    tx_cnt <= tx_cnt + 1'b1;
                else 
                    tx_cnt <= 4'd0;
            end
            else
                tx_cnt <= tx_cnt;
        end
        else
            tx_cnt <= 4'd0;
    end

    
    //txd赋值,默认值即空闲状态为高电平
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            UART_txd <= 1'b1;
        else if(tx_flag == 1'b1) begin
            case(tx_cnt)
                4'd0:begin UART_txd <= 1'b0; end
                4'd1:begin UART_txd <= data_in_r[0]; end
                4'd2:begin UART_txd <= data_in_r[1]; end
                4'd3:begin UART_txd <= data_in_r[2]; end
                4'd4:begin UART_txd <= data_in_r[3]; end
                4'd5:begin UART_txd <= data_in_r[4]; end
                4'd6:begin UART_txd <= data_in_r[5]; end
                4'd7:begin UART_txd <= data_in_r[6]; end
                4'd8:begin UART_txd <= data_in_r[7]; end
                4'd9:begin UART_txd <= 1'b1; end
                default:begin UART_txd <= 1'b1; end
            endcase
        end
        else
            UART_txd <= 1'b1;
    end


    //发送完成标志位
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            tx_done_flag <=  1'b0;
        else if(tx_cnt == 4'd9)
            tx_done_flag <= 1'b1;
        else
            tx_done_flag <= 1'b0;
    end
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            tx_done_flag_r <=  1'b0;
        else 
            tx_done_flag_r <= tx_done_flag;
    end

endmodule

(D)接收数据模块

module UART_receive(
    input               clk     ,
    input               rst_n   ,
    input               UART_rxd,
    output reg [7:0]    data_out 
    );


    //接收过程有效标志信号,用过数据的下降沿得到,接收结束后归0
    reg uart_rxd_r;
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            uart_rxd_r <= 1'b0;
        else
            uart_rxd_r <= UART_rxd;
    end

    reg rx_done_flag;
    reg rx_done_flag_r;
    reg rx_flag;
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            rx_flag <= 1'b0;
        else if(uart_rxd_r&(~UART_rxd))
            rx_flag <= 1'b1;
        else if(rx_done_flag_r&(~rx_done_flag))
            rx_flag <= 1'b0;
        else
            rx_flag <= rx_flag;
    end


    //波特率周期计数器,在发送过程有效标志有效时计数
    reg [12:0] clk_cnt;
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            clk_cnt <= 13'd0;
        else if(rx_flag == 1'b1)begin
            if(clk_cnt == 13'd5207)
                clk_cnt <= 13'd0;
            else
                clk_cnt <= clk_cnt + 1'b1;
        end
        else
            clk_cnt <= 13'd0;
    end
    
    //UART接收数据状态计数,共有10个状态
    reg [3:0] rx_cnt;
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            rx_cnt <= 4'd0;
        else if(rx_flag == 1'b1)begin
            if(clk_cnt == 13'd5207)begin
                if(rx_cnt < 4'd9)
                    rx_cnt <= rx_cnt + 1'b1;
                else 
                    rx_cnt <= 4'd0;
            end
            else
                rx_cnt <= rx_cnt;
        end
        else
            rx_cnt <= 4'd0;
    end

    //rxd赋值,将传输的有效数据取出
    reg [7:0] data_out_r;
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            data_out <= 8'd0;
            data_out_r <= 8'd0;
        end
        else if(rx_flag == 1'b1) begin
            case({rx_cnt,clk_cnt})
                {4'd1,13'd2603}:begin data_out_r[0] <= UART_rxd; end
                {4'd2,13'd2603}:begin data_out_r[1] <= UART_rxd; end
                {4'd3,13'd2603}:begin data_out_r[2] <= UART_rxd; end
                {4'd4,13'd2603}:begin data_out_r[3] <= UART_rxd; end
                {4'd5,13'd2603}:begin data_out_r[4] <= UART_rxd; end
                {4'd6,13'd2603}:begin data_out_r[5] <= UART_rxd; end
                {4'd7,13'd2603}:begin data_out_r[6] <= UART_rxd; end
                {4'd8,13'd2603}:begin data_out_r[7] <= UART_rxd; end
                {4'd9,13'd0}:begin data_out <= data_out_r;  end
                default:begin data_out_r <= data_out_r; end
            endcase
        end
        else begin
            data_out_r <= 8'd0;
            data_out <= data_out;
        end
    end

    //接收完成标志位
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            rx_done_flag <=  1'b0;
        else if(rx_cnt == 4'd9)
            rx_done_flag <= 1'b1;
        else
            rx_done_flag <= 1'b0;
    end
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            rx_done_flag_r <=  1'b0;
        else 
           rx_done_flag_r <= rx_done_flag;
    end
endmodule

(3)结果

(A)顶层模块

发送了两个数据,8’b0011_0101和8’b1110_0001,最终收到的数据是一致的;
在这里插入图片描述

(B)发送数据模块

以发送第一个数据8’b0011_0101为例;
在这里插入图片描述

(C)接收数据模块

以接收第一个数据8’b0011_0101为例
在这里插入图片描述

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值