首先搞清楚的是该模块实现的功能:利用FPGA将一个并行的数据(我的理解是可以来自FPGA内部,也可以外部存储器中),以串行的方式发送给PC(或者其他MCU)
串口发送的时序图参照了开源骚客的课程:
baud_cnt 换成了cnt0
bit_cnt 换成了cnt0
rs232_tx 换成了uart_tx
取消了内部信号:bit_flag(这个信号主要为了指示一个bit的信号发完了,我在计数器中直接用了end_cnt0代替)
代码的大体思路:
在tx_trig信号为高的时候(至少为1个周期的高电平)表示有并行的数据tx_data过来了(以上两个信号都是输入信号,真正运行的时候应该是外部给出的,是不用我们提供的,但是我们需要依据这两个信号设计其他的型号,主要是设计输出信号,问题又来了仅仅这两个信号能设计出输出信号吗?当然不能了,所以才设计一系列的内部辅助信号cnto,cnt1,tx_flag等)。
过来的tx_data 用tx_data_reg寄存一下(感觉是为了时序同步),然后没过5208个时钟周期(波特率为9600时),按从低到高的顺序一位一位的把数据传送给uart_tx(当然首先应该把线拉低,表示起始位)
代码:
module uart_tx(
input wire clk ,
input wire rst_n ,
input wire tx_trig , //传输的触发信号
input wire[7:0] tx_data , //需要传输的并行数据
output reg uart_tx //并转串后输出的数据
);
/*参数及内部信号定义*/
reg tx_flag;
reg[12:0] cnt0;
reg[3:0] cnt1;
reg[7:0] tx_data_reg;
wire add_cnt0;
wire end_cnt0;
wire add_cnt1;
wire end_cnt1;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
tx_data_reg<=8'b0;
end
else if(tx_trig==1&&tx_flag==0)begin
tx_data_reg<=tx_data;
end
end
//cnt0 计数5208
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt0<=0;
end
else if(add_cnt0)begin
if(end_cnt0)begin
cnt0<=0;
end
else begin
cnt0<=cnt0+1;
end
end
end
assign add_cnt0=tx_flag;
assign end_cnt0=add_cnt0&&cnt0==5208-1;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt1<=0;
end
else if(add_cnt1)begin
if(end_cnt1)begin
cnt1<=0;
end
else begin
cnt1<=cnt1+1;
end
end
end
assign add_cnt1=end_cnt0;
assign end_cnt1=add_cnt1&&cnt1==9-1;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
tx_flag<=0;
end
else if(tx_trig==1&&tx_flag==0) begin
tx_flag<=1;
end
else if(cnt1==8&&cnt0==5207) begin
tx_flag<=0;
end
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
uart_tx<=1;
end
else if(tx_flag==1)begin
case(cnt1)
0:uart_tx<=0; //开始位
1:uart_tx<=tx_data[0]; //从低位往高位传输
2:uart_tx<=tx_data[1];
3:uart_tx<=tx_data[2];
4:uart_tx<=tx_data[3];
5:uart_tx<=tx_data[4];
6:uart_tx<=tx_data[5];
7:uart_tx<=tx_data[6];
8:uart_tx<=tx_data[7];
default:
uart_tx<=1; //结束后回高位
endcase
end
end
endmodule
测试模块:
`timescale 1ns/1ns
module tb_uatr_tx();
reg clk ;
reg rst_n ;
reg tx_trig ;
reg[7:0] tx_data ;
wire uart_tx ;
initial begin
clk= 0;
rst_n= 0;
#100
rst_n= 1;
#100
tx_trig=1;
tx_data=8'h55;
#100
tx_trig=0;
end
always #10 clk=~clk ;
//模块例化
uart_tx uart_tx_inst(
. clk (clk) ,
. rst_n (rst_n) ,
. tx_trig (tx_trig) , //传输的触发信号
. tx_data (tx_data) , //需要传输的并行数据
. uart_tx (uart_tx) //并转串后输出的数据
);
endmodule
modelsim仿真: