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;如果服务器设置服务器权限后可能会出现权…

潜伏三年,核弹级危机一触即发,亚信安全深度分析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…

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

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

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

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

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

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

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

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

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

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

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

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

C++ 指针与结构

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

【已解决】ZIP压缩文件如何设置密码?

ZIP是常用的压缩格式之一&#xff0c;对于重要的ZIP文件&#xff0c;我们还可设置密码保护&#xff0c;那ZIP压缩文件怎么设置密码呢&#xff1f;不清楚的小伙伴一起来看看吧&#xff01; 给ZIP文件设置密码&#xff0c;我们需要用到支持ZIP格式的解压缩软件&#xff0c;比如7…

2024HW-->Wireshark攻击流量分析

在HW中&#xff0c;最离不开的&#xff0c;肯定是看监控了&#xff0c;那么就要去了解一些wireshark的基础用法以及攻击的流量&#xff01;&#xff01;&#xff01;&#xff01; 1.Wireshark的基本用法 比如人家面试官给你一段流量包&#xff0c;你要会用 1.分组详情 对于我…

UE4_如果快速做出毛玻璃效果_假景深

UE4_如果快速做出毛玻璃效果_假景深 2022-08-20 15:02 一个SpiralBlur-SceneTexture材质节点完成效果&#xff0c;启用半透明材质通过修改BlurAmount数值大小调整效果spiralBlur-SceneTexture custom节点&#xff0c;HLSL语言float3 CurColor 0;float2 BaseUV MaterialFloa…

pytest的时候输出一个F后面跟很多绿色的点解读

使用pytest来测试pyramid和kotti项目&#xff0c;在kotti项目测试的时候&#xff0c;输出一个F后面跟很多绿色的点&#xff0c;是什么意思呢&#xff1f; 原来在使用pytest进行测试时&#xff0c;输出中的“F”代表一个失败的测试&#xff08;Failed&#xff09;&#xff0c;而…

隧道风速风向检测器的工作原理

TH-SQX1隧道风速风向检测器是一种专门用于隧道内部风速和风向监测的设备。它基于超声波技术进行测量&#xff0c;通过发射和接收超声波信号&#xff0c;利用信号传输时间差来精确测量风速和风向。这种检测器具有测量准确、响应速度快、稳定性好等优点&#xff0c;适用于隧道内部…

技术再度取得优势,人工智能兴起推动需求,美芯涨价收割市场,收割中国制造?...

独家首发 ------------- 分析机构指出一季度全球存储芯片涨价了15%左右&#xff0c;而近期三星半导体预测全球存储芯片的价格还将继续上涨&#xff0c;预计二季度至少上涨两成&#xff0c;显示出美系芯片在忍受了一年多的亏损之后再度联手涨价。 2022年中国存储芯片取得了重大进…

08 Python进阶:XML 解析

什么是 XML&#xff1f; XML&#xff08;可扩展标记语言&#xff0c;Extensible Markup Language&#xff09;是一种用于表示和传输数据的标记语言。它被设计用来以一种结构化的形式描述文档的内容&#xff0c;并且具有良好的跨平台和跨语言的特性。XML使用标签来定义数据的结构…

免费https详细教程

简单叙述一下https的定义和实现https的一些基本作用&#xff0c;然后会给到申请SSL证书的方式以及安装部署流程&#xff0c;最终实现网站的https访问。 随着互联网的快速发展&#xff0c;网络安全问题日益凸显。在互联网上传输敏感信息、进行在线交易和共享个人数据时&#xf…

Spring boot微服务分布式框架Rouyi Cloud权限认证

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 往期热门专栏回顾 专栏…

Go 程序的启动流程【1/2】

Go 程序的启动流程 本文将以一个简单的 HelloWorld 程序为例&#xff0c;探究 Go 程序的启动流程 package mainfunc main() {_ "Hello World" }入口 我们先通过 go build . 将代码编译成可执行文件&#xff0c;众所周知&#xff0c;我们在一个 shell 中执行可执行…