FPGA——串口收发

这篇具有很好参考价值的文章主要介绍了FPGA——串口收发。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

常用的三大低速串口通信有UART,SPI,IIC。这里使用FPGA实现UART通信。UART通信只有两根线,一根是发送数据tx,一根是接受数据rx。PC和PFGA通过两个线实现数据通信。

fpga实现串口收发,fpga开发
完成FPGA部分的收发设计实现串口通信。

RS232
1、RS232 是 UART 的一种,没有时钟线,只有两根数据线,分别是 rx 和 tx,这两根线都是 1bit 位宽的。其中 rx 是接收数据的线,tx 是发送数据的线。
2、rx 位宽为 1bit,PC 机通过串口调试助手往 FPGA 发 8bit 数据时,FPGA 通过串口线rx 一位一位地接收,从最低位到最高位依次接收,最后在 FPGA 里面位拼接成 8 比特数据。
3、tx 位宽为 1bit,FPGA 通过串口往 PC 机发 8bit 数据时,FPGA 把 8bit 数据通过 tx线一位一位的传给 PC 机,从最低位到最高位依次发送,最后上位机通过串口助手按照RS232 协议把这一位一位的数据位拼接成 8bit 数据。
4、串口数据的发送与接收是基于帧结构的,即一帧一帧的发送与接收数据。每一帧除了中间包含 8bit 有效数据外,还在每一帧的开头都必须有一个起始位,且固定为 0;在每一帧的结束时也必须有一个停止位,且固定为 1,即最基本的帧结构(不包括校验等)有10bit。在不发送或者不接收数据的情况下,rx 和 tx 处于空闲状态,此时 rx 和 tx 线都保持高电平,如果有数据帧传输时,首先会有一个起始位,然后是 8bit 的数据位,接着有 1bit的停止位,然后 rx 和 tx 继续进入空闲状态,然后等待下一次的数据传输。如图 28-7 所示为一个最基本的 RS232 帧结构。
fpga实现串口收发,fpga开发
1bit表示二进制中1or0的一位。一个二进制的码元(1or0)就能携带1bit的信息(1or0)。一个八进制的码元就可以携带3bit的信息。
s232串口波特率就也是码元传输速率。9600Baud/s.表示每秒传输9600个码元。bit(bps)比特率=(Bps)波特数单个调制状态对应的二进制,上图就是9600/1。Ps:串口发送或者接受一个数据时间为波特。串口波特率为9600Bps,那么一个波特时间就为1/9600s。如果系统时钟为50Mhz,那么在9600波特下,一个波特就相当于1/9600s再除以20ns=5208个系统周期。也就是串口每传输一个bit的信息,系统时钟要保持5208个周期。
FPGA接受模块

module	uart_rx
#(
	parameter		UART_BAUD = 'd9600, 	//波特率
	parameter		CLK_FRE	 = 'd50_000_000	//系统时钟
)
(
	input	wire		sys_clk		,
	input	wire		sys_rst_n	,
	input	wire		rx			,//由助手发过来的串行数据
	
	
	
	output	reg [7:0]	po_data		,//传出的并行数据
	output	reg			po_flag		 //数据发送的标志信号
);

parameter		BAUD_MAX = CLK_FRE/UART_BAUD;//每传输一个bit数据所需要的传输时间

reg			rx_reg1;//打三拍,减少亚稳态的影响
reg			rx_reg2;//由于信号达到寄存器的建立时间和保持时间不满足要求
reg			rx_reg3;//所以产生了亚稳态
reg			start_nedge;
reg			work_on;
reg	[12:0]	baud_cnt;
reg			bit_flag;
reg	[3:0]	bit_cnt;
reg	[7:0]	rx_data;
reg			rx_flag;

always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		rx_reg1 <= 1'b1;
	else
		rx_reg1 <= rx;

always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		rx_reg2 <= 1'b1;
	else
		rx_reg2 <= rx_reg1;

always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		rx_reg3 <= 1'b1;
	else
		rx_reg3 <= rx_reg2;
//检测到rx_reg的下降沿时,产生一个时钟的高电平。检测下降沿时,可以把信号延迟
//一个时钟,然后通过如下提取出一个标志信号来。		
always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		start_nedge <= 1'b0;
	else	if((rx_reg2 == 1'b0) && (rx_reg3 == 1'b1) && (work_on == 1'b0))
		start_nedge <= 1'b1;
	else
		start_nedge <= 1'b0;
//可以通过提取出来的标志信号来确定一个使能信号。使用使能信号可以确定数据的采样范围		
always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		work_on <= 1'b0;
	else	if(start_nedge == 1'b1)
		work_on <= 1'b1;
	else	if(bit_flag == 1'b1 && bit_cnt == 4'd8)	
		work_on	<= 1'b0;
	else	
		work_on <= work_on;
//波特率计数器计数,一个bit信息所需要的时间。50_000_000/9600=5208
always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		baud_cnt <= 13'd0;
	else	if(baud_cnt == BAUD_MAX - 1 || work_on == 1'b0)
		baud_cnt <= 13'd0;
	else	if(work_on == 1'b1)
		baud_cnt <= baud_cnt + 1'b1;
//当计数器计数到中间时采样的数据最稳定
//此时拉高一个标志信息表示数据可以被取走		
always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		bit_flag <= 1'b0;
	else	if(baud_cnt == BAUD_MAX/2 - 1)
		bit_flag <= 1'b1;
	else	
		bit_flag <= 1'b0;
//有效数据个数的计数器,8个有效数据(不含起始位0和停止位1)
always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		bit_cnt <= 4'd0;
	else	if(bit_cnt == 4'd8 && bit_flag == 1'b1)
		bit_cnt <= 4'd0;
	else	if(bit_flag == 1'b1)
		bit_cnt <= bit_cnt + 1'b1;
//输入的数据进行移位
always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		rx_data <= 8'h00;
	else	if(bit_cnt >= 4'd1 && bit_cnt <= 4'd8 && bit_flag == 1'b1)
		rx_data <= {rx_reg3,rx_data[7:1]};
//输入的数据完成时,拉高一个时钟的电平		
always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		rx_flag <= 1'b0;
	else	if(bit_cnt == 4'd8 && bit_flag == 1'b1)
		rx_flag <= 1'b1;
	else	
		rx_flag <= 1'b0;
//完成输出8位有效数据		
always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		po_data <= 8'h00;
	else	if(rx_flag == 1'b1)
		po_data <= rx_data;
//输出数据有效标志位
always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		po_flag <= 1'b0;
	else
		po_flag <= rx_flag;




endmodule



FPGA发送模块

module	uart_tx
#(
	parameter 		UART_BPS = 'd9600,//串口波特率
	parameter		CLK_FRE = 'd50_000_000//时钟频率
)
(
	input	wire		sys_clk		,
	input	wire		sys_rst_n	,
	input	wire [7:0]	pi_data		,//模块输入的8bit数据
	input	wire 		pi_flag		,//并行数据的有效标志信号
	
	
	output	reg		tx				//串转并的1bit数据
);


parameter		BAUD_CNT = CLK_FRE/UART_BPS;//

reg			work_on;
reg	[12:0]	baud_cnt;
reg			bit_flag;
reg	[3:0]	bit_cnt;



always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		work_on <= 1'b0;
	else	if(pi_flag == 1'b1)
		work_on <= 1'b1;
	else	if(bit_flag == 1'b1 && bit_cnt == 4'd9)
		work_on <= 1'b0;
	else
		work_on <= work_on;

always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		baud_cnt <= 0;
	else	if(baud_cnt == BAUD_CNT - 1 || work_on == 1'b0)
		baud_cnt <= 0;
	else	if(work_on == 1'b1)
		baud_cnt <= baud_cnt + 1'b1;
		
		
always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		bit_flag <= 1'b0;
	else	if(baud_cnt == 0 && work_on == 1'b1)
		bit_flag <= 1'b1;
	else
		bit_flag <= 1'b0;

always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		bit_cnt <= 0;
	else	if(bit_cnt == 4'd9 && bit_flag == 1'b1)
		bit_cnt <= 4'd0;
	else	if(bit_flag == 1'b1 && work_on == 1'b1)
		bit_cnt <= bit_cnt + 1'b1;

always@(posedge sys_clk or negedge sys_rst_n)
	if(sys_rst_n == 1'b0)
		tx <= 1'b1;
	else	if(bit_flag == 1'b1)
	begin
		case(bit_cnt)
			0:	tx <= 1'b0;
			1:	tx <= pi_data[0];
			2:	tx <= pi_data[1];
			3:	tx <= pi_data[2];
			4:	tx <= pi_data[3];
			5:	tx <= pi_data[4];
			6:	tx <= pi_data[5];
			7:	tx <= pi_data[6];
			8:	tx <= pi_data[7];
			9:	tx <= 1'b1;
			default: tx <= 1'b1;		
		endcase
	end



endmodule

顶层模块

module	rs232
(
	input	wire		sys_clk		,
	input	wire		sys_rst_n	,
	input	wire		rx			,
	
	output	wire		tx
);

wire	[7:0]	po_data;
wire			po_flag;





uart_rx
#(
	.UART_BAUD(9600), 	//波特率
	.CLK_FRE(50_000_000)	//系统时钟
)
uart_rx_inst
(
	.sys_clk		(sys_clk),
	.sys_rst_n		(sys_rst_n),
	.rx				(rx),//由助手发过来的串行数据

	.po_data		(po_data),//传出的并行数据
	.po_flag		(po_flag) //数据发送的标志信号
);


uart_tx
#(
	.UART_BPS(9600),
	.CLK_FRE(50_000_000)
)
uart_tx_inst
(
	.sys_clk		(sys_clk),
	.sys_rst_n		(sys_rst_n),
	.pi_data		(po_data),
	.pi_flag		(po_flag),


	.tx             (tx)
);




endmodule

仿真结果
fpga实现串口收发,fpga开发
串口助手调试结果
fpga实现串口收发,fpga开发文章来源地址https://www.toymoban.com/news/detail-553364.html

到了这里,关于FPGA——串口收发的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于QT做上位机开发,实现FPGA通过cyusb3014芯片完成数据的收发

    #任务要求: 要求用qt编写上位机程序,实现FPGA通过cyusb3014芯片完成数据的收发。下面是采用通过cypress并安装usb官方驱动的环境搭建,后续继续更新程序的编写。 一、安装nodejs ①下载地址:https://nodejs.org/en/ ①.1: 安装时,除了选择安装路径根据需要选择外,其他都可以默认

    2024年02月06日
    浏览(58)
  • FPGA-结合协议时序实现UART收发器(五):串口顶层模块UART_TOP、例化PLL、UART_FIFO、uart_drive

    串口顶层模块UART_TOP、例化PLL、UART_FIFO、uart_drive,功能实现。 对照代码,串口发送模块UART_TOP实现功能包括: PLL锁相环,实现稳定系统输入时钟功能 UART_FIFO,数据先进先出,实现数据缓存功能,防止出现数据错乱 w_clk_rst = ~w_system_pll_locked;保证复位电平是先高位再地位 r_use

    2024年02月08日
    浏览(89)
  • 基于vivado+Verilog FPGA开发 — GT收发器

    代码规范:Verilog 代码规范_verilog代码编写规范-CSDN博客 开发流程:FPGA基础知识----第二章 FPGA 开发流程_fpga 一个项目的整个流程-CSDN博客   源码下载:GitHub - Redamancy785/FPGA-Learning-Record: 项目博客:https://blog.csdn.net/weixin_51460407 零、低速通信接口的缺陷 1、同步通信要求传输数据

    2024年04月17日
    浏览(64)
  • FPGA实现ESP8266驱动且进行数据包收发

    本次将使用正点原子的ESP8266 WIFI模块,来实现PC与FPGA之间的TCP通讯,其中ESP8266与FPGA之间的接口是UART。 模块实物图如下,到手就可以使用了,RST和IO_0两个IO口不接或者接高电平就可以了。 在使用之前,需要通过AT指令对模块进行配置,比如说是AP模式,还是STA模式。AP模式就

    2024年02月04日
    浏览(45)
  • 【Python】串口通信-与FPGA、蓝牙模块实现串口通信(Python+FPGA)

    🎉欢迎来到Python专栏~与FPGA、蓝牙模块实现串口通信 ☆* o(≧▽≦)o *☆ 嗨 ~我是 小夏与酒 🍹 ✨ 博客主页: 小夏与酒的博客 🎈该系列 文章专栏: Python学习专栏 文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏 📜 欢迎大家关注! ❤️ Python与FPGA串口通信

    2024年02月15日
    浏览(45)
  • 【FPGA】FPGA实现UART串口通信回环

    关于UART协议的基础理论部分已经在上一篇文章中讲述,不再重复介绍。 UART通信协议 本文主要介绍如何使用Verlilog编程,通过FPGA实现UART串口通信回环工程。在本工程中所使用的系统时钟为50MHz,如果选择115200的波特率进行数据传输,那么传输1bit所用的时钟周期数就是50_000_

    2024年02月05日
    浏览(66)
  • FPGA-结合协议时序实现UART收发器(一):UART协议、架构规划、框图

    记录FPGA的UART学习笔记,以及一些细节处理,主要参考奇哥fpga学习资料。 本次UART主要采用计数器方法实现,实现uart的稳定性发送和接收功能,最后实现串口数据回环进行功能测试。 UART协议如图。 包含:空闲位、起始位、数据位、校验位、停止位、空闲位(一般没有) 对于

    2024年02月08日
    浏览(67)
  • FPGA使用GTH实现SDI视频回环收发 提供工程源码和技术支持

    FPGA实现SDI视频编解码目前有两种方案: 一是使用专用编解码芯片,比如典型的接收器GS2971,发送器GS2972,优点是简单,比如GS2971接收器直接将SDI解码为并行的YCRCB,GS2972发送器直接将并行的YCRCB编码为SDI视频,缺点是成本较高,可以百度一下GS2971和GS2972的价格; 另一种方案是

    2024年02月11日
    浏览(54)
  • FPGA开发基础篇之一(接口篇)UART串口

    写在前面 从本文开始,将连载fpga开发基础知识,将这几年浅显的fpga开发经验整理出来,一是梳理一下这几年给别人做fpga的经历,同时也是分享给大家,也希望大牛批评指正。 一、UART串口通信基本概念 串口通信是非常基本且应用十分广泛的低速通信接口,无论是在dsp、单片

    2024年02月02日
    浏览(61)
  • FPGA基于GS2971/GS2972实现SDI视频收发 提供工程源码和技术支持

    FPGA实现SDI视频编解码目前有两种方案: 一是使用专用编解码芯片,比如典型的接收器GS2971,发送器GS2972,优点是简单,比如GS2971直接将SDI解码为并行的YCRCB,缺点是成本较高,可以百度一下GS2971的价格; 另一种方案是使用FPGA实现编解码,利用FPGA的GTP/GTX资源实现解串,优点

    2024年02月07日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包