UART设计

一、UART通信简介

通用异步收发器,

特点:串行、异步、全双工通信

优点:通信线路简单,传输距离远

缺点:传输速度慢

数据传输速率:波特率(单位:baud,波特)

常见的波特率为:1200、2400、4800、19200、38400、57600、115200

最常用的:9600、115200                

数据通信格式:1个数据位+n个数据位+1个校验位+1个结束位

其中n个数据位:通常为8位,即1个字节

空闲位:当总线处于空闲状态时信号线的状态为1,表示当前线路没有进行数据传输。

起始位:每开始一次通信时发送方先发出一个逻辑0的信号,表示传输字符的开始。(因为总线空闲时为高电平,所以开始一次通信时先发送一个明显区别于空闲状态的信号,即低电平)

数据位:起始位之后就是我们所要传输的数据,数据位可以是5,6,7,8,9位等,构成一个字符。先发送最低位,最后发送最高位

奇偶校验位

数据位加上这一位后,使得1的位数应为偶数(偶校验)或奇数(奇校验)。

串口校验的几种方式:

  1. 无校验
  2. 奇校验:如果数据位中“1”的数目是偶数,则校验位为1,如果“1”的数目是奇数,则校验位为0
  3. 偶校验:如果数据位中1的数目是偶数,则校验位为0,如果是奇数,校验位为1
  4. Mark parity:校验位始终为1(不常用)
  5. Parity:校验位始终为0(不常用)

停止位:

它是一个字符数据的结束标志。可以是1位、2位的高电平。由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备之间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟的机会。停止位个数越多,数据传输越稳定,但是数据传输速度也越慢

传输时间:计数=时钟频率除以波特频率

二、Verilog实现:

1.UART_TX设计框图

信号

位宽

类型

功能描述

clk

1bit

input

工作时钟,频率50MHz

tx_data

8bit

input

发送数据

tx_flag

1bit

input

发送数据的有效标志信号

tx

1bit

output

串口发送信号

Verilog代码:

uart_tx:

module uart_tx
#(parameter  UART_BPS = 'd9600, //串口波特率parameter CLK_FREQ  = 'd50_000_000  //时钟频率)(input wire clk, //系统时钟input wire rstn,    //全局复位input wire [7:0] tx_data,   //发送8bit数据input wire tx_flag, //发送数据有效标志信号output reg tx //串转并后的1bit数据
);localparam cnt_max = CLK_FREQ / UART_BPS;reg [12:0] bd_cnt;reg bit_flag;reg [3:0] bit_cnt;reg work_en;    //接收数据工作使能信号//work_en:接收数据工作使能信号always @(posedge clk or negedge rstn) beginif (rstn == 1'b0) work_en <= 1'b0;else if (tx_flag == 1'b1) work_en <= 1'b1;else if((bit_flag == 1'b1)&&(bit_cnt == 4'd9))work_en <= 1'b0;end//bd_cnt:波特率计数器计数,从0计数到5207always @(posedge clk or negedge  rstn) beginif(rstn == 1'b0)bd_cnt <= 13'b0;else if((bd_cnt == cnt_max - 1) ||(work_en == 1'b0))bd_cnt <= 13'b0;else if(work_en == 1'b1)bd_cnt <= bd_cnt + 1'b1;   end//bit_flag : 当bd_cnt计数器计数到1时让bit_flag拉高一个时钟的高电平always @(posedge clk or negedge rstn) beginif(rstn == 1'b0)bit_flag <= 1'b0;else if(bd_cnt == 13'd1)bit_flag <= 1'd1;else bit_flag <= 1'b0;end//bit_cnt:数据位数个数计数,10个有效数据(含起始位和停止位)到来后计数器清零always@(posedge clk or negedge rstn) beginif(rstn == 1'b0)bit_cnt <= 4'b0;else if((bit_flag == 1'b1)&&(bit_cnt == 4'd9))bit_cnt <= 4'b0;else if((bit_flag == 1'b1)&&(work_en == 1'b1))bit_cnt <= bit_cnt + 1'b1;end//tx:输出数据在满足uart协议(起始位为0,停止位为1)的情况下一位一位输出always @(posedge clk or negedge rstn) beginif(rstn == 1'b0)tx <= 1'b1; //空闲状态为高电平else if(bit_flag == 1'b1)case(bit_cnt)0: tx <= 1'b0 ;1: tx <= tx_data[0];2: tx <= tx_data[1];3: tx <= tx_data[2];4: tx <= tx_data[3];5: tx <= tx_data[4];6: tx <= tx_data[5];7: tx <= tx_data[6];8: tx <= tx_data[7];9: tx <= 1'b1;default : tx <= 1'b1;endcaseendendmodule

testbench:

module tb_uart_tx();reg clk;reg rstn;reg [7:0] tx_data;reg tx_flag;wire tx;//初始化系统时钟,全局复位initial beginclk = 1'b1;rstn = 1'b0;#20;rstn <= 1'b1;end//模拟发送8次数据,分别为0~7initial begintx_data <= 8'b0;tx_flag <= 1'b0;#200//发送数据0tx_data <= 8'd0;tx_flag <= 1'b1;#20tx_flag <= 1'b0;// 每发送1bit数据需要5208个时钟周期,一帧数据为10bit//所以需要数据延时(5208*20*10)后再产生下一个数据#(5208*20*10);//发送数据1tx_data <= 8'd1;tx_flag <= 1'b1;#20tx_flag <= 1'b0;#(5208*20*10);//发送数据2tx_data <= 8'd2;tx_flag <= 1'b1;#20tx_flag <= 1'b0;#(5208*20*10);//发送数据3tx_data <= 8'd3;tx_flag <= 1'b1;#20tx_flag <= 1'b0;#(5208*20*10);//发送数据4tx_data <= 8'd4;tx_flag <= 1'b1;#20tx_flag <= 1'b0;#(5208*20*10);//发送数据5tx_data <= 8'd5;tx_flag <= 1'b1;#20tx_flag <= 1'b0;#(5208*20*10);//发送数据6tx_data <= 8'd6;tx_flag <= 1'b1;#20tx_flag <= 1'b0;#(5208*20*10);//发送数据7tx_data <= 8'd7;tx_flag <= 1'b1;#20tx_flag <= 1'b0;end//clk:每10ns电平翻转一次,产生一个50MHz的时钟信号always #10 clk = ~clk;uart_tx uart_tx_inst(.clk(clk),.rstn(rstn),.tx_data(tx_data),.tx_flag(tx_flag),.tx(tx));endmodule

仿真截图:

接收模块

uart_rx的设计框图:

信号

位宽

类型

功能描述

clk

1bit

Input

工作时钟,频率50MHz

rstn

1bit

Input

复位信号,低电平有效

rx

1bit

Input

串口接收信号

rx_data

8bit

output

串口接收后转成的8bit数据

rx_flag

1bit

output

串口接收后转成的8bit数据有效标志

Verilog代码:

module uart_rx
#(parameter UART_BPS = 'd9600,parameter CLK_FREQ = 'd50_000_000
)(input wire clk,input wire rstn,input wire rx,  //串口接收数据output reg[7:0] rx_data, //串转并后的8bit数据output reg rx_flag //串转并后的数据有效标志信号
);localparam cnt_max = CLK_FREQ / UART_BPS;reg rx_reg1;reg rx_reg2;reg rx_reg3;reg start_nedge;reg work_en;reg [12:0] bd_cnt;reg bit_flag;reg [3:0] bit_cnt;reg [7:0] data;reg flag;//插入两级寄存器进行数据同步,用来消除亚稳态//rx_reg1:第一级寄存器,寄存器空闲状态复位为1always @(posedge clk or negedge rstn) beginif(rstn == 1'b0)rx_reg1 <= 1'b1;elserx_reg1 <= rx;end//rx_reg2:第二级寄存器,寄存器空闲状态复位为1always @(posedge clk or negedge rstn) beginif(rstn == 1'b0)rx_reg2 <= 1'b1;elserx_reg2 <= rx_reg1;   end//reg3:第三级寄存器和第二级寄存器共同构成下降沿检测always @(posedge clk or rstn) beginif(rstn == 1'b0)rx_reg3 <= 1'b1;elserx_reg3 <= rx_reg2;end//start_nedge:检测到下降沿时start_nedge产生一个时钟的高电平always @(posedge clk or negedge rstn) beginif(rstn == 1'b0)start_nedge <= 1'b0;else if((~rx_reg2) && (rx_reg3))start_nedge <= 1'b1;else start_nedge <= 1'b0;end//work_en:接收数据工作使能信号always @(posedge clk or negedge rstn) beginif(rstn == 1'b0)work_en <= 1'b0;else if(start_nedge == 1'b1)work_en <= 1'b1;else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))work_en <= 1'b0;end//bd_cnt:波特率计数器计数,从0计数到5207always @(posedge clk or negedge rstn) beginif(rstn == 1'b0)bd_cnt <= 13'b0;else if((bd_cnt == cnt_max - 1)||(work_en == 1'b0))bd_cnt <= 13'b0;else if(work_en == 1'b1)bd_cnt <= bd_cnt + 1'b1;end//bit_flag : bd_cnt计数器计数到中间数时采样的数据最稳定//此时拉高一个标志信号表示数据可以被取走always @(posedge clk or negedge rstn) beginif(rstn == 1'b0)bit_flag <= 1'b0;else if(bd_cnt == cnt_max/2 - 1)bit_flag <= 1'b1;elsebit_flag <= 1'b0;end//bit_cnt:有效数据个数计数器,当8个有效数据(不含起始位和停止位)//都接收完成后计数器清零always @(posedge clk or negedge rstn) beginif(rstn == 1'b0)bit_cnt <= 4'b0;else if((bit_cnt == 4'd8) && (bit_flag == 1'b1))bit_cnt <= 4'b0;else if(bit_flag == 1'b1)bit_cnt <= bit_cnt + 1'b1;end//data:输入数据进行移位always @(posedge clk or negedge rstn) beginif(rstn == 1'b0)data <= 8'b0;else if((bit_cnt >= 4'd1)&&(bit_cnt <= 4'd8)&&(bit_flag == 1'b1))data <= {rx_reg3,data[7:1]};end//flag:输入数据移位完成时flag拉高一个时钟的高电平always @(posedge clk or negedge rstn) beginif(rstn == 1'b0)flag <= 1'b0;else if((bit_cnt == 4'd8)&&(bit_flag == 1'b1))flag <= 1'b1;elseflag <= 1'b0;end//rx_data:输出完整的8位有效数据always @(posedge clk or negedge rstn) beginif(rstn == 1'b0)rx_data <= 8'b0;else if(rx_flag == 1'b1)rx_data <= data;end//rx_flag:输出数据有效标志(比flag延后一个时钟周期,为了和rx_data同步)always @(posedge clk or rstn) beginif(rstn == 1'b0)rx_flag <= 1'b0;elserx_flag <= flag;endendmodule

tb_uart_rx:

module tb_uart_rx();reg clk;reg rstn;reg rx;wire [7:0] rx_data;wire rx_flag;//初始化系统时钟,全局复位和输入信号initial beginclk = 1'b1;rstn <= 1'b0;rx <= 1'b1;#20rstn <= 1'b1;end//模拟发送8次数据,分别为0~7initial begin#200rx_bit(8'd0);rx_bit(8'd1);rx_bit(8'd2);rx_bit(8'd3);rx_bit(8'd4);rx_bit(8'd5);rx_bit(8'd6);rx_bit(8'd7);endalways #10 clk = ~clk;//定义一个名为rx_bit的任务,每次发送的数据有10位//data的值分别为0~7由i的值传递进来//任务以task开头, 后面紧跟任务名,调用时使用task rx_bit(input [7:0] data);integer  i;//用for循环产生一帧数据,for括号中最后执行的内容只能写i=i+1;for(i=0;i<10;i=i+1) begincase(i)0: rx <= 1'b0;1: rx <= data[0];2: rx <= data[1];3: rx <= data[2];4: rx <= data[3];5: rx <= data[4];6: rx <= data[5];7: rx <= data[6];8: rx <= data[7];9: rx <= 1'b1;endcase#(5208*20); // 每发送1位数据延时5208个时钟周期endendtask //任务以endtask结束uart_rx uart_rx_inst(.clk(clk),.rstn(rstn),.rx(rx),.rx_data(rx_data),.rx_flag(rx_flag));endmodule

仿真截图

参考资料:

5. 串口rs232 — [野火]FPGA Verilog开发实战指南——基于Altera EP4CE10 征途Pro开发板 文档

FPGA协议篇:最简单且通用verilog实现UART协议 - 知乎

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

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

相关文章

如何高效学习Python编程语言

理解Python的应用场景 不同的编程语言有不同的发展历史和应用场景,了解Python主要应用在哪些领域对于学习它会有很大帮助。Python最初是一种通用脚本语言,主要用于系统级任务自动化。随着时间的推移,它逐步成为数据处理、科学计算、Web开发、自动化运维等众多领域的主要编程语…

Navicat设置mysql权限

新建用户&#xff1a; 注意&#xff1a;如果不生效执行刷新命令:FLUSH PRIVILEGES; 执行后再重新打开查看&#xff1b; 查询权限命令&#xff1a;1234为新建的用户名&#xff0c;localhost为访问的地址 SHOW GRANTS FOR 1234localhost;如果服务器设置服务器权限后可能会出现权…

【算法】求一个数组中三个数乘积最大值 - 线性扫描

题目 给定一个数组&#xff0c;找出数组中乘积最大的三个数。 原理 一个数组中最大值只有两种情况&#xff1a;两个最小的负数和一个最大的正数 & 三个最大的正数。线性扫描找出这五个数字&#xff0c;即可求出最大值。 代码 public static void main(String[] args) {…

潜伏三年,核弹级危机一触即发,亚信安全深度分析XZ Utils后门事件

2024年3月29日星期五上午8点&#xff0c;有研究人员称xz/liblzma中的后门导致SSH服务器内存泄露&#xff0c;使得SSH服务异常&#xff08;https://www.openwall.com/lists/oss-security/2024/03/29/4&#xff09;。github中“xz”压缩工具主要由Larhzu和Jia Tan共同负责维护&am…

QToolTip设置背景色没有生效原因与解决方法

设置全局QToolTip的背景色&#xff0c;有两种方法&#xff1a; 1. 样式表设置&#xff1b; 2. QToolTip::setPalette(pal);调色板设置&#xff1b; QPalette pal QToolTip::palette(); //修改背景色 pal.setColor(QPalette::Inactive,QPalette::ToolTipBase,QColor(240, 25…

力扣25. K 个一组翻转链表

Problem: 25. K 个一组翻转链表 文章目录 题目描述思路复杂度Code 题目描述 思路 1.创建虚拟头节点dummy并将其next指针指向head&#xff0c;创建指针pre、end均指向dummy&#xff1b; 2.编写反转单链表的函数reverse 3.当end -> next 不为空时&#xff1a; 3.1.每次k个一组…

Java强连通分量知识点(含面试大厂题和源码)

在大厂面试中&#xff0c;与拓扑排序相关的问题通常涉及到对图的处理和算法设计。以下是三道可能出现在大厂面试中的编程题目&#xff0c;以及相应的Java源码实现。 题目 1&#xff1a;课程依赖关系 描述&#xff1a; 给定一个课程列表和课程之间的依赖关系&#xff0c;为所有…

Bigtable [OSDI‘06] 论文阅读笔记

原论文&#xff1a;Bigtable: A Distributed Storage System for Structured Data (OSDI’06) 1. Introduction Bigtable 是一种用于管理结构化数据的分布式存储系统&#xff0c;可扩展到非常大的规模&#xff1a;数千台服务器上的数据量可达 PB 级别&#xff0c;同时保证可靠…

学习java第三十五

Spring事务传播行为&#xff1a; PROPAGATION_REQUIRED(默认) 如果当前没有事务&#xff0c;就新建一个事务&#xff0c;如果已经存在一个事务中&#xff0c;加入到这个事务中 PROPAGATION_SUPPORTS 支持当前事务&#xff0c;如果当前没有事务&#xff0c;就以非事务方式执行 P…

golang语言和JAVA对比

引言: 在当今的软件开发领域,有许多编程语言供开发人员选择。其中,Golang和Java是两种备受开发者青睐的语言。本文将探讨Golang和Java之间的比较和对比,分析它们在语言特性、性能、平台支持、社区和生态系统、开发效率和可维护性等方面的异同。 一、语言特性和性能 Golang…

二维相位解包理论算法和软件【全文翻译-路径跟踪方法(4.1)】

4.1 引言 在第 2 章中我们注意到,从一个像素点开始计算的解包相位可能取决于积分路径。如果我们沿着两条不同的路径从一个像素点到另一个像素点,我们可能会得到两个不同的解包裹相位答案。我们发现,这些不一致是由称为残差的点状结构造成的。残差位于由四个像素组成的 &quo…

加密算法(二)

1、SHA-256加密算法&#xff1a; package com.arithmetic.encryption; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; //使用java.security.MessageDigest类来进行SHA-256摘要的计算。 //通过getInstance("SHA-256")方法获取…

阿里巴巴拍立淘API新功能揭秘:图片秒搜商品,实现智能化个性化购物新体验

在数字化快速发展的今天&#xff0c;智能化和个性化已经成为购物体验中不可或缺的元素。为了满足消费者日益增长的购物需求&#xff0c;阿里巴巴中国站不断推陈出新&#xff0c;其中拍立淘API的新功能——图片秒搜商品&#xff0c;无疑为智能化个性化购物体验开创了新的篇章。 …

js怎样判断status

相信大家都知道Switch开关吧&#xff0c;他有两种状态&#xff0c;通常用1/2表示&#xff0c;开启时为true&#xff0c;关闭时为false&#xff0c;那么我们该怎样判断他是否为开启还是关闭你? 我们可以声明一个变量&#xff0c;让它等于status&#xff0c;判断它是否等于1/2&…

【机器学习入门】使用YOLO模型进行物体检测

系列文章目录 第1章 专家系统 第2章 决策树 第3章 神经元和感知机 识别手写数字——感知机 第4章 线性回归 第5章 逻辑斯蒂回归和分类 第5章 支持向量机 第6章 人工神经网络(一) 第6章 人工神经网络(二) 卷积和池化 第6章 使用pytorch进行手写数字识别 文章目录 系列文章目录前…

GitHub与Namecheap域名绑定解除指南:删除CNAME文件

github namecheap 域名到期怎么解绑 什么是CNAME文件&#xff1f; CNAME文件是位于你的username.github.io仓库根目录中的一个简单文本文件&#xff0c;它指明了你的GitHub Pages站点要绑定的自定义域名。GitHub通过读取这个文件中的内容来配置DNS解析&#xff0c;从而将你的自…

八股面试速成—计算机网络部分

暑期实习面试在即&#xff0c;这几天八股和算法轮扁我>_ 八股部分打算先找学习视屏跟着画下思维导图&#xff0c;然后看详细的面试知识点&#xff0c;最后刷题 其中导图包含的是常考的题&#xff0c;按照思维导图形式整理&#xff0c;会在复盘后更新 细节研究侧重补全&a…

基于单片机冬季供暖室温调节控制系统

**单片机设计介绍&#xff0c;基于单片机冬季供暖室温调节控制系统 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的冬季供暖室温调节控制系统是一种集温度检测、控制和显示功能于一体的智能化系统。该系统以单片机为…

Linux多进程下载之aria2c

安装 sudo apt-get install aria2下载 aria2c -x4 [link]在这个命令中&#xff0c;-x4’表示你想要使用4个连接来下载文件。你可以根据你的需求调整这个数字。 如果遇到这个错误&#xff1a;errorCode1 SSL/TLS handshake failure: not signed by known authorities or inva…

C++ 指针与结构

三种存取结构成员的方式&#xff1a; ① 通过结构变量名&#xff1b; ②通过指向结构的指针和间接运算符(*)&#xff1b; ③通过指向结构的指针和指向成员运算符(->);