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…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...

ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...
API网关Kong的鉴权与限流:高并发场景下的核心实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 引言 在微服务架构中,API网关承担着流量调度、安全防护和协议转换的核心职责。作为云原生时代的代表性网关,Kong凭借其插件化架构…...
在golang中如何将已安装的依赖降级处理,比如:将 go-ansible/v2@v2.2.0 更换为 go-ansible/@v1.1.7
在 Go 项目中降级 go-ansible 从 v2.2.0 到 v1.1.7 具体步骤: 第一步: 修改 go.mod 文件 // 原 v2 版本声明 require github.com/apenella/go-ansible/v2 v2.2.0 替换为: // 改为 v…...
书籍“之“字形打印矩阵(8)0609
题目 给定一个矩阵matrix,按照"之"字形的方式打印这个矩阵,例如: 1 2 3 4 5 6 7 8 9 10 11 12 ”之“字形打印的结果为:1,…...