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