三大低速总线之一:UART

news2024/11/13 21:48:59

三大低速总线之一:UART

文章目录

  • 三大低速总线之一:UART
  • 前言
  • 一、UART协议
  • 二、设计
    • 1.整体说明
    • 2.rx波形设计
  • 三 程序实现


前言

三大低速总线:UART、IIC、SPI,其中IIC和SPI是同步通讯,UART是异步的。

优点:
简单:tx和rx都是一根线,使用简单的帧结构传输。 UART通信协议相对简单,易于实现和调试。
适用性广泛:UART被广泛应用于各种设备之间的通信,具有较好的兼容性。
距离:UART通信距离较远,适用于需要长距离传输的场景。
缺点:

速度较低:UART通信速度相对较低,不适用于对速度要求较高的应用。
双工:UART通信是双工的,可以进行低速双工传输数据,进行数据的发送和接收。
不可靠:由于UART是异步通信,可能会受到噪声和干扰的影响,导致数据传输不可靠。

为我们的项目选择合适的协议:

通信速度:SPI 提供高速度,UART 提供高灵活性,I2C 适用于速度要求较低,接线简单的配置。
电路设计:I2C 可实现多个设备的高效空间管理,SPI 可实现大型设计中的性能,而 UART 可实现简单性和多功能性。
距离和通信环境:UART 在长距离上具有稳定性,而 I2C 更适合短距离。
双工要求:SPI 和 UART 提供全双工功能,而 I2C 仅限于半双工。

小结:

  • 使用帧传输,没有时钟的适合长距离,比如UART(如果是差分就更好了),但是帧传输会有冗余信息,传输相对较慢(但这个只针对一般接口,对于高速IO接口的工作频率会很高就不存在这个问题)
  • 带有随路时钟的,因为可能存在各种干扰,对时钟不友好,不适合长距离。
  • 使用哪种协议也要看使用的io资源,spi协议使用的端口就比较多,但是速度快
    应用案例:
    应用案例:
    uart:
    微控制器和外设之间的连接:用于简单直接的数据交换。
    GPS 模块和与计算机的串行接口:用于可靠、低复杂性的通信。
    工业机器:UART 通常用于工业设备中以实现稳定的通信。
    使用 RS 标准(例如 RS-232、RS-485):这些标准支持更长距离的 UART 通信,并提供使用适当的收发器创建多从属网络的可能性,从而增加 UART 应用的灵活性和广度。
    微控制器和外设之间的连接:用于简单直接的数据交换。
    GPS 模块和与计算机的串行接口:用于可靠、低复杂性的通信。
    工业机器:UART 通常用于工业设备中以实现稳定的通信。
    使用 RS 标准(例如 RS-232、RS-485):这些标准支持更长距离的 UART 通信,并提供使用适当的收发器创建多从属网络的可能性,从而增加 UART 应用的灵活性和广度。
    spi:
    SPI 非常适合需要快速可靠的数据传输的情况,例如 TFT 显示器SD 存储卡无线通信模块。然而,在具有许多从站的复杂系统中,其有效性会降低。
    IIC:
    就其应用而言,连接方面,I2C在需要简单经济的通信环境中表现出色。它尤其擅长在小型传感器、LCD 屏幕和 RTC(实时时钟)模块中使用。此外,I2C 由于其在紧凑电路中的效率,在温度控制设备电池管理系统LED 控制器中很有用。但是,在需要快速或长距离数据传输的项目中,最好选择其他协议

一、UART协议

特点:

  • 低速协议
  • rx 和 tx两根线
    帧结构
    在这里插入图片描述

二、设计

1.整体说明

整体框图
在这里插入图片描述
模块说明
在这里插入图片描述

2.rx波形设计

在这里插入图片描述
TX波形设计
在这里插入图片描述

三 程序实现

RX设计思想:根据上面时序图的端口顺序

  1. 同步
  2. 帧起始位判断(边沿检测,并用中间控制信号en代替flag,只检测一次)
  3. 帧比特率计数(其他的都是依靠这个衍生的)
  4. bit标志位
  5. bit_cnt
  6. 每bit的数据接受输出
  7. 稳定数据输出(不输出正在接受变化的数据,而是接受完毕后,在用数据接受完毕的flag来输出最后的数据)
  8. 稳定数据flag输出(需要延迟一拍rx_flag)

需要注意的点有下面几个:

同步的时候需要两拍,但是用这两拍判断帧的沿是不稳定的,需要用第二排和第三拍的输出
数据采样的时候依靠flag,但是flag为高的时候,才的数据是flag变化之前的,即实际上是从1bit开始采样,采样到8的时候,有效数据采集完毕,起始和结束是没有采样的
变化的数据不能传递给下一个模块,要稳定的时候去传递,因此rx_data,只是中间数据,po_data才是最后的数据,同时po_plag也要同步域po_data(相对于rx_flag沿延迟一拍)

`timescale  1ns/1ns

module  uart_rx
#(
    parameter   UART_BPS    =   'd9600,         //串口波特率
    parameter   CLK_FREQ    =   'd50_000_000    //时钟频率
)
(
    input   wire            sys_clk     ,   //系统时钟50MHz
    input   wire            sys_rst_n   ,   //全局复位
    input   wire            rx          ,   //串口接收数据

    output  reg     [7:0]   po_data     ,   //串转并后的8bit数据
    output  reg             po_flag         //串转并后的数据有效标志信号
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//localparam    define
localparam  BAUD_CNT_MAX    =   CLK_FREQ/UART_BPS   ;

//reg   define
reg         rx_reg1     ;
reg         rx_reg2     ;
reg         rx_reg3     ;
reg         start_nedge ;
reg         work_en     ;
reg [12:0]  baud_cnt    ;
reg         bit_flag    ;
reg [3:0]   bit_cnt     ;
reg [7:0]   rx_data     ;
reg         rx_flag     ;

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//插入两级寄存器进行数据同步,用来消除亚稳态
//rx_reg1:第一级寄存器,寄存器空闲状态复位为1
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rx_reg1 <= 1'b1;
    else
        rx_reg1 <= rx;

//rx_reg2:第二级寄存器,寄存器空闲状态复位为1
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rx_reg2 <= 1'b1;
    else
        rx_reg2 <= rx_reg1;

//rx_reg3:第三级寄存器和第二级寄存器共同构成下降沿检测
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rx_reg3 <= 1'b1;
    else
        rx_reg3 <= rx_reg2;

//start_nedge:检测到下降沿时start_nedge产生一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        start_nedge <= 1'b0;
    else    if((~rx_reg2) && (rx_reg3))
        start_nedge <= 1'b1;
    else
        start_nedge <= 1'b0;

//work_en:接收数据工作使能信号
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        work_en <= 1'b0;
    else    if(start_nedge == 1'b1)
        work_en <= 1'b1;
    else    if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
        work_en <= 1'b0;

//baud_cnt:波特率计数器计数,从0计数到BAUD_CNT_MAX - 1
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        baud_cnt <= 13'b0;
    else    if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0))
        baud_cnt <= 13'b0;
    else    if(work_en == 1'b1)
        baud_cnt <= baud_cnt + 1'b1;

//bit_flag:当baud_cnt计数器计数到中间数时采样的数据最稳定,
//此时拉高一个标志信号表示数据可以被取走
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        bit_flag <= 1'b0;
    else    if(baud_cnt == BAUD_CNT_MAX/2 - 1)
        bit_flag <= 1'b1;
    else
        bit_flag <= 1'b0;

//bit_cnt:有效数据个数计数器,当8个有效数据(不含起始位和停止位)
//都接收完成后计数器清零
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        bit_cnt <= 4'b0;
    else    if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
        bit_cnt <= 4'b0;
     else    if(bit_flag ==1'b1)
         bit_cnt <= bit_cnt + 1'b1;

//rx_data:输入数据进行移位
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rx_data <= 8'b0;
    else    if((bit_cnt >= 4'd1)&&(bit_cnt <= 4'd8)&&(bit_flag == 1'b1))
        rx_data <= {rx_reg3, rx_data[7:1]};

//rx_flag:输入数据移位完成时rx_flag拉高一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        rx_flag <= 1'b0;
    else    if((bit_cnt == 4'd8) && (bit_flag == 1'b1))
        rx_flag <= 1'b1;
    else
        rx_flag <= 1'b0;

//po_data:输出完整的8位有效数据
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        po_data <= 8'b0;
    else    if(rx_flag == 1'b1)
        po_data <= rx_data;

//po_flag:输出数据有效标志(比rx_flag延后一个时钟周期,为了和po_data同步)
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        po_flag <= 1'b0;
    else
        po_flag <= rx_flag;

endmodule

**TX设计思想:**根据上面时序图的端口顺序

  1. 判断有效数据输入标志flag
  2. 进行baud率计数器计数
  3. 一般不在边界进行采样或者发送,这个选择计数后的1作为1bit发送的标志信号(在发送的时候也使用这个信号)
  4. 生成bit_cnt
  5. 发送数据帧,以flag信号为标志进行发送(注意:bit_cnt加1是延迟一拍的,发送的时候使用flag发送的,比如采样到flag为1的时候,实际上cnt_bit是0,然后下一排cnt_bit才+1,即实际上当前发送的是第0,即起始位)
`timescale  1ns/1ns

module  uart_tx
#(
    parameter   UART_BPS    =   'd9600,         //串口波特率
    parameter   CLK_FREQ    =   'd50_000_000    //时钟频率
)
(
     input   wire            sys_clk     ,   //系统时钟50MHz
     input   wire            sys_rst_n   ,   //全局复位
     input   wire    [7:0]   pi_data     ,   //模块输入的8bit数据
     input   wire            pi_flag     ,   //并行数据有效标志信号
 
     output  reg             tx              //串转并后的1bit数据
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//localparam    define
localparam  BAUD_CNT_MAX    =   CLK_FREQ/UART_BPS   ;

//reg   define
reg [12:0]  baud_cnt;
reg         bit_flag;
reg [3:0]   bit_cnt ;
reg         work_en ;

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//work_en:接收数据工作使能信号
always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            work_en <= 1'b0;
        else    if(pi_flag == 1'b1)
            work_en <= 1'b1;
        else    if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
            work_en <= 1'b0;

//baud_cnt:波特率计数器计数,从0计数到BAUD_CNT_MAX - 1
always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            baud_cnt <= 13'b0;
        else    if((baud_cnt == BAUD_CNT_MAX - 1) || (work_en == 1'b0))
            baud_cnt <= 13'b0;
        else    if(work_en == 1'b1)
            baud_cnt <= baud_cnt + 1'b1;

//bit_flag:当baud_cnt计数器计数到1时让bit_flag拉高一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            bit_flag <= 1'b0;
        else    if(baud_cnt == 13'd1)
            bit_flag <= 1'b1;
        else
            bit_flag <= 1'b0;

//bit_cnt:数据位数个数计数,10个有效数据(含起始位和停止位)到来后计数器清零
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        bit_cnt <= 4'b0;
    else    if((bit_flag == 1'b1) && (bit_cnt == 4'd9))
        bit_cnt <= 4'b0;
    else    if((bit_flag == 1'b1) && (work_en == 1'b1))
        bit_cnt <= bit_cnt + 1'b1;

//tx:输出数据在满足rs232协议(起始位为0,停止位为1)的情况下一位一位输出
always@(posedge sys_clk or negedge sys_rst_n)
        if(sys_rst_n == 1'b0)
            tx <= 1'b1; //空闲状态时为高电平
        else    if(bit_flag == 1'b1)
            case(bit_cnt)
                0       : tx <= 1'b0;
                1       : tx <= pi_data[0];
                2       : tx <= pi_data[1];
                3       : tx <= pi_data[2];
                4       : tx <= pi_data[3];
                5       : tx <= pi_data[4];
                6       : tx <= pi_data[5];
                7       : tx <= pi_data[6];
                8       : tx <= pi_data[7];
                9       : tx <= 1'b1;
                default : tx <= 1'b1;
            endcase

endmodule

(1)奇偶校验的检错率只有50%,因为只有奇数个数据位发生变化能检测到,如果偶数个数据位发生变化则难以发现;
(2)奇偶校验每传输一个字节都需要加一位校验位,对传输效率影响很大。
(3)奇偶校验只能发现错误,但不能纠正错误。

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

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

相关文章

CSS\JS实现页面背景气泡logo上浮效果

效果图&#xff1a; 源码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Bubble Logo…

Linux_at任务调度

目录 at定时任务 基本介绍 at命令格式 at命令选项 at时间定义 at任务调度实例 at定时任务 基本介绍 at是一次性的定时计划任务&#xff0c;默认atd守护进程每60秒检测作业队列&#xff0c;检查作业运行时间&#xff0c;时间与当前时间匹配则执行。 ps-ef指令检测当前在运…

如何使用ssm实现农家乐信息平台的设计与实现+vue

TOC ssm066农家乐信息平台的设计与实现vue 第1章 绪论 1.1 课题背景 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。所以各…

话费api充值接口对接

全网话费折扣API接口的对接合作流程确实涉及几个关键步骤&#xff0c;确保了应用程序能够顺利集成话费充值服务。以下是该流程的概述以及一些补充的考虑因素&#xff1a; 1.申请API接口&#xff1a; 开发者联系第三方话费充值服务提供商&#xff0c;提交API接口使用申请。获得…

基于FreeRTOS的STM32多功能手表

前言 项目背景 项目演示 使用到的硬件 项目原理图 目前版本实现的功能 设计到的freertos知识 实现思路 代码讲解 初始化GPIO引脚、配置时钟 蜂鸣器初始化以及软件定时器创建 系统默认创建的defaultTaskHandle 创建七个Task&#xff0c;代表七个功能 ShowTimeTask …

代码随想录算法训练营 | 动态规划 part08

121. 买卖股票的最佳时机 121. 买卖股票的最佳时机 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最…

轻松入门大模型:150页精炼指南,简化你的学习之路

如果问个问题&#xff1a;有哪些产品曾经创造了伟大的奇迹&#xff1f;ChatGPT 应该会当之无愧入选。仅仅发布 5 天&#xff0c;ChatGPT 就吸引了 100 万用户——当然&#xff0c;数据不是关键&#xff0c;关键是其背后的技术开启了新的 AI 狂潮&#xff0c;成为技术变革的点火…

ctfshow-web入门-sql注入(web231-web236)update 注入

目录 1、web231 2、web232 3、web233 4、web234 5、web235 6、web236 1、web231 拼接的是 update 语句 //分页查询$sql "update ctfshow_user set pass {$password} where username {$username};"; password 和 username 可控&#xff0c;注入地方还是在 …

laravel发送邮件的使用方法?有哪些技巧?

laravel发送邮件怎么实现&#xff1f;如何使用Laravel发送邮件&#xff1f; Laravel&#xff0c;作为一个流行的PHP框架&#xff0c;提供了强大且灵活的邮件发送功能&#xff0c;使得开发者可以轻松地集成邮件服务到他们的应用中。AokSend将详细介绍如何在Laravel中使用larave…

conda虚拟环境中安装cuda和cudnn

目录 一、cuda安装步骤 1&#xff09;cuda的安装 1、查看conda支持的cuda版本 2、下载cuda并安装cuda 2&#xff09;cudnn的安装 1、查看cuda对应的cudnn版本 2、下载cudnn并安装 二、torch的安装和tensorflow的安装 1&#xff09;安装tensorflow 1、确定安装版本并安…

Java入门:06.Java中的方法--进阶02.03

2 可变参数 方法调用时&#xff0c; 传递的实参数量&#xff0c;是由被调用方法的参数列表数列决定的。 一般来讲&#xff0c;传递的实参数量必须与形参变量数量相同&#xff0c;但是也有一种特殊的参数&#xff0c;允许调用时传递的实参数量是可变&#xff0c;这种参数就称为…

《黑神话·悟空》游戏开发教程来了,全部开源。。。

黑神话悟空游戏&#xff0c;官网说明使用UE5引擎开发. 这篇文章发一个UE5游戏开发的系统教程。 1 开发悟空游戏的UE5 UE5&#xff0c;即 Unreal Engine 5&#xff0c;是由 Epic Games 开发的一款高度先进的游戏引擎。 UE5 是 Unreal Engine 系列的最新版本&#xff0c;它提供…

Qt第十八章 XML和Json格式解析

文章目录 JSON格式解析Json生成案例 XML简介与HTML的区别格式XML解析流的方式DOM XML生成 JSON与XML的区别比较 JSON 格式 JSON是一个标记符的序列。这套标记符包含六个构造字符、字符串、数字和三个字面名 六个构造字符 开始和结束数组&#xff1a;[ ]开始和结束对象&#x…

应用商场的搭建

前言&#xff1a; 使用mysql做主从设置&#xff0c;redis数据库做热门访问数据库。mycat读写分离&#xff0c;zookeeperkafka做数据收集&#xff0c;使用三台虚拟机 关掉防火墙和selinux,做时间同步 192.168.121.11 node1 mycat.example.com 192.168.121.21 node2 …

提高LabVIEW电机控制速度

在LabVIEW中执行绝对位移命令时&#xff0c;其运行时间主要与以下电机参数有关&#xff1a; 电机加速度和减速度&#xff1a; 加速度和减速度参数决定了电机从静止到达到目标速度&#xff0c;以及从高速到停止的时间。这些参数直接影响电机响应的迅速程度。如果加速度和减速度设…

如何使用ssm实现基于bs模式的医院在线挂号预约系统的设计与实现

TOC ssm072基于bs模式的医院在线挂号预约系统的设计与实现jsp 第1章 绪论 1.1 课题背景 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人…

B/S架构和C/S架构的区别

B/S架构、C/S架构区别 1. B/S架构 1.1 什么是B/S架构 B/S架构的全称为Browser/Server&#xff0c;即浏览器/服务器结构。Browser指的是Web浏览器&#xff0c;极少数事务逻辑在前端实现&#xff0c;但主要事务逻辑在服务器端实现。B/S架构的系统无须特别安装&#xff0c;只需要…

实战OpenCV之绘制图形

基础入门 OpenCV除了用于图像显示之外&#xff0c;还提供了一系列接口和工具&#xff0c;以帮助开发者在图像上绘制各种图形。这里的图形包括&#xff1a;直线、矩形、圆形、椭圆、多边形等。另外&#xff0c;OpenCV还支持在图像上添加文字&#xff0c;对多张图像进行叠加操作。…

NACOS 2.4.1如何开启账号密码登录功能

Nacos Server 2.4.0+已正式发布取消管理员用户 nacos 的默认密码支持初始化指定密码。 本章教程,主要介绍如何给nacos加上鉴权,支持通过用户名和密码的方式进行访问nacos页面。 NACOS 2.4.1版本下载地址:https://github.com/alibaba/nacos/releases/tag/2.4.1 1、开启认证功…

驱动:insmod

一、驱动模块的加载 1. 静态 编译进内核2. 动态 编译成模块 如下&#xff1a; 解决方法 结果 led电灯例子 创建一个led.c 修改Makefile、Kconfigmake modulescp drivers/char/led.ko /home/linux/nfs/rootfs开发板 insmod led.ko去 /home/linux/nfs/rootfs 上 写程序.carm-l…