先了解一下关于uart和rs232的基础知识
文章目录
- 一、RS232的回环测试
- 1.1模块整体架构
- 1.2 rx模块设计
- 1.2.1 波形设计
- 1.2.2代码实现与tb
- 1.2.4 仿真
- 1.3 tx模块设计
- 1.3.1 波形设计
- 1.3.2 代码实现与tb
- 1.3.4 顶层设计
- 1.3.3 仿真
本篇内容:
一、RS232的回环测试
上位机由串口助手通过 rx 线往 FPGA 发 8 比特数据,当 FPGA接收到 8 比特数据后,再通过 tx 线把接收到的 8 比特数据给上位机发回去,要求上位机接收到的数据和上位机发送的数据一样,并且保证连续发送也没问题。
1.1模块整体架构
1.2 rx模块设计
1.2.1 波形设计
1.2.2代码实现与tb
代码:
module uart_rx(
input wire clk,
input wire rst,
input wire rx,
output reg [7:0]po_data,
output reg po_flag
);
parameter CNT_END=100; //9600bps cnt=5207 sim时,cnt=100;
parameter CNT_END_HALF=CNT_END/2;
reg rx_t;
reg rx_tt;
reg rx_tt_reg;
reg [12:0] cnt;
reg cnt_flag;
reg bit_flag;
reg [3:0]bit_cnt;
// rx_t
always @(posedge clk) begin
if(rst==1'b1) begin
rx_t <= 'd1;
end
else begin
rx_t<=rx ;
end
end
// rx_tt
always @(posedge clk) begin
if(rst==1'b1) begin
rx_tt <= 'd1;
end
else begin
rx_tt<=rx_t ;
end
end
// rx_tt_reg
always @(posedge clk) begin
if(rst==1'b1) begin
rx_tt_reg <= 'd1;
end
else begin
rx_tt_reg<=rx_tt ;
end
end
//cnt
always @(posedge clk) begin
if(rst==1'b1) begin
cnt<= 'd0;
end
else if (cnt_flag==1'b1 && cnt==CNT_END) begin
cnt<='d0;
end
else if (cnt_flag==1'b1) begin
cnt<=cnt+1'b1;
end
else if (bit_cnt=='d8 && bit_flag==1'b1) begin
cnt<='d0;
end
end
//bit_flag
always @(posedge clk) begin
if(rst==1'b1) begin
bit_flag <= 'd0;
end
else if (cnt_flag==1'b1 && cnt==CNT_END_HALF) begin
bit_flag<='d1;
end
else
bit_flag<='d0;
end
// cnt_flag
always @(posedge clk) begin
if(rst==1'b1) begin
cnt_flag <= 'd0;
end
else if (rx_tt==1'b0 && rx_tt_reg==1'b1) begin
cnt_flag<='d1;
end
else if (bit_cnt=='d8 && cnt==CNT_END_HALF) begin
cnt_flag<='d0;
end
end
// bit_cnt
always @(posedge clk) begin
if(rst==1'b1) begin
bit_cnt <= 'd0;
end
else if (bit_cnt=='d8 && bit_flag==1'b1) begin
bit_cnt<='d0;
end
else if (bit_flag==1'b1) begin
bit_cnt<=bit_cnt+1'b1;
end
end
// po_data
always @(posedge clk) begin
if(rst==1'b1) begin
po_data <= 'd0;
end
else if (bit_cnt>0 && bit_flag==1'b1) begin
po_data<={rx,po_data[7:1]};
end
end
// po_flag
always @(posedge clk) begin
if(rst==1'b1) begin
po_flag<= 'd0;
end
else if (bit_cnt=='d8 && bit_flag==1'b1) begin
po_flag<='d1;
end
else
po_flag<='d0;
end
endmodule
tb:
`timescale 1ns / 1ps
module tb_rx();
reg clk;
reg rst;
reg rx;
wire [7:0] po_data;
wire po_flag;
initial begin
clk=0;
rst=1;
#100
rst=0;
end
initial begin
rx=1;//空闲状态
#100
gen_rx();
end
//这里模拟发送20帧数据,每次发送8个0~1的任意数,发送前rx拉低,表示起始位
//由于9600波特率需要计数5207次,为了仿真方便,假设只需要计数100次。
task gen_rx;
integer i;
integer j;
begin
for (j = 0; j < 20; j=j+1) begin
rx=0;
for ( i = 0; i < 8; i=i+1) begin
repeat(100) begin //每隔100周期发送1bit数据;
@(posedge clk);
end
rx={$random};
end
rx=1; //每发送完一帧数据后,rx恢复空闲状态,维持10个周期后继续发送数据,直到发够20帧数据。
repeat(10) begin
@(posedge clk);
end
end
end
endtask
always #5 clk=~clk;
uart_rx inst_uart_rx (
.clk (clk),
.rst (rst),
.rx (rx),
.po_data (po_data),
.po_flag (po_flag)
);
endmodule
1.2.4 仿真
1.3 tx模块设计
1.3.1 波形设计
1.3.2 代码实现与tb
module uart_tx(
input wire clk,
input wire rst,
input wire[7:0] po_data,
input wire po_flag,
output reg tx
);
parameter CNT_END=100; // bps为9600时,这里为:5207, 为仿真方便设为100。
reg [7:0] po_data_reg;
reg [12:0]cnt;
reg cnt_flag;
reg bit_flag;
reg [3:0] bit_cnt;
// po_data_reg
always @(posedge clk) begin
if(rst==1'b1) begin
po_data_reg<= 'd0;
end
else
po_data_reg<=po_data;
end
// cnt
always @(posedge clk) begin
if(rst==1'b1) begin
cnt <= 'd0;
end
else if (cnt_flag==1'b1 && cnt==CNT_END) begin
cnt <= 'd0;
end
else if (cnt_flag==1'b1) begin
cnt<=cnt+1'b1;
end
end
//cnt_flag
always @(posedge clk) begin
if(rst==1'b1) begin
cnt_flag <= 'd0;
end
else if (po_flag==1'b1) begin
cnt_flag<='d1;
end
else if (bit_cnt=='d8 && bit_flag==1'b1) begin
cnt_flag<='d0;
end
end
// bit_flag
always @(posedge clk) begin
if(rst==1'b1) begin
bit_flag <= 'd0;
end
else if (cnt==CNT_END-1 && cnt_flag==1'b1) begin
bit_flag<='d1;
end
else
bit_flag<='d0;
end
// bit_cnt
always @(posedge clk) begin
if(rst==1'b1) begin
bit_cnt <= 'd0;
end
else if (bit_flag==1'b1 && bit_cnt=='d8) begin
bit_cnt<='d0;
end
else if (bit_flag==1'b1) begin
bit_cnt<=bit_cnt+1'b1;
end
end
// tx
always @(posedge clk) begin
if(rst==1'b1) begin
tx <= 'd1;
end
else if (po_flag==1'b1) begin
tx<='d0;
end
else if (bit_flag==1'b1 && bit_cnt=='d8) begin
tx<='d1;
end
else if (bit_flag==1'b1) begin
tx<=po_data_reg[bit_cnt];
end
end
endmodule
tb:
`timescale 1ns / 1ps
module tb_rx();
reg clk;
reg rst;
reg rx;
wire tx;
initial begin
clk=0;
rst=1;
#100
rst=0;
end
initial begin
rx=1;//空闲状态
#100
gen_rx();
end
//这里模拟发送20次数据,每次发送8个0~1的任意数,发送前rx拉低,表示起始位
//由于9600波特率需要计数5207次,为了仿真方便,假设只需要计数100次。
task gen_rx;
integer i;
integer j;
begin
for (j = 0; j < 20; j=j+1) begin
rx=0;
for ( i = 0; i < 8; i=i+1) begin
repeat(100) begin //每隔100周期发送1bit数据;
@(posedge clk);
end
rx={$random};
end
rx=1; //每发送完一帧数据后,rx恢复空闲状态,维持100个周期(方便tx端完整传输完一帧数据)后继续发送数据,直到发够20帧数据。
repeat(1000) begin
@(posedge clk);
end
end
end
endtask
always #5 clk=~clk;
top_uart inst_top_uart (.clk(clk), .rst(rst), .rx(rx), .tx(tx));
endmodule
1.3.4 顶层设计
module top_uart(
input wire clk,
input wire rst,
input wire rx,
output wire tx
);
wire [7:0] po_data;
wire po_flag;
uart_rx inst_uart_rx (
.clk (clk),
.rst (rst),
.rx (rx),
.po_data (po_data),
.po_flag (po_flag)
);
uart_tx inst_uart_tx (
.clk (clk),
.rst (rst),
.po_data (po_data),
.po_flag (po_flag),
.tx (tx)
);
endmodule
1.3.3 仿真
可以看到,rx和tx波形一致,则能实现传输要求。