• FPGA-结合协议时序实现UART收发器(二):串口发送模块实现uart_tx


    FPGA-结合协议时序实现UART收发器(二):串口发送模块实现uart_tx


    实现架构框图中的uart_tx串口发送模块功能。


    一、功能实现

    对照代码,串口发送模块uart_tx实现功能包括:

    • ro_user_tx_ready,握手,控制发送数据
    • r_cnt,计数信号,计数数据
    • r_tx_data ,寄存数据
    • ro_uart_tx ,发送寄存数据
    • r_tx_check ,计算校验位

    二、uart_tx代码

    `timescale 1ns / 1ps
    //
    // Company: 
    // Engineer: 
    // 
    // Create Date: 2023/09/09 13:06:58
    // Design Name: 
    // Module Name: uart_tx
    // Project Name: 
    // Target Devices: 
    // Tool Versions: 
    // Description: 
    // 
    // Dependencies: 
    // 
    // Revision:
    // Revision 0.01 - File Created
    // Additional Comments:
    // 
    //
    
    
    module uart_tx#(
        //串口可调参数
        parameter    P_SYSTEM_CLK        = 50_000_000,    
        parameter    P_UART_BUADRATE    = 9600,
        parameter    P_UART_DATA_WIDTH  = 8,
        parameter    P_UART_STOP_WIDTH  = 1,
        parameter    P_UART_CHECK       = 0
    )( 
        //串口驱动输入输出
        input   i_clk   ,
        input   i_rst   ,
        
    
        output  o_uart_tx,
    
        input   [P_UART_DATA_WIDTH - 1 : 0] i_user_tx_data  ,//用户输出数据,作为驱动的输入,即先输入到驱动处理再输出
        input                               i_user_tx_valid ,//握手
        output                              o_user_tx_ready 
    
    );
    
    //只要有output信号,就要有reg,因为需要寄存器进行输出
    reg                                             ro_uart_tx;
    reg                                             ro_user_tx_ready;   
    reg [15:0]                                      r_cnt;//计数器位宽高于16bit时,组合逻辑的逻辑级数过高,谨慎使用。
    reg [P_UART_DATA_WIDTH - 1 : 0]                 r_tx_data;
    reg                                             r_tx_check;       
    
    
    //发送激活信号
    wire                w_tx_active;
    
    
    
    assign              o_uart_tx = ro_uart_tx;
    assign              o_user_tx_ready = ro_user_tx_ready;
    assign              w_tx_active = i_user_tx_valid & o_user_tx_ready;//valid和ready都为1时才激活发送,达成握手
    
    
    
    
    
    //处理ready信号
    //重点处理可以握手的情况,已经达成激活握手时ro_user_tx_ready == 0,即此时没有ready即不需要握手,因为正在握手传数据
    //待数据处理完毕时,ro_user_tx_ready == 1,即可以再次握手了,可以再次发送数据了
    always @(posedge i_clk or posedge i_rst)
    begin
        if (i_clk) 
            ro_user_tx_ready <= 'd1;//协议初始状态是高位    
        else if (w_tx_active) 
            ro_user_tx_ready <= 'd0;//已经激活了,正在发送数据,暂时不需要进行握手
        else if(r_cnt == 2 + P_UART_DATA_WIDTH + P_UART_STOP_WIDTH - 3 && P_UART_CHECK == 0)//2 + P_UART_DATA_WIDTH + P_UART_STOP_WIDTH - 3 表示计数到校验位位置(根据uart协议来看),并且没有开启校验位,即此时也计数完毕了,可以再次握手了
            ro_user_tx_ready <= 'd1;
        else if(r_cnt == 2 + P_UART_DATA_WIDTH + P_UART_STOP_WIDTH - 2 && P_UART_CHECK > 0)//2 + P_UART_DATA_WIDTH + P_UART_STOP_WIDTH - 2 表示计数到校验位位置,并且开启了校验位,即此时也计数完毕了,可以再次握手了
            ro_user_tx_ready <= 'd1;
        else
            ro_user_tx_ready <= ro_user_tx_ready;
    end
    
    //处理r_cnt计数信号
    always @(posedge i_clk , posedge i_rst) 
    begin
        if (i_rst)
            r_cnt <= 'd0;
        else if(r_cnt == 1 + P_UART_DATA_WIDTH + P_UART_STOP_WIDTH + P_UART_CHECK -1)//计数完毕
            r_cnt <= 'd0;
        else if(!ro_user_tx_ready)//ro_user_tx_ready==0说明发送激活,可以发送数据
            r_cnt <= r_cnt + 1;
        else
            r_cnt <= r_cnt;
    
    end
    
    //处理用户发送数据,寄存在r_tx_data
    //进行用户发送数据寄存操作
    always @(posedge i_clk or posedge i_rst) 
    begin
        if(i_rst)
            r_tx_data <= 'd0;
        else if(w_tx_active)
            r_tx_data <= i_user_tx_data;
        else if(!ro_user_tx_ready)
            r_tx_data <= r_tx_data >> 1;//ro_user_tx_ready==0,可发送数据,移位后发送r_tx_data的低位给ro_uart_tx
        else
            r_tx_data <= r_tx_data;
    end 
    
    //处理串口发送输出操作
    //将用户寄存的数据发送出去
    always @(posedge i_clk or posedge i_rst) 
    begin
        if(i_rst)
            ro_uart_tx <= 'd1;//uart协议空闲状态为1,所以最初值就是1
        else if(w_tx_active)
            ro_uart_tx <= 'd0;//起始位为0
        else if(r_cnt == 3 + P_UART_DATA_WIDTH - 3 && P_UART_CHECK > 0)//当r_cnt计数到校验位,且开启校验位时
            ro_uart_tx <= P_SYSTEM_CLK == 1 ? ~r_tx_check : r_tx_check;
        else if(r_cnt == 3 + P_UART_DATA_WIDTH - 3 && P_UART_CHECK == 0)//当r_cnt计数到校验位,且不开启校验位时,直接发送停止位高电平
            ro_uart_tx <= 'd1;//直接拉高
        else if(r_cnt == 3 + P_UART_DATA_WIDTH - 2 && P_UART_CHECK > 0)//有校验位时,且发送完了校验位,此时改发送停止位了,停止位发送高电平
            ro_uart_tx <= 'd1;
        else if(!ro_user_tx_ready)
            ro_uart_tx <= r_tx_data[0];//ro_user_tx_ready==0可以发送数据,进行移位发送,uart先发送低位再发送高位
        else
            ro_uart_tx <= 'd1;
    
    end
    
    //处理校验位r_tx_check,计算校验位
    always @(posedge i_clk or posedge i_rst) 
    begin
        if(i_rst)
            r_tx_check <= 'd0;
        else if(r_cnt == 3 + P_UART_DATA_WIDTH - 1)
            r_tx_check <= 'd0;
        else
            r_tx_check <= r_tx_check ^ r_tx_data[0];
    
    end
    
    
    endmodule
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145

    总结

    串口发送模块uart_tx的功能实现,代码根据协议和时序进行实现,采用了握手来控制发送数据,具体详情可参考代码注释内容。

  • 相关阅读:
    【数据库三大范式】让我们来聊一聊数据库的三大范式和反范式设计
    [EIS 2019]EzPOP
    数字ic验证门槛高吗?
    MacOS ventura跳过配置锁
    一个由硬链接引发的问题
    【表达式计算】表达式计算问题的通用解法(练习加强版,含总结)
    DicomObjects COM 8.XX.1102.0: 2022-10-18
    1686. 石子游戏 VI
    7-126 2018我们要赢
    写一个flutter程序
  • 原文地址:https://blog.csdn.net/Bellwen/article/details/132836303