FPGA串口通信上——串口发送

1.前言

本次主要学习串口通信协议的FPGA实现,使用ModelSim仿真并在锆石科技A4-plus开发板上做验证,由于串口发送和接收整篇篇幅较长,所以这里我将串口发送分开来写,本次主要写串口发送,串口接收部分将在下一篇实现。

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语言实现串口通信,程序分为6给always模块,即6个线程,首先第一个模块用来选择波特率技术延时,由于本次开发板的的时钟是50MHz,所以always模块每隔20ns进去一次,所以需要设置不同的波特率对应的不同计数值,比如115200的波特率每隔1/115200s改变一位数据,即8680ns,8680÷20=434,所以115200的波特率需要计数到434。同时,其他波特率4800、9600、38400、128000、230400、256000的计数值分别为10417、5208、2604、1302、391、217、195。所以第一个线程通过一个位选来选择所使用的波特率,设置默认为115200。第二个线程用来实现串口发送使能,当计数到1s之后,使能发送信号,当一帧数据发送完成之后,使能信号清零。第三个线程用来实现波特率计数器,当计数到对应波特率的最大计数值时,计数清零,否则计数值加一。第四个线程用来实现位计数器,即传发送的位数,当波特率计数到最大值时,发送位数加一发送下一位。第五个线程用来数据发送延时计数器,设计延时一秒发送数据延时。最后一个线程用来实现位发送逻辑,根据当前位计数器的值发送起始位、8位串行数据为、停止位(本次没有设置奇偶校验位)。至此,串口发送程序完成。之后编写testbench仿真,并进行板级验证。

部分verilog主程序如下:(注意仿真时需要将计数值26'd50_000_000改为26'd500000,即将1s发送一帧数据改为10ms发送一帧数据,节约仿真时间,否则在仿真中看不要数据波形的变化)

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

module uart_byte_tx(
	input CLK,//50MHZ时钟信号
	input RST,//复位信号
	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 send_en;//发送使能端口
reg [25:0]delay_cnt;//一秒延时计数
reg [3:0]cnt;//发送位计数
always@(posedge CLK or negedge RST)
begin
	if(!RST)
		send_en <= 14'd0;//复位清零
	else if(delay_cnt == 26'd50_000_000-1)
		send_en <= 14'd1;
	else if(cnt==10 && baud_cnts == baud_cnt-1)
		send_en <= 14'd0;
end
//实现波特率计数器
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
end


endmodule

仿真波形如下图所示:

最后进行板级验证,串口助手接收到的数据如下所示:

完成verliog工程链接(基于quartus II):FPGA纯verliog实现串口通信,串口发送资源-优快云文库

4.总结

至此,本博客关于串口发送的简介就结束了,通过实现仿真和板级验证,希望对各位读者有所帮助,本程序还有很多优化的方面,比如如何设置不让它一直发等等。下一篇我们将介绍串口接收数据,同时将本次的串口发送整合进来,当接收到数据的时候把接收到的数据发送过来。同时串口接收存在一个亚稳态的问题,各位读者可以先思考一下。

最后,希望各位都学有所成,有什么问题可以私信我。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

得之坦然,失之淡然。

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

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

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

打赏作者

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

抵扣说明:

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

余额充值