UART自适应任意(典型)波特率原理以及FPGA实现

news2024/10/6 22:29:50

文章目录

  • 前言
  • 一、特征值自适应原理
  • 二、整体结构框图
  • 三、接收模块
  • 四、发送模块
  • 五、编写仿真测试文件以及结果分析
  • 六、上板测试
  • 参考


前言

  在上一篇文章《详解UART通信协议以及FPGA实现》我们实现了UART的通信,我们知道UART通信需要双方约定好波特率,如果想要更换波特率,则需要重新更改代码,重新编译,十分的不方便。所以有没有一种方案就能让通信双方不约定波特率,主机按照主机的波特率发送数据,从机自适应调整自己的波特率跟主机通信。在实际中可以采用特征值匹配的方法实现自适应波特率发生器。

一、特征值自适应原理

示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。
  在双方开始通信前,主机通过串行接口以自己设定的通信波特率向从机发送 1 个字节的波特率校准信号0X55,从机测量每一个高与低电平的宽度,不算起始位和停止位,一共测量8个码元的宽度值W,最后再除以8得到一个码元的宽度bitwidth,再用测量的码元宽度与典型波特率的码元宽度进行比较,误差1%范围内就算匹配成功。

b i t w i d t h = W 8 bitwidth = \frac{W}{8} bitwidth=8W

二、整体结构框图

在这里插入图片描述
  接收模块在rx线拉低时候,开始接收0X55的校准信号,同时计算每个高低电平的宽度,计算完成后,拉高auto_done信号和正确的波特率码元宽度值给tx模块,tx模块根据新的波特率进行发送。

三、接收模块

在这里插入图片描述

  1. 判断模块:由于典型波特率大部分都成倍数关系,因此码元宽度也成倍数关系,防止给计算模块造成误导,因此保险起见,记录上每个高低电平的宽度。否则如果只计算一个码元的宽度,很容易算错,例如以下情况:
    在这里插入图片描述
      设定系统时钟频率50M,如果主机以115200波特率发送(0X66)数据,如果只判断一个码元的长度,那么计算的值将会是868(波特率为57600),不符合设计要求。
      因此我们设定一个bit宽度计数器,每隔一个沿开始,清空此计数器,如果次计数器超过了最大码元宽度值,表示此数据不是特征值0X55,调整失败。否者就一直累加8次,最后判断一个码元宽度是否在典型波特率的1%误差范围内。
典型波特率码元宽度值
波特率码元宽度
1200CLK_FREQ/1200
2400CLK_FREQ/2400
4800CLK_FREQ/4800
9600CLK_FREQ/9600
19200CLK_FREQ/19200
38400CLK_FREQ/38400
57600CLK_FREQ/57600
115200CLK_FREQ/115200
  1. 接收模块:与上文的rx模块基本上一致,只是接受数据前判断auto_done信号,如果信号拉高了,表示波特率更新完成,可以正常接收数据,然后调整自己的波特率计算值,准备接收数据。否者不会接收数据。

四、发送模块

  与上文的rx模块基本上一致,只是接受数据前判断auto_done信号,如果信号拉高了,表示波特率更新完成,可以正常发送数据,然后调整自己的波特率计算值,准备发送数据。否者不会发送数据。代码如下:

`timescale 1ns / 1ps
module uart_tx
(
    input                                               clk ,
    input                                               rst_n   ,
    input           [23:0]                              baud_cnt_max    ,
    input                                               auto_done   ,  
    input           [7:0]                               tx_data ,       //发送数据
    input                                               tx_data_en  ,   //发送数据有效信号
    output  reg                                         tx  
);

    reg             [7:0]                               tx_data_reg ;
    reg             [23:0]                              baud_cnt    ;
    reg             [3:0]                               bit_cnt ;
    reg                                                 bit_flag;    
    reg                                                 tx_flag ;

//将待发送的数据缓存起来
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)
        tx_data_reg <= 'd0;
    else if(tx_data_en == 1'b1)
        tx_data_reg <= tx_data;
    else
        tx_data_reg <= tx_data_reg;
end

//tx_flag拉高时刻
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)
        tx_flag <= 1'b0;
    else if(tx_data_en == 1'b1 && auto_done == 1'b1)
        tx_flag <= 1'b1;
    else if(bit_cnt == 'd9 && bit_flag == 1'b1)
        tx_flag <= 1'b0;
    else
        tx_flag <= tx_flag;
end

//baud_cnt 计数器
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)
        baud_cnt <= 'd0;
    else if(baud_cnt == baud_cnt_max)
        baud_cnt <= 'd0;
    else if(tx_flag == 1'b1)
        baud_cnt <= baud_cnt + 1'b1;
    else
        baud_cnt <= 'd0;
end
//bit_flag拉高时刻
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)
        bit_flag <= 1'b0;
    else if(baud_cnt == 'd1 && auto_done == 1'b1)
        bit_flag <= 1'b1;
    else
        bit_flag <= 1'b0;
end

//bit_cnt 计数器
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)
        bit_cnt <= 'd0;
    else if(bit_cnt == 'd9 && bit_flag == 1'b1)
        bit_cnt <= 'd0;
    else if(bit_flag == 1'b1)
        bit_cnt <= bit_cnt + 1'b1;
    else
        bit_cnt <= bit_cnt;
end

//移位data,由低到高发送至tx
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)
        tx <= 1'b1;
    else if(bit_flag == 1'b1)
        case(bit_cnt)
        0:  tx <= 1'b0;
        1:  tx <= tx_data_reg[0];
        2:  tx <= tx_data_reg[1];
        3:  tx <= tx_data_reg[2];
        4:  tx <= tx_data_reg[3];
        5:  tx <= tx_data_reg[4];
        6:  tx <= tx_data_reg[5];
        7:  tx <= tx_data_reg[6];
        8:  tx <= tx_data_reg[7];
        9:  tx <= 1'b1;
        default:tx <= 1'b1;
        endcase
end

endmodule

五、编写仿真测试文件以及结果分析

  第一次仿真文件测试,使用上一篇文章的测试文件,此时发送的数据中没有特征值0X55,模拟波特率38400发送。

`timescale 1ns / 1ps
module tb_uart_top();

    reg                                                 clk ;
    reg                                                 rst_n   ;
    reg                                                 rx  ;
    wire                                                tx  ;

initial begin
        clk = 0;
        rst_n = 0;
        rx = 1;
        #100
        rst_n = 1;
    end

//调用task函数,连续发送八个数据,不含特征值0X55
    initial begin
        #300
        tx_data(8'h6);
        tx_data(8'h6);
        tx_data(8'h1);
        tx_data(8'hA);
        tx_data(8'hB);
        tx_data(8'hC);
        tx_data(8'hD);
        tx_data(8'hE);
        tx_data(8'hF);
    end

//定义task函数
    task tx_data(
        input   [7:0] tx_data
    );
        integer  i;
        for (i=0; i<10; i=i+1 ) begin
            case(i)
            0:  rx <= 1'b0;
            1:  rx <= tx_data[0];
            2:  rx <= tx_data[1];
            3:  rx <= tx_data[2];
            4:  rx <= tx_data[3];
            5:  rx <= tx_data[4];
            6:  rx <= tx_data[5];
            7:  rx <= tx_data[6];
            8:  rx <= tx_data[7];
            9:  rx <= 1'b1;
            endcase
            #(1302*20);//每发送完一个bit数据后,延迟一个码元的时间
        end
    endtask

always #10 clk  =~clk;
uart_auto_bps u_uart_auto_bps(
    .clk    ( clk    ),
    .rst_n  ( rst_n  ),
    .rx     ( rx     ),
    .tx     ( tx     )
);

endmodule

在这里插入图片描述
  由于没有发现特征值0X55,因此波特率调整失败,auto_done一直拉低,rx_data以及valid信号也都为0;

  我们修改一下仿真文件,在发送数据前,发送特征值0X55。代码如下:

`timescale 1ns / 1ps
module tb_uart_top();

    reg                                                 clk ;
    reg                                                 rst_n   ;
    reg                                                 rx  ;
    wire                                                tx  ;

initial begin
        clk = 0;
        rst_n = 0;
        rx = 1;
        #100
        rst_n = 1;
    end

//调用task函数,连续发送八个数据,第一个含特征值0X55
    initial begin
        #300
        tx_data(8'h55);
        tx_data(8'h6);
        tx_data(8'h6);
        tx_data(8'h1);
        tx_data(8'hA);
        tx_data(8'hB);
        tx_data(8'hC);
        tx_data(8'hD);
        tx_data(8'hE);
        tx_data(8'hF);
    end

//定义task函数
    task tx_data(
        input   [7:0] tx_data
    );
        integer  i;
        for (i=0; i<10; i=i+1 ) begin
            case(i)
            0:  rx <= 1'b0;
            1:  rx <= tx_data[0];
            2:  rx <= tx_data[1];
            3:  rx <= tx_data[2];
            4:  rx <= tx_data[3];
            5:  rx <= tx_data[4];
            6:  rx <= tx_data[5];
            7:  rx <= tx_data[6];
            8:  rx <= tx_data[7];
            9:  rx <= 1'b1;
            endcase
            #(1302*20);//每发送完一个bit数据后,延迟一个码元的时间
        end
    endtask

always #10 clk  =~clk;
uart_auto_bps u_uart_auto_bps(
    .clk    ( clk    ),
    .rst_n  ( rst_n  ),
    .rx     ( rx     ),
    .tx     ( tx     )
);

endmodule

在这里插入图片描述
  因为发送数据前发送了特征值,所以判断模块输出了auto_done以及波特率码元值1302(50000000/1302=)38402波特率,与主机设定的一致。后续接收到了主机后面发送的八个数据06、06、01、0a、0b、0c、0d、0e、0f
发送给tx模块,tx模块也正确的发送了这八个数据。

六、上板测试

  将程序下载到板卡上,用上位机发送数据,用不同波特率发送数据测试一下。
在这里插入图片描述
  从上位机可以看出,以115200波特率,如果没有发送特征值,接受区域没有接收到任何数据。我们发送特征0X55,然后再发送一些数据看看结果。
在这里插入图片描述
  在波特率115200情况下发送特征值0x55后,发送一系列数据都收到了。表示波特率调整完成。我们修改一下波特率,再做同样的实验看看结果怎样。
在这里插入图片描述
  我们将波特率调整到9600,发送一些列数据(不包括特征值),接受区域依然空白。我们把特征值加上去后,再看看结果。

在这里插入图片描述

结果依然正确,换成其它典型波特率结果一致。

参考

《基于FPGA的UART自适应波特率发生器的实现》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1601291.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Hadoop大数据处理技术-配置连接篇

​2024/4/17 Hadoop学习前的准备 3&#xff09;连接虚拟机 上一节配置完成了基础的虚拟机配置及网络配置 下面我们开始建立连接 我们为什么要与虚拟机建立链接呢&#xff1f; 连接虚拟机就好像跟亲友联系一样 总得找个便捷又好用的工具才行 Secure CRT就像是一把能打开通向…

材料物理 笔记-6

原内容请参考哈尔滨工业大学何飞教授&#xff1a;https://www.bilibili.com/video/BV18b4y1Y7wd/?p12&spm_id_frompageDriver&vd_source61654d4a6e8d7941436149dd99026962 或《材料物理性能及其在材料研究中的应用》&#xff08;哈尔滨工业大学出版社&#xff09; 文…

手写spring IOC底层源码来模拟spring如何利用多级缓存解决循环依赖的问题

在文章开始之前&#xff0c;先来看一张spring IOC加载过程的脑图吧 Spring IOC的加载过程 首先,当我们去new了一个applicationContext,它底层呢就会把我们配置的bean进行扫描,然后创建成一个一个的beanDefinition放在我们的beanDefinitionMap中,此时就有了一切创造bean的原料信…

k-means聚类算法的MATLAB实现及可视化

K-means算法是一种无监督学习算法&#xff0c;主要用于数据聚类。其工作原理基于迭代优化&#xff0c;将数据点划分为K个集群&#xff0c;使得每个数据点都属于最近的集群&#xff0c;并且每个集群的中心&#xff08;质心&#xff09;是所有属于该集群的数据点的平均值。以下是…

「GO基础」文件名规范、关键字与标识符

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

【数据结构与算法】最大公约数与最小公倍数

最大公因数&#xff08;英语&#xff1a;highest common factor&#xff0c;hcf&#xff09;也称最大公约数&#xff08;英语&#xff1a;greatest common divisor&#xff0c;gcd&#xff09;是数学词汇&#xff0c;指能够整除多个非零整数的最大正整数。例如8和12的最大公因数…

社交创新的标杆:解读Facebook的社交模式

引言 在当今数字化时代&#xff0c;社交媒体已成为人们日常生活和沟通的重要工具。作为全球最大的社交媒体平台&#xff0c;Facebook不仅改变了我们的社交模式&#xff0c;而且对全球的社交文化、商业活动和公共事务产生了深远的影响。本文将深入探讨Facebook的社交模式&#…

关于Qt主窗口的菜单部件

前言 在介绍主窗口的两大部件之前&#xff0c;我们要先知道关于主窗口的一些知识。 主窗口 一个主窗口可以没有菜单条、工具条、状态条&#xff0c;但必须设置中心部件。在 Q 生成的 C头文件 ui_mainwindow.h 代码中,我们可以看到以下代码: centralWidget new Qwidget(MainWi…

Three.js加载glb / gltf模型,Vue加载glb / gltf模型(如何在vue中使用three.js,vue使用threejs加载glb模型)

简介&#xff1a;Three.js 是一个用于在 Web 上创建和显示 3D 图形的 JavaScript 库。它提供了丰富的功能和灵活的 API&#xff0c;使开发者可以轻松地在网页中创建各种 3D 场景、模型和动画效果。可以用来展示产品模型、建立交互式场景、游戏开发、数据可视化、教育和培训等等…

BetterDisplay Pro for Mac 显示器校准和优化软件

BetterDisplay Pro for Mac是一款适用于Mac电脑的显示器校准和优化软件。它可以帮助用户校准显示器的颜色、亮度、对比度和伽马值等参数&#xff0c;使得显示器更加准确和清晰&#xff0c;提高用户的工作效率。 BetterDisplay Pro for Mac v2.0.11激活版下载 这款软件具有直观的…

RS232、RS485、RS422、TTL、CAN各自的区别

目录 一&#xff1a;工业串口通信标准RS232、RS485、RS422的区别 第一个区别、硬件管脚接口定义不同 第二个区别、工作方式不同 第三个区别、通信方式不同 第四个区别&#xff0c;逻辑特性不同 第五个区别、抗干扰性、传输距离和传输速率也不同 二&#xff1a;RS232、RS…

记录Python链接mysql数据的增删改查方法

一、添加方法 db pymysql.connect(hostlocalhost,userroot,password123456,dbpython) cursor db.cursor() sql """insert into EMPLOYEEVALUES(3,张,天爱,35,F,8000) """ try:cursor.execute(sql)db.commit() #提交后&#xff0c;数据才会变 …

上班最大的意义,不是那点工资

最近在网上看到这样一段话&#xff1a;“上班最大的意义&#xff0c;不是那点工资&#xff0c;而是工作能让你有规律的生活&#xff0c;有见人的机会&#xff0c;有稳定的社交圈子&#xff0c;还有来自客户&#xff0c;同事&#xff0c;或者或少的压力&#xff0c;一可以锻炼心…

数字革命的先锋:Web3对社会的影响

引言 在信息技术飞速发展的当下&#xff0c;Web3作为一个新兴的互联网模式&#xff0c;正在逐渐改变我们的生活方式、商业模式和社会结构。本文将深入探讨Web3的核心特点、它在各个领域中的应用以及对社会产生的深远影响。 1. Web3的核心特点 1.1 去中心化 Web3强调去中心化…

使用阿里云试用Elasticsearch学习:使用内置模型 lang_ident_model_1 创建管道并使用

文档&#xff1a;https://www.elastic.co/guide/en/machine-learning/current/ml-nlp-deploy-model.html 部署刚刚下载好的内置模型 部署内存不够用 还得花钱&#xff0c;拉几把倒吧。就用自带的吧。 测试模型 POST _ml/trained_models/lang_ident_model_1/_infer {"doc…

大数据快速搭建环境 CDH QuickStart VM虚拟机版本安装

虚拟机镜像安装 下载 https://downloads.cloudera.com/demo_vm/vmware/cloudera-quickstart-vm-5.8.0-0-vmware.zip https://downloads.cloudera.com/demo_vm/vmware/cloudera-quickstart-vm-5.12.0-0-vmware.zip https://downloads.cloudera.com/demo_vm/vmware/cloudera-…

.net core webapi 发布后出现访问不了swagger让人抓狂的原因

.net core webapi 发布出现访问不了swagger让人抓狂 小编最近发布一个测试的webapi,想要给三方测试使用&#xff0c;结果发布后访问不了swagger&#xff0c;找了半天原因急死了。 第一&#xff0c;查看开放端口&#xff0c;都开放了第二&#xff0c;本次编译器执行&#xff0…

FAGLL03H 新增自定义字段

1、SGLPOS_N_GL_CT、SGLPOS_N_CT两个结构新增自定义字段 2、执行t-code:HDBVIEWS 3、实施增强 FAGL_LIB 4、使用select data方法 5、代码示例: method IF_FAGL_LIB~SELECT_DATA.FIELD-SYMBOLS: <fs> TYPE any.FIELD-SYMBOLS <ls_data> TYPE any.F…

Since Maven 3.8.1 http repositories are blocked.

编译maven 项目时候报错提示下面信息&#xff1a; Since Maven 3.8.1 http repositories are blocked.Possible solutions: - Check that Maven settings.xml does not contain http repositories - Check that Maven pom files do not contain http repository http://XXXXXX:…

Proxyman Premium for Mac v5.1.1激活版:卓越的网络调试与分析工具

Proxyman Premium for Mac是一款功能强大的网络调试与分析工具&#xff0c;专为开发人员和测试人员精心打造。它集多种功能于一身&#xff0c;为用户提供了全面、高效的网络开发体验。 Proxyman Premium for Mac v5.1.1激活版下载 作为一款跨平台代理工具&#xff0c;Proxyman …