FPGA串口通信下——串口接收+发送

目录

1.前言

2.串口通信简介

3.程序设计

4.总结

(附源码)FPGA驱动将串口接收到的数据发送出去!!!,看完你就懂了。

1.前言

之前我们介绍了串口通信的发送部分,即每秒自动发送一帧数据,那么如果我们不想让他一直发送数据该怎么办呢?下面我们就来介绍一下不自动发送数据,当接收到数据时,将接收到的数据发送出来,没有接收到数据时不发送。最后贴出代码供大家参考一下,希望可以起到抛砖引玉的作用。

2.串口通信简介

本次还是同样介绍一下串口通信,防止没看过之前博客的同学不了解。

日常通信方式中主要分为串行通信和并行通信,并行通信通常情况下是由多个发送或接收数据线组成的,每根线传输一位或多位,传输速率较快,但成本较高,不适合用于长距离通信。而串行通信通常是数据发送或接收在一条数据线上,数据的每一位按特定的通信协议顺序传输,这种方法会减少使用成本,但传输速率较并行传输来说较慢。而串口通信协议数据串行通信,所以我们本次主要来讲解下串行通信。

串行通信主要分为两种,同步串行通信和异步串行通信,同步串行通信需要通信双方在同一时钟控制下同步传输数据,如SPI、IIC等。异步串行通信是指不规则数据段传输特性的串行数据传输,如串口通信等。UART采用异步串行通信方式,在发送数据时,将并行数据转化成串行数据发送,在接收端将接收到的串行数据转化成并行数据来处理。

串口通信数据线包括TX和RX,TX用来发送,RX用来接收,连接为TX接RX,RX接TX。串口通信数据帧格式如下图所示。串口通信数据帧由起始位,数据位,奇偶校验位和停止位组成,起始位低电平有效,8位数据位用来传输一个8位的数据(还可以是5、6、7位,大多数情况下是8位),奇偶校验位用来平衡数据位中“1”的个数+奇偶校验位“1”的个数为奇数或者偶数(如果不使用奇偶检验位数据位可以是9位),最后停止位高电平有效。串口通信速率由波特率来表示,常用的有9600、19200、38400、57600、115200等等,比如115200表示1s之内可以传输115200个位,即一位的传输时间为1/115200s。

3.程序设计

本次使用verilog实现串口通信,系统主要分为三个模块,分别是串口发送、串口接收和主函数。下面将分别实现。串口发送部分即上篇博客实现的功能,只不过是将原来的每隔一秒自动发送的控制信号去掉,同时添加发送使能信号以及发送完成信号,例化为该模块的输入输出,供主模块调用。对此我们就简单说到这里。串口接收部分主要流程也是同样的,判断每一位接收的数据,起始位、数据位、停止位等,从而将串行数据整合成并行数据,我这里在一帧数据的每一位判断一次,如果希望抗干扰能力强,可以在一帧的每一位判断多次来确定当前位的数值,同时在接收中存在一个亚稳态的问题,即在系统时钟边沿接收到下降沿信号,这是就无法接收到下降沿信号,可能造成接收不到起始位从而把数据位的某一位判断成了起始位,造成数据接收紊乱,解决这一办法的问题也很简单,就是添加一个锁存器,将接收到的数据锁存起来,在下一个时钟到来的时候判断。最后主函数模块用来例化一个串口接收和发送的模块,并实现相关逻辑,将接收到的数据送给发送模块发送。之后编写testbench文件进行波形仿真,最后进行下板验证。

仿真波形如图所示,可以看到tx将rx接收到的数据发送了出来。

最后下板验证如下图所示,通过串口助手发送并接收数据,可以正常发送和接收数据。

基于quartus II的工程地址如下:

FPGA纯verliog实现串口通信,串口回环资源-优快云文库

部分程序展示:

uart_byte_tx.v

/*
	功能:串口发送一个字节(8位)模块设计
	作者:王志川
	时间:2024.6.29
*/

module uart_byte_tx(
	input CLK,//50MHZ时钟信号
	input RST,//复位信号
	input send_en,//发送使能信号
	input [7:0]data,//发送的数据
	output reg send_done,//发送完成信号
	output reg uart_tx//串口发送引脚
);

/*
	波特率115200即每秒发送115200个数据位
	本次开发板时钟频率为50MHZ
	本次支持的波特率包括4800,9600,19200,38400,115200,128000,230400,256000;
	其中发送间隔最长的为4800,间隔为208333ns
	50MHZ的时钟相邻上升沿的时间间隔为20ns,大约需要10417个时钟上升沿,对应二进制数位宽为14位  
	其余波特率对应的上升沿计数次数为5208,2604,1302,434,391,217,195
*/ 
/*
	baud_set=0,baud=4800;
	baud_set=1,baud=9600;
	baud_set=2,baud=19200;
	baud_set=3,baud=38400;
	baud_set=4,baud=115200;
	baud_set=5,baud=128000;
	baud_set=6,baud=230400;
	baud_set=7,baud=256000;
*/
//波特率选择,0-7对应上述波特率
reg [13:0]baud_cnt;//计数值
reg [2:0]baud_set = 3'd4; //波特率选择
always@(*)
begin
	case(baud_set)
		0:baud_cnt <= 10417;
		1:baud_cnt <= 5208;
		2:baud_cnt <= 2604;
		3:baud_cnt <= 1302;
		4:baud_cnt <= 434;
		5:baud_cnt <= 391;
		6:baud_cnt <= 217;
		7:baud_cnt <= 195;
		default:baud_cnt <= 434;
	endcase
end

reg [13:0]baud_cnts;//波特率计数值
reg [3:0]cnt;//发送位计数
//实现波特率计数器
always@(posedge CLK or negedge RST)
begin
	if(!RST)
		baud_cnts <= 14'd0;//复位清零
	else if(send_en)begin
		if(baud_cnts == baud_cnt-1)//计数到最大值清零
			baud_cnts <= 14'd0;
		else
			baud_cnts <= baud_cnts + 1'd1;//否则计数器自加
	end
	else
		baud_cnts <= 14'd0;
end

//实现位计数器,即发送位的计数
always@(posedge CLK or negedge RST)
begin
	if(!RST)
		cnt <= 4'd0;//复位清零
	else if(baud_cnts == baud_cnt-1)begin//计数到最大值才开始发送位
		if(cnt == 4'd11)
			cnt <= 4'd0;
		else
			cnt <= cnt +1'd1;
	end
	else if(send_done == 1'd1)
		cnt <= 4'd0;
end

//位发送实现逻辑
always@(posedge CLK or negedge RST)
begin
	if(!RST)
		uart_tx <= 1'd1;//复位
	else
		case(cnt)
			0:begin 
				send_done <= 1'd0;//起始位
				uart_tx <= 1'd1;
			end
			1:uart_tx <= 1'd0;//开始发送
			2:uart_tx <= data[0];
			3:uart_tx <= data[1];
			4:uart_tx <= data[2];
			5:uart_tx <= data[3];
			6:uart_tx <= data[4];
			7:uart_tx <= data[5];
			8:uart_tx <= data[6];
			9:uart_tx <= data[7];
			10:uart_tx <= 1'd1;//停止位
			11:send_done <= 1'd1;//发送完成
			default:uart_tx<= 1'd1;
		endcase
end

endmodule

4.总结

本次串口通信到此结束,希望各位学有所成,有什么问题可以私信我。

### FPGA 中实现 UART 发送接收功能 #### 1. UART 基本原理 UART 是一种用于异步串行通信的标准接口,允许两个设备之间交换数据。在FPGA中实现UART发送接收功能涉及到配置波特率、设置起始位、停止位以及校验位等参数[^1]。 #### 2. Verilog 模块结构概述 对于初学者来说,建议先理解UART的工作机制而不是简单复制粘贴现有代码。通常情况下,会创建独立的发送(TX)和接收(RX)模块,并在一个顶层文件里实例化它们。这种方式有助于更好地掌握内部工作流程并便于后续调试与修改[^2]。 #### 3. 状态机控制逻辑 为了更深入地理解和优化性能,可以采用有限状态机(FSM)来管理UART的操作过程。例如,在发送操作中定义多个阶段如空闲态、加载字符、移位输出直到结束;同样地,接收端也需要相应处理接收到的数据流变化情况。 #### 4. 定时器与时钟分频电路 由于不同应用场景可能要求不同的波特率设定,因此需要构建可编程定时器或利用时钟分频技术来满足特定速率下的采样精度需求。这一步骤至关重要因为它直接影响到通讯质量的好坏[^4]。 #### 5. Loopback 测试验证方法 Loopback模式是一种有效的自我检测手段,它通过把发送出来的信号直接反馈给输入端来进行闭环检验。此方法可以帮助确认整个系统的连通性和稳定性,同时也可用于初步的功能性测试[^3]。 ```verilog // 示例:简单的UART TX模块框架 (部分伪代码) module uart_tx ( input wire clk, rst_n, input wire tx_start, input wire [7:0] data_in, output reg tx_done, output wire txd ); // ...省略其他声明... always @(posedge clk or negedge rst_n) begin : proc_state if (!rst_n) begin state <= IDLE; // 初始化其余寄存器... end else case(state) IDLE: /* 处理空闲状态 */; LOAD_DATA: /* 加载待发数据 */; SHIFT_OUT: /* 移位输出每一位 */; STOP_BIT: /* 输出停止位 */ ; default: state <= IDLE; // 防呆措施 endcase end endmodule ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

得之坦然,失之淡然。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值