FPGA学习-UART串口发送单字节(UART时序分析+真正的FPGA设计看图写代码)

2023-05-16

首先看UART发送时序图:

        要发送一个完整字节,需要“1位起始位+ 8位数据位+1位停止位”,图上的第11位,是确认一个字节发送完的一位。

        重点是每一位之间的发送时间需要保持一致,也就是bps_clk的每个高脉冲之间的间隔相等稳定,bps_clk的频率就是波特率。例如波特率为9600,就是1秒内有9600个脉冲,可以发送9600位。

        因此,发送速率(波特率)需要严格控制,以便稳定发送。

发送模块简化图、RTL电路设计图 :

UART发送单字节模块,除去必要的clk系统时钟、rst_n系统复位,还需要三个输入分别是

        波特率选择bps_set,

        发送数据输入data_byte,

        发送开始标志单脉冲信号tx_en。

三个输出分别是

        发送输出端口rs232_tx,

        发送停止标志单脉冲信号tx_down,

        串口工作状态uart_state。

RTL电路图看起来比较复杂,分模块理解就比较容易了。

        首先为了发送稳定,需要特定的波特率,就需要一个计数器给系统时钟clk分频生成bps_clk;

        波特率肯定不知能只有一种,所以需要一个查找表,查找波特率对应的计数值;

        要对生成的bps_clk从1~11计脉冲数以便知道将要发送一个字节的第几位;

        通过一个比较器比较,当计数到11时,清零重新计数;

        data_byte+start_bit+stop_bit通过一个10选1的多路器,计数到哪一位时就选哪一位的数据进行发送;

        最后加一个描述uart_state状态的标志信号监视UART的工作状态。

RTL程序:

module uart_byte_tx(clk50M,rst_n,data_byte,tx_en,bps_set,rs232_tx,tx_down,uart_state);
input clk50M;
input rst_n;
input [7:0] data_byte;        //输入想要发送的8位数据
input [2:0] bps_set;          //波特率选择查找表的输入
input tx_en;                  //发送开始的标志单脉冲信号
output reg rs232_tx;          //输出发送数据端
output reg tx_down;           //发送停止的标志单脉冲信号
output reg uart_state;        //UART工作状态信号,1为发送,0为空闲

reg [15:0] counter;           //分频器计数寄存器
reg [15:0] bps_DR;            //选定的波特率的最大计数值
reg [3:0] bps_cnt;            //1~11的位计数
reg [7:0] r_data_byte;        //data_byte进来 先寄存一次,以便后续稳定发送
reg bps_clk;                  //波特率时钟


localparam start_bit = 1'b0;  //定义起始位为0低电平
localparam stop_bit = 1'b1;   定义停止位为1高电平

/*************波特率对应的分频计数值查找表**************/
always @ (posedge clk50M or negedge rst_n)begin
	if(!rst_n)
		bps_DR<=16'd5207;
	else begin
		case(bps_set)
			3'd0:bps_DR<=16'd5207;//9600
			3'd1:bps_DR<=16'd2603;//19200
			3'd2:bps_DR<=16'd1301;//38400
			3'd3:bps_DR<=16'd867;//57600
			3'd4:bps_DR<=16'd433;//115200
			default:bps_DR<=16'd5207;
		endcase
	end
end
/****************************************************/


/********************分频计数器生成********************/
always @ (posedge clk50M or negedge rst_n)begin
	if(!rst_n)
		counter<=16'd0;
	else if(uart_state) begin
		if(counter==bps_DR)
			counter<=16'd0;
		else
			counter<=counter+1'd1;
	end
	else
		counter<=16'd0;
end
/****************************************************/


/********************分频时钟生成*********************/
always @ (posedge clk50M or negedge rst_n)begin
	if(!rst_n)
		bps_clk<=1'b0;
	else if(counter==16'd1)
		bps_clk<=1'b1;
	else
		bps_clk<=1'b0;
end
/****************************************************/


/****************bps_clk计数(最大11)****************/
always @ (posedge clk50M or negedge rst_n)begin
	if(!rst_n)
		bps_cnt<=4'd0;
	else if(bps_cnt==4'd11)
		bps_cnt<=4'd0;
	else if(bps_clk)
		bps_cnt<=bps_cnt+1'd1;
	else
		bps_cnt<=bps_cnt;
end
/****************************************************/



/************tx_down发送停止单脉冲标志信号*************/
always @ (posedge clk50M or negedge rst_n)begin
	if(!rst_n)
		tx_down<=1'b0;
	else if(bps_cnt==4'd11)
		tx_down<=1'b1;
	else
		tx_down<=1'b0;
end
/****************************************************/



/******************寄存一下data_byte******************/
always @ (posedge clk50M or negedge rst_n)begin
	if(!rst_n)
		r_data_byte<=8'd0;
	else if(tx_en)
		r_data_byte<=data_byte;
	else 
		r_data_byte<=r_data_byte;
end
/****************************************************/



/**********************发送模块***********************/
always @ (posedge clk50M or negedge rst_n)begin
	if(!rst_n)
		rs232_tx<=1'b1;
	else begin
		case(bps_cnt)
			0:rs232_tx<=1'b1;
			1:rs232_tx<=start_bit;
			2:rs232_tx<=r_data_byte[0];
			3:rs232_tx<=r_data_byte[1];
			4:rs232_tx<=r_data_byte[2];
			5:rs232_tx<=r_data_byte[3];
			6:rs232_tx<=r_data_byte[4];
			7:rs232_tx<=r_data_byte[5];
			8:rs232_tx<=r_data_byte[6];
			9:rs232_tx<=r_data_byte[7];
			10:rs232_tx<=stop_bit;
			default:rs232_tx<=1'b1;
		endcase
	end
end
/****************************************************/



/********************状态标志信号*********************/
always @ (posedge clk50M or negedge rst_n)begin
	if(!rst_n)
		uart_state<=1'b0;
	else if(tx_en)
		uart_state<=1'b1;
	else if(bps_cnt==4'd11)
		uart_state<=1'b0;
	else
		uart_state<=uart_state;	
end
/****************************************************/

endmodule

testbench文件:

`timescale 1ns/1ns
`define clock_period 20

module uart_byte_tx_tb;
	reg clk;
	reg rst_n;
	reg [7:0]data_byte;
	reg tx_en;
	reg [2:0]bps_set;
	wire rs232_tx;
	wire tx_down;
	wire uart_state;


	uart_byte_tx uart_byte_tx(
	.clk50M(clk),
	.rst_n(rst_n),
	.data_byte(data_byte),
	.tx_en(tx_en),
	.bps_set(bps_set),
	.rs232_tx(rs232_tx),
	.tx_down(tx_down),
	.uart_state(uart_state)
	);


	initial clk=1;
	always #(`clock_period/2) clk=~clk;
	initial begin
		//首先激励初始化,波特率查找表默认选4,也就是115200.然后复位结束,系统工作
		rst_n=0;               
		data_byte=0;
		tx_en=0;
		bps_set=4'd4;
		#(`clock_period*20);
		rst_n=1;
		#(`clock_period*50);
		
		//发送0xaa,等待tx_down到来时延时五千个系统周期
		tx_en=1;
		data_byte=8'haa;
		#(`clock_period);
		tx_en=0;
		@(posedge tx_down)
		#(`clock_period*5000);

		//发送0x37,等待tx_down到来时延时五千个系统周期。然后停止仿真
		tx_en=1;
		data_byte=8'h37;
		#(`clock_period);
		tx_en=0;
		@(posedge tx_down)
		#(`clock_period*5000);
		$stop;
	end
endmodule

波形图:

        可以看到先要发送的data_byte,和已经发送的rs232_tx一致。而且1~11是从 data_byte的低位到高位进行选取数据发送。每产生一个bps_cnt就发送一位。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FPGA学习-UART串口发送单字节(UART时序分析+真正的FPGA设计看图写代码) 的相关文章

  • Verilog实现两路组相联cache

    cache代码 timescale 1ns 1ps cache共32块 分为16组 每组2块 即两路组相联 1块 4字 1字 4字节 主存共1024块 4096个字 主存地址共12位 1 0 为块内偏移 5 2 为组地址 11 6 为Tag
  • Verilog的基础知识

    Verilog的基本介绍 硬件描述语言发展至今已有二十多年历史 当今业界的标准中 IEEE标准 主要有VHDL和Verilog HDL 这两种硬件描述语言 一个设计往往从系统级设计开始 把系统划分成几个大的基本的功能模块 每个功能模块再按一
  • 八段数码管动态显示(输入数据为BCD编码)

    八段数码管动态显示 输入数据为BCD编码 一 数码管概述 图1 八段共阴数码管内部等效原理图 图2 八段共阳数码管内部等效原理图 上面两图分别是对应八段共阴 共阳的数码管内部等效图 共阴是将八个LED数码管的阴极连接在一起接低 阳极segm
  • win10下安装vivado 2018.3之后ise14.7 的impact 无法使用

    软件版本号 操作系统win10 ise14 7 vivado 2018 3 ise14 7 在win10里面问题总结 1 ise14 7 闪退问题 比较好解决 论坛上比较多的解决方法 2 ise 14 7 windows 10 版本的ise
  • 采用Vivado 配置xilinx GTX的SATA设计

    从Vivado开始 配置GTX的时候 多了一个SATA协议支持 但有些小地方还需要自己另外设置 整理了一下 分享给大家 首先打开Transceivers wizard 打开页签 线速率和参考时钟选择 在协议里面选择SATA2或者SATA3
  • [HDLBits] Exams/ece241 2014 q7a

    Design a 1 12 counter with the following inputs and outputs Reset Synchronous active high reset that forces the counter
  • 【PIPE】流水线设计中的基本模块

    大概分成以下几节 1 概述及协议 2 valid forward valid超前 3 bubble collapse 消除气爆 4 input output skid 不知中文怎么说 5 pipe halt 流水停顿 6 idle pres
  • FPGA学习笔记(一)__电平知识

    常见电平标准 文章目录 1 TTL电平标准 2 LVTTL电平标准 1 LVTTL3V3 2 LVTTL2V5 3 CMOS电平标准 4 LVCOMS电平标准 1 LVCOMS3V3 2 LVCOMS2V5 3 LVCOMS1V8 4 LV
  • 基于FPGA的AHT10传感器温湿度读取

    文章目录 一 系统框架 二 i2c接口 三 i2c控制模块 状态机设计 状态转移图 START INIT CHECK INIT IDLE TRIGGER WAIT READ 代码 四 数据处理模块 串口 代码 五 仿真 testbench设
  • FPGA_MIG驱动DDR3

    FPGA MIG驱动DDR3 说明 FPGA zynq 7z100 DDR3 MT41K256M16TW 107 内存大小为512MB 数据接口为16bit 环境 Vivado2018 2 IP核 Memory Interface Gene
  • Spartan-3E 上的随机数生成

    我需要在 Spartan 3E FPGA 上为我的遗传算法生成伪随机数 并且我想在 verilog 中实现它 您能给我任何关于此的指示吗 当然 Adam 的随机生成器是不可合成的 您必须显式创建一个LFSR 以下示例可能会有所帮助 它是一个
  • UART ISR Tx Rx 架构

    我让事情变得复杂了吗 我正在构建我的代码 以便通过 UART 从 8051 micro 与外围设备进行通信 外设响应主机的命令 一次只能响应一个命令 这是一个简单的发送和接收协议 tx1 rx1 tx2 rx2 tx3 rx3 每个 TX
  • Android Things:连接到串行调试控制台

    我一直在尝试连接到串行控制台树莓派 3 with 安卓事物 using USB to TTL cable从我的Linux Ubuntu 机器 尽管我按照文档连接了电缆 但执行时我得到的只是minicom命令如下 with 没有机会输入任何字
  • 异步FIFO设计之格雷码

    目录 二进制转格雷码 格雷码转二进制 相邻的格雷码只有1bit的差异 因此格雷码常常用于异步fifo设计中 保证afifo的读地址 或写地址 被写时钟 或读时钟 采样时最多只有1bit发生跳变 在不考虑路径延时的情况下 因为源数据 读写地址
  • 异步FIFO设计之格雷码

    目录 二进制转格雷码 格雷码转二进制 相邻的格雷码只有1bit的差异 因此格雷码常常用于异步fifo设计中 保证afifo的读地址 或写地址 被写时钟 或读时钟 采样时最多只有1bit发生跳变 在不考虑路径延时的情况下 因为源数据 读写地址
  • VHDL - PhysDesignRules:367

    当我尝试从 VHDL 代码合成 实现和生成程序文件时 我收到警告 当我尝试合成时出现此错误 WARNING Xst 647 Input
  • Linux驱动程序DMA传输到PC作为主机的PCIe卡

    我正在开发一个 DMA 例程 将数据从 PC 传输到 PCIe 卡上的 FPGA 我阅读了 DMA API txt 和 LDD3 ch 15 详细信息 但是 我不知道如何从 PC 到 PCIe 卡上的一致 iomem 块进行 DMA 传输
  • UIO 设备上的 mmap EINVAL 错误

    在尝试使用 UIO 而不是直接映射后 我在 Xilinx Zynq 上映射物理内存时遇到问题 dev mem 虽然计划是以普通用户身份运行应用程序 而不是root这仍在运行root 显然 第一个映射成功 其余映射到同一个文件描述符12 de
  • FPGA 有哪些实际应用?

    我对我的程序为一个小型七段显示器提供动力感到非常兴奋 但是当我向不在现场的人展示它时 他们总是说 那么你能用它做什么 我永远无法给他们一个简洁的答案 谁能帮我吗 第一 它们不需要具有易失性存储器 事实上 大厂商 Xilinx Altera
  • 嵌入式Linux中UART上的9位协议

    我正在尝试在嵌入式 Linux 中的 UART 上强制使用 9 位协议 目前我正在 am335x evm 板上对此进行测试 我计划使用坚持平价来做到这一点 理想情况下 我希望不需要实际修改 omap serial c 驱动程序的任何代码 9

随机推荐

  • pixhawk px4 commander.cpp

    对于复杂的函数 xff0c 要做的就是看函数的输入是什么 来自哪里 xff0c 经过处理后得到什么 给谁用 xff0c 这样就可以把程序逻辑理清 中间的分析就是看函数如何处理的 span class hljs keyword extern
  • ESP8266 读取多个传感器数据(风速、风向、颗粒物、CO)

    文章目录 1 ESP8266开发板资源2 Arduino编程1 准备工作2 读取多个串口数据1 定义软串口 2 涉及传感器简介 3 集成代码 xff08 注释详细 xff09 4 Arduino 串口监视器 1 ESP8266开发板资源 一
  • ESP8266采集多个传感器数据通过WIFI上传到本地数据库(风速、风向、CO、颗粒物)

    文章目录 1 数据库使用简介1 Navicat premium连接2 新建数据库3 在数据库中新建表 2 代码实现代码 1 数据库使用简介 建立数据库连接 xff0c 在连接里新建数据库 xff0c 在数据库里新建表 1 Navicat p
  • STM32读取串口传感器(颗粒物传感器,被动传输)

    文章目录 1 串口2中断 xff08 在主动上传的基础上 xff09 1 添加发送字符和数组函数2 主函数调用3 串口助手接收数据 2 遇到的串口通信不成功问题 1 串口2中断 xff08 在主动上传的基础上 xff09 1 添加发送字符和
  • STM32采集问答式串口传感器数据写入SD卡(spi模式)

    文章目录 1 实验工具2 接线说明3 部分代码说明1 文件的覆盖问题1 文件系统的文件打开方式2 移动文件初始写入指针位置 2 变量的转换及写入问题1 sprintf函数2 CSV文件创建 3 数据采集流程 xff08 主函数 中断函数处理
  • (1)STM32 RC522模块测试代码

    文章目录 1 使用资源2 RC522模块2 1 RC522简介2 2 RC522工作模式 3 模块测试代码 工程文件源码链接 1 使用资源 使用32 的SPI1资源 xff1a SDA PA4 RST PA1 普通io SCK PA5 MI
  • (3)STM32 SG90舵机模块测试

    文章目录 1 资源简介2 测试源码 1 资源简介 stm32 rct6板SG90舵机模块 接线引脚 xff1a 橙色 xff1a 信号线 红色 xff1a 电源 43 5v 咖色 xff1a GND 此模块三条线固定在一起 xff0c 如果
  • (4) STM32 AS608指纹识别模块测试代码

    文章目录 1 使用资源2 实现思路简述3 指纹测试代码3 1 部分代码介绍3 2 源码链接 1 使用资源 stm32RCT6板子AS608指纹模块 软件资源 xff1a 串口二资源连接AS608 TX RX接线AS608 wak线连接PA8
  • 通过路由器连接JetsonNano与地面站

    通过路由器连接JetsonNano与地面站 一 前期准备注意事项连接局域网虚拟机网络设置 二 获取IP地址和设备名称IP地址设备名称 三 配置Nano修改bashrc文件修改hosts文件 四 配置地面站修改bashrc文件修改hosts文
  • jvm 堆 栈中存什么?

    数据类型 Java虚拟机中 xff0c 数据类型可以分为两类 xff1a 基本类型和引用类型 基本类型的变量保存原始值 xff0c 即 xff1a 他代表的 值就是数值本身 xff1b 而引用类型的变量保存引用值 引用值 代表了某个对象的引
  • YOLOv5 数据集划分及生成labels

    0 本人文件夹存放格式 xff08 因为要测试多个数据集和不同的yolov5版本和其他算法 xff0c 所以数据集整体放到外面 xff09 1 划分数据集 验证集 测试集 coding utf 8 import os import rand
  • mission planner发送数据之mavlink

    前段时间研究mp的地面站 xff0c 看了几天有点体会 xff0c 看网上的解析比较少 xff0c 写上来和大家分享下 xff0c 全是自己的理解 xff0c 东西比较少 xff0c 硬货不多 xff0c 还请见谅 最开始是想做个无人机超声
  • 实验三、嵌入式Linux网络通信实验

    实验三 嵌入式Linux网络通信实验 一 实验目的 1 掌握TCP与UDP协议原理 2 掌握套接字通信原理 2 掌握TCP套接字服务器端与客户端通信方法 二 实验基本要求 1 学习TCP与UDP协议原理 2 掌握TCP套接字服务器端与客户端
  • QT重载keyPress焦点问题

    最近项目上需要用到键盘上的快捷键 xff0c 就重载了键盘的按下事件 xff0c 以为万事大吉 实际界面上有很多控件 xff0c 导致如果鼠标点击了其中一个不能接收焦点的控件 xff0c 就不知道焦点传到了什么地方 上网查大致两种思路 xf
  • QT实现地图或图片的细节图(抓取图片的细节,放大图片)

    最近由于项目上的要求 xff0c 需要实现一个细节图 xff0c 就是一个矩形框中加载一个大图 xff0c 右下或者左下方有一个小矩形框 xff0c 可以加载全图 xff0c 并显示大矩形框中图片在全图的位置 xff0c 有点拗口 xff0
  • centos7 搭建vtk7.1.1+Qt开发环境+运行编译工程

    一 CMAKE安装 vtk必须用cmake编译 xff0c 但是 xff0c 由于高版本的cmake没有支持qt5的gui xff0c 所以选择低版本的 xff0c 但是低版本的必须得依赖于qt4 xff0c 而qt4相较于qt5 xff0
  • centos搭建vtk开发环境

    一 OpenGL3 0 vtk有个硬性要求就是OpenGL3 0及以上版本 xff0c 由于笔者此前使用的是centos7 xff0c 照着网上的教程配置OpenGL xff0c 但是之后glxinfo grep OpenGL发现openg
  • 读取ugrid格式文件

    include lt iostream gt include lt vector gt include lt string gt include lt fstream gt using namespace std int main int
  • C语言:#define详解

    define定义标识符 语法 xff1a define name stuff tips xff1a 我们在define定义标识符的时候 xff0c 不建议在后面加上 xff1b xff0c 这样很容易出问题 比如说在以下的情况中 xff1a
  • FPGA学习-UART串口发送单字节(UART时序分析+真正的FPGA设计看图写代码)

    首先看UART发送时序图 xff1a 要发送一个完整字节 xff0c 需要 1位起始位 43 8位数据位 43 1位停止位 xff0c 图上的第11位 xff0c 是确认一个字节发送完的一位 重点是每一位之间的发送时间需要保持一致 xff0