FPGA-结合协议时序实现UART收发器(四):串口驱动模块uart_drive、例化uart_rx、uart_tx
FPGA-结合协议时序实现UART收发器(四):串口驱动模块uart_drive、例化uart_rx、uart_tx
串口驱动模块uart_drive、例化uart_rx、uart_tx,功能实现
文章目录
- FPGA-结合协议时序实现UART收发器(四):串口驱动模块uart_drive、例化uart_rx、uart_tx
- 一、功能实现
- 二、uart_drive代码
- 总结
一、功能实现
对照代码,串口发送模块uart_drive实现功能包括:
- CLK_DIV时钟分频,将系统输入时钟分频成串口所需波特率时钟
- rst_gen_module复位产生模块,分频后的波特率时钟复位不稳定,自己产生波特率时钟复位
- r_rx_overvalue 过采样,动态时钟纠正方法,识别获取起始位位置
- r_rx_overlock 过采样锁,控制过采样开关
- r_user_rx_valid 用户接受有效,利用valid来判断valid上升沿从而判断数据接收完毕,用于控制过采样锁r_rx_overlock
- r_uart_rx_clk_rst,处理纠正后的准确时钟复位r_uart_rx_clk_rst,利用准确的复位+系统时钟产生所需要的准确的串口接收时钟
- 统一到同一时钟域中,即波特率时钟域,慢两拍
-r_user_rx_data_1 <= w_user_rx_data;
r_user_rx_data_2 <= r_user_rx_data_1;
r_user_rx_valid_1 <= w_user_rx_valid;
r_user_rx_valid_2 <= r_user_rx_valid_1;
二、uart_drive代码
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/09/09 13:14:22
// Design Name:
// Module Name: uart_drive
// Project Name:
// Target Devices:
// Tool Versions:
// Description: 串口数据的回环驱动模块
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//module uart_drive#(//串口可调参数parameter P_SYSTEM_CLK = 50_000_000, parameter P_UART_BUADRATE = 9600,parameter P_UART_DATA_WIDTH = 8,parameter P_UART_STOP_WIDTH = 1,parameter P_UART_CHECK = 0
)( //串口驱动输入输出input i_clk ,input i_rst ,input i_uart_rx ,output o_uart_tx ,input [P_UART_DATA_WIDTH - 1 : 0] i_user_tx_data ,//用户输出数据,作为驱动的输入,即先输入到驱动处理再输出input i_user_tx_valid ,//握手output o_user_tx_ready ,output [P_UART_DATA_WIDTH - 1 : 0] o_user_rx_data ,//用户输入数据,作为驱动的输出,即先经过驱动输出再输入到用户output o_user_rx_valid ,output o_user_clk,output o_user_rst);localparam P_CLK_DIV_NUMBER = P_SYSTEM_CLK / P_UART_BUADRATE;//分频数wire w_uart_buadclk ;//串口波特率时钟线
wire w_uart_buadclk_rst ;
wire w_uart_rx_clk ;//串口接收时钟线
wire w_uart_rx_rst ;
reg r_uart_rx_clk_rst ;
reg [2:0] r_rx_overvalue ;
reg [2:0] r_rx_overvalue_1d ;//延迟1拍信号
reg r_rx_overlock ;//过采样锁,控制过采样
reg r_user_rx_valid ;//用户接收有效,用于判断可进行再次接收,即再次过采样判断起始位
wire [P_UART_DATA_WIDTH - 1 : 0] w_user_rx_data ;
wire w_user_rx_valid ;reg [P_UART_DATA_WIDTH - 1 : 0] r_user_rx_data_1 ;
reg [P_UART_DATA_WIDTH - 1 : 0] r_user_rx_data_2 ;
reg r_user_rx_valid_1 ;
reg r_user_rx_valid_2 ;//统一到同一时钟域中,即波特率时钟域
assign o_user_clk = w_uart_buadclk;
assign o_user_rst = w_uart_buadclk_rst;
assign o_user_rx_data = r_user_rx_data_2;
assign o_user_rx_valid = r_user_rx_valid_2;//分频模块,将时钟频率分频成串口波特率时钟
CLK_DIV_module#(.P_CLK_DIV_CNT (P_CLK_DIV_NUMBER) //最大为65535
)
CLK_DIV_module_u0(.i_clk (i_clk) ,//输入时钟.i_rst (i_rst) ,//high value,分配时钟的复位不准确,所以需要重新生成复位rst_gen_module.o_clk_div (w_uart_buadclk) //分频后的时钟
);//复位产生模块,因为分频时钟后复位不准确,所以自己来产生复位
rst_gen_module#(.P_RST_CYCLE (10) //复位的周期
)
rst_gen_module_u0
(.i_clk (w_uart_buadclk) ,.o_rst (w_uart_buadclk_rst));//分频模块,用于过采样计数判断起始位下降沿,用于串口接收使用
//产生能够准确获取中间数据的始终
CLK_DIV_module#(.P_CLK_DIV_CNT (P_CLK_DIV_NUMBER) //最大为65535
)
CLK_DIV_module_u1(.i_clk (i_clk) ,//输入时钟.i_rst (r_uart_rx_clk_rst) ,//初始状态高电平.o_clk_div (w_uart_rx_clk) //分频后的时钟
);uart_rx#(//串口可调参数.P_SYSTEM_CLK (P_SYSTEM_CLK ), .P_UART_BUADRATE (P_UART_BUADRATE ),.P_UART_DATA_WIDTH (P_UART_DATA_WIDTH ),.P_UART_STOP_WIDTH (P_UART_STOP_WIDTH ),.P_UART_CHECK (P_UART_CHECK )
)
uart_rx_u0( //串口驱动输入输出.i_clk (w_uart_rx_clk) ,.i_rst (w_uart_buadclk_rst) ,.i_uart_rx (i_uart_rx) , .o_user_rx_data (w_user_rx_data) ,//用户输入数据,作为驱动的输出,即先经过驱动输出再输入到用户.o_user_rx_valid (w_user_rx_valid));uart_tx#(//串口可调参数.P_SYSTEM_CLK (P_SYSTEM_CLK ),.P_UART_BUADRATE (P_UART_BUADRATE ),.P_UART_DATA_WIDTH (P_UART_DATA_WIDTH ),.P_UART_STOP_WIDTH (P_UART_STOP_WIDTH ),.P_UART_CHECK (P_UART_CHECK )
)
uart_tx_u0( //串口驱动输入输出.i_clk (w_uart_buadclk) ,.i_rst (w_uart_buadclk_rst) ,.o_uart_tx (o_uart_tx) ,.i_user_tx_data (i_user_tx_data) ,//用户输出数据,作为驱动的输入,即先输入到驱动处理再输出.i_user_tx_valid (i_user_tx_valid) ,//握手.o_user_tx_ready (o_user_tx_ready));/*
串口接收会存在亚稳态状态,虽然可以使用打两拍的方法解决,但不够稳妥,一样出现较大累计误差
故采用时钟来动态纠正,使用过采样方法来检测起始位的下降沿,产生新的分频后的时钟,使用该时钟可以保证每次读取数据时都在数据上升沿的中间位置
虽然使用时钟动态纠正方法一样会存在累计误差,但因为每次串口传输8bit数据,并且每次都进行了时钟纠正,所以足以稳定满足使用效果
*///处理过采样r_rx_overvalue,不断获取传输值
always @(posedge i_clk or posedge i_rst)
beginif(i_rst) //初始状态r_rx_overvalue <= 'd0;else if(!r_rx_overlock) //变化状态r_rx_overvalue <= {r_rx_overvalue[1:0] , i_uart_rx};//低位获取i_uart_rx再左移,此处先发低位还是先发高位影响不大,主要是进行高低电平判断起始位用else //保持状态r_rx_overvalue <= 3'b111;
end//处理过采样锁r_rx_overlock,控制过采样,因为只需要过采样起始位的位置
//通过读取三位数据来判断当前是否为起始位的位置,当前3拍全为低电平0,前3拍全为高电平1,则判断为起始位下降沿位置
always @(posedge i_clk or posedge i_rst)
beginif(i_rst)r_rx_overlock <= 'd0;else if(!w_user_rx_valid && r_user_rx_valid) //本次传输完成,可以再次进行过采样了,使用vaild判断,同样采用慢一拍来判断上升沿,当前信号r_user_rx_valid为1,前一拍信号w_user_rx_valid为0,即上升沿,表示传输完成r_rx_overlock <= 'd0;else if(r_rx_overvalue == 3'b000 && r_rx_overvalue_1d == 3'b111) //识别到起始位的位置,此时不需要再次过采样了r_rx_overlock <= 'd1;elser_rx_overlock <= r_rx_overlock;
end//处理用户接收有效信号r_user_rx_valid,用于表示本次接收数据完毕,可再次进行接收数据即再次过采样来判断起始位位置
//同样也是采用慢一拍的信号来结合判断vaild的上升沿
always @(posedge i_clk or posedge i_rst)
beginif(i_rst)r_user_rx_valid <= 'd0;elser_user_rx_valid <= w_user_rx_valid; //r_user_rx_valid比w_user_rx_valid慢一拍,即同一时刻,w_user_rx_valid为当前值,r_user_rx_valid为前一拍值
end//处理纠正后的准确时钟复位r_uart_rx_clk_rst,利用准确的复位+系统时钟产生所需要的准确的串口接收时钟
//利用准确的时钟复位作为分频模块的复位输入,输出准确的串口接收时钟,即每次都在数据位中间上升沿
always @(posedge i_clk or posedge i_rst)
beginif(i_rst)r_uart_rx_clk_rst <= 'd1;else if(r_rx_overvalue == 3'b000 && r_rx_overvalue_1d == 3'b111)//起始位时r_uart_rx_clk_rst <= 'd0;elser_uart_rx_clk_rst <= r_uart_rx_clk_rst;
end/*
//uart的rx的output与tx的输入不是同一时钟域的,需要统一到同一时钟域中
//即o_user_rx_data、o_user_rx_vaild统一到w_uart_buadclk波特率时钟域中
//因为他们的时钟频率比较相近,要求不严格,所以打两拍就算统一到波特率时钟域了!!!!!!!我目前也不太理解!!!
*/
//处理统一始终域问题,打两拍
always @(posedge w_uart_buadclk or posedge w_uart_buadclk_rst)
beginif(w_uart_buadclk_rst)beginr_user_rx_data_1 <= 'd0;r_user_rx_data_2 <= 'd0;r_user_rx_valid_1 <= 'd0;r_user_rx_valid_2 <= 'd0;endelsebeginr_user_rx_data_1 <= w_user_rx_data;r_user_rx_data_2 <= r_user_rx_data_1;r_user_rx_valid_1 <= w_user_rx_valid;r_user_rx_valid_2 <= r_user_rx_valid_1;end
endendmodule
总结
串口驱动模块uart_drive实现,功能包含实现,同时例化uart_rx、uart_tx
相关文章:
FPGA-结合协议时序实现UART收发器(四):串口驱动模块uart_drive、例化uart_rx、uart_tx
FPGA-结合协议时序实现UART收发器(四):串口驱动模块uart_drive、例化uart_rx、uart_tx 串口驱动模块uart_drive、例化uart_rx、uart_tx,功能实现 文章目录 FPGA-结合协议时序实现UART收发器(四)࿱…...
Transformers-Bert家族系列算法汇总
🤗 Transformers 提供 API 和工具,可轻松下载和训练最先进的预训练模型。使用预训练模型可以降低计算成本、碳足迹,并节省从头开始训练模型所需的时间和资源。这些模型支持不同形式的常见任务,例如: 📝 自…...
Vulnhub系列靶机---HarryPotter-Fawkes-哈利波特系列靶机-3
文章目录 信息收集主机发现端口扫描dirsearch扫描gobuster扫描 漏洞利用缓冲区溢出edb-debugger工具msf-pattern工具 docker容器内提权tcpdump流量分析容器外- sudo漏洞提权 靶机文档:HarryPotter: Fawkes 下载地址:Download (Mirror) 难易程度ÿ…...
【服务器】ASUS ESC4000-E11 安装系统
ASUS ESC4000-E11说明书 没找到 ASUS ESC4000-E11的说明书,下面是ESC4000A-E11的说明书: https://manualzz.com/doc/65032674/asus-esc4000a-e11-servers-and-workstation-user-manual 下载地址: https://www.manualslib.com/manual/231379…...
创建java文件 自动添加作者、时间等信息 – IDEA 技巧
2023 09 亲测 文章目录 效果修改位置配置信息 效果 每次创建文件的时候,自动加上作者、时间等信息 修改位置 打开:File —> Settings —> Editor —> File and Code Templates —> includes —> FileHeader 配置信息 /*** author : Java…...
第27章_瑞萨MCU零基础入门系列教程之freeRTOS实验
本教程基于韦东山百问网出的 DShanMCU-RA6M5开发板 进行编写,需要的同学可以在这里获取: https://item.taobao.com/item.htm?id728461040949 配套资料获取:https://renesas-docs.100ask.net 瑞萨MCU零基础入门系列教程汇总: ht…...
Java学习之--类和对象
💕粗缯大布裹生涯,腹有诗书气自华💕 作者:Mylvzi 文章主要内容:Java学习之--类和对象 类和对象 类的实例化: 1.什么叫做类的实例化 利用类创建一个具体的对象就叫做类的实例化! 当我们创建了…...
Unity技术手册-UGUI零基础详细教程-Canvas详解
点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 👉关于作者 专注于Android/Unity和各种游…...
破天荒呀!小杜微信有名额了
写在前面 小杜粉,众所周知前面加小杜微信为好友的基本都是由名额限制的。一般都是付费进入社群且进行备注,小杜才会长期保留微信好友。主要由于,添加的人数太多了,微信账号人数名额有限。因此,小杜过一段时间…...
领域驱动设计:领域模型与代码模型的一致性
文章目录 领域对象的整理从领域模型到微服务的设计领域层的领域对象应用层的领域对象 领域对象与微服务代码对象的映射典型的领域模型非典型领域模型 DDD 强调先构建领域模型然后设计微服务,以保证领域模型和微服务的一体性,因此我们不能脱离领域模型来谈…...
TypeScript命名空间和模块
🎬 岸边的风:个人主页 🔥 个人专栏 :《 VUE 》 《 javaScript 》 ⛺️ 生活的理想,就是为了理想的生活 ! 目录 命名空间(Namespace) 命名空间(Namespace)使用场景 第三方库 兼容…...
C++学习笔记--函数重载(1)
文章目录 序言一、洞悉函数重载决议1.1、重载决议的基本流程1.2、Name Lookup1.2.1、Qualified Name Lookup1.2.1.1、Class Member Lookup1.2.1.2、Namespace Member Lookup 1.2.2、Unqualified Name Lookup1.2.2.1、Usual Unqualified Lookup1.2.2.2、Argument Dependant Look…...
交叉编译poco-1.9.2
目录 一、文件下载二、编译三、可能遇到的问题和解决方法3.1 error "Unknown Hardware Architecture."3.2 error Target architecture was not detected as supported by Double-Conversion一、文件下载 下载地址:poco-1.9.2 二、编译 解压目录后打开build/config/…...
C++中如何处理超长的数字(long long类型的整数都无法存储的)
C中如何处理超长的数字(long long类型的整数都无法存储的) 在 C中,如果数字超出了 long long 类型的范围,可以考虑使用字符串或第三方库(如 Boost.Multiprecision)来表示和处理超长数字。要使用第三方库需…...
RabbitMQ MQTT集群方案官方说明
RabbitMQ MQTT 官方网说明 官方地址: https://www.rabbitmq.com/mqtt.html 从3.8开始,该MQTT插件要求存在一定数量的群集节点。这意味着三分之二,五分之三,依此类推。 该插件也可以在单个节点上使用,但不支持两个节点的集群。 如…...
深圳唯创知音电子将参加IOTE 2023第二十届国际物联网展•深圳站
2023年9月20~22日,深圳唯创知音电子将在 深圳宝安国际会展中心(9号馆9B1)为您全面展示最新的芯片产品及应用方案,助力传感器行业的发展。 作为全球领先的芯片供应商之一,深圳唯创知音电子一直致力于为提供高质量、…...
《TCP/IP网络编程》阅读笔记--I/O复用
目录 1--基于I/O复用的服务器 2--select()函数 3--基于I/O复用的回声服务器端 4--send()和recv()函数的常用可选项 5--readv()和writev()函数 1--基于I/O复用的服务器 多进程服务器端具有以下缺点:当有多个客户端发起连接请求时,就会创建多个进程来…...
[C#] 允许当前应用程序通过防火墙
通常在一台装有防火墙的电脑上运行程序的场合,往往会弹出对话框提示:是否允许执行该应用程序。 我们在开发软件的时候,可以事先在软件里面设置当前软件为防火墙允许通过的软件。这样,用户在使用时就可以避开前面提到的弹框了。 在…...
帆软FineReport决策报表Tab实现方案
最近有个需求是要做首页展示,为了减少前端工作量,利用采购的帆软FineReport来实现,记录过程,方便备查。 需求 做个Tab页,实现多个页切换。 方案一、利用帆软自带切换 帆软自带的有Tab控件,可实现切换&a…...
只打印文名
CMakeLists.txt set(CMAKE_C_FLAGS "-O0 -ggdb -D__NOTDIR_FILE__$(notdir $<)") // set(CMAKE_C_FLAGS "-O0 -ggdb -D__NOTDIR_FILE__$(notdir $<) -D__FILENAME__$(subst $(dir $<),,$<)")C文件 #include <stdio.h>#ifdef __NOTDIR_…...
微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...
DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...
论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
【Go语言基础【12】】指针:声明、取地址、解引用
文章目录 零、概述:指针 vs. 引用(类比其他语言)一、指针基础概念二、指针声明与初始化三、指针操作符1. &:取地址(拿到内存地址)2. *:解引用(拿到值) 四、空指针&am…...
