FPGA入门之串口通信(UART)接收模块设计

如题所述

设计串口通信(UART)接收模块需要解决的主要问题包括:如何实现数据的同步接收,如何处理起始位、数据位和停止位,以及如何确保数据的正确性。

针对这些问题,可以将接收模块拆解为以下小部分:波特率分频计数器,用于确定接收每一位的位时间;起始位的下降边沿判断,使用D触发器保存上一时刻的值与本时刻进行运算;波特率计数器使能判断,决定何时开始和停止波特率计数;位计数器,用于判断接收到的哪一位;位接收逻辑,将接收到的数据位输出;接收完成标志信号,指示接收已完成。

实现上述逻辑时,需要关注的问题包括亚稳态不稳定因素的处理,波特率分频计数器的实现,以及位接收逻辑的正确性验证。

以下是Verilog代码实现,包括模块定义、参数声明、输入输出定义、内部信号定义、各个功能的实现逻辑等。

verilog
module uart_rx(
sysclk_p,
rstn_i,
data,
uart_rx,
recv_over
);
parameter CLK_FRQ = 50_000_000;
parameter BAUD = 9600;
parameter M_CNT_BAUD = CLK_FRQ/BAUD - 1'b1;
input sysclk_p;
input rstn_i;
input data;
output reg [7:0] uart_rx;
output reg recv_over;
reg [29:0] cnt_div_baud;
reg [3:0] cnt_bit;
reg en_cnt_baud;
reg r_data;
reg diff0_data;
reg diff1_data;
reg [7:0]r_uart_rx;
wire start_data_down;
wire r_recv_over;
// 波特率分频计数器
always @(posedge sysclk_p or negedge rstn_i) begin
if(!rstn_i) cnt_div_baud <= 0;
else if(en_cnt_baud) begin
if(cnt_div_baud == M_CNT_BAUD) cnt_div_baud <= 0;
else cnt_div_baud <= cnt_div_baud + 1'b1;
end else cnt_div_baud <= 0;
end
// 起始位的下降边沿判断
always @(posedge sysclk_p) begin
diff0_data <= data;
end
always @(posedge sysclk_p) begin
diff1_data <= diff0_data;
end
always @(posedge sysclk_p) begin
r_data <= diff1_data;
end
assign start_data_down = (!diff1_data)&&(r_data);
// 波特率计数器使能判断
always @(posedge sysclk_p or negedge rstn_i) begin
if(!rstn_i) en_cnt_baud <= 0;
else if(start_data_down) en_cnt_baud <= 1'b1;
else if((cnt_div_baud == M_CNT_BAUD/2)&&(cnt_bit == 0)&&(diff1_data == 1))
en_cnt_baud <= 0;
else if((cnt_div_baud == M_CNT_BAUD)&&(cnt_bit == 9))
en_cnt_baud <= 0;
end
// 位计数器
always @(posedge sysclk_p or negedge rstn_i) begin
if(!rstn_i) cnt_bit <= 0;
else if(cnt_div_baud == M_CNT_BAUD) begin
if(cnt_bit == 4'd9) cnt_bit <= 0;
else cnt_bit <= cnt_bit + 1'b1;
end else cnt_bit <= cnt_bit;
end
// 位接收逻辑
always @(posedge sysclk_p or negedge rstn_i) begin
if(!rstn_i) uart_rx <= 0;
else if(cnt_div_baud == M_CNT_BAUD/2) begin
case(cnt_bit)
1:r_uart_rx[0] <= diff1_data;
2:r_uart_rx[1] <= diff1_data;
3:r_uart_rx[2] <= diff1_data;
4:r_uart_rx[3] <= diff1_data;
5:r_uart_rx[4] <= diff1_data;
6:r_uart_rx[5] <= diff1_data;
7:r_uart_rx[6] <= diff1_data;
8:r_uart_rx[7] <= diff1_data;
default:diff1_data <= diff1_data;
endcase
end
end
// 接收完成标志信号
assign r_recv_over = (cnt_div_baud == M_CNT_BAUD)&&(cnt_bit == 9);
always @(posedge sysclk_p) begin
recv_over <= r_recv_over;
end
// 确保接收完一次数据后,输出串口接收数据
always @(posedge sysclk_p) begin
if(r_recv_over) uart_rx <= r_uart_rx;
end
endmodule

此外,还提供了testbench代码,用于模拟发送数据,并对接收模块进行测试。

verilog
module uart_rx_tb();
reg sysclk_p;
reg rstn_i;
reg data;
wire [7:0]uart_rx;
wire recv_over;
uart_rx uart_rx_inst0(
.sysclk_p(sysclk_p),
.rstn_i(rstn_i),
.data(data),
.uart_rx(uart_rx),
.recv_over(recv_over)
);
initial begin
sysclk_p = 1;
rstn_i = 0;
data = 1;
#201;
rstn_i = 1;
#200
data = 0;
#(5208*20);
data = 0;
#(5208*20);
data = 1;
#(5208*20);
data = 0;
#(5208*20);
data = 1;
#(5208*20);
data = 0;
#(5208*20);
data = 1;
#(5208*20);
data = 0;
#(5208*20);
data = 1;
#(5208*20);
data = 1;
#(5208*20*10);
data = 0;
#(5208*20);
data = 1;
#(5208*20);
data = 0;
#(5208*20);
data = 1;
#(5208*20);
data = 0;
#(5208*20);
data = 1;
#(5208*20);
data = 0;
#(5208*20);
data = 1;
#(5208*20);
data = 0;
#(5208*20);
data = 1;
#(5208*20*10);
data = 0;
#(5208*20);
data = 0;
#(5208*20);
data = 0;
#(5208*20);
data = 1;
#(5208*20);
data = 1;
#(5208*20);
data = 1;
#(5208*20);
data = 1;
#(5208*20);
data = 0;
#(5208*20);
data = 0;
#(5208*20);
data = 1;
#(5208*20*10);
$stop;
end
always #10 sysclk_p = ~sysclk_p;
endmodule

仿真结果图展示了接收模块在测试环境下的行为,包括接收到的数据、接收完成标志信号等。
温馨提示:内容为网友见解,仅供参考
无其他回答

FPGA入门之串口通信(UART)接收模块设计
if(!rstn_i) uart_rx <= 0;else if(cnt_div_baud == M_CNT_BAUD\/2) begin case(cnt_bit)1:r_uart_rx[0] <= diff1_data;2:r_uart_rx[1] <= diff1_data;3:r_uart_rx[2] <= diff1_data;4:r_uart_rx[3] <= diff1_data;5:r_uart_rx[4] <= diff1_data;6:r_uar...

FPGA入门之串口通信(UART)
FPGA入门教程中,串口通信(UART)是一个重要模块。它用于在硬件与计算机之间进行数据传输,主要通过发送和接收数据信号。使用Verilog编程在FPGA中实现UART发送模块,首先需要理解其工作原理,包括波特率生成、位计数、数据发送和同步控制等关键步骤。具体实现中,首先设定一个波特率计数器(MCNT_BAUD)和位计数...

UART串口通信(二)
UART接收模块专门处理接收到的数据。UART发送模块负责生成并发送数据。UART环回模块协调接收和发送模块,确保通信的顺畅。UART顶层模块整合所有功能,形成完整通信系统。激励模块用于输入信号,模拟实际通信场景。仿真结果展示了UART通信系统各部分的交互与响应,验证了设计的有效性。

UART通信协议
UART通信协议解析 UART, 或称为通用异步接收发送器,是串行通信的基础,如RS232和RS485接口。它专为低速、长距离和简化调试设计,tx和rx线连接设备,支持全双工数据传输。在FPGA设计中, UART 通过loopback测试验证数据链路的稳健性,尤其是在传感器调试和高速接口简化方面。数据接收与同步 在接收模块中,...

【紫光同创国产FPGA教程】【PGL50H第四章】串口收发实验例程
串口通信使用TXD(发送)和RXD(接收)线,加上起始位、数据位、无校验位和结束位。波特率的计算是通过计数器实现,发送和接收模块需独立设计。实验设计包括发射模块(发送数据,无校验位)、接收模块(锁定数据并提供数据使能信号)、发射控制模块(1S间隔触发信号)和顶层模块(集成发送和接收任务)。实验...

孩子都能学会的FPGA:第九课——多字节数据的发送和接收
课程最后通过具体的模块设计与实例演示,展示了如何通过寄存器、状态机参数及三段式设计方法,实现数据发送与接收功能。发送模块通过参数传递控制数据长度、帧头与帧尾的传输,接收模块则通过检测信号变化及状态机逻辑,实现数据的正确接收。顶层文件uart_top整合了发送与接收模块,通过参数传递实现功能集成。课程...

想要系统学习一下fpga串口通信,spi,axi总线协议的知识,有
在学习FPGA串口通信时,确保掌握基本的串口原理和通信模式,如UART、SPI等。理解时序和数据传输过程,这对于实际应用至关重要。在学习SPI时,关注其数据传输的时序控制,以及与FPGA的接口配置。而对于AXI总线协议,重点在于理解其数据传输的高效性和并行性,以及如何在FPGA中实现高速数据交换。在深入学习时,...

FPGA 怎么实现UART串口和IIC口或SPI 通讯?可以大概说一下吗?
FPGA是属于硬件编程,程序是并行执行的,可以有多个进程,同时执行不同的功能。2. FPGA实现UART,IIC,SPI。如果是简单的应用(比如说不用校验等等),完全可以自己写,例如下面的程序,VHDL写的,既可以作为UART发送程序(改改就是接收),也可以做SPI发送或者接收(加一个时钟)。如果需要较完善的功能的...

UART串口通讯协议
【嵌牛鼻子】 UART 【嵌牛提问】串口协议解决了信息传输中的什么问题?【嵌牛正文】在实现生活中,往往不是单独工作的,需要与别人进行合作,这就需要交流,以传达信息。在FPGA中,各个芯片之间也是相对独立的,要想协同一起工作,双方之间的通讯是必不可少的。1. 何时发送数据:  什么时候开始,我...

纯逻辑配置AD9361教程\/通过UART串口发送配置文件配置AD9361\/通过rom配置...
首先,通过前面的文章创建一个AD9361配置文件。使用AD936x Evaluation Software进行配置,生成配置文件tran。接着,通过转换软件Trans2.0.exe将配置文件转化为dat文件。双击打开软件,导入配置文件,更改文件名为tran.txt,导入转换,另存为dat文件。然后,打开FPGA工程。介绍包含四个关键文件:Ad9361config.v...

相似回答
大家正在搜