目录

方法一

方法二

波特率参数化产生方法


上篇博文介绍了:RS232接口是如何工作的?

讲到了该接口的传输速率,也就是波特率可以为:

  • 1200 bauds.
  • 9600 bauds.
  • 38400 bauds.
  • 115200 bauds (usually the fastest you can go).

在这里,我们希望以最大速度使用串行链路,即115200波特(较慢的速度也很容易生成)。 FPGA通常以MHz速度运行,远高于115200Hz(按照今天的标准,RS-232相当慢)。 我们需要找到一种方法来生成(从FPGA时钟)一个“tick”,尽可能接近每秒115200次。

产生波特率的方法可以分为两种,原理近似:

方法一


传统上,RS-232芯片使用1.8432MHz时钟,因为这样可以非常容易地生成标准波特频率...... 1.8432MHz除以16得到115200Hz。

可以以下面的方法来分频得到分频时钟(波特率时钟):

// let's assume the FPGA clock signal runs at 1.8432MHz
// we create a 4-bit counter
reg [3:0] BaudDivCnt;
always @(posedge clk) BaudDivCnt <= BaudDivCnt + 1; // count forever from 0 to 15// and a tick signal that is asserted once every 16 clocks (so 115200 times a second)
wire BaudTick = (BaudDivCnt==15);

那很简单。 但是,如果不是1.8432MHz,你有2MHz的时钟怎么办? 要从2MHz时钟产生115200Hz,我们仍可以采用分频的方法,但是这里的分频会产生误差,尽管如此,这是FPGA所容许的。

2000_000/115200=17.361111111111111111111111111111

可以采用17分频的方法来产生这样的波特率。

采用Verilog描述:

module baud_gen_n17d(input clk,input enable,output reg BaudTick = 0);reg [4:0] baud_count = 0;/*   always@(posedge clk) beginif(enable && baud_count < 16) beginbaud_count <= baud_count + 1;BaudTick <= 0;endelse if(enable && baud_count == 16) beginbaud_count <= 0;BaudTick <= 1;endelse ;end */always@(posedge clk) beginif(enable) beginif(baud_count < 16) beginbaud_count <= baud_count + 1;BaudTick <= 0;endelse if(baud_count == 16) beginbaud_count <= 0;BaudTick <= 1;endelse ;endelse ;endendmodule

Testbench文件为:

module baud_gen_f17_tb();reg enable;reg clk;wire Baud_Tick;initial beginclk = 0;forever # 250 clk = ~clk;endinitial enable = 1;baud_gen_n17d u0(.clk(clk),.enable(1'b1),.BaudTick(Baud_Tick));endmodule

仿真波形为:

从仿真波形中可以看出,传输一位数据需要8.75us,那么传输10bit数据需要87.5us;

如果波特率为标准的115200的话,那么传输1bit数据需要8.68us,那么传输10bit数据需要86.8us;

二者误差相差0.7us;

如果采用标准波特率的话,一位停止位就占了8.68us,这点误差算的了什么呢?况且RS232接收数据采用过采样,所以,不必担心采用分频时钟生成的波特率不准确的问题。

下面是请教前辈的聊天记录:

有这样的前辈,耐心的教我这个菜鸟,还真是很感动呢!


方法二

前面方法一是一种常规意义上的分频而已,没有那么多的花里胡哨,也很好理解,但是在我们的主要参考链接中给出了另外一种方法,链接:Baud generator

还以2MHz的系统时钟为例,要产生115200的波特率时钟。

前面我们算过二者的比率为:2000000/115200=17.361111111111111111111111111111;

文中的思路是:

期望2000000是2的幂。 显然2000000不是。 所以我们改变比率...而不是“2000000/115200”,让我们使用“1024/59”= 17.356。 这非常接近我们的理想比率,并且实现了高效的FPGA实现:我们使用增量为59的10位累加器,每次累加器溢出时都会标记一个Tick。

这是个什么原理呢?

通过比率相似,我们可以取一个计数器,位数恰好能计数到1024,那么选一个10位的计数器(实际上是11位,后面解释),累加器每次累加59,会发现计数到第17个59时,累加器溢出,溢出一个时钟,这样我们可以取溢出位为Tick,这样就实现了计数17,Tick就有效一次,和17分频原理一致呀。

这种方法的要点在于,我们需要找到一个2的幂次的分子,来凑出相似比率。

当然,如果你忘记了这种方法,还可以直接用方法一,也即是直接分频的方法。

下面对这种方法进行仿真:


以FPGA系统时钟为2MHz为例,

Verilog描述代码:

module BaudGen(input clk,input enable,output BaudTick);// let's assume the FPGA clock signal runs at 2.0000MHz// we use a 10-bit accumulator plus an extra bit for the accumulator carry-outreg [10:0] acc = 0;   // 11 bits total!// add 59 to the accumulator at each clockalways @(posedge clk) beginif(enable)acc <= acc[9:0] + 59; // use 10 bits from the previous accumulator result, but save the full 11 bits resultelse    acc <= 59;endassign BaudTick = acc[10]; // so that the 11th bit is the accumulator carry-outendmodule

testbench文件:

module BaudGen_tb();reg clk;wire BaudTick;initial beginclk = 0;forever #250 clk = ~clk;endBaudGen u_BaudGen(.clk(clk),.enable(1'b1),.BaudTick(BaudTick));endmodule

仿真波形为:

看细节:

计数值超过1024后,最高位变为1,同时BaudTick变为高电平,持续时间为一个时钟周期。

通过下图计算下传输1bit数据需要多久:

经过简单计算,需要8.5us传输1bit,那么1s中传输多少位呢?1000000/8.5=117647;

然后我们算算误差多大:(117647 - 115200)/115200 = 0.02;可见误差很小。

前面方法一也说了,这种误差我们完全可以接受。


波特率参数化产生方法

由于前面已经铺垫过了,所以这种参数化完全是套用下参数而已,直接引用链接:https://www.fpga4fun.com/SerialInterface2.html

参数化FPGA波特率发生器

之前的设计使用的是10位累加器,但随着时钟频率的增加,需要更多的位。

这是一个25MHz时钟和16位累加器的设计。 设计参数化,易于定制。

parameter ClkFrequency = 25000000; // 25MHz
parameter Baud = 115200;
parameter BaudGeneratorAccWidth = 16;
parameter BaudGeneratorInc = (Baud<<BaudGeneratorAccWidth)/ClkFrequency;

reg [BaudGeneratorAccWidth:0] BaudGeneratorAcc;
always @(posedge clk)
  BaudGeneratorAcc <= BaudGeneratorAcc[BaudGeneratorAccWidth-1:0] + BaudGeneratorInc;

wire BaudTick = BaudGeneratorAcc[BaudGeneratorAccWidth];

最后一个实现问题:“BaudGeneratorInc”计算错误,因为Verilog使用32位中间结果,计算超出了这个。 更改以下行以获得解决方法。

parameter BaudGeneratorInc = ((Baud<<(BaudGeneratorAccWidth-4))+(ClkFrequency>>5))/(ClkFrequency>>4);

此行还具有对结果进行舍入而不是截断的附加优势。

现在我们拥有足够精确的波特率发生器,我们可以继续使用RS-232发送器和接收器模块。


最后一个参数化还是会让人产生疑惑的,算了还是直接用自己的方法吧,花里胡哨的:

module BaudGen_param(input clk,input enable,output BaudTick);parameter ClkFrequency = 25000000; // 25MHzparameter Baud = 115200;parameter Ratio = ClkFrequency/Baud;parameter BaudGeneratorAccWidth = 16;parameter BaudGeneratorInc = (1<<BaudGeneratorAccWidth)/Ratio;reg [BaudGeneratorAccWidth:0] BaudGeneratorAcc = 0;always @(posedge clk)if(enable)BaudGeneratorAcc <= BaudGeneratorAcc[BaudGeneratorAccWidth-1:0] + BaudGeneratorInc;elseBaudGeneratorAcc <= BaudGeneratorInc;assign BaudTick = BaudGeneratorAcc[BaudGeneratorAccWidth];endmodule

测试文件为:

module BaudGen_Param_tb;reg clk;wire BaudTick;initial beginclk = 0;forever#20 clk = ~clk;endBaudGen_param u0(.clk(clk),.enable(1'b1),.BaudTick(BaudTick));endmodule

行为仿真波形图:

可见,波特周期是8.68us,与115200的波特率对应的波特周期差不多。

RS232 波特率时钟产生方法?相关推荐

  1. FPGA 串口波特率时钟的概念

    一 : 串口波特率等概念,115200等到底什么意思 1:比特率:9600bps .115200bps 就是每秒中传输9600bit.115200bit,也就是相当于每一秒中划分成了9600等份. 9 ...

  2. FPGA提升串口波特率、QT增加波特率选项的方法

    FPGA提升串口波特率.QT提高波特率支持的方法 ​ 本文主要讲解FPGA计算串口波特率的方法以及QT5对230400以上波特率的支持方法. 1.FPGA提升串口波特率 1.1确定FPGA串口的模块的 ...

  3. Xilinx FPGA单端时钟设计方法

    1.1 Xilinx FPGA单端时钟设计方法 1.1.1 本节目录 1)本节目录: 2)本节引言: 3)FPGA简介: 4)Xilinx FPGA单端时钟设计方法: 5)结束语. 1.1.2 本节引 ...

  4. 亚稳态原因以及跨时钟处理方法

    亚稳态原因以及跨时钟处理方法 1.亚稳态原因:不满足建立时间与保持时间要求 (1)结论:数据早来晚走可以避免亚稳态,减少时序违例. (2)建立时间与保持时间概念: 建立时间Tsu:时钟触发事件来临之前 ...

  5. 华为SDH传输设备时钟配置方法

    华为SDH传输设备时钟配置方法 时钟ID设置原则: 1:所有外接的BITS都分配时钟ID 2:所有接入外部BITS节点,其内部时钟源都分配时钟ID 3:所有由链或环网进入另一环网的节点内部时钟源都分配 ...

  6. 跨时钟域方法(同步器、异步FIFO、边沿检测器、脉冲同步器、同步FIFO)

    目录 1.跨时钟域方法的原因 2.跨时钟处理的两种思路 3.跨时钟域分类--单比特信号跨时钟 3.1.1慢时钟---快时钟.(满足三边沿准则,有效事件可以被安全采样) 3.1.2慢时钟---快时钟.( ...

  7. STM32时钟配置方法详解

    一.在STM32中,有五个时钟源,为HSI.HSE.LSI.LSE.PLL. ①HSI是高速内部时钟,RC振荡器,频率为8MHz. ②HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率 ...

  8. STM32F7配置时钟的方法(keil)

    关于时钟的基本知识,可参考此大佬的博客: https://blog.csdn.net/as480133937/article/details/98845509 首先是选择系统时钟的来源,可以是HSI, ...

  9. 3.STM32F429时钟系统配置方法

    目录 1.时钟系统 1.1.时钟源 1.2.系统时钟SYSCLK计算 1.3.AHB和APB总线时钟 1.4.其它时钟 2.时钟配置函数 2.1.SystemInit函数 2.2.Stm32_Cloc ...

最新文章

  1. 计算机视觉怎样实现自我超越?更大规模更精准的数据
  2. easyui 传递参数报错(错误:uncaught SyntaxError: Unexpected identifier)
  3. GPU Gems2 - 12 基于贴面的纹理映射(Tile-Based Texture Mapping)
  4. .NET-记一次架构优化实战与方案-梳理篇
  5. [css] 请问class与[class=xxx]的区别是什么?两者是否等价?
  6. 全量增量数据同步方法(Hive date_add date_sub)
  7. winxp如何打开计算机的端口,xp系统怎么打开445端口呢?开启445端口的教程
  8. 【Unity】U3D TD游戏制作实例(五)防御塔设计:对象排序、锁定敌人、攻击敌人、防御塔特色功能实现
  9. 京东金融支持的银行卡只有几张
  10. win10内存占用率过高怎么办_win10系统终极优化
  11. 热辊的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  12. Android图片编解码实现方案(Skia)
  13. 【MOOC】华中科技大学计算机组成原理慕课答案-第六章-中央处理器(一)
  14. (二)回顾硅谷:硅谷历史
  15. PostgreSQL集群方案-citus
  16. 如何在苹果手机上安装自制的AD证书
  17. SpringSecurity详细介绍RememberMe功能
  18. Nuxt3 全栈 项目服务器部署 全网最全最细保姆级教程 解决各种小坑 时光小灶
  19. 我就纳闷了。。。红黑联盟。。的水印真的好明显,欺负我大csdn
  20. Leetcode刷题100天—706. 设计哈希映射(哈希表)—day74

热门文章

  1. 黑马程序员-Java基础知识预备之Java流程控制与数组
  2. C#对图片文件的压缩、裁剪操作初探
  3. 电脑粉碎文件 c语言,文件操作(二):文件粉碎机
  4. xmpp协议抓包_开源网络抓包与分析框架学习-Packetbeat篇
  5. 日期如何比较 java_如何比较Java中的日期?
  6. python找出值为nan_Python Numpy:找到list中的np.nan值方法
  7. BufferedInputStream与BufferedOutputStream用法简介
  8. 如何制作linux文件系统,linux文件系统制作(一)
  9. Java Excel表格数据的导入导出
  10. 测试半桥电路 TPS28225,NCP3420驱动MOS半桥