FPGA实现UART协议的接收与发送

一、接收模块uart_rx.v

        UART协议,空闲时,TX和RX数据线都是通过上拉电阻拉高的状态,这样才能在起始位到来时检测到一个下降的边沿。 

 UART数据格式

uart_rx.v模块输入输出示意图

uart_rx.v模块输入输出示意图

 

  1. RX_start。首先,找到起始位的开始时刻RX_start,这是一个接收字节的最一开始。对RX打拍两次得到RX_1、RX_2。并找出传输每个字节的RX的起始时刻RX_start。

    (注意!:只有在cnt=0时RX出现的下降沿才是起始时刻,否则RX传输过程中也会有由高电平变低电平的情况,这种情况显然不能判定为起始时刻)

  2. cnt。最小是0,最大是传输(1+8+0.5)byte所用时间。cnt平时为0,RX_start出现时cnt立刻开始累加,一直累加到最大值才停止然后恢复到0,等待下一个RX_start到来从新触发cnt累加。cnt不为零的时候,就是说明RX线上正在传输一个字节。
  3. 在何时刻读取RX线上的数据位?定义一个8位的临时寄存器——RX_data_r。在cnt累加到bit1_OK时,到达LSB最低位的中间时刻,中间时刻是最稳定的所以选择在每一位的中间时刻保存该位。以此类推,当cnt累加到bit8_OK时即保存到第8位MSB,这样就保存完一个字节。
  4. 输出结果RX_data、RX_OK。每次都是在cnt累加到bitstop_OK处,把RX_data_r赋值给RX_data,同时产生一个与数据同步的单脉冲RX_OK告知外界本字节接收完且数据可用(注意!:cnt累加到bitstop_OK处时,其实不算完全接收完,因为刚刚接收完停止位的一半)
  5. uart_rx.v程序如下:
module uart_rx#(parameter	OSC 		= 50_000_000,parameter	BPS 		= 9600,parameter	bit_1_cnt 	= 5208,	//bit_1_cnt = OSC/BPS。代表接收1位UART数据时,需要的clk周期个数parameter	bit_0_5_cnt = 2604,	//bit_0_5_cnt = bit_1_cnt/2。代表接收0.5位UART数据时,需要的clk周期个数parameter	cnt_max 	= 52083	//cnt_max = bit_1_cnt*10。代表接收10位UART数据时,需要的clk周期个数
)(input				clk,input				RSTn,//input				RX,output reg [7:0]	RX_data,	//接收到的字节数据,在停止位的中间时刻被赋值生效output reg			RX_OK		//当一个字节传输完后,也就接收完毕,在停止位结束的最后一刻产生一个接收完成单脉冲信号。RX_data和RX_OK不同步
);//******************************************************
//		parameter
//******************************************************
localparam	bit1_OK 	= bit_0_5_cnt+bit_1_cnt;
localparam	bit2_OK 	= bit_0_5_cnt+bit_1_cnt+bit_1_cnt;
localparam	bit3_OK 	= bit_0_5_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;
localparam	bit4_OK 	= bit_0_5_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;
localparam	bit5_OK 	= bit_0_5_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;
localparam	bit6_OK 	= bit_0_5_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;
localparam	bit7_OK 	= bit_0_5_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;
localparam	bit8_OK 	= bit_0_5_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;
localparam	bitstop_OK 	= bit_0_5_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;//-------------------------RX_1,RX_2-----------------------------------
reg RX_1,RX_2;		//对输入进来的RX信号打两拍,方便检测出下降沿
wire RX_start;		//起始位到来那一时刻,产生一个单脉冲信号//-------------------------cnt-----------------------------------
reg [31:0] cnt;//-------------------------RX_data_r-----------------------------------
reg [7:0] RX_data_r;//******************************************************
//		RX_1,RX_2
//******************************************************
always@(posedge clk or negedge RSTn)beginif(!RSTn)beginRX_1<=1'b0;RX_2<=1'b0;endelse beginRX_1<=RX;RX_2<=RX_1;end
endassign RX_start = ((~RX_1&RX_2)&&(cnt==32'd0))?1'b1:1'b0;
//******************************************************
//		cnt
//******************************************************
always@(posedge clk or negedge RSTn)beginif(!RSTn)cnt<=32'd0;else if(cnt==32'd0&&RX_start==1'b1)		//平常cnt等于0,当检测到RX_start脉冲,就开始计数,一直计10个UART比特位发送时长(根据波特率不同,cnt计数最大值也不同)cnt<=32'd1;else if(cnt!=32'd0&&cnt<cnt_max-bit_0_5_cnt)cnt<=cnt+1'b1;else if(cnt>=cnt_max-bit_0_5_cnt)cnt<=32'd0;else cnt<=cnt;	
end
//******************************************************
//		RX_data_r
//******************************************************
always@(posedge clk or negedge RSTn)beginif(!RSTn)RX_data_r<=8'd0;else if(cnt==bit1_OK)RX_data_r<={RX,RX_data_r[7:1]};else if(cnt==bit2_OK)RX_data_r<={RX,RX_data_r[7:1]};else if(cnt==bit3_OK)RX_data_r<={RX,RX_data_r[7:1]};else if(cnt==bit4_OK)RX_data_r<={RX,RX_data_r[7:1]};else if(cnt==bit5_OK)RX_data_r<={RX,RX_data_r[7:1]};else if(cnt==bit6_OK)RX_data_r<={RX,RX_data_r[7:1]};else if(cnt==bit7_OK)RX_data_r<={RX,RX_data_r[7:1]};else if(cnt==bit8_OK)RX_data_r<={RX,RX_data_r[7:1]};elseRX_data_r<=RX_data_r;
end
//******************************************************
//		RX_data	RX_OK
//******************************************************
always@(posedge clk or negedge RSTn)beginif(!RSTn)RX_data<=8'd0;else if(cnt==bitstop_OK)RX_data<=RX_data_r;elseRX_data<=RX_data;
endalways@(posedge clk or negedge RSTn)beginif(!RSTn)RX_OK<=1'b0;else if(cnt==bitstop_OK)RX_OK<=1'b1;elseRX_OK<=1'b0;
endendmodule

二、发送模块uart_tx.v

        发射模块的程序非常简单,就是在对应的时刻拉高或者拉低电平,达到模拟TX信号线的目的。  

 uart_rx.v模块输入输出示意图

        TX_start是个单周期脉冲,是外界给的,当有TX_start单脉冲时,发送TX_data寄存器中的数据。

  1. 进入模块,只有当TX_start=1时,才将TX_data寄存到TX_data_r。其余时刻保持刚刚寄存下来的值。
  2. cnt是时间轴,什么时刻发送第几位,都是根据cnt判断的。最小是0,最大是cnt_max。平时cnt是0,只有当TX_start到来时cnt才开始累加,一直累加到cnt_max(10个完整的数据位占用的等长的clk周期个数)
  3. TX。0~cnt_max平均分成10份,对应着10个数据位,以次发送(改变电平)。
  4. TX_end。cnt==cnt_max时,产生TX_end单脉冲,表示完成一个字节的传输。
  5. uart_tx.v程序如下:
module uart_tx#(parameter	OSC 		= 50_000_000,parameter	BPS 		= 9600,parameter	bit_1_cnt	= 5208,	//bit_1_cnt = OSC/BPSparameter 	bit_0_5_cnt	= 2604,parameter	cnt_max 	= 52083	//cnt_max = bit_1_cnt*10
)(input			clk,input			RSTn,//input [7:0]		TX_data,	//要发送的数据input			TX_start,	//发送开始单脉冲使能。TX_data和TX_start同步到来output reg		TX,output			TX_end
);//******************************************************
//		parameter
//******************************************************
localparam	bit1_send = bit_1_cnt;
localparam	bit2_send = bit_1_cnt+bit_1_cnt;
localparam	bit3_send = bit_1_cnt+bit_1_cnt+bit_1_cnt;
localparam	bit4_send = bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;
localparam	bit5_send = bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;
localparam	bit6_send = bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;
localparam	bit7_send = bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;
localparam	bit8_send = bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;
localparam	bitstop_send = bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt+bit_1_cnt;//------------------TX_data_r-----------------------------
reg [7:0] TX_data_r;	//每次在TX_start到来时,寄存一下要发送的数据TX_data给TX_data_r寄存器//------------------cnt-----------------------------
reg [31:0] cnt;//******************************************************
//		TX_data_r
//******************************************************
always@(posedge clk or negedge RSTn)beginif(!RSTn)TX_data_r<=8'd0;else if(TX_start==1'b1)TX_data_r<=TX_data;elseTX_data_r<=TX_data_r;
end
//******************************************************
//		cnt
//******************************************************
always@(posedge clk or negedge RSTn)beginif(!RSTn)cnt<=32'd0;else if(cnt==32'd0&&TX_start==1'b1)		//平时cnt=0,当TX_start到来时cnt开始累加1,一直加到对应波特率下10个比特位全部发送完cnt<=32'd1;else if(cnt!=32'd0&&cnt<cnt_max)cnt<=cnt+1'b1;else if(cnt>=cnt_max)cnt<=32'd0;elsecnt<=cnt;
end
//******************************************************
//		TX
//******************************************************
always@(posedge clk or negedge RSTn)beginif(!RSTn)TX<=1'b1;else if(cnt>=32'd1&&cnt<bit1_send)TX<=1'b0;		//起始位else if(cnt>=bit1_send&&cnt<bit2_send)TX<=TX_data_r[0];else if(cnt>=bit2_send&&cnt<bit3_send)TX<=TX_data_r[1];else if(cnt>=bit3_send&&cnt<bit4_send)TX<=TX_data_r[2];else if(cnt>=bit4_send&&cnt<bit5_send)TX<=TX_data_r[3];else if(cnt>=bit5_send&&cnt<bit6_send)TX<=TX_data_r[4];else if(cnt>=bit6_send&&cnt<bit7_send)TX<=TX_data_r[5];else if(cnt>=bit7_send&&cnt<bit8_send)TX<=TX_data_r[6];else if(cnt>=bit8_send&&cnt<bitstop_send)TX<=TX_data_r[7];else if(cnt>=bitstop_send&&cnt<cnt_max)TX<=1'b1;		//停止位elseTX<=1'b1;
end
//******************************************************
//		TX_end
//******************************************************
assign TX_end = (cnt==cnt_max)?1'b1:1'b0;endmodule

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/26727.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ElasticSearch学习(1) 基础操作

目前使用的ES版本是7&#xff0c;借用下其他的文档。说明下ES的存储。 ES首先是index 对应的是数据库&#xff0c;7以前有type的概念&#xff0c;7没有type的概念&#xff0c;也就是说现在ES7 一个库(index)只有一个表(type)。 一个表(type)可以有多行(doc) 一行(doc)有多列…

Web自动化 —— Selenium元素定位与防踩坑

1. 基本元素定位一 from selenium import webdriver from selenium.webdriver.chrome.service import Service from selenium.webdriver.common.by import By # selenium Service("../../chromedriver.exe") # driver webdriver.Chrome(serviceService) # driver.…

react+unittest+flask 接口自动化测试平台

目录 1 前言 2 框架 2-1 框架简介 2-2 框架介绍 2-3 框架结构 3 平台 3-1 平台组件图 1 新建用例 2 生成测试任务 3 执行并查看测试报告 3-2 用例管理 3-2-1 用例设计 3-3 任务管理 3-3-1 创建任务 3-3-2 执行任务 3-3-3 测试报告 3-3-4 邮件通知 1 前言 在现…

神经网络模型在深度学习中的作用

神经网络模型是一种模拟人脑神经元之间连接和相互作用的数学模型。它由多个神经元&#xff08;节点&#xff09;以层次结构相互连接而成&#xff0c;每个神经元通过学习权重和偏置&#xff0c;根据输入数据产生相应的输出。 在深度学习中&#xff0c;神经网络模型被广泛应用于…

【LeetCode 75】第三题(1431)拥有最多糖果的孩子

题目: 示例: 分析: 题目是简单题,也确实简单,不过示例给出的解释有些复杂,甚至有些误导.我们只需要遍历得出分配糖果之前的糖果最大值,然后再依次遍历每个孩子拥有的糖果数,若某孩子原有的糖果数加上待分配的所有糖果数大于等于分配前的糖果最大值,则给该孩子对应下标的结果置…

在After Effects 加速渲染的 21个技巧,记得收藏!

如何减少After Effects 渲染时间&#xff1f; 1.升级内存 减少渲染时间的一种有效方法是升级 RAM&#xff08;随机存取存储器&#xff09;。RAM 在渲染过程中起着至关重要的作用&#xff0c;因为它存储并快速访问渲染任务所需的数据。增加系统中的 RAM 量可提供更多的数据存储…

MinUv2靶场详解

MinUv2靶场详解 这个靶场我学到了.bash_history文件&#xff0c;每个用户都有一个名为 .bash_history 的文件&#xff0c;它位于用户的主目录中&#xff0c;默认有500行最近执行的命令。 这个靶场我用vmware是不能打开的&#xff0c;用virtualBox就可以&#xff0c;并且打开时…

Java设计模式之行为型-命令模式(UML类图+案例分析)

目录 一、基础概念 二、UML类图 三、角色设计 四、案例分析 1、基本实现 2、点餐案例 五、总结 一、基础概念 1、将一个请求封装为一个对象&#xff0c;使您可以用不同的请求对客户进行参数化。 2、对请求排队或记录请求日志&#xff0c;以及支持可撤销的操作。 3、…

用Python采用Modbus-Tcp的方式读取PLC模块数据

使用计算器得到需要的寄存器地址 这里PLC地址是83,对应的程序16进制读取地址是53 实际上由于PLC地址从1开始&#xff0c;所以这里实际地址应该是52&#xff0c;因为计算机从0开始 使用网络调试助手生成报文 使用Python中的内置函数int()。以下是将人员卡号’b’3b44’转换为十…

webpack基础知识

webpack基础知识 1、定义2、环境安装3、初始化项目4、简单使用 1、定义 webpack的本质是一个第三方模块包&#xff0c;用于分析&#xff0c;并打包代码 支持所有类型的文件打包支持less/sass> css支持ES6/7/8>ES5压缩代码&#xff0c;提高加载速度 2、环境安装 yarn安…

出差在外,远程访问企业局域网象过河ERP系统【内网穿透】

文章目录 概述1.查看象过河服务端端口2.内网穿透3. 异地公网连接4. 固定公网地址4.1 保留一个固定TCP地址4.2 配置固定TCP地址 5. 使用固定地址连接 概述 ERP系统对于企业来说重要性不言而喻&#xff0c;不管是财务、生产、销售还是采购&#xff0c;都需要用到ERP系统来协助。…

cocos2d-js中jsc逆向为js

1.mac系统 2.安装php7以上的版本 ubuntu $ sudo apt install php7.0 mac $ brew install php7.0 windows just google an binary one 查看php安装的版本这里mac电脑为例子: 输入:php -v 只要7以上的版本即可 3.cd到自己的项目位置 cd path/to/project 安装composer,…