十六、uart(4)带FIFO缓存(浅显模式)

1、uart_tx.v

/*
*
*@Author: X-Z
*@Date:2023-02-09 12:44:54
*@Function:串口发送模块,将接收模块接收到的1帧10bit并行数据转换为10bit的串行数据并通过发送引脚tx输出送到pc机的接收引脚
*/

module  uart_tx(
    input    wire               clk        ,
    input    wire               rst_n      ,
    input    wire    [7:0]      din        ,//发送端送给接收端的有效的8bit并行数据
    input    wire               din_vld    ,//输入数据有效标志信号

    output   reg                uart_tx     , //发送引脚  
    output   wire               ready         //指示可以数据让它发送
);

    // wire [7:0] din;
    // //测试
    // assign din = 8'h5a;

    //波特率为115200时传输1位所需的时钟周期
    parameter CNT_MAX_BPS = 9'd433;//(50_000_000/115200)=434
    reg  [8:0] cnt_bps    ;
    wire       add_cnt_bps;
    wire       end_cnt_bps;

    reg [3:0]  cnt_bit    ;//计数0-9构成一帧数据
    wire       add_cnt_bit;
    wire       end_cnt_bit;

    //对din_vld信号时长延长
    reg             din_vld_flag;
    reg  [9:0]      data ;

    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            din_vld_flag <= 1'b0;
        end
        else if(end_cnt_bit && end_cnt_bps)begin//一帧数据发送完后拉低
            din_vld_flag <= 1'b0; 
        end
        else if(din_vld)begin
            din_vld_flag <= 1'b1;
        end
    end

    //1bit计数器
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_bps <= 1'b0;
        end
        else if(add_cnt_bps)begin
            if(end_cnt_bps)begin
                cnt_bps <= 1'b0;
            end
            else begin
                cnt_bps <= cnt_bps + 1'b1;
            end
        end
    end 

    assign add_cnt_bps = din_vld_flag;
    assign end_cnt_bps = add_cnt_bps && cnt_bps == CNT_MAX_BPS;

    //1帧数据计数器10bit
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_bit <= 1'b0;
        end
        else if(add_cnt_bit)begin
            if(end_cnt_bit)begin
                cnt_bit <= 1'b0;
            end
            else begin
                cnt_bit <= cnt_bit + 1'b1;
            end
        end
    end

    assign add_cnt_bit = end_cnt_bps;
    assign end_cnt_bit = add_cnt_bit && cnt_bit == 4'd9;
    
    always@(posedge clk or negedge rst_n)begin//一帧数据发送完后拉低
        if(!rst_n)
            data <= 10'd0;
        else if(din_vld)
            data <= {1'b1,din[7:0],1'b0};
    end 

    //根据通信协议发送数据帧的每一位
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            uart_tx <= 1'b1;//初始化空闲状态高电平
        end
        else if(din_vld_flag && cnt_bps == 1)
            uart_tx <= data[cnt_bit];
        else begin
            uart_tx <= uart_tx;//其他情况为空闲状态
        end
    end

    // always@(posedge clk or negedge rst_n)begin
    //     if(!rst_n)
    //         ready <= 1'b0;
    //     else if(end_cnt_bit)
    //         ready <= 1'b1; 
    //     else 
    //         ready <= 1'b0;    
    // end

    assign ready = ~din_vld_flag;//当tx发送数据的时候ready无效不能从fifo中读数据,只要发送完成才可以读取下一个数据
    
endmodule

2、uart_rx.v

module uart_rx (
    input     wire          clk         ,
    input     wire          rst_n       ,
    input     wire          uart_rx     ,

    output    reg  [7:0]    dout        ,
    output    reg           dout_vld      //数据接收完成标志信号
);

    //波特率为115200时传输1位所需的时钟周期
    parameter CNT_MAX_BPS = 9'd433;//(50_000_000/115200)=434
    reg  [8:0] cnt_bps    ;
    wire       add_cnt_bps;
    wire       end_cnt_bps;

    reg [3:0]  cnt_bit    ;//计数0-9构成一帧数据
    wire       add_cnt_bit;
    wire       end_cnt_bit;

    //同步打拍信号定义
    reg        rx_reg0;   
    reg        rx_reg1;

    //开始计数使能信号
    reg        start_en;

    wire       bit_flag;//指示提取到哪一bit了

    reg  [9:0] rx_data;//寄存并行数据

    //同步打拍rx信号
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            rx_reg0 <= 1'b1;
            rx_reg1 <= 1'b1;
        end
        else begin
            rx_reg0 <= uart_rx;//同步(跨时钟域处理信号会产生亚稳态)
            rx_reg1 <= rx_reg0;//打第一拍
        end
    end

    //nedge下降沿
    assign nedge = rx_reg1 && (~rx_reg0);

    //开始计数使能信号
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            start_en <= 1'b0;//复位初始化
        end
        else if(end_cnt_bit)
            start_en <= 1'b0;
        else if(nedge)begin
            start_en <= 1'b1;
        end
    end

    //1bit计数器
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_bps <= 1'b0;
        end
        else if(add_cnt_bps)begin
            if(end_cnt_bps)begin
                cnt_bps <= 1'b0;
            end
            else begin
                cnt_bps <= cnt_bps + 1'b1;
            end
        end
    end 

    assign add_cnt_bps = start_en;
    assign end_cnt_bps = add_cnt_bps && cnt_bps == CNT_MAX_BPS ;

    assign bit_flag = (cnt_bps == (CNT_MAX_BPS >> 1)) ? 1'b1:1'b0;//计数到一半给高电平

    //1帧数据计数器10bit
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_bit <= 1'b0;
        end
        else if(add_cnt_bit)begin
            if(end_cnt_bit)begin
                cnt_bit <= 1'b0;
            end
            else begin
                cnt_bit <= cnt_bit + 1'b1;
            end
        end
    end

    assign add_cnt_bit = end_cnt_bps;
    assign end_cnt_bit = add_cnt_bit && cnt_bit == 4'd9 ;

    //串并转换
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            rx_data <= 10'd0;
        else if(end_cnt_bit && end_cnt_bps)
            rx_data <= 10'd0;
        else if(bit_flag && start_en)
            rx_data <= {rx_reg1,rx_data[9:1]}; 
        else 
            rx_data <= rx_data;
    end

    //输出赋值
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            dout <= 8'd0;//复位初始化
        end
        else if(end_cnt_bit && end_cnt_bps)begin
            dout <= rx_data[8:1];
        end
    end

    //输出赋值
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            dout_vld <= 1'd0;//复位初始化
        end
        else if(end_cnt_bit && end_cnt_bps)begin
            dout_vld <= 1'b1;
        end
        else 
            dout_vld <= 1'b0;
    end

endmodule

3、control.v

module control(
    input       wire            clk        ,
    input       wire            rst_n      ,
    input       wire  [7:0]     rx_data    ,
    input       wire            rx_data_vld,
    input       wire            ready      ,//准备好开始fifo读信号控制rd_req

    output      wire   [7:0]    tx_data    ,
    output      wire            tx_data_vld
);

    wire            rd_req            ;
    wire            wr_req            ;
    wire            empty             ;
    wire            full              ;
    wire    [2:0]   usedw             ;

    reg             tx_flag           ;

    fifo_s  u_fifo_s (
        .aclr   ( ~rst_n    ),
        .clock  ( clk       ),
        .data   ( rx_data   ),
        .rdreq  ( rd_req    ),
        .wrreq  ( wr_req    ),

        .empty  ( empty     ),
        .full   ( full      ),
        .q      ( tx_data   ),
        .usedw  ( usedw     )
    );

    //只要fifo中数据大于4个就将fifo清空
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            tx_flag <= 1'b0;
        else if(usedw >= 3'd4) 
            tx_flag <= 1'b1;
        else if(empty)
            tx_flag <= 1'b0;//读空fifo后拉低
    end

    //写请求wr_req
    assign wr_req = ~full && rx_data_vld;//数据有效开始写

    assign rd_req = tx_flag && ready;

    assign tx_data_vld = rd_req;

endmodule

4、uart_top.v

/*
*
*@Author: X-Z
*@Date:2023-02-09 11:22:56
*@Function:串口通信顶层的设计
*/

module uart_top(
    input           clk         ,
    input           rst_n       ,
    input           uart_rx     ,//接收引脚

    output          uart_tx      //发送引脚
);

    //中间信号定义
    wire    [7:0]       rx_data,tx_data        ;//8bit的数据
    wire                rx_data_vld,tx_data_vld;
    wire                ready                  ;

    //例化接收模块uart_rx
    uart_rx u_uart_rx(
        .clk          (clk         ),
        .rst_n        (rst_n       ),
        .uart_rx      (uart_rx     ),

        .dout         (rx_data     ),
        .dout_vld     (rx_data_vld )   //10bit数据接收完成标志信号
    );

    //控制模块
    control u_control(
        .  clk        (clk        ),
        .  rst_n      (rst_n      ),
        .  rx_data    (rx_data    ),
        .  rx_data_vld(rx_data_vld),
        .  ready      (ready      ),//准备好开始fifo读信号控制rd_req

        .  tx_data    (tx_data    ),
        .  tx_data_vld(tx_data_vld)
    );

    //发送模块例化uart_tx
    uart_tx u_uart_tx(
        .clk           (clk        ),
        .rst_n         (rst_n      ),
        .din           (tx_data    ),
        .din_vld       (tx_data_vld),//发送端输入数据有效标志信号

        .uart_tx       (uart_tx    ),
        .ready         (ready      )                 
    );


endmodule

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值