FPGA串口收发(三):接收数据,再转发出去
功能:测试串口接收数据,再将数据从串口发出
// 模拟串口信号线,串行接收数据 1101_1000 ,转换为并行数据, 并显示 D8
// 把并行数据 D8 传给串口输出模块,串行输出数据 1101 1000
时钟40MHz,波特率115200
1、源文件
uart_rx.v
uart_tx.v
2、仿真文件 testbench
tb_uart_rx_tx.v
`timescale 1ns / 1ps
//
// Company: Myminieye
// Engineer: Nill
//
// Create Date:
// Design Name:
// Module Name:
// Project Name:
// Target Devices:
// Tool Versions:
// Description: 测试串口接收数据,再将数据从串口发出
// 模拟串口信号线,串行接收数据 1101_1000 ,转换为并行数据, 并显示 D8
// 把并行数据 D8 传给串口输出模块,串行输出数据 1101 1000
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
`define UD #1
module tb_uart_rx_tx();
//==========================================================================
//wire and reg 定义:信号与参数
//==========================================================================
reg sim_clk; //模拟时钟信号
//reg tx_pulse; // active posedge
reg sim_rst_n;
// input to rx module
reg uart_rx; //串口发送信号线
//output from rx module
wire [7:0] rx_data; //送入串口发送模块,准备发送的数据
wire rx_finish; //串口接收数据有效,接收完成拉高1个BPS
// input to tx module
reg tx_pulse; // active posedge
reg [7:0] tx_data; //送入串口发送模块,准备发送的数据
//output from tx module
wire uart_tx; //串口发送信号线
wire tx_busy; //串口发送模块状态
//时钟参数
parameter SYS_CLK_FRE = 40_000_000; //系统频率40MHz 40_000_000
parameter SYS_CLK_PERIOD = 1_000_000_000/SYS_CLK_FRE; //周期25ns
parameter RST_CYCLE = 5; //复位持续时间,clk时钟周期数
parameter RST_TIME = RST_CYCLE * SYS_CLK_PERIOD; //复位时间:5个时钟周期
//波特率参数
parameter BAUD_RATE = 115200; //串口波特率
parameter BAUD_RATE_PERIOD = 1_000_000_000/BAUD_RATE;
//波特率周期,0.104ms = 104us,1/9600 s = 1^9 /9600 ns = 4167 sim_clk
//波特率周期, 1/115200 = 8680 ns = 8.7us = 347 sim_clk
//波特率+时钟参数
parameter [15:0] BPS_NUM = SYS_CLK_FRE / BAUD_RATE; //时钟/波特率,用时钟周期构造波特率周期
// BPS_NUM = 40_000_000/115200 = 347.22 = 16'd347
// 1 bit位宽所需时钟周期的个数。最长的波特率计数,10417,二进制有14位,取16位
// parameter BPS_4800: 40MHz set 8333 ; 50MHz set 10417
// parameter BPS_9600: 40MHz set 4167 ; 50MHz set 5208
// parameter BPS_115200: 40MHz set 347; 50MHz set 434
//==========================================================================
//模拟:信号的输入,显示输出结果
//==========================================================================
//模拟系统时钟:40MHz,25ns
always #((SYS_CLK_PERIOD+1)/2-1) sim_clk = ~sim_clk; //延时,电平翻转
initial begin
//模拟复位信号:拉低一次
#0;
sim_clk = 1'b0;
sim_rst_n = 1'b0; //复位拉低,有效,
uart_rx = 1'b1; //串口线,默认高,起始拉低
//rx_data <= `UD 8'h00; //rx_data 初始化,在 uart_rx中完成
tx_pulse = 1'b0; //触发发送,高有效,先拉低
tx_data = 8'h00; //数据默认为0
//#RST_TIME; //延时:保持足够长时间(至少5个clk)
#BAUD_RATE_PERIOD; //5个clk时间轴太短,仿真改为1个BPS,更明显
sim_rst_n = 1'b1; //解除复位
//==========================================================================
//模拟串口接收:串行信号输入,转化成并行数据,并显示
//==========================================================================
uart_rx = 1'b1; //串口发送线,默认拉高
repeat( BPS_NUM*1 ) @(posedge sim_clk); //循环347个时钟周期,即一个波特率周期
//#BAUD_RATE_PERIOD; //直接延时,一个波特率周期
$display("Initialization complete. BAUD_RATE is %d",BAUD_RATE); //命令行显示初始化完成,输出BAUD_RATE
//串口:起始位
uart_rx = 1'b0;
#BAUD_RATE_PERIOD;
//串行数据,一位一位送入接收信号线:***从位0到位7***,依次发送
//测试数据为8'hD8=8'b1101_1000
uart_rx = 1'b0;
#BAUD_RATE_PERIOD;
uart_rx = 1'b0;
#BAUD_RATE_PERIOD;
uart_rx = 1'b0;
#BAUD_RATE_PERIOD;
uart_rx = 1'b1;
#BAUD_RATE_PERIOD;
uart_rx = 1'b1;
#BAUD_RATE_PERIOD;
uart_rx = 1'b0;
#BAUD_RATE_PERIOD;
uart_rx = 1'b1;
#BAUD_RATE_PERIOD;
uart_rx = 1'b1;
#BAUD_RATE_PERIOD;
$display("The uart_rx 8'hD8 = 8'b1101_1000 has been sent."); //命令行显示:串口信号线数据已发送
//串口:结束位
uart_rx = 1'b1;
#BAUD_RATE_PERIOD;
$display("The uart_rx has received. rx_data = 8'h%h",rx_data);
//命令行显示:串口信号线接收已结束,显示接收到的数据
//==========================================================================
//模拟串口发送:并行数据,串行输出
//==========================================================================
//***串口接收模块收到的数据,传递给串口输出模块***
repeat( BPS_NUM*1 ) @(posedge sim_clk); //循环347个时钟周期,即一个波特率周期
//#BAUD_RATE_PERIOD; //直接延时,一个波特率周期
//传递 第一组数据:8位并行数据,一次性送入串口发送模块
tx_data = rx_data; //串口接收数据,传给串口发送
#BAUD_RATE_PERIOD;
//开启触发信号:串口发送
//tx_pulse = 1; //用 rx_en 代替 模拟tx_pulse,直接触发
#BAUD_RATE_PERIOD; //rx_en 串口接收数据有效,接收完成拉高1个BPS
//结束触发:串口发送
//tx_pulse = 0;
#BAUD_RATE_PERIOD;
repeat( BPS_NUM*9 ) @(posedge sim_clk); //发送数据,等待8个波特率周期
$display("The first tx_data 8'h%h has been sent.",tx_data); //命令行显示:第1组数据发送完
#BAUD_RATE_PERIOD;
$stop; //结束仿真
end
//==========================================================================
//调用top模块
//==========================================================================
//串口发送
uart_rx #(
//.CLK_SYS ( SYS_CLK_FRE), //系统时钟
.BPS_NUM ( BPS_NUM ) // 时钟/波特率,1 bit位宽所需时钟周期的个数
)
u_uart_rx(
.clk ( sim_clk ),// input clk,
//.rst_n ( sim_rst_n ),// input
.uart_rx ( uart_rx ),// input reg 串口接收信号线
.rx_data ( rx_data ),// output 接收到的数据
.rx_finish( rx_finish)// output 串口接收数据有效,接收完成拉高1个BPS
//.rx_end ( rx_end ) // output //接收到停止位,拉高1个clk,没啥用
);
//串口发送
uart_tx #(
//.CLK_SYS ( SYS_CLK_FRE), //系统时钟
.BPS_NUM ( BPS_NUM ) // 时钟/波特率,用时钟周期构造波特率周期
)
u_uart_tx(
.clk ( sim_clk ),// input clk,
.tx_data ( tx_data ),// input [7:0] tx_data,
.tx_pulse ( rx_finish),// input 外部输入,开始产生数据->开启串口发送状态
.uart_tx ( uart_tx ),// output reg uart_tx,
.tx_busy ( tx_busy ), // output 输出,串口接收忙状态
.tx_finish( tx_finish) // output //串口发送数据结束标志,8位数据发完,拉高一个BPS
);
endmodule
3、仿真结果
ModelSim波形
命令行显示
增加 tx_finish 和 rx_finish