UART串口通信——FPGA学习笔记9

2024-09-04 19:28

本文主要是介绍UART串口通信——FPGA学习笔记9,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、数据通信基本概念

按数据通信方式分类:

串行通信、并行通信

按数据传输方向分类:

单工通信、半双工通信、全双工通信

按数据同步方式分类:

同步通信、异步通信

常见的串行通信接口:

二、串口通信:

        UART 是一种采用异步串行通信方式的通用异步收发传输器(universal asynchronous receiver-transmitter),它在发送数据时将并行数据转换成串行数据来传输,在接收数据时将接收到的串行数据转换成并行数据。

        UART 串口通信需要两根信号线来实现, 一根用于串口发送,另外一根负责串口接收。 UART 在发送或接收过程中的一帧数据由 4 部分组成,起始位、数据位、奇偶校验位和停止位,如图 19.1.1 所示。其中,起始位标志着一帧数据的开始,停止位标志着一帧数据的结束, 数据位是一帧数据中的有效数据。 校验位分为奇校验和偶校验, 用于检验数据在传输过程中是否出错。 奇校验时, 发送方应使数据位中 1 的个数与校验位中 1 的个数之和为奇数;接收方在接收数据时, 对 1 的个数进行检查,若不为奇数,则说明数据在传输过程中出了差错。 同样,偶校验则检查 1 的个数是否为偶数。

        直接在数据信号中穿插一些同步用的信号位,或者把主体数据进行打包,以数据帧的格式传输数据。例如规定由起始位、数据位、奇偶校验位、停止位等。某些通讯中还需要双方约定数据的传输速率,以便更好地同步、

物理层:       

 UART 通信过程中的数据格式及传输速率是可设置的,为了正确的通信,收发双方应约定并遵循同样的设置。数据位可选择为 5、 6、 7、 8 位,其中 8 位数据位是最常用的, 在实际应用中一般都选择 8 位数据位;校验位可选择奇校验、偶校验或者无校验位;停止位可选择 1 位(默认) , 1.5 或 2 位。 串口通信的速率用波特率表示,它表示每秒传输二进制数据的位数,单位是 bps(位/秒) ,常用的波特率有 9600、 19200、38400、 57600 以及 115200 等。

        在设置好数据格式及传输速率之后, UART 负责完成数据的串并转换, 而信号的传输则由外部驱动电路实现。 电信号的传输过程有着不同的电平标准和接口规范, 针对异步串行通信的接口标准有 RS232、 RS422、RS485 等, 它们定义了接口不同的电气特性,如 RS-232 是单端输入输出,而 RS-422/485 为差分输入输出等。

        RS232 接口标准出现较早, 可实现全双工工作方式,即数据发送和接收可以同时进行。在传输距离较短时(不超过 15m) , RS232 是串行通信最常用的接口标准, RS-232 标准的串口最常见的接口类型为 DB9,样式如图 19.1.2 所示,工业控制领域中用到的工控机一般都配备多个串口, 很多老式台式机也都配有串口。

协议层:

UART通信协议

起始位:一帧的开始,必须保持一个比特位的低电平0

数据位:传输的有效数据,数据位可选5~8位;LSB(低位)在前,MSB(高位)在后

校验位:可选位,占用1个比特位,也可以没有校验

停止位:一帧的结束,必须有,可选占用0.5/1/1.5/2个比特位,保持逻辑高电平1

UART的传输速率:波特率

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

计算:

例如通信速率115200         那么一个比特位所占用的时间为\frac{1x10^{9}ns}{115200}=8680ns

如果系统时钟为50MHz(周期20ns),那么每个周期占用时间为8680/20=434个时钟周期。

三、程序设计

1、实验任务

        本节的实验任务是上位机通过串口调试助手发送数据给开发板,开发板通过USB UART串口接收数据并将接收到的数据发送给上位机,完成串口数据环回。UART通信波特率:115200,停止位:1,数据位:8位,无校验位。

2、框图分析

 

接收模块要有接收完成标志

 发送模块要求有忙信号标志

串口通信实现思维导图:

针对异步信号的同步处理——打三拍

什么是亚稳态?亚稳态是由于违背了触发器的建立和保持时间而产生的。寄存器采样需要满足一定的建立时间(setup)和保持时间(holdup),而异步电路没有办法保证建立时间(setup)和保持时间(holdup),所以会出现亚稳态。

消除亚稳态

3、波形分析

接收模块:

发送模块:

四、代码编写

1、 串口接收部分

`timescale 1ns / 1psmodule uart_rx(
input               sys_clk,
input               sys_rst_n,
input               uart_rxd,                   //串口输入信号
output  reg         uart_rx_done,               //串口接收完成信号
output  reg  [7:0]  uart_rx_data                //串口接收数据
);parameter  CLK_FREQ      = 50_000_000;        //时钟
parameter  UART_BPS      = 115200;            //波特率
localparam BAUD_CNT_MAX  = CLK_FREQ / UART_BPS;   //50Mhz 115200reg             uart_rx_d0  ;       
reg             uart_rx_d1  ;
reg             uart_rx_d2  ;
reg             rx_flag     ;       //高 在进行读取
reg   [3:0]     rx_cnt      ;       //位数计数器
reg   [15:0]    baud_cnt    ;       //波特率计数器
reg   [7:0]     rx_data_t   ;       //临时寄存器wire        start_en    ;  //开始信号  assign start_en = uart_rx_d2 &(!uart_rx_d1)&(!rx_flag);//数据打拍
always @(posedge sys_clk or negedge sys_rst_n ) beginif(!sys_rst_n)beginuart_rx_d0  <= 1'b0     ;uart_rx_d1  <= 1'b0     ;uart_rx_d2  <= 1'b0     ;endelse beginuart_rx_d0  <= uart_rxd    ;uart_rx_d1  <= uart_rx_d0  ;uart_rx_d2  <= uart_rx_d1  ;end
end//给接收标志rx_flag赋值
always @(posedge sys_clk or negedge sys_rst_n ) beginif (!sys_rst_n) beginrx_flag <= 1'b0;endelse if (start_en == 1'b1) beginrx_flag <= 1'b1;end//计数到9,在停止位一半的时候拉低else if ((rx_cnt == 4'd9)&&(baud_cnt == BAUD_CNT_MAX/2 - 1'b1)) beginrx_flag <= 1'b0;endelse beginrx_flag <= rx_flag;end
end//对波特率计数器baud_cnt 赋值
always @(posedge sys_clk or negedge sys_rst_n ) beginif (!sys_rst_n) beginbaud_cnt <= 16'd0;endelse if (rx_flag == 1'b1) beginif(baud_cnt < BAUD_CNT_MAX - 1'b1)beginbaud_cnt <= baud_cnt + 16'b1;endelse beginbaud_cnt <= 16'd0;endendelse beginbaud_cnt <= 16'd0;    end
end//对数据计数器rx_cnt 赋值
always @(posedge sys_clk or negedge sys_rst_n) beginif (!sys_rst_n) beginrx_cnt <= 4'd0;endelse if(rx_flag == 1'b1)beginif (baud_cnt == BAUD_CNT_MAX - 1'b1) beginrx_cnt <= rx_cnt + 4'b1;endelse beginrx_cnt <= rx_cnt;endendelse beginrx_cnt <= 4'd0;       end
end//根据rx_cnt寄存输入数据
always @(posedge sys_clk or negedge sys_rst_n  ) beginif (!sys_rst_n) beginrx_data_t <= 8'd0;endelse if (rx_flag == 1'b1) beginif(baud_cnt == BAUD_CNT_MAX/2 - 1'b1)begincase (rx_cnt)4'd1: rx_data_t[0] <= uart_rx_d2;4'd2: rx_data_t[1] <= uart_rx_d2;4'd3: rx_data_t[2] <= uart_rx_d2;4'd4: rx_data_t[3] <= uart_rx_d2;4'd5: rx_data_t[4] <= uart_rx_d2;4'd6: rx_data_t[5] <= uart_rx_d2;4'd7: rx_data_t[6] <= uart_rx_d2;4'd8: rx_data_t[7] <= uart_rx_d2;default: ;endcaseendelse beginrx_data_t <= rx_data_t;endendelse beginrx_data_t <= 8'd0;   end
end//给接收完成信号uart_rx_done 和接收uart_rx_data 赋值
always @(posedge sys_clk or negedge sys_rst_n ) beginif (!sys_rst_n) beginuart_rx_done <= 1'b0;uart_rx_data <= 8'd0;endelse if ((rx_cnt == 4'd9)&&(baud_cnt == BAUD_CNT_MAX/2 - 1'b1)) beginuart_rx_done <= 1'b1;uart_rx_data <= rx_data_t;endelse beginuart_rx_done <= 1'b0;uart_rx_data <= uart_rx_data;        end
endendmodule

2、串口发送部分

`timescale 1ns / 1ps
module uart_tx(
input           sys_clk,
input           sys_rst_n,
input           uart_tx_en,             //串口发送数据使能
input   [7:0]   uart_tx_data,           //串口准备发送的数据
output  reg     uart_txd,               //串口输出
output  reg     uart_tx_busy            //串口忙的标志
);parameter  CLK_FREQ      = 50_000_000;              //时钟
parameter  UART_BPS      = 115200;                  //波特率
localparam BAUD_CNT_MAX  = CLK_FREQ / UART_BPS;     //50Mhz 115200reg     [7:0]   tx_data_t;
reg     [3:0]   tx_cnt;
reg     [15:0]  baud_cnt    ;       //波特率计数器//当uart_tx_en为高时    寄存输入的并行数据   且拉高busy信号
always @(posedge sys_clk or negedge sys_rst_n ) beginif (!sys_rst_n) begintx_data_t       <= 8'd0;uart_tx_busy    <= 1'b0;endelse if (uart_tx_en == 1'b1) begintx_data_t       <= uart_tx_data;uart_tx_busy    <= 1'b1;endelse if ((tx_cnt == 4'd9)&&(baud_cnt == BAUD_CNT_MAX - BAUD_CNT_MAX/16)) begintx_data_t       <= 8'd0;uart_tx_busy    <= 1'b0;        endelse begintx_data_t       <=  tx_data_t     ;uart_tx_busy    <=  uart_tx_busy  ;      end
end//对波特率计数器baud_cnt 赋值
always @(posedge sys_clk or negedge sys_rst_n ) beginif (!sys_rst_n) beginbaud_cnt <= 16'd0;endelse if (uart_tx_busy == 1'b1) beginif(baud_cnt < BAUD_CNT_MAX - 1'b1)beginbaud_cnt <= baud_cnt + 16'b1;endelse beginbaud_cnt <= 16'd0;endendelse beginbaud_cnt <= 16'd0;    end
end//对数据计数器tx_cnt 赋值
always @(posedge sys_clk or negedge sys_rst_n) beginif (!sys_rst_n) begintx_cnt <= 4'd0;endelse if(uart_tx_busy == 1'b1)beginif (baud_cnt == BAUD_CNT_MAX - 1'b1) begintx_cnt <= tx_cnt + 4'b1;endelse begintx_cnt <= tx_cnt;endendelse begintx_cnt <= 4'd0;       end
end//根据tx_cnt控制TXD信号
always @(posedge sys_clk or negedge sys_rst_n) beginif (!sys_rst_n) beginuart_txd <= 1'd1;endelse if (uart_tx_busy == 1'b1) begincase (tx_cnt)4'd0: uart_txd <= 1'b0;             //起始位4'd1: uart_txd <= tx_data_t[0];     //d04'd2: uart_txd <= tx_data_t[1];     //d14'd3: uart_txd <= tx_data_t[2];     //d24'd4: uart_txd <= tx_data_t[3];     //d34'd5: uart_txd <= tx_data_t[4];     //d44'd6: uart_txd <= tx_data_t[5];     //d54'd7: uart_txd <= tx_data_t[6];     //d64'd8: uart_txd <= tx_data_t[7];     //d74'd9: uart_txd <= 1'b1;             //停止位default: uart_txd <= 1'b1;endcaseendelse beginuart_txd <= 1'b1;end
endendmodule

3、顶层代码

`timescale 1ns / 1psmodule uart_loopback(
input           sys_clk,
input           sys_rst_n,//UART端口
input           uart_rxd,
output          uart_txd);parameter  CLK_FREQ      = 50_000_000   ;              //时钟
parameter  UART_BPS      = 115200       ;                  //波特率wire           uart_rx_done ;
wire    [7:0]  uart_rx_data ;uart_rx #(.CLK_FREQ   (CLK_FREQ),.UART_BPS   (UART_BPS)  )u_uart_rx(.sys_clk        (sys_clk     )  ,.sys_rst_n      (sys_rst_n   )  ,.uart_rxd       (uart_rxd    )  ,    .uart_rx_done   (uart_rx_done)  ,.uart_rx_data   (uart_rx_data)
);uart_tx #(.CLK_FREQ   (CLK_FREQ),.UART_BPS   (UART_BPS) )u_uart_tx(.sys_clk        (sys_clk     )  ,.sys_rst_n      (sys_rst_n   )  ,.uart_tx_en     (uart_rx_done)  ,  .uart_tx_data   (uart_rx_data)  ,.uart_txd       (uart_txd    )  ,    .uart_tx_busy   ()  
);endmodule

 4、tb代码

`timescale 1ns / 1psmodule tb_uart_loopbak( );parameter       CLK_PERIOD = 20;reg     sys_clk;
reg     sys_rst_n;
reg     uart_rxd;
wire    uart_txd;initial beginsys_clk <= 1'b0;sys_rst_n <= 1'b0;uart_rxd <= 1'b1;   //空闲状态#200sys_rst_n <= 1'b1;#1000//发送0x55   8'b0101_0101uart_rxd  <= 1'b0;  //起始位#8680uart_rxd  <= 1'b1;  //d0#8680uart_rxd  <= 1'b0;  //d1#8680uart_rxd  <= 1'b1;  //d2#8680uart_rxd  <= 1'b0;  //d3#8680uart_rxd  <= 1'b1;  //d4#8680uart_rxd  <= 1'b0;  //d5#8680uart_rxd  <= 1'b1;  //d6#8680uart_rxd  <= 1'b0;  //d7#8680uart_rxd  <= 1'b1;  //停止位#8680uart_rxd <= 1'b1;   //空闲状态
endalways #(CLK_PERIOD/2) sys_clk = !sys_clk;uart_loopback u_uart_loopback(
.sys_clk        (sys_clk  ) ,
.sys_rst_n      (sys_rst_n) , 
.uart_rxd       (uart_rxd ) ,
.uart_txd       (uart_txd ) 
);endmodule

5、管脚定义 

五、仿真与程序验证

1、Modelsim仿真

仿真结果符合预期结果。

2、下载验证

最终结果符合预期。

六、源码获取

私聊笔者获取源码

这篇关于UART串口通信——FPGA学习笔记9的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1136816

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

线性代数|机器学习-P36在图中找聚类

文章目录 1. 常见图结构2. 谱聚类 感觉后面几节课的内容跨越太大,需要补充太多的知识点,教授讲得内容跨越较大,一般一节课的内容是书本上的一章节内容,所以看视频比较吃力,需要先预习课本内容后才能够很好的理解教授讲解的知识点。 1. 常见图结构 假设我们有如下图结构: Adjacency Matrix:行和列表示的是节点的位置,A[i,j]表示的第 i 个节点和第 j 个

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件