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

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


实现架构框图中的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


总结

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

你可能感兴趣的:(FPGA开发,fpga开发)