UART 和 RS232
1、UART 的全称叫做通用异步收发传输器。将数据在串行通信和并行通信间的传 输转换。通俗的讲就是把多比特的数据转化为单比特的数据,或者把单比特的数 据转化为多比特的数据。工作原理是将数据的每个 bit 一位接一位地传输。
2、UART 是一种通用串行数据总线,用于异步通信。该总线双向通信,可以实现 全双工传输和接收。
3、RS232 是 UART 的一种,是目前最常用的一种串行通讯接口,用于 pc 机跟外 部板级通信。RS232 通信协议 1、rs232 是 uart 的一种,有两根线,分别是 rx 和 tx,这两根线都是 1 比特位 宽的。其中 rx 是接收线,tx 是发送线。 2、rx,位宽为 1 比特,pc 机通过串口往 FPGA 发 8 比特数据时,FPGA 通过串口 线 rx 一位一位地接收,从最低位到最高位依次接收,最后在 FPGA 里面位拼接成 8 比特数据。
4、在不发送或者不接收数据的情况下,rx 和 tx 处于空闲状态,此时 rx 和 tx 线都保持高电平(1),如果有数据传递,首先会有一个起始位(0),然后是 8 比特的数据位,接着有 1 比特的停止位(1),如果停止位以后不再发数据,将进入空闲状态,否则又将数据线拉低(进入起始位状态)。
5、波特率:在串口通信时的速率,单位时间内载波变化的次数,这里选用的是 9600Bd,即发送一比特数据需要的时间为 1/9600 秒。
6、用串口发送或者接收数据(起始位、数据位、停止位)时,每发送或者接收一 位数据的时间都需要 1 个波特,即 1/9600 秒。
7、串口发送或者接收一比特数据的时间为一个波特(1/9600),因此如果用 50M 的系统时钟来计数,就需要记数 cnt=(1/9600s)/20ns≈5208 个系统时钟,才再 次发送或者接收下一个数据。
8、上位机通过串口发 8 比特数据时,会自动在发 8 位有效数据前发一个波特时 间的起始位,也会自动在发完 8 位有效数据后发一个停止位。同理,串口助手接 收 fpga 发送的数据前,必须检测到一波特的起始位才会接收数据,接收完数据 后,再接收一个停止位,所以 FPGA 通过串口除了发数据以外,还要发起始位和 停止位。
设计要求:
写一个测试回环:上位机由串口助手通过 rx 线往 FPGA 发 8 比特数据,当 FPGA 接收到 8 比特数据后,再通过 tx 线把接收到的 8 比特数据给上位机发回去,要 求上位机接收到的数据和上位机发送的数据一样,并且保证连续发送也没问题。 rx 和 tx 写在两个单独的模块里面。
顶层模块设计
顶层模块示意图:
顶层模块代码实现:
module uart_top(
input wire clk,
input wire rst_n,
input wire rx,
input wire tx
);
wire [7:0] po_data;
wire po_flag;
uart_rx uart_rx_inst(
.clk(clk),
.rst_n(rst_n),
.rx(rx),
.po_data(po_data),
.po_flag(po_flag)
);
uart_tx uart_tx_inst(
.clk(clk),
.rst_n(rst_n),
.pi_flag(po_flag),
.pi_data(po_data),
.tx(tx)
);
endmodule
接收模块设计
接收模块示意图:
接收模块波形图:
接收模块代码实现:
module uart_rx(
input wire clk,
input wire rst_n,
input wire rx,
output reg [7:0] po_data,
output reg po_flag
);
reg rx1;
reg rx2;
reg rx2_reg;
reg rx_flag;
reg bit_flag;
reg [3:0] bit_cnt;
reg [12:0] baud_cnt;
always @(posedge clk) begin
rx1<=rx;
rx2<=rx1;
rx2_reg<=rx2;
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
baud_cnt<='d0;
end
else if(baud_cnt=='d5207) begin
baud_cnt<='d0;
end
else if(bit_cnt=='d8 && bit_flag==1'b1) begin
baud_cnt<='d0;
end
else if (rx_flag==1'b1) begin
baud_cnt<=baud_cnt+1'b1;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
bit_flag<=1'b0;
end
else if (baud_cnt=='d2603) begin
bit_flag<=1'b1;
end
else begin
bit_flag<=1'b0;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
bit_cnt<='d0;
end
else if(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 posedge rst_n) begin
if (!rst_n) begin
rx_flag<=1'b0;
end
else if (rx2_reg==1'b1 && rx2==1'b0) begin
rx_flag<=1'b1;
end
else if(bit_cnt=='d8 && bit_flag==1'b1) begin
rx_flag<=1'b0;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
po_data<='d0;
end
else if (bit_flag==1'b1 && bit_cnt>=1'b1) begin
po_data<={rx2,po_data[7:1]};
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
po_flag<=1'b0;
end
else if (bit_cnt=='d8 && bit_flag==1'b1) begin
po_flag<=1'b1;
end
else begin
po_flag<=1'b0;
end
end
endmodule
发送模块设计
发送模块示意图:
发送模块波形图:
发送模块代码实现:
module uart_tx(
input wire clk,
input wire rst_n,
input wire pi_flag,
input wire [7:0] pi_data,
output reg tx
);
reg [7:0] data_reg;//data_reg,数据缓存,避免上个模块输出变量发生变化而影响
reg tx_flag;
reg bit_flag;
reg [3:0] bit_cnt;
reg [12:0] baud_cnt;
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
bit_flag<=1'b0;
end
else if (baud_cnt==5206) begin
bit_flag<=1'b1;
end
else begin
bit_flag<=1'b0;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
bit_cnt<='d0;
end
else if(bit_cnt=='d8 && bit_flag==1'b1 ) begin
end
else if (bit_flag==1'b1) begin
bit_cnt<=bit_cnt+1'b1;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
data_reg<='d0;
end
else if (pi_flag==1'b1) begin
data_reg<=pi_data;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
tx_flag<=1'b0;
end
else if (pi_flag==1'b1) begin
tx_flag<=1'b1;
end
else if(bit_cnt=='d8 && bit_flag==1'b1) begin
tx_flag<=1'b0;
end
end
always @(posedge clk or posedge rst_n) begin
if (!rst_n) begin
tx<=1'b1;
end
else if(pi_flag==1'b1) begin
tx<=1'b0;
end
else if(bit_flag==1'b1 && bit_cnt<=7) begin
tx<=data_reg[bit_cnt];
end
else if(bit_cnt=='d8 && bit_flag==1'b1) begin
tx<=1'b1;
end
end
endmodule