uart串口:回环实验
实验目标
设计并实现基于串口 RS232 的数据收、发模块,使用收、发模块,完成串口数据回环
实验。
实验框图
uart_tx.v 时序图
uart_tx.v代码
module uart_tx (
input wire sys_clk,
input wire sys_rst_n,
input wire [7:0]pi_data,
input wire pi_flag,
output reg tx
);
reg work_en; //发送使能信号
reg [12:0]baud_cnt; //波特计数
wire bit_flag;
reg [3:0]bit_cnt; //位计数
always @(posedge sys_clk or negedge sys_rst_n ) begin
if (~sys_rst_n) begin
work_en <= 1'b0;
end
else if (pi_flag) begin
work_en <= 1'b1;
end
else if (bit_cnt == 4'd9 && bit_flag) begin
work_en <= 1'b0;
end
else begin
work_en <= work_en;
end
end
//波特率为9600,那么码元1bit要1/9600s,即cnt = ((1s * 10^9)ns / 9600)ns / 20ns ≈ 5208 个系统时钟周期
always @(posedge sys_clk or negedge sys_rst_n) begin
if (~sys_rst_n) begin
baud_cnt <= 13'd0;
end
else if (baud_cnt == 13'd5207) begin
baud_cnt <= 13'd0;
end
else if (work_en) begin
baud_cnt <= baud_cnt + 13'd1;
end
else begin
baud_cnt <= 13'd0;
end
end
assign bit_flag = (baud_cnt == 13'd1)?1'b1:1'b0;
always @(posedge sys_clk or negedge sys_rst_n) begin
if (~sys_rst_n) begin
bit_cnt <= 4'd0;
end
else if (bit_cnt == 4'd9 && bit_flag) begin
bit_cnt <= 4'd0;
end
else if (bit_flag) begin
bit_cnt <= bit_cnt + 4'd1;
end
else begin
bit_cnt <= bit_cnt;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if (~sys_rst_n) begin
tx <= 1'b1;
end
else if (bit_flag) begin
case (bit_cnt)
4'd0: tx <= 1'b0; //起始位
4'd1: tx <= pi_data[0];
4'd2: tx <= pi_data[1];
4'd3: tx <= pi_data[2];
4'd5: tx <= pi_data[4];
4'd4: tx <= pi_data[3];
4'd6: tx <= pi_data[5];
4'd7: tx <= pi_data[6];
4'd8: tx <= pi_data[7];
4'd9: tx <= 1'b1; //结束位
default: tx <= 1'b1;
endcase
end
end
endmodule
uart_rx.v 时序图
uart_rx.v代码
module usrt_rx (
input wire sys_clk,
input wire sys_rst_n,
input wire rx,
output reg [7:0]po_data,
output reg po_flag
);
reg rx_reg1;
reg rx_reg2;
reg rx_reg3;
reg work_en;
reg start_nedge;
reg [12:0]baud_cnt;
reg bit_flag;
reg [3:0]bit_cnt;
reg [7:0]rx_data;
reg rx_flag;
//单比特信号从慢速时钟域同步到快速时钟域需要使用打两拍的方式消除亚稳态。
always @(posedge sys_clk or negedge sys_rst_n) begin
if (~sys_rst_n) begin
rx_reg1 <= 1'b1;
end
else begin
rx_reg1 <= rx;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if (~sys_rst_n) begin
rx_reg2 <= 1'b1;
end
else begin
rx_reg2 <= rx_reg1;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if (~sys_rst_n) begin
rx_reg3 <= 1'b1;
end
else begin
rx_reg3 <= rx_reg2;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if (~sys_rst_n) begin
start_nedge <= 1'b0;
end
else if (rx_reg2 == 1'b0 && rx_reg3 == 1'b1 && work_en == 1'b0) begin
start_nedge <= 1'b1;
end
else begin
start_nedge <= 1'b0;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if (~sys_rst_n) begin
work_en <= 1'b0;
end
else if (start_nedge) begin
work_en <= 1'b1;
end
else if (bit_flag && bit_cnt == 4'd8) begin
work_en <= 1'b0;
end
else begin
work_en <= work_en;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if (~sys_rst_n) begin
baud_cnt <= 13'b0;
end
else if (baud_cnt == 13'd5207) begin
baud_cnt <= 13'd0;
end
else if (work_en) begin
baud_cnt <= baud_cnt + 13'd1;
end
else begin
baud_cnt <= 13'b0;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if (~sys_rst_n) begin
bit_flag <= 1'b0;
end
else if (baud_cnt == 13'd2603) begin
bit_flag <= 1'b1;
end
else begin
bit_flag <= 1'b0;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if (~sys_rst_n) begin
bit_cnt <= 4'd0;
end
else if (bit_cnt == 4'd8 && bit_flag) begin
bit_cnt <= 4'd0;
end
else if (bit_flag) begin
bit_cnt <= bit_cnt + 4'b1;
end
else begin
bit_cnt <= bit_cnt;
end
end
//将输入的串行数据转为并行
always @(posedge sys_clk or negedge sys_rst_n) begin
if (~sys_rst_n) begin
rx_data <= 8'b0;
end
else if (bit_cnt >= 4'd1 && bit_cnt <= 4'd8 && bit_flag) begin
rx_data <= {rx_reg3,rx_data[7:1]};
end
else begin
rx_data <= rx_data;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if (~sys_rst_n) begin
rx_flag <= 1'b0;
end
else if (bit_cnt == 4'd8 && bit_flag) begin
rx_flag <= 1'b1;
end
else begin
rx_flag <= 1'b0;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if (~sys_rst_n) begin
po_data <= 8'd0;
end
else if (rx_flag) begin
po_data <= rx_data;
end
else begin
po_data <= po_data;
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if (~sys_rst_n) begin
po_flag <= 1'b0;
end
else begin
po_flag <= rx_flag;
end
end
endmodule
顶层模块
module serial (
input wire sys_clk,
input wire sys_rst_n,
input wire rx,
output wire tx
);
wire [7:0]po_data;
wire po_flag;
uart_tx uart_tx (
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.pi_data(po_data),
.pi_flag(po_flag),
.tx(tx)
);
usrt_rx usrt_rx (
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.rx(rx),
.po_data(po_data),
.po_flag(po_flag)
);
endmodule
上板验证
可见,发出的“444”经回环后成功接收。