- 串口简介
通用异步收发传输器,简称UART。
UART是一种通用的数据通信协议,发送数据时将并行数据转换为串行数据来传输,接收数据时将接收到的串行数据转换为并行数据。
使用多级寄存器,减少亚稳态,如下图所示:
经过三级寄存器,减少亚稳态。
时钟周期为20ns,波特率为9600,可以计算出一个波特占用的周期数如下:
(1/9600*10^9)/20=5208(个)
取中间值做信号提取,波形图如下:
编写串口模块代码如下:
module uart_rx
#(
parameter UART_BPS = 'd9600 ,
parameter CLK_FREQ = 'd50_000_000
)
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire rx ,
output reg [7:0] po_data ,
output reg po_flag
);
parameter BAUD_CNT_MAX = CLK_FREQ / UART_BPS;
reg rx_reg1 ;
reg rx_reg2 ;
reg rx_reg3 ;
reg start_flag ;
reg work_en ;
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)
if(sys_rst_n == 1'b0)
rx_reg1 <= 1'b1;
else
rx_reg1 <= rx;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_reg2 <= 1'b1;
else
rx_reg2 <= rx_reg1;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_reg3 <= 1'b1;
else
rx_reg3 <= rx_reg2;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
start_flag <= 1'b0;
else if((rx_reg3 == 1'b1) && (rx_reg2 == 1'b0) && (work_en == 1'b0))
start_flag <= 1'b1;
else
start_flag <= 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
work_en <= 1'b0;
else if(start_flag == 1'b1)
work_en <= 1'b1;
else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
work_en <= 1'b0;
else
work_en <= work_en;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
baud_cnt <= 16'd0;
else if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0))
baud_cnt <= 16'd0;
else
baud_cnt <= baud_cnt + 1'b1;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_flag <= 1'b0;
else if(baud_cnt == BAUD_CNT_MAX / 2 -1 )
bit_flag <= 1'b1;
else
bit_flag <= 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_cnt <= 4'd0;
else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
bit_cnt <= 4'd0;
else if(bit_flag == 1'b1)
bit_cnt <= bit_cnt + 1'b1;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_data <= 8'b0;
else if((bit_cnt >= 4'd1) && (bit_cnt <= 4'd8) &&(bit_flag == 1'b1))
rx_data <= {rx_reg3,rx_data[7:1]};
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rx_flag <= 1'b0;
else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
rx_flag <= 1'b1;
else
rx_flag <= 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
po_flag <= 1'b0;
else
po_flag <= rx_flag;
endmodule
编写仿真代码:
`timescale 1ns/1ns
module tb_uart_rx();
reg sys_clk ;
reg sys_rst_n ;
reg rx ;
wire [7:0] po_data ;
wire po_flag ;
initial
begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
rx <= 1'b0;
#20
sys_rst_n <= 1'b1;
end
initial
begin
#200
rx_bit(8'd0);
rx_bit(8'd1);
rx_bit(8'd2);
rx_bit(8'd3);
rx_bit(8'd4);
rx_bit(8'd5);
rx_bit(8'd6);
rx_bit(8'd7);
end
always #10 sys_clk = ~sys_clk;
task rx_bit
(
input [7:0] data
);
integer i;
for(i = 0;i < 10; i = i + 1)
begin
case(i)
0:rx <= 1'b0;
1:rx <= data[0];
2:rx <= data[1];
3:rx <= data[2];
4:rx <= data[3];
5:rx <= data[4];
6:rx <= data[5];
7:rx <= data[6];
8:rx <= data[7];
9:rx <= 1'b1;
endcase
#(5208*20);
end
endtask
uart_rx
#(
.UART_BPS (9600 ),
.CLK_FREQ (50_000_000)
)
uart_rx_inst
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n),
.rx (rx ),
.po_data (po_data),
.po_flag (po_flag)
);
endmodule
绘制UART-TX的波形
编写发送模块代码如下:
module uart_tx
#(
parameter UART_BPS = 'd9600 ,
parameter CLK_FREQ = 'd50_000_000
)
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire [7:0] pi_data ,
input wire pi_flag ,
output reg tx
);
parameter BAUD_CNT_MAX = CLK_FREQ / UART_BPS;
reg work_en ;
reg [15:0] baud_cnt ;
reg bit_flag ;
reg [3:0] bit_cnt ;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
work_en <= 1'b0;
else if(pi_flag == 1'b1)
work_en <= 1'b1;
else if((bit_cnt == 4'd9) && (bit_flag == 1'b1))
work_en <= 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
baud_cnt <= 16'd0;
else if((work_en == 1'b0) || (baud_cnt == BAUD_CNT_MAX - 1))
baud_cnt <= 16'd0;
else
baud_cnt <= baud_cnt + 1'b1;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_flag <= 1'b0;
else if(baud_cnt == 16'd1)
bit_flag <= 1'b1;
else
bit_flag <= 1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
bit_cnt <= 4'd0;
else if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
bit_cnt <= 4'b0;
else if((bit_flag == 1'b1) && (work_en == 1'b1))
bit_cnt <= bit_cnt + 1'b1;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
tx <= 1'b1;
else if(bit_flag == 1'b1)
case(bit_cnt)
0:tx <= 1'b0;
1:tx <= pi_data[0];
2:tx <= pi_data[1];
3:tx <= pi_data[2];
4:tx <= pi_data[3];
5:tx <= pi_data[4];
6:tx <= pi_data[5];
7:tx <= pi_data[6];
8:tx <= pi_data[7];
9:tx <= 1'b1;
default:tx <= 1'b1;
endcase
endmodule
编写顶层模块代码
module rs232
(
input wire sys_clk ,
input wire sys_rst_n ,
input wire rx ,
output wire tx
);
wire [7:0] rx_data;
wire rx_flag;
uart_rx
#(
.UART_BPS (9600 ),
.CLK_FREQ (50_000_000)
)
uart_rx_inst
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n),
.rx (rx ),
.po_data (rx_data),
.po_flag (rx_flag)
);
uart_tx
#(
.UART_BPS(9600 ),
.CLK_FREQ(50_000_000)
)
uart_tx_inst
(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n),
.pi_data (rx_data),
.pi_flag (rx_flag),
.tx ()
);
endmodule
编写顶层模块的仿真代码
`timescale 1ns/1ns
module tb_rs232();
reg sys_clk ;
reg sys_rst_n ;
reg rx ;
wire tx ;
initial
begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
rx <= 1'b1;
#20
sys_rst_n <= 1'b1;
end
always #10 sys_clk = ~sys_clk;
initial
begin
#200
rx_byte();
end
task rx_byte();
integer j;
for(j=0;j<9;j=j+1)
rx_data(j);
task rx_bit
(
input [7:0] data
);
integer i;
for(i = 0;i < 10; i = i + 1)
begin
case(i)
0:rx <= 1'b0;
1:rx <= data[0];
2:rx <= data[1];
3:rx <= data[2];
4:rx <= data[3];
5:rx <= data[4];
6:rx <= data[5];
7:rx <= data[6];
8:rx <= data[7];
9:rx <= 1'b1;
endcase
#(5208*20);
end
endtask
rs232 rs232_inst
(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.rx (rx),
.tx (tx)
);
endmodule