ZYNQ初识10(zynq_7010)UART通信实验
基于bi站正点原子讲解视频:
系统框图(基于串口的数据回环)如下:

以下,是串口接收端的波形图,系统时钟和波特率时钟不同,为异步时钟,,需要先延时两拍,将时钟同步过来,取到start_flag信号,由start_flag信号结合clk_cnt、bps_cnt两个计数器取到rx_flag信号,随后在rx_flag高电平时计算clk_cnt以及bps_cnt两个信号。最后两个信号uart_done、uart_data则在串口发送模块有所体现。
实际上,uart_done在串口发送模块中也就是uart_en信号,而uart_data也就是发送模块中的uart_din信号。

`timescale 1ns / 1ps
// Create Date: 2025/01/06 09:38:08
// Design Name:
// Module Name: uart_recv
module uart_recv(input sys_clk , //50Mhz系统时钟input sys_rst_n ,input uart_rxd , //接收到的数据output reg [7:0] uart_data , //输出的并行数据output reg uart_done //一帧信号接收完成);parameter sys_freq = 50_000_000;parameter uart_bps = 115_200;parameter bps_cnt = sys_freq/uart_bps - 1;//从0开始计算reg uart_rxd_d0;reg uart_rxd_d1;wire start_flag;reg rx_flag;reg [15:0] clk_cnt;reg [3:0] rx_cnt;reg [7:0] rx_data;//中间变量存储提取到的每个位的数据来实现串口端的串并转换//由高电平向低电平的跳变(下降沿),相当于d1延时2个时钟周期;d0延时1个时钟周期//因此判断d1是否为高且d0是否为低即可。assign start_flag = uart_rxd_d1 & (~uart_rxd_d0);//异步时钟同步化处理always@(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)beginuart_rxd_d0 <= 1'b1;uart_rxd_d1 <= 1'b1;endelse beginuart_rxd_d0 <= uart_rxd;uart_rxd_d1 <= uart_rxd_d0;endend//rx_flagalways@(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)rx_flag <= 1'b0;else if(start_flag == 1'b1)rx_flag <= 1'b1;else if((rx_cnt == 4'd9) && (clk_cnt == bps_cnt/2 - 1'b1)) //为监测到下一帧数据的起始位留半个周期的时间rx_flag <= 1'b0;else rx_flag <= 1'b1;end//clk_cntalways@(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)clk_cnt <= 16'd0;else if(rx_flag == 1'b1)
// begin //效果相同否?
// if(clk_cnt == uart_bps)
// clk_cnt <= 16'd0;
// else
// clk_cnt <= clk_cnt + 16'd1;
// endbegin if(clk_cnt < uart_bps - 16'd1) clk_cnt <= clk_cnt + 16'd1; else clk_cnt <= 16'd0; end else clk_cnt <= 16'd0; end//rx_cntalways@(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)rx_cnt <= 4'd0;else if(rx_flag == 1'b1)beginif(clk_cnt == uart_bps - 16'd1)rx_cnt <= rx_cnt + 4'd1;else rx_cnt <= rx_cnt;endelserx_cnt <= 4'd0;end//rx_dataalways@(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)rx_data <= 8'd0;else if((rx_flag == 1'b1)&&(clk_cnt == uart_bps/2)) begincase(rx_cnt)//数据的串转并_uart_rxd是异步信号//所以要需要两拍之后的信号uart_rxd_d1。4'd1: rx_data[0] <= uart_rxd_d1;4'd2: rx_data[1] <= uart_rxd_d1;4'd3: rx_data[2] <= uart_rxd_d1;4'd4: rx_data[3] <= uart_rxd_d1;4'd5: rx_data[4] <= uart_rxd_d1;4'd6: rx_data[5] <= uart_rxd_d1;4'd7: rx_data[6] <= uart_rxd_d1;4'd8: rx_data[7] <= uart_rxd_d1;endcaseendendalways@(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)beginuart_data <= 8'd0;uart_done <= 1'd0;endelse if(rx_cnt == 4'd9)begin uart_data <= rx_data; uart_done <= 1'd1; end elsebegin uart_data <= 8'd0; uart_done <= 1'd0; end end
endmodule
以下:如何在程序中捕获信号的高低电平:(可实现异步时钟的同步处理以及信号的边沿检测)
d0 <= 1'b1;
d1 <= 1'b1;
d0 <= uart_rxd;
d1 <= d0;
也就是说,在初始状态时将d0、d1拉高,通过两次打拍将d0延时1个时钟周期,d1延时2个时钟周期,从而根据d0和d1的状态,设置wire型的标志位flag来捕获需要的高低电平。
以下,是是串口发送端的波形图,整体过程和接收端基本类似,只需要进行某些变量名称的修改即可,但需要注意,接收到的数据实际上是串口接收端的发送的数据(uart_data);uart_done信号也在发送端检测边沿电平过程中以uart_en的形式完成了两次打拍延迟。

`timescale 1ns / 1ps
// Create Date: 2025/01/06 14:50:27
// Design Name:
// Module Name: uart_sendmodule uart_send(input sys_clk , //50Mhz系统时钟 input sys_rst_n , output reg uart_txd , //准备发送的数据 input uart_en , input [7:0] uart_din //从发送模块接收到的数据 );parameter sys_freq = 50_000_000;parameter uart_bps = 115_200;parameter bps_cnt = sys_freq/uart_bps - 1;//从0开始计算reg uart_en_d0;reg uart_en_d1; reg tx_flag;reg [15:0] clk_cnt;reg [3:0] tx_cnt; reg [7:0] tx_data;//中间变量存储提取到的每个位的数据来实现串口端的串并转换wire en_flag;//由高电平向低电平的跳变(下降沿),相当于d1延时2个时钟周期;d0延时1个时钟周期//因此判断d1是否为高且d0是否为低即可。assign en_flag = (~uart_en_d1) & uart_en_d0;//边沿信号检测,检测上升沿always@(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)beginuart_en_d0 <= 1'b1;uart_en_d1 <= 1'b1;endelse beginuart_en_d0 <= uart_en;uart_en_d1 <= uart_en_d0;endend//tx_dataalways@(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)tx_data <= 8'd0; else if(en_flag == 1'b1) tx_data <= uart_din;else tx_data <= tx_data;end//tx_flagalways@(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)tx_flag <= 1'b0;else if(en_flag == 1'b1)tx_flag <= 1'b1;else if((tx_cnt == 4'd9) && (clk_cnt == bps_cnt/2 - 1))tx_flag <= 1'b0;else //tx_flag <= tx_flag; //这两句话在这里作用相同否?tx_flag <= 1'b1;end//clk_cntalways@(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)clk_cnt <= 16'd0;else if(tx_flag == 1'b1)
// begin
// if(clk_cnt == uart_bps)
// clk_cnt <= 16'd0;
// else
// clk_cnt <= clk_cnt + 16'd1;
// endbegin if(clk_cnt < uart_bps - 16'd1) clk_cnt <= clk_cnt + 16'd1; else clk_cnt <= 16'd0; end else clk_cnt <= 16'd0; end//tx_cntalways@(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)tx_cnt <= 4'd0;else if(tx_flag == 1'b1)beginif(clk_cnt == uart_bps - 16'd1)tx_cnt <= tx_cnt + 4'd1;else tx_cnt <= tx_cnt;endelserx_cnt <= 4'd0;end//uart_txdalways@(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)uart_txd <= 1'b1;else if((tx_flag == 1'b1)&&(clk_cnt == 16'd0)) begincase(tx_cnt)//数据并转串,首先判断起始位,赋值低电平;//随后将tx_data一次赋值给输出端口uart_txd;//最后注意一帧数据的停止位,赋值高电平。4'd0: uart_txd <= 1'b0;4'd1: uart_txd <= tx_data[0];4'd2: uart_txd <= tx_data[1];4'd3: uart_txd <= tx_data[2];4'd4: uart_txd <= tx_data[3];4'd5: uart_txd <= tx_data[4];4'd6: uart_txd <= tx_data[5];4'd7: uart_txd <= tx_data[6];4'd8: uart_txd <= tx_data[7];4'd9: uart_txd <= 1'b1;endcaseendendendmodule
以下是顶层文件,分别将串口发送端和接收端两部分程序例化。
`timescale 1ns / 1ps
// Create Date: 2025/01/06 15:49:15
// Design Name:
// Module Name: top_uartmodule top_uart(input sys_clk , //50Mhz系统input sys_rst_n , input uart_rxd , //接收到的数据output uart_txd //准备发送的数据 );wire [7:0] uart_data;wire uart_done;//串口接收模块的例化:uart_recv uart_recv_u(.sys_clk (sys_clk ) , //50Mhz系统时钟.sys_rst_n (sys_rst_n ) ,.uart_rxd (uart_rxd ) , //接收到的数据.uart_data (uart_data ) , //输出的并行数据.uart_done (uart_done ) //一帧信号接收完成);// wire uart_en ;
// wire [7:0] uart_din;//串口发送模块的例化;uart_send uart_send_u(.sys_clk (sys_clk ) , //50Mhz系统时钟 .sys_rst_n (sys_rst_n) , .uart_txd (uart_txd ) , //准备发送的数据 .uart_en (uart_done ) , .uart_din (uart_data ) //从发送模块接收到的数据 );endmodule
以下是对应程序的RTL视图:

另注意1:
打两拍的异步时钟的同步处理,打一拍是为了将异步时钟转为同步时钟,如上本例子是将波特率时钟(115200bps)转换为系统时钟50Mhz,打两拍则是为了消除亚稳态(0 1之间的状态)。
参考连接:【Chips】跨时钟域的亚稳态处理、为什么要打两拍不是打一拍、为什么打两拍能有效?_跨时钟域为什么打两拍-CSDN博客
另注意2:
为什么在程序中最后1位的停止位需要延时半个周期而不是一个完整的周期?也就是发送模块的如下程序:
always@(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)tx_flag <= 1'b0;else if(en_flag == 1'b1)tx_flag <= 1'b1;else if((tx_cnt == 4'd9) && (clk_cnt == bps_cnt/2 - 1))//停止位只有半个波特率周期tx_flag <= 1'b0;else //tx_flag <= tx_flag; //tx_flag <= 1'b1;end
首先延时半个周期是为了给下一帧数据接收时检测起始位留够时间,在数据回环过程中不会出现太大问题,但是如果单独调用串口的发送模块(或者接收模块)时就会出现问题,在单独调用发送模块时,因为停止位只有半个周期,所以发送1帧数据过程总会先于上位机正常接收而提前结束,造成错误。
所以选择将停止位周期设置为1个时钟周期,但是实际上位机的波特率和实际计算的波特率仍有微小误差,在将停止位设置为1个时钟周期时,上位机(串口助手)的波特率实际会和自己设置的波特率(如9600,115200等)存在或多或少的误差,因此需要将停止位周期设置为1/2--1之间,和上位机什么时候检测到1帧数据的停止位有关。
另附加上视频中给出得数据环回模块的程序:

`timescale 1ns / 1ps
// Create Date: 2025/01/07 10:50:37
// Intrduction: 将串口接收到的数据进行缓存,消除上位机和串口模块之间的时间误差;
// Module Name: uart_loopmodule uart_loop(input sys_clk , //50Mhz系统时input sys_rst_n , input recv_done , //接收完成信号 input [7:0] recv_data , //接收到的数据 input tx_busy ,output reg send_en , output reg [7:0] send_data //待发送数据);reg recv_done_d0 ;reg recv_done_d1 ;reg tx_ready ;wire recv_done_flag; //捕获上升沿assign recv_done_flag = (~recv_done_d0) & recv_done_d1;//打两拍实现边沿检测always@(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)beginrecv_done_d0 <= 1'b0;recv_done_d1 <= 1'b0;endelse begin recv_done_d0 <= recv_done;recv_done_d1 <= recv_done_d0;end end//判断接收完成信号,并在串口发送模块空闲时发送是使能信号always@(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)begintx_ready <= 1'b0;send_en <= 1'b0; send_data <= 8'd0;endelsebeginif(recv_done_flag) begintx_ready <= 1'b1; send_en <= 1'b0; send_data <= recv_data; end else if(tx_ready&&(~tx_busy))begintx_ready <= 1'b0;send_en <= 1'b1;endendend endmodule
再者,vivado中串口默认波特率115200bps,在调试过程需要注意,如哦需要修改可参考下链接:
https://zhuanlan.zhihu.com/p/633150036
相关文章:
ZYNQ初识10(zynq_7010)UART通信实验
基于bi站正点原子讲解视频: 系统框图(基于串口的数据回环)如下: 以下,是串口接收端的波形图,系统时钟和波特率时钟不同,为异步时钟,,需要先延时两拍,将时钟同…...
专题 - STM32
基础 基础知识 STM所有产品线(列举型号): STM产品的3内核架构(列举ARM芯片架构): STM32的3开发方式: STM32的5开发工具和套件: 若要在电脑上直接硬件级调试STM32设备,则…...
2 XDMA IP中断
三种中断 1. Legacy 定义:Legacy 中断是传统的中断处理方式,使用物理中断线(例如 IRQ)来传递中断信号。缺点: 中断线数量有限,通常为 16 条,限制了可连接设备的数量。中断处理可能会导致中断风…...
自然语言转 SQL:通过 One API 将 llama3 模型部署在 Bytebase SQL 编辑器
使用 Open AI 兼容的 API,可以在 Bytebase SQL 编辑器中使用自然语言查询数据库。 出于数据安全的考虑,私有部署大语言模型是一个较好的选择 – 本文选择功能强大的开源模型 llama3。 由于 OpenAI 默认阻止出站流量,为了简化网络配置&#…...
抖音矩阵是什么
抖音矩阵是指在同一品牌或个人IP下,通过创建多个不同定位的抖音账号(如主号、副号、子号等),形成一个有机的整体,以实现多维度、多层次的内容覆盖和用户互动。以下是关于抖音矩阵的详细介绍: 抖音矩阵的类…...
怎么抓取ios 移动app的https请求?
怎么抓取IOS应用程序里面的https? 这个涉及到2个问题 1.电脑怎么抓到IOS手机流量? 2.HTTPS怎么解密? 部分app可以使用代理抓包的方式,但是正式点的app用代理抓包是抓不到的,例如pin检测,证书双向校验等…...
pyqt鸟瞰
QApplication是Qt框架中的一个类,专门用于管理基于QWidget的图形用户界面(GUI)应用程序的控制流和主要设置。QApplication类继承自QGuiApplication,提供了许多与GUI相关的功能,如窗口系统集成、事件处理等。 QAppli…...
【Docker】入门教程
目录 一、Docker的安装 二、Docker的命令 Docker命令实验 1.下载镜像 2.启动容器 3.修改页面 4.保存镜像 5.分享社区 三、Docker存储 1.目录挂载 2.卷映射 四、Docker网络 1.容器间相互访问 2.Redis主从同步集群 3.启动MySQL 五、Docker Compose 1.命令式安装 …...
Token和JWT的关系详细讲解
Token 和 JSON Web Token (JWT) 是两个相关但概念上不同的术语,它们在现代 Web 应用程序的身份验证和授权中扮演着重要角色。下面将详细介绍两者之间的关系以及 JWT 的具体工作原理。 1. Token 概述 Token 是一种广义的概念,指的是任何可以证明用户身份…...
【Linux系列】Curl 参数详解与实践应用
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
解决 Git SSL 连接错误:OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno
问题描述 在执行 git pull 命令时遇到以下错误: > git pull --tags origin main fatal: unable to access github仓库: OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 0这个错误通常表示 Git 在尝试通过 HTTPS 连接到 GitHub 时遇到了 SSL 连接问题。 解决方案…...
《Vue3 八》<script setup> 语法
<script setup> 是在单文件中使用 Composition API 的编译时语法糖,里面的代码会被编译成组件 setup() 函数的内容。 <script setup> 中的代码在每次组件实例被创建的时候都都会被执行。 定义数据: 在 <script setup> 语法糖的写法中…...
51单片机和STM32集成蓝牙模块实用指南
51单片机和STM32集成蓝牙模块实用指南 蓝牙模块(如HC-05、HC-06、JDY-31等)是嵌入式开发中常用的无线通信模块,广泛应用于智能家居、物联网、机器人等领域。本文将详细介绍如何将蓝牙模块集成到 51单片机 和 STM32 中,并提供一个…...
Transformer:深度学习的变革力量
深度学习领域的发展日新月异,在自然语言处理(NLP)、计算机视觉等领域取得了巨大突破。然而,早期的循环神经网络(RNN)在处理长序列时面临着梯度消失、并行计算能力不足等瓶颈。而 Transformer 的横空出世&am…...
sql 函数
# 四则运算 - * / # 函数 distinct 、count、sum、max、min、avg、sum、round select concat(device_id 是,device_id ) device_id from device_id_apply_factor where device_id D6A42CE6A0; select concat_ws(|||,device_id ,factor_a ,module_type) from 、device_id_app…...
C# OpenCV机器视觉:OCR产品序列号识别
在一个看似平常却又暗藏玄机的工作日,阿明正坐在办公室里,对着堆积如山的文件唉声叹气。突然,电话铃声如炸雷般响起,吓得他差点从椅子上摔下来。原来是公司老板打来的紧急电话:“阿明啊,咱们刚生产出来的那…...
2012wtl,学习活扩
原文 WTL学习注意–活扩 在Win32下,活扩控件已是个成熟的概念了,即使对COM不太了解,使用活扩控件仍是件容易的事情.既然是控件,无非要关注两个方面,第一是如何调用它的函数,其次是如何接收它的事件. 看看在WTL中,如何使用活扩控件(基本对话框): 1.创建项目时,让对话框支持活…...
使用Deepseek搭建类Cursor编辑器
使用Deepseek搭建类Cursor编辑器 Cursor想必大家都用过了,一个非常强大的AI编辑器,在代码编写上为我们省了不少事,但高昂的价格让我们望而却步,这篇文章教你在Visual Studio Code上搭建一个类Cursor的代码编辑器。 步骤其实非常…...
mysql,PostgreSQL,Oracle数据库sql的细微差异(2) [whith as; group by; 日期引用]
sql示例(MySQL) WITHtemp1 AS (SELECT name AS resultsFROM Users uJOIN MovieRating m ON u.user_id m.user_idGROUP BY m.user_idORDER BY COUNT(*) DESC,left(name,1)LIMIT 1),temp2 AS (SELECT title AS resultsFROM Movies mJOIN MovieRating r ON m.movie_id r.movie_…...
基于改进粒子群优化的无人机最优能耗路径规划
目录 1. Introduction2. Preliminaries2.1. Particle Swarm Optimization Algorithm2.2. Deep Deterministic Policy Gradient2.3. Calculation of the Total Output Power of the Quadcopter Battery 3.OptimalEnergyConsumptionPathPlanningBasedonPSO-DDPG3.1.ProblemModell…...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...
YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
