小梅哥课程学习——串口发送应用之发送数据(可在vivado中仿真出现正确波形)

2023-03-12,,

//1、底层代码源代码发送10位数据
module uart_pr(
clk,
reset_n,
send_go,
data,
baud_set,
tx_done,
uart_tx
);
input clk;
input reset_n;
input send_go;
input [7:0]data;
input [2:0]baud_set;
output reg tx_done;
output reg uart_tx; //再书写关于bps_DR的选择计算
reg [17:0] bps_DR;
always@(*)
case(baud_set)
0:bps_DR=50000000/9600;
1:bps_DR=50000000/19200;
2:bps_DR=50000000/38400;
3:bps_DR=50000000/57600;
4:bps_DR=50000000/115200;
default:bps_DR=50000000/9600;
endcase
reg send_en;
always@(posedge clk or negedge reset_n)
if(!reset_n)
send_en<=0;
else if(send_go)//记住这边只能用顶层的计数counter,不能用底层的div_cnt以及bps_cnt;
send_en<=1;
else if(tx_done)
send_en<=0; //存储数据
reg [7:0]r_data;
always@(posedge clk or negedge reset_n)//这里为什么不需要复位的下降沿
if(!reset_n)
r_data<=0;
else if(send_go)
r_data<=data;
else
r_data<=r_data;
//首先书写对应波特率的计数,分频div_cnt
//根据最低的波特率来确定div_cnt的宽度
reg [17:0]div_cnt;
always@(posedge clk or negedge reset_n)
if(!reset_n)
div_cnt<=0;
else if(send_en)begin
if(div_cnt==bps_DR-1)
div_cnt<=0;
else
div_cnt<=div_cnt+1'b1;
end
else
div_cnt<=0; wire bps_clk;
assign bps_clk=(div_cnt==1);
//开始书写下一个计数bps_cnt,来实现10为数据的发送
reg [3:0] bps_cnt;
always@(posedge clk or negedge reset_n)
if(!reset_n)
bps_cnt<=0;
else if(send_en)begin
if(bps_clk)begin
if(bps_cnt==11)
bps_cnt<=0;
else
bps_cnt<=bps_cnt+1'b1;
end
end
else
bps_cnt=0;
//开始书写发送10位的数据
always@(posedge clk or negedge reset_n)
if(!reset_n)
uart_tx<=1;
else case(bps_cnt)
1:uart_tx<=0;
2:uart_tx<=r_data[0];
3:uart_tx<=r_data[1];
4:uart_tx<=r_data[2];
5:uart_tx<=r_data[3];
6:uart_tx<=r_data[4];
7:uart_tx<=r_data[5];
8:uart_tx<=r_data[6];
9:uart_tx<=r_data[7];
10:uart_tx<=1;
11:uart_tx<=1;
default:uart_tx<=1;
endcase always@(posedge clk or negedge reset_n)
if(!reset_n)
tx_done<=0;
else if((bps_cnt==10)&&(bps_clk==1))
tx_done<=1;
else
tx_done<=0;
endmodule
//2、底层代码仿真文件
`timescale 1ns / 1ps
module uart_pr_tb();
reg clk;
reg reset_n;
reg send_en;
reg [7:0]data;
reg [2:0]baud_set;
wire tx_done;
wire uart_tx;
uart_pr uart_pr_tb(
.clk(clk),
.reset_n(reset_n),
.send_en(send_en),
.data(data),
.baud_set(baud_set),
.tx_done(tx_done),
.uart_tx(uart_tx)
);
initial clk=1;
always#10 clk=!clk; initial begin
reset_n=0;
data=0;
send_en=0;
baud_set=4;
#201;
reset_n=1;
#20;
data=8'h57;
send_en=1;
@(posedge tx_done)
send_en=0;
#2000;
data=8'h75;
send_en=1;
@(posedge tx_done)
send_en=0;
#20000;
$stop;
end endmodule
3、顶层代码源文件
//每10ms以115200的波特率发送一个数据,每次发送的
//数据比前一个数据大一(计数器)
//顶层设计模块
module uart_test1(
clk,
reset_n,
uart_tx
);
input clk;
input reset_n;
output uart_tx; reg send_go;//这是顶层的send_en放在下面会出错
reg [7:0] data;
//先将发送10位数据的uart进行例化
uart_pr uart_pr_inst0(
.clk(clk),
.reset_n(reset_n),
.send_go(send_go),
.data(data),
.baud_set(3'd4),
.tx_done(tx_done),
.uart_tx(uart_tx)
);
//先写出一个10ms的计数器
reg [18:0]counter;
always@(posedge clk or negedge reset_n)
if(!reset_n)
counter<=0;
else if(counter==499999)
counter<=0;
else
counter<=counter+1'b1;
//书写发送信号send_en
//底层不是控制过send_en了吗??怎么这里还写控制send_en
//因为底层控制send_en在testbench中控制的,最后不会在板级验证的时候起作用
//那只在testbench中也就是仿真波形中会出现。
always@(posedge clk or negedge reset_n)
if(!reset_n)
send_go<=0;
else if(counter==1)//记住这边只能用顶层的计数counter,不能用底层的div_cnt以及bps_cnt;
send_go<=1;
else //设置send_go的时候一定要注意,什么时候开始,什么时候结束要形成闭环。
send_go<=0;//else还是要加,只不过不用带tx_done因为tx_done已经在顶层模块说明过了
//书写data的每次加1;
always@(posedge clk or negedge reset_n)
if(!reset_n)
data<=0;
else if(tx_done)
data<=data+1'b1;
endmodule
4、顶层代码仿真文件
`timescale 1ns / 1ps
module uart_test1_tb();
reg clk;
reg reset_n;
wire uart_tx;
uart_test1 uart_test1_inst0(
.clk(clk),
.reset_n(reset_n),
.uart_tx(uart_tx)
); initial clk=1;
always #10 clk=!clk; initial begin
reset_n=0;
#201;
reset_n=1; #50000000;
$stop; end
endmodule

小梅哥课程学习——串口发送应用之发送数据(可在vivado中仿真出现正确波形)的相关教程结束。

《小梅哥课程学习——串口发送应用之发送数据(可在vivado中仿真出现正确波形).doc》

下载本文的Word格式文档,以方便收藏与打印。