FPGA-结合协议时序实现UART收发器(五):串口顶层模块UART_TOP、例化PLL、UART_FIFO、uart_drive
串口顶层模块UART_TOP、例化PLL、UART_FIFO、uart_drive,功能实现。
文章目录
一、功能实现
对照代码,串口发送模块UART_TOP实现功能包括:
- PLL锁相环,实现稳定系统输入时钟功能
- UART_FIFO,数据先进先出,实现数据缓存功能,防止出现数据错乱
- w_clk_rst = ~w_system_pll_locked;保证复位电平是先高位再地位
- r_user_tx_ready,用户输出ready信号慢一拍,用于判断数据是否发送完毕,是否为结束状态
- r_rden_lock,fifo使能锁控制
- r_fifo_rden,fifo读使能情况
- r_uart_tx_vaild比FIFO中的读使能r_fifo_rden慢一拍,为实现有效信号和数据能够匹配上,所以对有效信号进行打一拍来延迟一个周期,从而实现信号和数据匹配,正确获取数据
一、UART_TOP代码
c
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/09/09 13:13:15
// Design Name:
// Module Name: UART_TOP
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//不要直接用系统时钟!!!
//要添加一个pll锁相环,进行滤波稳定时钟,方便后续处理
//
module UART_TOP(
//模块输入输出
input i_clk ,
input i_uart_rx ,
output o_uart_tx
);
wire w_clk_50Mhz;
wire w_clk_rst;
wire w_system_pll_locked;
wire [7:0] w_user_tx_data;
wire w_user_tx_ready;
wire [7:0] w_user_rx_data;
wire w_user_rx_vaild;
wire w_user_clk;
wire w_user_rst;
wire w_fifo_empty;
reg r_fifo_rden;
reg r_uart_tx_vaild;
reg r_rden_lock;//fifo使能锁
reg r_user_tx_ready;
//pll锁存器在时钟不稳定的时候是低电平,在稳定后是高电平,即先低电平后高电平
//系统中习惯使用复位信号先高后低,即上电先高电平进行复位,然后再低电平,故需进行取反
assign w_clk_rst = ~w_system_pll_locked;
system_pll system_pll_u0
(
.clk_in1 (i_clk), // input clk_in1
.clk_out1 (w_clk_50Mhz), // output clk_out1
.locked (w_system_pll_locked) // output locked
);
uart_drive#(
//串口可调参数
.P_SYSTEM_CLK (50_000_000),
.P_UART_BUADRATE (115200),
.P_UART_DATA_WIDTH (8),
.P_UART_STOP_WIDTH (1),
.P_UART_CHECK (0)
)
uart_drive_u0(
//串口驱动输入输出
.i_clk (w_clk_50Mhz),
.i_rst (w_clk_rst),
.i_uart_rx (i_uart_rx),
.o_uart_tx (o_uart_tx),
.i_user_tx_data (w_user_tx_data),//用户输出数据,作为驱动的输入,即先输入到驱动处理再输出
.i_user_tx_vaild (r_uart_tx_vaild),//握手
.o_user_tx_ready (w_user_tx_ready),
.o_user_rx_data (w_user_rx_data),//用户输入数据,作为驱动的输出,即先经过驱动输出再输入到用户
.o_user_rx_vaild (w_user_rx_vaild),
.o_user_clk (w_user_clk),
.o_user_rst (w_user_rst)
);
UART_FIFO UART_FIFO_U0 (
.clk (w_user_clk), // input wire clk
.srst (w_user_rst), // input wire srst
.din (w_user_rx_data), // input wire [7 : 0] din
.wr_en (w_user_rx_vaild), // input wire wr_en
.rd_en (r_fifo_rden), // input wire rd_en
.dout (w_user_tx_data), // output wire [7 : 0] dout
.full (), // output wire full
.empty (w_fifo_empty) // output wire empty
);
//处理用户输出ready信号慢一拍
//用于判断数据是否发送完毕,是否为结束状态
always @(posedge w_user_clk or posedge w_user_rst)
begin
if(w_user_rst)
r_user_tx_ready <= 'd0;
else
r_user_tx_ready <= w_user_tx_ready;
end
//处理fifo使能控制,使能锁r_rden_lock
//防止fifo使能持续两个周期,导致读取两个数据,但握手只会读取一个数据,就会导致数据丢失,故需要使能锁控制来fifo只持续一个周期
always @(posedge w_user_clk or posedge w_user_rst)
begin
if(w_user_rst) //初始状态
r_rden_lock <= 'd0;
else if(w_user_tx_ready && !r_user_tx_ready) //结束状态,当前为高电平1,前一拍为低电平,即上升沿判断为结束状态
r_rden_lock <= 'd0;
else if(~w_fifo_empty && w_user_tx_ready) //变化状态,即fifo内有数据+ready好了
r_rden_lock <= 'd1;
else
r_rden_lock <= r_rden_lock;
end
//处理fifo读使能情况,r_fifo_rden
always @(posedge w_user_clk or posedge w_user_rst)
begin
if(w_user_rst)
r_fifo_rden <= 'd0;
else if(~w_fifo_empty && w_user_tx_ready)
r_fifo_rden <= 'd1;
else
r_fifo_rden <= 'd0;
end
//因为发送的数据是比FIFO中的读使能r_fifo_rden满一个周期
//为实现有效信号和数据能够匹配上,所以对有效信号进行打一拍来延迟一个周期,从而实现信号和数据匹配,正确获取数据
always @(posedge w_user_clk or posedge w_user_rst)
begin
if(w_user_rst)
r_uart_tx_vaild <= 'd0;
else
r_uart_tx_vaild <= r_fifo_rden;
end
endmodule
总结
串口顶层模块UART_TOP、例化PLL、UART_FIFO、uart_drive,功能实现,数据缓存先进先出fifo实现,fifo使能控制等功能实现。