首页 > 其他分享 >FPGA接口系列——UART

FPGA接口系列——UART

时间:2024-03-26 21:33:06浏览次数:30  
标签:din wire FPGA UART 通信 接口 串行 reg

FPGA接口系列——UART

一、UART简介

UART是一种采用异步串行通信方式的通用异步收发传输器。这里我们主要弄明白两个问题:①什么是串行通信,与并行通信有什么区别 ②同步串行通信和异步串行通信有什么区别 ③我们常说的UART和 RS232 以及 RS485 又有什么区别?

串行通信和并行通信

串行通信只用一根数据线,将数据转换成一个bit一个bit进行发送;并行通信则可以采用8根或16根数据线,将数据逐个Byte或者Word发送出去。

同步串行通信和异步串行通信:

同步串行通信需要双方在同意时钟的控制下,同步传输数据;异步串行通信的原理大致是Transmitter端在发送数据之前会给出一个跳变信号,随即进行信号的传输,而不需要额外的时钟线,这个时候Transmitter的发送频率就叫做波特率,Receiver端的采样频率一般要比Transmitter端的频率高出4-16倍。

UART,RS232和RS485

串口、COM口是指的物理接口形式(硬件),TTL、RS232、RS485是指的电平标准(电信号)。TTL标准是低电平为0,高电平为1(+5V电平)。RS-232标准是正电平为0,负电平为1(±15V电平),是单端输入输出。RS-485与RS-232类似,但是采用差分信号负逻辑。一般我们见到的串口,有D型9针插头和4针杜邦头两种。

二、数据格式

1.传输时序

1.1

一般常用的数据位是:一个起始位、八个数据位和一个校验位以及一个停止位;关于校验位,奇校验要求校验位和数据位中“1”的结果是一个奇数;一个题外话就是在verilog中使用奇校验应为数据位异或取反。

奇校验 = ~(^data);  偶校验 = ^ data

2.传输速率:波特率

串口通信的速率用波特率表示,它表示麦苗传输二进制数据的位数,单位是bps(位/秒)。常用的波特率有9600、19200、35400、57600以及115200等

项目中使用时,考虑计数器的计数阈值就要结合波特率来考虑。比如波特率设计为9600,那么就是9600bit/s,如果系统时钟是50MHz,(1/9600)÷(1/50M)=5208.333333,也就是说,系统计数器计数到5209则可以完成一个bit数据的transmit。省略校验位,大概一个Byte数据的transmit需要10位(1起始加上8数据加上1停止)

3.程序设计

程序的设计和验证主要分为核心文件和testbench文件的编写,下面简要阐述一下发生的问题:

  1. 注意接口与接口之间的对应,切忌在文件编写例化调用的时候定义错数据的位宽,这种操作往往为造成数据的高阻态
  2. 在编写testbench仿真的时候出现了很多细小的问题,比如数据传输的问题,应该去找到源头进行分析,比如你定义的txt文件为“1 2 3 4”,实际仿真得到接受的字符却是“ 24 56 78 21”这种,就要考虑字符的失序,时序可能存在没有对齐的操作,像我这一步就是因为没有留出足够的空闲时间(因为前面有打过三拍)造成了数据的丢失与失序。

4.上板验证

上板验证中出现了一个待解决的问题

1711459258205

这里主要的变动是因为:我将原作者 咸鱼FPGA 代码中的(1起始+8数据+0.5停止)改成了(1起始+8数据+1停止)然后就发生了失序,这是一个待解决的问题,主要的猜想可能是,设计0.5个停止位就是空出时间以待接受新的数据?少了这0.5个余量之后可能发生了失序。

module uart_rx 
#(
parameter			CNT_MAX		=	'd5208	,
parameter			CNT_HALF	=	'd2603	
)
(
	//system signals
	input				clk					,  //系统时钟 50M
	input				rst_n				,
	//input and output signals
	input		wire				din				,
	output		reg		[7:0]		dout			,
	output		reg					da_vld			
);
//========================================================================\
// =========== Define Parameter and Internal signals =========== 
//========================================================================/

reg 				[2:0]	din_reg			; // 寄存器打拍信号,用于消除亚稳态
wire						din_neg			; // 下降沿检测信号
reg 						flag			; // 状态检测信号
wire						flag_convert	; // 数据转换标志信号
reg 				[12:0]	cnt_50M			; // 系统时钟计数器
reg 				[3:0]	cnt_bit			; // 传输位数计数器
reg 				[7:0]	data			; // 缓存PC机传输过来的数据

wire						begin_cnt1			;
wire						begin_cnt2			;
wire						end_cnt1			;
wire						end_cnt2			;
//=============================================================================
//****************************     Main Code    *******************************
//=============================================================================

//=============================================================================
//==			消除亚稳态加上下降沿检测
//=============================================================================

assign din_neg = din_reg[2] & (~din_reg[1]);

always @(posedge clk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		// reset
		din_reg <= 1'b0;
	end
	else begin
		din_reg <= {din_reg[1],din_reg[0],din};
	end
end
//=============================================================================
//==			接受状态指示
//=============================================================================
always @(posedge clk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		// reset
		flag <= 1'b0;
	end
	else if (din_neg) begin
		flag <= 1'b1;
	end
	else if (end_cnt2)begin
		flag <= 1'b0;
	end
end
//=============================================================================
//==			波特率计数
//=============================================================================
always @(posedge clk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		// reset
		cnt_50M <= 1'b0;
	end
	else if (begin_cnt1) begin
		if (end_cnt1) 
		    begin
		        cnt_50M <= 1'b0;
		    end
		else 
		    begin
		        cnt_50M <= cnt_50M + 1'b1;
		    end
	end
end

assign begin_cnt1 = flag;
assign end_cnt1 = cnt_50M == CNT_MAX || end_cnt2;
//=============================================================================
//==			1起始8数据和0.5停止
//=============================================================================
always @(posedge clk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		// reset
		cnt_bit <= 1'b0;
	end
	else if (begin_cnt2) begin
		if (end_cnt2) 
		    begin
		        cnt_bit <= 1'b0;
		    end
		else 
		    begin
		        cnt_bit <= cnt_bit + 1'b1;
		    end
	end
end

assign begin_cnt2 = end_cnt1;
assign end_cnt2 = (cnt_50M == CNT_MAX) && (cnt_bit == 'd9);
//=============================================================================
//==			数据转换与缓存
//=============================================================================
always @(posedge clk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		// reset
		data <= 1'b0;
	end
	else if (flag_convert) begin
		data[cnt_bit-1] <= din_reg[2];
	end
end
assign flag_convert = flag && (cnt_bit > 0) && (cnt_bit < 9) && (cnt_50M == CNT_HALF);
//=============================================================================
//==			输出数据
//=============================================================================
always @(posedge clk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		// reset
		dout <= 1'b0;
	end
	else if (end_cnt2) begin
		dout <= data;
	end
end

always @(posedge clk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		// reset
		da_vld <= 1'b0;
	end
	else if (end_cnt2) begin
		da_vld <= 1'b1;
	end
	else begin
		da_vld <= 1'b0;
	end
end
endmodule

标签:din,wire,FPGA,UART,通信,接口,串行,reg
From: https://www.cnblogs.com/qier0220/p/18097641

相关文章

  • 规范 - 接口文档
    作者:Zonezzc最后更新时间:2024-03-2619:13:06​​原则接口的命名最终一定是便于理解的中文。接口的说明中一定包含接口原名如getSellerStandardsProfile,若存在第三方在线接口文档,该原名设置为引向原文的超链接。所有的参数都要有中文注释。命名规范对接口理解不透彻......
  • Temu api接口 获取商品详情 数据采集
    iDataRiver平台https://www.idatariver.com/zh-cn/提供开箱即用的Temu电商数据采集API,供用户按需调用。接口使用详情请参考Temu接口文档接口列表1.获取商品详情参数类型是否必填默认值示例值描述apikeystring是idr_***从控制台里复制apikeycountryst......
  • 规范 - 接口文档
    规范-接口文档作者:Zonezzc最后更新时间:2024-03-2619:13:06​​原则接口的命名最终一定是便于理解的中文。接口的说明中一定包含接口原名如getSellerStandardsProfile,若存在第三方在线接口文档,该原名设置为引向原文的超链接。所有的参数都要有中文注释。命名规范......
  • springboot整合knife4j接口文档
    1、添加knife4j依赖这里是最新版本的依赖,我也会使用这个最新版本的依赖来进行举例。knife4j官网<dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-openapi3-spring-boot-starter</artifactId><version>4.4.0</version></d......
  • FPGA亚稳态学习总结
     首先是组合逻辑电路考虑的是竞争冒险,冒险会产生毛刺。重点研究如何去毛刺时序逻辑电路考虑的是时序不满足会产生的亚稳态问题:如何考量时序满不满足呢?根据不同的场景又有不同的说法。时序分析的两组基本概念建立时间与保持时间1.在同步系统和异步系统(跨时钟域传输)中有两个......
  • 【SpringBoot3+Mybatis】小程序和后台管理系统 员工/分类/菜品/套餐管理 上传文件 CRU
    文章目录一、项目介绍&Github二、技术选型三、开发环境搭建四、员工管理4.1新增员工①sql②对象拷贝DTO与Entity③异常捕获与处理④动态获取当前登录者Id⑤ThreadLocal4.2员工分页查询①请求参数实体与响应数据实体②controller层③service层使用pageHelper......
  • [QLIE] 封包接口Hook
    [QLIE]封包接口Hook这个主题快拖了半个月,中间一直没空写,今天看着实在有点久了,必须写一写了,不然就快忘记了。起因前不久HappyLiveShowUp发了官中,但是又搞的奇奇怪怪的加密,很是无聊,稍微调了下和之前ハミダシクリエイティブ官中是挺像的。steam的dll是用Themida保护的,其......
  • Mybatis的接口映射原理
    1、问题引入在使用Mybaits时,只需要写一个Mapper接口(不用写实现类),并在对应的xml文件中写好sql。然后,Mybatis就自动实现了具体的CRUD方法调用。通常我们使用Mybatis的主要步骤是:构建SqlSessionFactory(通过xml配置文件,或者直接编写Java代码)从SqlSessionFactor......
  • SpringBoot手动取消接口执行方案
    实际开发中经常会遇到比较耗时的接口操作,但页面强制刷新或主动取消接口调用后后台还是会继续运行,特别是有大量数据库操作时会增加服务器压力,所以进行研究测试后总结了一套主动取消接口调用的解决方案自定义注解用于标记耗时接口@Retention(RetentionPolicy.RUNTIME)@Target({El......
  • ISBN信息查询api接口
     基本说明:接口地址:http://data.isbn.work/openApi/getInfoByIsbn?isbn={isbn}&appKey={appkey}返回格式:json请求方式:get请求示例:http://data.isbn.work/openApi/getInfoByIsbn?isbn=9787513159074&appKey=ae1718d4587744b0b79f940fbef69e77伽薇 809137232请求参数说明:名......