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学习之串口发送模块设计与验证相关推荐

  1. 小梅哥FPGA学习笔记——串口发送模块

    串口发送模块 串口发送模块结构框图 顶层模块 串口发送模块结构框图 发送模块具体实现结构框图如图所示,按照图片的内容一步步实现发送模块的设计. DR_LUT查找表的作用是选择不同波特率时,得到对应波特 ...

  2. UART串口发送模块设计Verilog

    1.知识点 1.1 UART通信协议实现 定义 UART (Universal Asynchronous Receiver and Transmitter)即通用异步接收发送器,是一种通用的串行数据总 ...

  3. FPGA学习之串口发送程序设计(来自小梅哥的教程学习者)

    1. UART说明 可参考维基百科的文档:https://zh.wikipedia.org/wiki/UART 2. 实现逻辑图示 3. 程序实现 module UART_TX(rst_n,clk,s ...

  4. 基于FPGA的UART异步串行通信发送模块设计与实现

    欢迎关注微信公众号"FPGA科技室",更多内容请关注 下一篇文请点击下列链接(接收模块设计) [基于FPGA的UART异步串行通信接收模块设计与实现] 本文发送模块: 在电子系统中 ...

  5. 串口发送模块uart_tx详解

    1. 原理介绍 本文是学习小梅哥串口模块教程后的整理总结. 用于数据接收与发送的常用通信协议: UART(通用异步收发传输器).I2C(集成电路总线).USB2.0/3.0(通用串行总线).SPI(串 ...

  6. UART 异步串行通信发送模块设计与实现

    UART 异步串行通信发送模块设计与实现 串口发送模块接口设计 注意:在每一次设计端口时,我们都要求可以随时控制该模块开始和结束,因此在设计每一个模块时,务必要加模块的使能端口(EN)和模块结束端口( ...

  7. FPGA学习之串口篇

    FPGA学习之串口篇 文章目录 FPGA学习之串口篇 前言 二.UART发送代码 三.UART接收代码 三. 总结 前言   UART(Universal Asynchronous Receiver/ ...

  8. 从零开始研发GPS接收机连载——6、捕获模块设计与验证

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 从零开始研发GPS接收机连载--6.捕获模块设计与验证 前言 数据位宽 捕获算法选择 捕获参数设计 FPGA实现的一些组成模块 上板测 ...

  9. 基于FPGA的简易DDS信号发生器的设计与验证

    基于FPGA的简易DDS信号发生器的设计与验证 一,理论介绍 补充:举例理解 二,代码实现 1,实验目标 2,MATLAB代码 3,verilog代码及实现思路 一,理论介绍 DDS 是直接数字式频率 ...

最新文章

  1. 利用LVS+Keepalived 实现高性能高可用负载均衡服务器
  2. python从网上获取数据失败怎么解决_求助:scrapy爬取数据失败,反复调试都不成功...
  3. Hadoop分布式集群搭建hadoop2.6+Ubuntu16.04
  4. 各国家分析-奥地利斯洛伐克北欧的社会体系
  5. 高校胜负欲PK合辑,看看你的母校在拼什么?最服的还是它!
  6. 通过百度 vs 奇虎,来谈博客搜索
  7. 萧山职称计算机考试培训,浙江萧山2017年职称计算机考试时间安排
  8. PL/SQL Developer 9 注册机
  9. mac python运行按哪个键_#mac python如何使用教程#怎么在mac终端运行python程序
  10. 飞鸽传书,又见飞鸽传书,
  11. explode php 正则,php用preg_replace和explode将li列表分割成纯文本数组
  12. 18. JSON 操作
  13. java栈链_java实现链栈与队列详解
  14. Unity游戏基本框架
  15. C语言/c++:实验报错[Error] ld returned 1 exit status的解决方案
  16. 白领巧学燕子飞可治颈椎疼
  17. 一. APP连续闪退修复方案初版
  18. 怎么样才能进入BAT公司的研发部门
  19. 用malloc开辟二维数组的三种办法
  20. Python「剪藏」网页为 PDF

热门文章

  1. wpsjs excel二次开发大数据写入缓慢解决方案
  2. 弱网测试在app测试中探索
  3. 侠客风云传前传专区文章内容导航九阴飞絮篇获得方法介绍
  4. 网络营销之qq群推广技巧
  5. 元宇宙仍处于黎明前的暗夜,底层技术基础决定产业未来走向
  6. touchstart, touchmove, touchend, mousedown, mousemove, mouseup, 手机端和pc端点击及触摸事件
  7. Java面试复习---MySQL(狂神版)
  8. ps透明背景下更改内容
  9. Android studio项目中LitePal配置详细过程与使用
  10. video标签样式属性设置