FPAG需要与其他设备进行通信,如上位机、传感器、执行器或其他处理器。UART提供了一种简单而广泛支持的通信方式,使FPAG能够与各种外部设备进行数据交换。下面将对UART的特性进行介绍。
1.UART的相关概念
UART全称是通用异步收发器(Universal Asynchronous Receiver-Transmitter)
主要是将数据在串行通信和并行通信间传输转换。简单来说就是将多比特数据在发送端转化为单比特的数据进行传输,或者将多比特转化为单比特的数据进行传输。
串行:即同一时刻只能传输一个数据位的数据
并行:同一时刻可以传输多个数据位的数据
异步:无同步时钟,即UART通常使用异步通信,意味着发送端和接收端的时钟不同步
2.UART的基本工作原理:
串行数据传输:UART通过一个引脚发送和接收数据,这两个引脚分别是TX(发送)和RX(接收)。发送端将要发送的数据转换为串行格式,并将其发送到TX引脚。接收端从RX引脚接收串行数据,并将其转换回并行数据。
帧结构:UART使用一组位来表示每个数据帧。帧通常由起始位、数据位、可选的校验位和停止位组成。起始位指示数据帧的开始,停止位指示数据帧的结束。校验位用于检测数据传输中的错误。
波特率:UART通信的速率由波特率(即数据传输速率)决定。波特率表示每秒传输的位数。发送端和接收端必须以相同的波特率进行通信,以确保数据能够正确传输。常见的波特率有9600Bd,115200Bd。
3.UART的verilog代码实现
以RS232为例,它是UAR的一种,常用于计算机和外部设备之间的数据传输。假设系统时钟50Hz,波特率9600Bd。
50Hz时钟,周期是20ns,1bit计数cnt = 1/9600/20 = 5208,即5208个计数才能发送或接收下一比特数据。
rx端:
1.rx传到FPGA中需要打俩拍,一是为了降低亚稳态,二是获取下降沿,作为开始的标志。
2.rx端在中间时刻采数据最稳定。
module uart_rx(
input wire clk,
input wire rst_n,
input wire rx,
output reg [7:0] po_data,
output reg po_flag
);
parameter CNT_BAUD_MAX = 5207;
parameter CNT_HALF_BAUD_MAX = 2603;
reg rx1,rx2,rx2_reg;
reg rx_flag;
reg [12:0] cnt_baud;
reg bit_flag;
reg [3:0] bit_cnt;
always @(posedge clk) begin
{rx2_reg,rx2,rx1}<={rx2,rx1,rx};
end
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
rx_flag <= 1'b0;
end
else if (bit_cnt == 4'd8 && bit_flag == 1'b1) begin
rx_flag <= 1'b0;
end
else if (rx2_reg == 1'b1 && rx2 == 1'b0) begin
rx_flag <= 1'b1;
end
end
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
cnt_baud <= 'd0;
end
else if (rx_flag == 1'b0) begin
cnt_baud <= 'd0;
end
else if (rx_flag == 1'b1 && cnt_baud == CNT_BAUD_MAX) begin
cnt_baud <= 'd0;
end
else if (rx_flag == 1'b1) begin
cnt_baud <= cnt_baud + 1'b1;
end
end
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
bit_flag <= 1'b0;
end
else if (rx_flag == 1'b1 && cnt_baud == CNT_HALF_BAUD_MAX) begin
bit_flag <= 1'b1;
end
else begin
bit_flag <= 1'b0;
end
end
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0) 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
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
po_data <='d0;
end
else if (bit_cnt >= 4'd1 && bit_flag == 1'b1) begin
po_data <= {rx2_reg,po_data[7:1]};
end
end
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
po_flag <= 1'b0;
end
else if (bit_cnt == 4'd8 && bit_flag == 1'b1) begin
po_flag <= 1'b1;
end
else begin
po_flag <= 1'b0;
end
end
endmodule
tx端:
module uart_tx(
input wire clk,
input wire rst_n,
input wire[7:0] pi_data,
input wire pi_flag,
output reg tx
);
reg [7:0] data_reg;
reg tx_flag;
reg [12:0] cnt_baud;
reg bit_flag;
reg [3:0] bit_cnt;
parameter CNT_BAUD_MAX = 5207;
always @(posedge clk or negedge rst_n) begin
if (rst_n ==1'b0 ) begin
data_reg <= 'd0;
end
else if (pi_flag == 1'b1) begin
data_reg <= pi_data;
end
end
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
tx_flag <= 'd0;
end
else if (bit_cnt == 'd8 && bit_flag == 1'b1) begin
tx_flag <= 'd0;
end
else if (pi_flag == 1'b1) begin
tx_flag <= 'd1;
end
end
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
cnt_baud <= 'd0;
end
else if(cnt_baud == CNT_BAUD_MAX&&tx_flag == 1'b1)begin
cnt_baud <= 'd0;
end
else if (tx_flag == 1'b1) begin
cnt_baud <= cnt_baud + 1'b1;
end
end
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
bit_flag <= 'd0;
end
else if (cnt_baud == CNT_BAUD_MAX-1&&tx_flag == 1'b1) begin
bit_flag <= 1'b1;
end
else begin
bit_flag <= 'd0;
end
end
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0) 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
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0) begin
tx <= 'd1;
end
else if(pi_flag == 1'b1)begin
tx <= 'd0;
end
else if (bit_flag == 1'b1 && bit_cnt<= 'd7) begin
tx <= data_reg[bit_cnt];
end
else if(bit_flag == 1'b1 && bit_cnt== 'd8)begin
tx <= 'd1;
end
end
endmodule
顶层top:
module top_uart(
input wire clk,
input wire rst_n,
input wire rx,
output wire tx
);
wire [7:0] data;
wire flag;
uart_rx inst_uart_rx (
.clk (clk),
.rst_n (rst_n),
.rx (rx),
.po_data (data),
.po_flag (flag)
);
uart_tx inst_uart_tx (
.clk (clk),
.rst_n (rst_n),
.pi_data (data),
.pi_flag (flag),
.tx (tx)
);
endmodule
最后可通过modelsim仿真。