FPGA学习之串口发送模块设计与验证
FPGA学习之串口发送模块设计与验证
1.实验目的:
实现一个串口输出,通过上位机PC查看接收到的是否是串口发送的数据。
2.实验介绍:
学习UART通信原理及其硬件电路设计,使用FPGA实现UART通信中的数据发送部分设计,并使用ISSP工具来进行板级验证。
3.实验原理
(1)异步串行通信原理
串行通信是指利用一条传输线将数据一位位的顺序传送,每位数据占据固定时间长度。
异步通信以一个字符为传输单位,通信中两个字符之间的时间间隔多少是不固定的,但同一个字符中的两个相邻位之间的时间间隔是固定的。
即下图中10位数据之间时间间隔是固定的,这个固定时间称为波特率,指每秒钟可以通信的数据比特个数,典型的波特率有1200bps,4800bps,9600bps,19200bps,115200bps等,一般通信两端波特率要一致。
(2)系统框架图
对于整个串口发送模块,基于上述原理,理解如下输入输出接口:
1.首先作为发送模块,必然有一个输出发送数据端口Rx232_Tx;
2.对于一个字符发送完成,必须要告诉上位机字符发送结束,启动下一次发送,即发送结束信号标志Tx_Done,当发送完成,输出一个时钟周期高电平。
3.当串口模块在发送数据期间,需要存在一个输出标志串口状态位uart_state,即处于发送状态时为1,告诉上位机目前模块正忙。
4.输入肯定有时钟Clk和复位输入Rst_n。
5.在上图中波特率固然有常用的几个,但是如何去选择对应上位机的波特率,来实现不同上位机通信,因此这里需要一个波特率选择输入端口baud_set[3:0]。
6.我们要发送一个数据,必须要控制模块在需要数据时刻发送,不能无休止的一直发送,因此必须有发送控制信号即发送使能信号send_en
7.待发送的数据输入data_byte[7:0];
那这些输入输出端口之间存在怎样的逻辑电路来将数据发送出去呢?
数据输出格式
对于要输出1字节10位数据,其中数据发送格式已知,即起始位+8位数据位+停止位(校验位默认无),那么这里需要10选一多路器,这样我们可以来选择究竟将哪一位数据发送出去。
由于RS232是异步收发器,因此为了保证发送的数据在时钟到来时处于稳定,需要对输入数据进行寄存。
8位有效数据经过寄存器发送到10选一多路中,再由sel选择信号选择输出哪位数据,选择好数据后,传输到data_reg寄存器中。
那么上图中sel选择信号怎么产生呢?
波特率时钟沿计数输出10选一多路器控制
首先sel选择信号选择的是哪位数据输出?由下图可知,我们可以将BPS_CLK的时钟沿进行计数,当每来一个上升沿就让计数器bps_cnt自加1,然后根据计数结果来选择数据位数输出,例如计数器计到7时,选择信号就会选择发送BIT[5]数据。
而且这个计数器最大只能计数到11(一个字节发送完毕),计数到11时,就需要产生清零clr信号。
这个清零clr信号根据上述输出端口Tx_Done而来,当结束信号标志Tx_Done输出一个时钟周期高电平,认定一个字节传输完毕。
当计数器bps_cnt_q等于11,结果为真,连接到clr清零信号线上,来实现清零动作。
同时比较结果又经过寄存器传输到Tx_Done信号上,告诉上位机字符发送结束。
查看上图可得,bps_cnt的输入BPS_Clk信号其实波特率对应的时钟信号。
分频计数器输出波特率时钟
因为一个字符相邻位的时间间隔对应的波特率,而每一位的传输是基于bps_clk的上升沿来的,因此我们需要不同的bps_clk来对应不同波特率(1200bps,4800bps,9600bps,115200bps)。
首先第一步是产生不同的波特率,因为系统时钟是50Mhz,系统时钟周期为20ns,这里采用依然采用分频计数器来实现不同波特率时钟,下表是常见波特率对应的计数器关系:
上表可知所谓波特率的生成,无非就是利用一个定时器来定时,产生频率与对应波特率时钟频率。
例如当我们使用9600bps时,则需要产生一个频率为9600Hz的时钟信号。那么如何去产生这个信号呢?
在这里,我们先将9600Hz的时钟信号周期计算出来,1秒钟为1000_000_000ns,因此9600bps波特率时钟的周期为1000_000_000/9600≈104166.6,即9600Hz时钟信号的一个周期为104166.6ns,每当定时时间当来,就产生一个系统时钟周期长度的高脉冲信号即可,由于系统时钟周期为20ns(50MHz),因此只需计数104166.6/20个系统时钟,即可获取到101166.6的定时。
分频计数器计数使能控制
对应一个分频计数器而言,在系统时钟运行过程中,什么时候开始计数即使能计数信号?计数什么时候开始工作呢?
本次设计采用两个二选一多路器来产生使能计数信号,首先这里有一个优先级的问题,因为当send_en发送使能信号为高电平时,那么我们的分频计数器也就要开始计数了。
然而send_en信号只是维持一个时钟周期的高电平,其余时间为低电平,这时就需要一个二选一多路器来实现当send_en信号为高电平时,输出“1”表示计数开始。
如何实现在send_en为低电平时,分频计数器还在计数呢?计数结束的标志是什么呢?
由上文可知在数据传输结束后会产生一个Tx_Done标志信号,这个信号是计数器bps_cnt等于11时产生的,在与11的比较结果会连接到计数器bps_cnt清零clr信号上,那么也可以将该信号作为另一个二选一多路器的选择端上。
因此send_en信号为低电平时会选择第二个二选一多路器MUX2_2作为输出,MUX2_2的选择端与clr同源,因此当比较结果为假时,则MUX2_2的输出即是原来的输入UART_state,即保持UART_state状态不变,依然表示分频计数器还在计数。
当比较结果为真时,即发送数据结束,MUX2_2会输出“0”,这时UART_state会输出低电平,使能计数en_cnt会控制分频计数器停止计数。
不同波特率查找计数值输出
如何产生选择不同波特率时钟信号对应的计数值bps_DR[15:0]呢?
这里利用查找表LUT的方式来实现baud_set信号选择不同的波特率,输出不同的系统时钟计数值。
系统框架图
因此可以得出串口发送模块基本逻辑的系统框架图:
4.代码实现
根据上文描述系统框架图来分别实现相应部分功能:
数据输出格式
波特率时钟沿计数输出10选一多路器控制
分频计数器输出波特率时钟
分频计数器计数使能控制
不同波特率查找计数值输出
总体代码:
//--------------------------------------------------------------------------------------------
// Component name : uart_Tx
// Author : 硬件嘟嘟嘟
// time : 2020.04.21
// Description : 串口发送模块
// src : FPGA系统设计与验证实战指南_V1.2
//--------------------------------------------------------------------------------------------module uart_tx(Clk,Rst_n,send_en,baud_set,data_byte,Rx232_Tx,Tx_Done,uart_state);input Clk,Rst_n;input send_en; //发送使能信号输入input [2:0] baud_set; //波特率选择输入input [7:0] data_byte; //待发送数据//output Rx232_Tx; //发送数据输出端口output Tx_Done; //一字节发送结束标志位output uart_state; //发送数据状态//数据输入寄存,输出格式及输出寄存模块//8位有效数据寄存
reg [7:0] r_data_byte;
always@(posedge Clk,negedge Rst_n)if(!Rst_n)r_data_byte <= 8'b0;else if(send_en)r_data_byte <= data_byte;elser_data_byte <= r_data_byte;//10选1多路器模块
reg [3:0] bps_cnt_q;
reg Rx232_Tx;
localparam START_BIT = 1'b0,STOP_BIT = 1'b1;
always@(posedge Clk,negedge Rst_n) if(!Rst_n)Rx232_Tx = 1'b1;else begin case(bps_cnt_q)0 : Rx232_Tx <= 1'b1;1 : Rx232_Tx <= START_BIT;2 : Rx232_Tx <= r_data_byte[0];3 : Rx232_Tx <= r_data_byte[1];4 : Rx232_Tx <= r_data_byte[2];5 : Rx232_Tx <= r_data_byte[3];6 : Rx232_Tx <= r_data_byte[4];7 : Rx232_Tx <= r_data_byte[5];8 : Rx232_Tx <= r_data_byte[6];9 : Rx232_Tx <= r_data_byte[7];10 : Rx232_Tx <= STOP_BIT;default : Rx232_Tx = 1'b1;endcaseend//波特率时钟沿计数输出10选一多路器控制
//10选1多路器控制信号产生
reg bps_clk;
always@(posedge Clk,negedge Rst_n)if(!Rst_n)bps_cnt_q <= 4'd0;else if(bps_clk)bps_cnt_q <= bps_cnt_q + 1'b1;else if(bps_cnt_q == 4'd11)bps_cnt_q <= 4'd0;else bps_cnt_q <= bps_cnt_q;//发送数据完成标志位
reg Tx_Done;
always@(posedge Clk,negedge Rst_n)if(!Rst_n)Tx_Done <= 1'b0;else if(bps_cnt_q == 4'd11)Tx_Done <= 1'b0;else Tx_Done <= 1'b1;//分频计数器输出波特率时钟//分频计数
reg [15:0] bps_DR;
reg [15:0] div_cnt;
reg uart_state ;//en_cnt信号由uart_cnt寄存器寄存
always@(posedge Clk,negedge Rst_n)if(!Rst_n)div_cnt <= 16'd0;else if(uart_state)beginif(div_cnt == bps_DR)div_cnt <= 16'd0;else div_cnt <= div_cnt + 1'b1;endelsediv_cnt <= 16'd0;
//输出波特率时钟信号模块
always@(posedge Clk,negedge Rst_n)if(!Rst_n)bps_clk <= 1'b0;else if(div_cnt == 16'd1)bps_clk <= 1'b1;else bps_clk <= 1'b0;//分频计数器计数使能控制
always@(posedge Clk ,negedge Rst_n)if(!Rst_n)uart_state <= 1'b0;else if(send_en)uart_state <= 1'b1;else if(bps_cnt_q == 4'd11)uart_state <= 1'b0;else uart_state <= uart_state;//不同波特率查找计数值输出
always@(posedge Clk,negedge Rst_n)
if(!Rst_n)
bps_DR <= 16'd5207;
else begincase (baud_set)0:bps_DR <= 16'd10416;1:bps_DR <= 16'd5207;2:bps_DR <= 16'd2603;3:bps_DR <= 16'd1301;4:bps_DR <= 16'd433;default : bps_DR <= 16'd5207;endcaseend
endmodule
FPGA学习之串口发送模块设计与验证相关推荐
- 小梅哥FPGA学习笔记——串口发送模块
串口发送模块 串口发送模块结构框图 顶层模块 串口发送模块结构框图 发送模块具体实现结构框图如图所示,按照图片的内容一步步实现发送模块的设计. DR_LUT查找表的作用是选择不同波特率时,得到对应波特 ...
- UART串口发送模块设计Verilog
1.知识点 1.1 UART通信协议实现 定义 UART (Universal Asynchronous Receiver and Transmitter)即通用异步接收发送器,是一种通用的串行数据总 ...
- FPGA学习之串口发送程序设计(来自小梅哥的教程学习者)
1. UART说明 可参考维基百科的文档:https://zh.wikipedia.org/wiki/UART 2. 实现逻辑图示 3. 程序实现 module UART_TX(rst_n,clk,s ...
- 基于FPGA的UART异步串行通信发送模块设计与实现
欢迎关注微信公众号"FPGA科技室",更多内容请关注 下一篇文请点击下列链接(接收模块设计) [基于FPGA的UART异步串行通信接收模块设计与实现] 本文发送模块: 在电子系统中 ...
- 串口发送模块uart_tx详解
1. 原理介绍 本文是学习小梅哥串口模块教程后的整理总结. 用于数据接收与发送的常用通信协议: UART(通用异步收发传输器).I2C(集成电路总线).USB2.0/3.0(通用串行总线).SPI(串 ...
- UART 异步串行通信发送模块设计与实现
UART 异步串行通信发送模块设计与实现 串口发送模块接口设计 注意:在每一次设计端口时,我们都要求可以随时控制该模块开始和结束,因此在设计每一个模块时,务必要加模块的使能端口(EN)和模块结束端口( ...
- FPGA学习之串口篇
FPGA学习之串口篇 文章目录 FPGA学习之串口篇 前言 二.UART发送代码 三.UART接收代码 三. 总结 前言 UART(Universal Asynchronous Receiver/ ...
- 从零开始研发GPS接收机连载——6、捕获模块设计与验证
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 从零开始研发GPS接收机连载--6.捕获模块设计与验证 前言 数据位宽 捕获算法选择 捕获参数设计 FPGA实现的一些组成模块 上板测 ...
- 基于FPGA的简易DDS信号发生器的设计与验证
基于FPGA的简易DDS信号发生器的设计与验证 一,理论介绍 补充:举例理解 二,代码实现 1,实验目标 2,MATLAB代码 3,verilog代码及实现思路 一,理论介绍 DDS 是直接数字式频率 ...
最新文章
- 利用LVS+Keepalived 实现高性能高可用负载均衡服务器
- python从网上获取数据失败怎么解决_求助:scrapy爬取数据失败,反复调试都不成功...
- Hadoop分布式集群搭建hadoop2.6+Ubuntu16.04
- 各国家分析-奥地利斯洛伐克北欧的社会体系
- 高校胜负欲PK合辑,看看你的母校在拼什么?最服的还是它!
- 通过百度 vs 奇虎,来谈博客搜索
- 萧山职称计算机考试培训,浙江萧山2017年职称计算机考试时间安排
- PL/SQL Developer 9 注册机
- mac python运行按哪个键_#mac python如何使用教程#怎么在mac终端运行python程序
- 飞鸽传书,又见飞鸽传书,
- explode php 正则,php用preg_replace和explode将li列表分割成纯文本数组
- 18. JSON 操作
- java栈链_java实现链栈与队列详解
- Unity游戏基本框架
- C语言/c++:实验报错[Error] ld returned 1 exit status的解决方案
- 白领巧学燕子飞可治颈椎疼
- 一. APP连续闪退修复方案初版
- 怎么样才能进入BAT公司的研发部门
- 用malloc开辟二维数组的三种办法
- Python「剪藏」网页为 PDF
热门文章
- wpsjs excel二次开发大数据写入缓慢解决方案
- 弱网测试在app测试中探索
- 侠客风云传前传专区文章内容导航九阴飞絮篇获得方法介绍
- 网络营销之qq群推广技巧
- 元宇宙仍处于黎明前的暗夜,底层技术基础决定产业未来走向
- touchstart, touchmove, touchend, mousedown, mousemove, mouseup, 手机端和pc端点击及触摸事件
- Java面试复习---MySQL(狂神版)
- ps透明背景下更改内容
- Android studio项目中LitePal配置详细过程与使用
- video标签样式属性设置