【FPGA】UART串口通信
文章目录
- 一、通信方式
- 1.串行通信
- 2.并行通信
- 二、UART串口通信
- 1.模块设计与时序图
- 2.代码实现
- 三、测试结果
- 1.仿真结果
- 2.上板验证
一、通信方式
1.串行通信
串行通信是指利用一条传输线将数据一位位地顺序传送。(也就是说串行通信传输的数据是1比特1比特的传送的)
常见串行通信接口
串行通信优点是传输距离远、占用资源少。
串行通信缺点是发送速度慢。
2.并行通信
并行是指多比特数据同时通过并行线进行传送,这样数据传送速度大大提高。
但并行传送的线路长度受到限制,因为长度增加,干扰就会增加,数据也就容易出错。
并行通信优点是发送速度快。
并行通信缺点是传输距离短、资源占用多。
二、UART串口通信
UART是一种异步全双工通信方式
1.模块设计与时序图
uart_tx模块时序图
uart_rx模块时序图
2.代码实现
uart.v(顶层模块)
module uart
(
input clk ,
input rst_n ,
input u_rx ,
output u_tx
);
wire [7:0] data ;
wire start ;
uart_rx uart_rx(
.clk (clk) ,
.rst_n (rst_n) ,
.data (data) ,
.start (start) ,
.u_rx (u_rx)
);
uart_tx uart_tx(
.clk (clk) ,
.rst_n (rst_n) ,
.data (data) ,
.start (start) ,
.u_tx (u_tx)
);
endmodule
uart_tx
module uart_tx
#(
parameter BAUD_MAX = 5208,
parameter BAUD_FLAG = 1
)
(
input clk ,
input rst_n ,
input [7:0] data ,
input start ,
output reg u_tx
);
reg [14:0] baud_cnt ;
reg [4:0] bit_cnt ;
reg data_state ;
reg bit_flag ;
reg done ;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
data_state <= 1'b0 ;
else if(start)
data_state <= 1'b1 ;
else if(done)
data_state <= 1'b0 ;
else
data_state <= data_state ;
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
baud_cnt <= 1'b0 ;
else if(data_state)begin
if(baud_cnt == BAUD_MAX - 1)
baud_cnt <= 1'b0 ;
else
baud_cnt <= baud_cnt + 1'b1 ;
end
else
baud_cnt <= 1'b0 ;
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
bit_flag <= 1'b0 ;
else if(baud_cnt == BAUD_FLAG)
bit_flag <= 1'b1 ;
else
bit_flag <= 1'b0 ;
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
bit_cnt <= 1'b0 ;
else if(bit_flag)begin
if(bit_cnt == 9)
bit_cnt <= 1'b0 ;
else
bit_cnt <= bit_cnt + 1'b1 ;
end
else
bit_cnt <= bit_cnt ;
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
u_tx <= 1'b1 ;
else if(bit_flag)begin
case(bit_cnt)
0 : u_tx <= 1'b0 ;
1 : u_tx <= data[0] ;
2 : u_tx <= data[1] ;
3 : u_tx <= data[2] ;
4 : u_tx <= data[3] ;
5 : u_tx <= data[4] ;
6 : u_tx <= data[5] ;
7 : u_tx <= data[6] ;
8 : u_tx <= data[7] ;
9 : u_tx <= 1'b1 ;
default : u_tx <= 1'b1 ;
endcase
end
else
u_tx <= u_tx ;
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
done <= 1'b0 ;
else if(bit_cnt == 9 && bit_flag)
done <= 1'b1 ;
else
done <= 1'b0 ;
end
endmodule
uart_rx
module uart_rx
#(
parameter BAUD_MAX = 5208,
parameter BAUD_FLAG = 2604
)
(
input clk ,
input rst_n ,
input u_rx ,
output reg start ,
output reg [7:0] data
);
reg u_rx0 ;
reg u_rx1 ;
reg u_rx2 ;
reg [14:0] baud_cnt ;
reg [4:0] bit_cnt ;
reg data_state ;
reg bit_flag ;
reg done ;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
u_rx0 <= 1'b1 ;
u_rx1 <= 1'b1 ;
u_rx2 <= 1'b1 ;
end
else begin
u_rx0 <= u_rx ;
u_rx1 <= u_rx0 ;
u_rx2 <= u_rx1 ;
end
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
data_state <= 1'b0 ;
else if((!u_rx1) && (u_rx2))
data_state <= 1'b1 ;
else if(done)
data_state <= 1'b0 ;
else
data_state <= data_state ;
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
baud_cnt <= 1'b0 ;
else if(data_state)begin
if(baud_cnt == BAUD_MAX - 1)
baud_cnt <= 1'b0 ;
else
baud_cnt <= baud_cnt + 1'b1 ;
end
else
baud_cnt <= 1'b0 ;
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
bit_flag <= 1'b0 ;
else if(baud_cnt == BAUD_FLAG)
bit_flag <= 1'b1 ;
else
bit_flag <= 1'b0 ;
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
bit_cnt <= 1'b0 ;
else if(bit_flag)begin
if(bit_cnt == 9)
bit_cnt <= 1'b0 ;
else
bit_cnt <= bit_cnt + 1'b1 ;
end
else
bit_cnt <= bit_cnt ;
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
data <= 8'b00000000 ;
else if(bit_flag)begin
case(bit_cnt)
0 : data <= data ;
1 : data[0] <= u_rx2 ;
2 : data[1] <= u_rx2 ;
3 : data[2] <= u_rx2 ;
4 : data[3] <= u_rx2 ;
5 : data[4] <= u_rx2 ;
6 : data[5] <= u_rx2 ;
7 : data[6] <= u_rx2 ;
8 : data[7] <= u_rx2 ;
9 : data <= data ;
default : data <= data ;
endcase
end
else
data <= data ;
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
done <= 1'b0 ;
else if(bit_cnt == 9 && bit_flag)
done <= 1'b1 ;
else
done <= 1'b0 ;
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
start <= 1'b0 ;
else
start <= done ;
end
endmodule
uart_tb
`timescale 1ps/1ps
module uart_tb();
reg clk ;
reg rst_n ;
reg u_rx ;
wire u_tx ;
uart u_uart
(
.clk (clk) ,
.rst_n (rst_n) ,
.u_rx (u_rx) ,
.u_tx (u_tx)
);
initial begin
clk = 1;
forever
#10
clk=~clk;
end
initial begin
rst_n = 1;
#10;
rst_n = 0;
#20;
rst_n = 1;
end
parameter TIMEPERIOD = 20;
initial begin
u_rx = 1'b1;
#200
//发送起始位
u_rx = 1'd0;
#(5027*TIMEPERIOD);
//发送数据0
u_rx = 1'd1;
#(5027*TIMEPERIOD);
//发送数据1
u_rx = 1'd0;
#(5027*TIMEPERIOD);
//发送数据2
u_rx = 1'd0;
#(5027*TIMEPERIOD);
//发送数据3
u_rx = 1'd0;
#(5027*TIMEPERIOD);
//发送数据4
u_rx = 1'd0;
#(5027*TIMEPERIOD);
//发送数据5
u_rx = 1'd1;
#(5027*TIMEPERIOD);
//发送数据6
u_rx = 1'd0;
#(5027*TIMEPERIOD);
//发送数据7
u_rx = 1'd0;
#(5027*TIMEPERIOD);
//发送结束位
u_rx = 1'd1;
#(100000*TIMEPERIOD);
$stop ;
end
endmodule