一、串口概念
串行通信分为两种方式:
- 同步串行通信(I2C/SPI)
- 异步串行通信(UART)
区别:
- 同步串行通信需要通信双方在同一时钟的控制下,同步传输数据。
- 异步串行通信是指通信双方使用各自的时钟控制数据的发送和接收过程。
二、UART协议
UART(Universal Asynchronous Receiver-Transmitter),它在发送数据时将并行数据转换成串行数据来传输,在接收数据时将接收到的串行数据转换成并行数据。 UART串口通信需要两根信号线来实现,一根用于发送,另外一根接收。控制高低电平达到数据的传输功能,输入全双工通信。
三、协议格式
一帧数据由4部分组成:
- 起始位(1bit)
- 数据位(6\7\8 bit)
- 奇偶校验位(1bit)
- 停止位(1bit\1.5bit\2bit)
常用的波特率有9600、19200、38400、57600以及115200等。
接受模块
发送模块
四、实验架构图
五、设计规范
设计uart的发送和接受模块,数据起始位1bit,数据位8bit, 停止位1bit,忽略奇偶检验位。
六、设计输入
uart_tx.v发送端模块文件
module uart_tx(
input clk ,
input rst_n ,
input [7:0] tx_data ,
input rx_vld ,
output tx
);
parameter TIME_BAUD = 9'd434 ;
reg [8:0] tx_data_r ;
reg tx_flag ;
reg [8:0] cnt_baud ;
wire add_cnt_baud ;
wire end_cnt_baud ;
reg [3:0] cnt_bit ;
wire add_cnt_bit ;
wire end_cnt_bit ;
reg tx_r ;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
tx_data_r <= 9'h1ff ;
end
else if(rx_vld) begin
tx_data_r <= {tx_data,1'b0};
end
else begin
tx_data_r <= tx_data_r ;
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
tx_flag <= 1'b0 ;
end
else if(rx_vld)begin
tx_flag <= 1'b1 ;
end
else if(end_cnt_bit)begin
tx_flag <= 1'b0 ;
end
else begin
tx_flag <= tx_flag ;
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt_baud <= 1'b0;
end
else if(add_cnt_baud)begin
if(end_cnt_baud)
cnt_baud <= 1'b0;
else
cnt_baud <= cnt_baud + 1'b1;
end
end
assign add_cnt_baud = tx_flag ;
assign end_cnt_baud = add_cnt_baud && cnt_baud == (TIME_BAUD-1);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt_bit <= 1'b0;
end
else if(add_cnt_bit)begin
if(end_cnt_bit)
cnt_bit <= 1'b0;
else
cnt_bit <= cnt_bit + 1'b1;
end
end
assign add_cnt_bit = end_cnt_baud ;
assign end_cnt_bit = add_cnt_bit && cnt_bit == 8;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
tx_r <= 1'b1 ;
end
else if(cnt_baud==(TIME_BAUD>>1))begin
tx_r <= tx_data_r[cnt_bit] ;
end
else if(end_cnt_bit)begin
tx_r <= 1'b1 ;
end
end
assign tx = tx_r ;
endmodule
rx_uart.v接收端模块文件
module uart_rx(
input clk ,
input rst_n ,
input rx ,
output [7:0] rx_dout ,
output reg rx_vld
);
parameter TIME_BAUD=9'd434 ;
reg rx0 ;
reg rx1 ;
wire nedge ;
reg add_flag ;
reg [8:0] cnt_baud ;
wire add_cnt_baud ;
wire end_cnt_baud ;
(*noprune*)reg [9:0] rx_data ;
reg [3:0] cnt_bit ;
wire add_cnt_bit ;
wire end_cnt_bit ;
reg [7:0] rx_data1 ;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
rx0 <= 1'b1 ;
rx1 <= 1'b1 ;
end
else begin
rx0 <= rx ;
rx1 <= rx0;
end
end
assign nedge = ~rx0 & rx1 ;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
add_flag <= 1'b0 ;
end
else if(nedge)begin
add_flag <= 1'b1 ;
end
else if(end_cnt_bit)begin
add_flag <= 1'b0 ;
end
else begin
add_flag <= add_flag ;
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt_baud <= 1'b0;
end
else if(add_cnt_baud)begin
if(end_cnt_baud)
cnt_baud <= 1'b0;
else
cnt_baud <= cnt_baud + 1'b1;
end
end
assign add_cnt_baud = add_flag ;
assign end_cnt_baud = add_cnt_baud && cnt_baud == (TIME_BAUD-1);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt_bit <= 1'b0;
end
else if(end_cnt_bit&&end_cnt_baud)begin
cnt_bit <= 1'b0 ;
end
else if(add_cnt_bit)begin
if(end_cnt_bit)
cnt_bit <= 1'b0;
else
cnt_bit <= cnt_bit + 1'b1;
end
end
assign add_cnt_bit = end_cnt_baud ;
assign end_cnt_bit = add_cnt_bit && cnt_bit == 8;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
rx_data <= 9'd0 ;
end
else if(add_flag&&(cnt_baud==(TIME_BAUD>>1)))begin
rx_data <= {rx1,rx_data[8:1]};
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
rx_data1 <= 8'd0 ;
end
else if(end_cnt_bit)begin
rx_data1 <= rx_data[8:1] ;
end
end
assign rx_dout = rx_data1 ;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
rx_vld <= 1'b0 ;
end
else if(end_cnt_bit)begin
rx_vld <= 1'b1 ;
end
else begin
rx_vld <= 1'b0 ;
end
end
endmodule
uart.v顶层模块文件
module uart(
input clk ,
input rst_n ,
input rx ,
output tx
);
wire [7:0] data ;
wire rx_vld ;
uart_rx u_rx(
/* input */ .clk (clk ) ,
/* input */ .rst_n (rst_n ) ,
/* input */ .rx (rx ) ,
/* output [7:0] */ .rx_dout(data) ,
/* output reg */ .rx_vld (rx_vld )
);
uart_tx u_tx(
/* input */ .clk (clk ) ,
/* input */ .rst_n (rst_n ) ,
/* input [7:0] */ .tx_data (data) ,
/* input */ .rx_vld (rx_vld ) ,
/* output */ .tx (tx )
);
endmodule
七、引脚分配
元件 | 管脚 |
---|---|
rx | M2 |
tx | G1 |
rst_n | E15 |
clk | E1 |
八、运行效果
九、Testbench文件
uart_tx_tb仿真文件
`timescale 1ns/1ns
module uart_tx_tb();
reg clk;
reg rst_n;
reg tx_req;
reg [7:0] tx_din;
wire tx_dout;
wire dout_vld;
always #(10) clk = ~clk;//每隔10ns翻转一次
initial begin//初始化信号
clk = 1'b0 ;//时钟信号初始化为0
rst_n = 1'b0 ;//复位信号初始化为0
#(10) ;//等待10ns
rst_n = 1'b1 ;//复位信号拉高电平
tx_req = 1'b1;
tx_din = 8'b00001111;
#(100_000);
tx_req = 1'b0;
$stop;
end
uart_tx u_uart_tx_tb(
.clk(clk) ,
.rst_n(rst_n) ,
.tx_req(tx_req),//发送请求
.tx_din(tx_din),//并行数据输入
.tx_dout(tx_dout),//串行数据输出
.dout_vld(dout_vld)//并转串完成标志
);
endmodule
uart_rx_tb仿真文件
`timescale 1ns/1ns
module uart_rx_tb();
reg clk;
reg rst_n;
reg rx_din;
wire [7:0] rx_dout;
wire dout_vld;
always #(10) clk = ~clk;//每隔10ns翻转一次
initial begin//初始化信号
clk = 1'b0 ;//时钟信号初始化为0
rst_n = 1'b0 ;//复位信号初始化为0
#(10) ;//等待10ns
rst_n = 1'b1 ;//复位信号拉高电平
rx_din = 1'b0;
#(8681);
rx_din = 1'b0;
#(8681);
rx_din = 1'b0;
#(8681);
rx_din = 1'b0;
#(8681);
rx_din = 1'b0;
#(8681);
rx_din = 1'b1;
#(8681);
rx_din = 1'b1;
#(8681);
rx_din = 1'b1;
#(8681);
rx_din = 1'b1;
#(8681);
rx_din = 1'b1;
#(8681);
$stop;
end
uart_rx u_uart_rx_tb(
.clk(clk) ,
.rst_n(rst_n) ,
.rx_din(rx_din),
.rx_dout(rx_dout),
.dout_vld(dout_vld)
);
endmodule
十、仿真结果
uart_tx仿真结果
uart_rx仿真结果