串口通信原理

article/2025/10/6 21:19:12

并行通信是指数据的各个位用多条数据线同时进行传输 

优点:传输速度快

缺点:占用引脚资源多

 串行通信是将数据分成一位一位的形式在一条传输线上逐个传输

 优点:通信线路简单、占用引脚资源少

缺点:传输速度慢

同步通信:带时钟同步信号的数据传输;发送方和接收方在同一时钟的控制下,同步传输数据。

异步通信:不带时钟同步信号的数据传输。发送方与接收方使用各自的时钟控制数据的发送和接收过程。

串行通信的传输方向:

单工   :数据只能沿一个方向传输

半双工:数据传输可以沿两个方向,但需要分时进行

全双工:数据可以同时进行双向传输

下面是常见的串行通信接口

 UART (universal asynchronous receiver-transmitter) 是一种采用异步串行通信方式的通用异步收发传输器。它在发送数据时将并行数据转换成串行数据来传输,在接收数据时将接收到的串行数据转换成并行数据。协议层:   通信协议(包括数据格式、传输速率等) 物理层:接口类型、电平标准等。

 UART串口通信需要两根信号线来实现,一根用于串口发送,另外一根负责串口接收。

串口通信的速率用波特率表示,它表示每秒传输二进制数据的位数,单位是bps(位/秒) 常用的波特率有9600、19200、38400、57600以及115200等。

针对异步串行通信的接口标准有RS23、RS422、RS485等

1.通信实验:开发板与上位机通过串口通信,完成数据环回实验

2.程序设计:

首先是分频时钟,用pll去设计ip核,输入时钟是50MHZ,输出一个时钟为1MHz,用于仿真。

具体ip核设计可以去看前面一篇文章:pll锁相环(可以根据系统时钟进行倍频、分频、相位偏移等等,而普通的计数器只能分频)_小泡芙❤的博客-CSDN博客

接收模块:

 

module uart_recv(input			  sys_clk,                  //系统时钟input             sys_rst_n,                //系统复位,低电平有效input             uart_rxd,                 //UART接收端口output  reg       uart_done,                //接收一帧数据完成标志信号output  reg [7:0] uart_data                 //接收的数据);//parameter define
parameter  CLK_FREQ = 50000000;                 //系统时钟频率
parameter  UART_BPS = 9600;                     //串口波特率
localparam BPS_CNT  = CLK_FREQ/UART_BPS;        //为得到指定波特率,//需要对系统时钟计数BPS_CNT次
//reg define
reg        uart_rxd_d0;
reg        uart_rxd_d1;
reg [15:0] clk_cnt;                             //系统时钟计数器
reg [ 3:0] rx_cnt;                              //接收数据计数器
reg        rx_flag;                             //接收过程标志信号
reg [ 7:0] rxdata;                              //接收数据寄存器//wire define
wire       start_flag;//*****************************************************
//**                    main code
//*****************************************************
//捕获接收端口下降沿(起始位),得到一个时钟周期的脉冲信号
assign  start_flag = uart_rxd_d1 & (~uart_rxd_d0);    //对UART接收端口的数据延迟两个时钟周期
always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) begin uart_rxd_d0 <= 1'b0;uart_rxd_d1 <= 1'b0;          endelse beginuart_rxd_d0  <= uart_rxd;                   uart_rxd_d1  <= uart_rxd_d0;end   
end//当脉冲信号start_flag到达时,进入接收过程           
always @(posedge sys_clk or negedge sys_rst_n) begin         if (!sys_rst_n)                                  rx_flag <= 1'b0;else beginif(start_flag)                          //检测到起始位rx_flag <= 1'b1;                    //进入接收过程,标志位rx_flag拉高else if((rx_cnt == 4'd9)&&(clk_cnt == BPS_CNT/2))rx_flag <= 1'b0;                    //计数到停止位中间时,停止接收过程elserx_flag <= rx_flag;end
end//进入接收过程后,启动系统时钟计数器与接收数据计数器
always @(posedge sys_clk or negedge sys_rst_n) begin         if (!sys_rst_n) begin                             clk_cnt <= 16'd0;                                  rx_cnt  <= 4'd0;end                                                      else if ( rx_flag ) begin                   //处于接收过程if (clk_cnt < BPS_CNT - 1) beginclk_cnt <= clk_cnt + 1'b1;rx_cnt  <= rx_cnt;endelse beginclk_cnt <= 16'd0;               //对系统时钟计数达一个波特率周期后清零rx_cnt  <= rx_cnt + 1'b1;       //此时接收数据计数器加1endendelse begin                              //接收过程结束,计数器清零clk_cnt <= 16'd0;rx_cnt  <= 4'd0;end
end//根据接收数据计数器来寄存uart接收端口数据
always @(posedge sys_clk or negedge sys_rst_n) begin if ( !sys_rst_n)  rxdata <= 8'd0;                                     else if(rx_flag)                            //系统处于接收过程if (clk_cnt == BPS_CNT/2) begin         //判断系统时钟计数器计数到数据位中间case ( rx_cnt )4'd1 : rxdata[0] <= uart_rxd_d1;   //寄存数据位最低位4'd2 : rxdata[1] <= uart_rxd_d1;4'd3 : rxdata[2] <= uart_rxd_d1;4'd4 : rxdata[3] <= uart_rxd_d1;4'd5 : rxdata[4] <= uart_rxd_d1;4'd6 : rxdata[5] <= uart_rxd_d1;4'd7 : rxdata[6] <= uart_rxd_d1;4'd8 : rxdata[7] <= uart_rxd_d1;   //寄存数据位最高位default:;                                    endcaseendelse rxdata <= rxdata;elserxdata <= 8'd0;
end//数据接收完毕后给出标志信号并寄存输出接收到的数据
always @(posedge sys_clk or negedge sys_rst_n) begin        if (!sys_rst_n) beginuart_data <= 8'd0;                               uart_done <= 1'b0;endelse if(rx_cnt == 4'd9) begin               //接收数据计数器计数到停止位时           uart_data <= rxdata;                    //寄存输出接收到的数据uart_done <= 1'b1;                      //并将接收完成标志位拉高endelse beginuart_data <= 8'd0;                                   uart_done <= 1'b0; end    
endendmodule	

发送模块

module uart_send(input	      sys_clk,                  //系统时钟input         sys_rst_n,                //系统复位,低电平有效input         uart_en,                  //发送使能信号input  [7:0]  uart_din,                 //待发送数据output  reg   uart_txd                  //UART发送端口);//parameter define
parameter  CLK_FREQ = 50000000;             //系统时钟频率
parameter  UART_BPS = 9600;                 //串口波特率
localparam BPS_CNT  = CLK_FREQ/UART_BPS;    //为得到指定波特率,对系统时钟计数BPS_CNT次//reg define
reg        uart_en_d0; 
reg        uart_en_d1;  
reg [15:0] clk_cnt;                         //系统时钟计数器
reg [ 3:0] tx_cnt;                          //发送数据计数器
reg        tx_flag;                         //发送过程标志信号
reg [ 7:0] tx_data;                         //寄存发送数据//wire define
wire       en_flag;//*****************************************************
//**                    main code
//*****************************************************
//捕获uart_en上升沿,得到一个时钟周期的脉冲信号
assign en_flag = (~uart_en_d1) & uart_en_d0;//对发送使能信号uart_en延迟两个时钟周期
always @(posedge sys_clk or negedge sys_rst_n) begin         if (!sys_rst_n) beginuart_en_d0 <= 1'b0;                                  uart_en_d1 <= 1'b0;end                                                      else begin                                               uart_en_d0 <= uart_en;                               uart_en_d1 <= uart_en_d0;                            end
end//当脉冲信号en_flag到达时,寄存待发送的数据,并进入发送过程          
always @(posedge sys_clk or negedge sys_rst_n) begin         if (!sys_rst_n) begin                                  tx_flag <= 1'b0;tx_data <= 8'd0;end else if (en_flag) begin                 //检测到发送使能上升沿                      tx_flag <= 1'b1;                //进入发送过程,标志位tx_flag拉高tx_data <= uart_din;            //寄存待发送的数据endelse if ((tx_cnt == 4'd9)&&(clk_cnt == BPS_CNT/2))begin                               //计数到停止位中间时,停止发送过程tx_flag <= 1'b0;                //发送过程结束,标志位tx_flag拉低tx_data <= 8'd0;endelse begintx_flag <= tx_flag;tx_data <= tx_data;end 
end//进入发送过程后,启动系统时钟计数器与发送数据计数器
always @(posedge sys_clk or negedge sys_rst_n) begin         if (!sys_rst_n) begin                             clk_cnt <= 16'd0;                                  tx_cnt  <= 4'd0;end                                                      else if (tx_flag) begin                 //处于发送过程if (clk_cnt < BPS_CNT - 1) beginclk_cnt <= clk_cnt + 1'b1;tx_cnt  <= tx_cnt;endelse beginclk_cnt <= 16'd0;               //对系统时钟计数达一个波特率周期后清零tx_cnt  <= tx_cnt + 1'b1;       //此时发送数据计数器加1endendelse begin                              //发送过程结束clk_cnt <= 16'd0;tx_cnt  <= 4'd0;end
end//根据发送数据计数器来给uart发送端口赋值
always @(posedge sys_clk or negedge sys_rst_n) begin        if (!sys_rst_n)  uart_txd <= 1'b1;        else if (tx_flag)case(tx_cnt)4'd0: uart_txd <= 1'b0;         //起始位 4'd1: uart_txd <= tx_data[0];   //数据位最低位4'd2: uart_txd <= tx_data[1];4'd3: uart_txd <= tx_data[2];4'd4: uart_txd <= tx_data[3];4'd5: uart_txd <= tx_data[4];4'd6: uart_txd <= tx_data[5];4'd7: uart_txd <= tx_data[6];4'd8: uart_txd <= tx_data[7];   //数据位最高位4'd9: uart_txd <= 1'b1;         //停止位default: ;endcaseelse uart_txd <= 1'b1;                   //空闲时发送端口为高电平
endendmodule	

 顶层模块

 

module uart_top(input           sys_clk,          //外部50M时钟input           sys_rst_n,        //外部复位信号,低有效//uart接口input           uart_rxd,         //UART接收端口output          uart_txd          //UART发送端口);//parameter define
parameter  CLK_FREQ = 50000000;       //定义系统时钟频率
parameter  UART_BPS = 115200;         //定义串口波特率//wire define   
wire       uart_en_w;                 //UART发送使能
wire [7:0] uart_data_w;               //UART发送数据
wire       clk_1m_w;                  //1MHz时钟,用于仿真调试//*****************************************************
//**                    main code
//*****************************************************
pll_clk u_pll(                        //时钟分频模块,用于调试.inclk0         (sys_clk),.c0             (clk_1m_w)
);uart_recv #(                          //串口接收模块.CLK_FREQ       (CLK_FREQ),       //设置系统时钟频率.UART_BPS       (UART_BPS))       //设置串口接收波特率
u_uart_recv(                 .sys_clk        (sys_clk), .sys_rst_n      (sys_rst_n),.uart_rxd       (uart_rxd),.uart_done      (uart_en_w),.uart_data      (uart_data_w));uart_send #(                          //串口发送模块.CLK_FREQ       (CLK_FREQ),       //设置系统时钟频率.UART_BPS       (UART_BPS))       //设置串口发送波特率
u_uart_send(                 .sys_clk        (sys_clk),.sys_rst_n      (sys_rst_n),.uart_en        (uart_en_w),.uart_din       (uart_data_w),.uart_txd       (uart_txd));endmodule 

仿真模块

 

`timescale 1 ns/ 1 ns
module uart_top_tb();parameter T = 20;
reg sys_clk;
reg sys_rst_n;
reg uart_rxd;wire uart_txd;wire       uart_en_w;                 //UART发送使能
wire [7:0] uart_data_w;               //UART发送数据
wire       clk_1m_w; reg         uart_en;                  //发送使能信号
reg  [7:0]  uart_din;                 //待发送数据reg       uart_done;                //接收一帧数据完成标志信号
reg [7:0] uart_data;    initial                                                
begin                                                  sys_clk = 1'b0;sys_rst_n = 1'b0;uart_rxd = 1;#200 sys_rst_n = 1'b1;//模拟发送一帧数据#200 uart_rxd = 0;   //起始位#110000 uart_rxd = 0; #110000 uart_rxd = 1; #110000 uart_rxd = 1; #110000 uart_rxd = 0; #110000 uart_rxd = 0; #110000 uart_rxd = 1; #110000 uart_rxd = 0; #110000 uart_rxd = 1; //停止位#1500000  $stop;end                                                    
always #(T/2)  sys_clk = ~sys_clk;                                              pll_clk u_pll(                        //时钟分频模块,用于调试.inclk0         (sys_clk),.c0             (clk_1m_w)
);u_uart_recv(                 .sys_clk        (sys_clk), .sys_rst_n      (sys_rst_n),.uart_rxd       (uart_rxd),.uart_done      (uart_en_w),.uart_data      (uart_data_w));u_uart_send(                 .sys_clk        (sys_clk),.sys_rst_n      (sys_rst_n),.uart_en        (uart_en_w),.uart_din       (uart_data_w),.uart_txd       (uart_txd));                              
endmodule

rtl图:


http://chatgpt.dhexx.cn/article/JBIMB7oy.shtml

相关文章

串口通讯基本原理 【详细】

串口通信的基本知识 本文介绍了串口通讯的基本概念、数据格式、通讯方式、典型的串口通讯标准等内容。 串口通讯&#xff0c;RS232,RS485&#xff0c;停止位&#xff0c;奇校验&#xff0c;偶校验 1 串口通讯 串口通讯(Serial Communication)&#xff0c;是指外设和计算…

串口通信的基本原理详解

目录 串口通信 串口通信的两种基本方式 异步数据的数据发送过程 异步通信的数据接收过程 9针串口&#xff08;DB9&#xff09; TTL与RS232区别 TTL: RS232&#xff1a; 串口通信的数据格式 通讯方式 偶校验与奇校验 停止位 波特率&#xff08;波特率就是每秒钟传输…

串口通信原理详解

串口通信是一种串行异步通信&#xff0c;通信双方以字符帧作为数据传输单位&#xff0c;字符帧按位依次传输&#xff0c;每个位占固定的时间长度。两个字符帧之间的传输时间间隔可以是任意的&#xff0c;即传输完一个字符帧之后&#xff0c;可以间隔任意时间再传输下一个字符帧…

14_串口通信原理

通信方式的两种: 并行通讯: 传输原理:数据各个位同时传输。 优点:速度快 缺点:占用引脚资源多 串行通信: 传输原理:数据按位顺序传输。 优点:占用引脚资源少 缺点:速度相对较慢 串行通信: 按照数据传送方向,分为: 单工:数据传输只支持数据在一个方向上传输。 半双工:…

【Linux】基于美信串行解串器实现UART串口通信

文章目录 前言一、环境介绍二、硬件配置1. MAX967632. MAX96752F 三、串口通信协议1. 帧格式2. 同步帧3. 应答帧4. 包格式&#xff08;包由帧组成&#xff09; 四、内核模块实现 前言 车载项目中串行/解串器是十分常见的外设&#xff0c;目前常用的有两种标准&#xff1a;GMSL…

毫米波雷达图解算法原理(基于TI雷达)

毫米波雷达数据处理原理 前言基础bin文件解读 以下我们取1帧进行操作&#xff1a;对数据矩阵进行操作前的转换——开始计算结果矩阵一维FFT&#xff08;距离&#xff09;二维FFT&#xff08;速度&#xff09;角度维FFT &#xff08;假设利用结果已经获取目标&#xff09;对目标…

【阵列信号处理】DOA估计算法

DOA估计中的ESPRIT算法 ESPRIT算法时一种利用子空间旋转法估计DOA参数的方法&#xff0c;其算法的基本思想是将阵列在结构上分成两个完全一致的子列&#xff0c;两个子列相应阵元偏移的距离相等&#xff0c;也就是说阵列的阵元被分成一对对的形式&#xff0c;而且每一对之间具…

Hector SLAM 原理详解、算法解析

目录 1.原理详解 2.算法解析 1.原理详解 Hector整体算法很直接&#xff0c;就是将激光点与已有的地图“对齐”&#xff0c;即扫描匹配。扫描匹配就是使用当前帧与已经有的地图数据构建误差函数&#xff0c;使用高斯牛顿法得到最优解和偏差量。其工作是实现激光点到栅格地图的转…

MPU 6050姿态角度融合算法

1、介绍 1.1 姿态角&#xff08;Euler角&#xff09;pitch yaw roll介绍 飞行器的姿态角并不是指哪个角度&#xff0c;是三个角度的统称。它们是&#xff1a;俯仰、滚转、偏航。你可以想象是飞机围绕XYZ三个轴分别转动形成的夹角。 地面坐标系&#xff08;earth-surface inert…

linemod算法过程理解

一、提取模板 1、预处理 使用高斯模糊预处理将要作为模板的RGB图 2、模板梯度计算 分别计算RGB三个通道中每个像素点x和y方向的梯度&#xff08;sobel算子&#xff09;&#xff0c;取幅值最大的作为该像素的梯度&#xff0c;若梯度幅度值小于阈值&#xff0c;则被舍弃 3、梯度离…

MATLAB函数angle、unwrap

一、angle 相位角 语法 P angle&#xff08;Z&#xff09;描述 P angle&#xff08;Z&#xff09;返回复数数组Z的每个元素的相角&#xff08;以弧度为单位&#xff09;。角度介于π之间。对于复数Z&#xff0c;幅值R和相角theta由下式给出 R 绝对值&#xff08;Z&#xff0…

fbp算法matlab实现,matlab实现fbp算法

matlab提供大量函数,可以方便的完成fbp算法 1)fbp算法原理: 中心切片定理 (CST) : 原数据投影的一维傅立叶变换等于原数据的二维傅立叶变换 投影 --> 一维傅立叶变换 --> 滤波 --> 二维傅立叶反变换 经过上述过程应该得到原始数据 2)投影相关知识 2.1)正投影:对…

一种简单的图形旋转算法

图形旋转好玩又有实用性, 这里介绍一种简单的图形旋转算法. 具体步骤如下: 1. 首先将原图和旋转图的坐标原点都变换到图形的中心位置处. 2. 历遍旋转图形中的每一个pixel, 将pixel的坐标(j,i)反向旋转映射到原图, 得到原图对应的坐标值(Xr,Yr). 3. 考虑到旋转图的尺寸可能大于…

多目标跟踪之数据关联算法——匈牙利算法

零、Track和Detection的cost matrix,distance metric。距离计算的方式有如下几种: 距离cost distance metric,track和detection的距离矩阵。 外观距离appearance distance,来自检测切片ROI的网络特征提取;——余弦距离 运动模型距离 马氏距离,来自检测-跟踪的kalman校正…

EAST算法简单解析

前言 最近写了很多算法代码的解析&#xff0c;但是却很少写原理的解析&#xff0c;这段时间学得快忘得也快&#xff0c;所以寻思这几天写几篇学过算法的原理&#xff0c;可能不是很详细但是一定很简单&#xff0c;利于理解。 算法介绍 EAST: An Efficient and Accurate Scen…

定位算法初探

定位算法初探 一、指纹定位算法介绍 指纹定位(finger-printing localization)算法&#xff0c;是基于室内环境复杂&#xff0c;信号反射折射所形成的在不同位置形成的不同的信号强度信息而提出的一套算法。 指纹算法能很好的利用了反射折射所形成的信号信息&#xff0c;离线首…

使用python模拟实现PID控制算法

使用python模拟实现PID控制算法 PID控制算法是工业应用中最广泛算法之一&#xff0c;在闭环系统的控制中&#xff0c;可自动对控制系统进行准确且迅速的校正。 P、I、D分别是“比例&#xff08;proportional&#xff09;、积分&#xff08;integral&#xff09;、微分&#xff…

TCP Nagle算法简述

TCP/IP协议中&#xff0c;无论发送多少数据&#xff0c;总是要在数据前面加上协议头&#xff0c;同时&#xff0c;对方接收到数据&#xff0c;也需要发送ACK表示确认。为了尽可能的利用网络带宽&#xff0c;TCP总是希望尽可能的发送足够大的数据。 &#xff08;一个连接会设置M…

倒角算法推导

推导原理基本很简单&#xff1a; 已知AB&#xff0c; BC两条线段&#xff0c;且交于B点&#xff0c;求倒角半径为 L&#xff0c;AB&#xff0c;BC的倒角 以最短边&#xff08;假定为AB&#xff09;长 LAB&#xff0c; 在BC中&#xff0c;以B为起点&#xff0c;找出与LAB同长度…

[控制算法]

[常用控制算法] 0.博览众长 0.1 视频 1. DR_CAN b站 0.2 文章 1.控制算法整理 0.3 传统 VS 现代控制算法 1. 传统 传统控制算法&#xff1a;PID&#xff0c;模糊&#xff0c;神经网络控制算法。 2. 现代 现代控制算法有比例&#xff0c;LQR算法(用于线性系统)&#x…