您当前的位置: 首页 >  ar

正点原子

暂无认证

  • 0浏览

    0关注

    382博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

【正点原子FPGA连载】第二十一章UART串口通信实验 -摘自【正点原子】新起点之FPGA开发指南_V2.1

正点原子 发布时间:2021-10-29 16:41:14 ,浏览量:0

1)实验平台:正点原子新起点V2开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=609758951113 2)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-300792-1-1.html 3)对正点原子FPGA感兴趣的同学可以加群讨论:994244016 4)关注正点原子公众号,获取最新资料更新 在这里插入图片描述

第二十一章UART串口通信实验 串口是“串行接口”的简称,即采用串行通信方式的接口。串行通信将数据字节分成一位一位的形式在一条数据线上逐个传送,其特点是通信线路简单,但传输速度较慢。因此串口广泛应用于嵌入式、工业控制等领域中对数据传输速度要求不高的场合。本章我们将使用新起点开发板上的UART串口完成与上位机的通信。 本章包括以下几个部分: 2121.1简介 21.2实验任务 21.3硬件设计 21.4软件设计 21.5下载验证 21.1简介 串行通信分为两种方式:同步串行通信和异步串行通信。同步串行通信需要通信双方在同一时钟的控制下,同步传输数据;异步串行通信是指通信双方使用各自的时钟控制数据的发送和接收过程。 UART是一种采用异步串行通信方式的通用异步收发传输器(universal asynchronous receiver-transmitter),它在发送数据时将并行数据转换成串行数据来传输,在接收数据时将接收到的串行数据转换成并行数据。 UART串口通信需要两根信号线来实现,一根用于串口发送,另外一根负责串口接收。UART在发送或接收过程中的一帧数据由4部分组成,起始位、数据位、奇偶校验位和停止位,如图 21.1.1所示。其中,起始位标志着一帧数据的开始,停止位标志着一帧数据的结束,数据位是一帧数据中的有效数据。校验位分为奇校验和偶校验,用于检验数据在传输过程中是否出错。奇校验时,发送方应使数据位中1的个数与校验位中1的个数之和为奇数;接收方在接收数据时,对1的个数进行检查,若不为奇数,则说明数据在传输过程中出了差错。同样,偶校验则检查1的个数是否为偶数。 在这里插入图片描述

图 21.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,样式如图 21.1.2所示,工业控制领域中用到的工控机一般都配备多个串口,很多老式台式机也都配有串口。 在这里插入图片描述

图 21.1.2 DB9接口 在这里插入图片描述

图 21.1.3 TYPE_C USB接口 由于传统的DB9接口体积较大,会占用开发板过多空间,在新起点开发板上我们采用的是TYPE_C USB接口,样式如图 21.1.3所示,另一端直接和电脑USB相连。连接示意图如图 21.1.4所示。 在这里插入图片描述

图 21.1.4 USB串口通信连接示意图 21.2实验任务 本节实验任务是上位机通过串口调试助手发送数据给FPGA,FPGA通过USB串口接收数据并将接收到的数据发送给上位机,完成串口数据环回。 21.3硬件设计 新起点FPGA开发板上USB串口的原理图如下所示: 在这里插入图片描述

图 21.3.1 串口原理图 原理图中的CH340就是图 21.1.4所示的转换芯片,其中UART1_RXD连接到FPGA芯片的的RX管脚,UART1_TXD连接到FPGA芯片的TX管脚(注意这里有一个编号P9的x4排针,在做串口通信实验时需要用跳线帽接上,具体接法看下载验证部分内容),CH340_P/N分别接到开发板的TYPE_C USB插座D+/-上。CH340具体的工作原理是:发送的时候把FPGA的UART1_TXD管脚送出的信号由TTL电平转换为USB差分电平并送到TYPE_C USB插座,接收的时候则把TYPE_C USB插座送来的USB差分电平转换为TTL电平送给FPGA的UART1_RXD管脚,同时我们通过USB数据线将TYPE_C USB插座D+/-直连到PC上相应的USB口的D+/-,当然也包括电源和地,这样就完成了USB串口通信的硬件准备工作。 本实验中,系统时钟、按键复位以及串口的接收、发送端口的管脚分配如下表所示: 表 21.3.1 串口通信实验管脚分配 在这里插入图片描述

对应的TCL约束语句如下所示: set_location_assignment PIN_M2 -to sys_clk set_location_assignment PIN_M1 -to sys_rst_n set_location_assignment PIN_N5 -to uart_rxd set_location_assignment PIN_M7 -to uart_txd 21.4程序设计 根据实验任务,我们不难想象本系统应该有一个串口接收模块,用来接收上位机发送的数据;还要有一个串口发送模块,用于将数据发回上位机;另外还应该有一个对数据进行环回控制的模块,它负责把从串口接收模块接收到的数据送给串口发送模块,以实现串口数据的环回。由此可以画出本次实验的系统框图,如下所示: 在这里插入图片描述

图 21.4.1 系统框图 由系统总体框图可知,整个工程包括四个模块,顶层模块、接收模块、发送模块和数据环回模块。其中在顶层模块中完成对另外三个模块的例化,顶层模块原理图如下所示: 在这里插入图片描述

图 21.4.2 顶层模块原理图 在图 21.4.2中,uart_recv为串口接收模块,从串口接收端口uart_rxd来接收上位机发送的串行数据,并在一帧数据接收结束后给出通知信号uart_done。 uart_send为串口发送模块,以uart_en为发送使能信号。uart_en的上升沿将启动一次串口发送过程,将uart_din接口上的数据通过串口发送端口uart_txd发送出去。 uart_loop模块负责完成串口数据的环回功能。它在uart_recv模块接收完成后,将接收到的串口数据发送到uart_send模块,并通过send_en接口给出一个上升沿,以启动发送过程。 在编写代码之前,我们首先要确定串口通信的数据格式及波特率。在这里我们选择串口比较常用的一种模式,数据位为8位,停止位为1位,无校验位,波特率为115200bps。则传输一帧数据的时序图如下图所示: 在这里插入图片描述

图 21.4.3 串口通信时序图 顶层模块的代码如下:

1   module uart_loopback_top(
2       input           sys_clk,            //外部50M时钟
3       input           sys_rst_n,          //外部复位信号,低有效
4   
5       input           uart_rxd,           //UART接收端口
6       output          uart_txd            //UART发送端口
7       );
8   
9   //parameter define
10  parameter  CLK_FREQ = 50000000;         //定义系统时钟频率
11  parameter  UART_BPS = 115200;           //定义串口波特率
12      
13  //wire define   
14  wire       uart_recv_done;              //UART接收完成
15  wire [7:0] uart_recv_data;              //UART接收数据
16  wire       uart_send_en;                //UART发送使能
17  wire [7:0] uart_send_data;              //UART发送数据
18  wire       uart_tx_busy;                //UART发送忙状态标志
19  
20  //*****************************************************
21  //**                    main code
22  //*****************************************************
23  
24  //串口接收模块     
25  uart_recv #(                          
26      .CLK_FREQ       (CLK_FREQ),         //设置系统时钟频率
27      .UART_BPS       (UART_BPS))         //设置串口接收波特率
28  u_uart_recv(                 
29      .sys_clk        (sys_clk), 
30      .sys_rst_n      (sys_rst_n),
31      
32      .uart_rxd       (uart_rxd),
33      .uart_done      (uart_recv_done),
34      .uart_data      (uart_recv_data)
35      );
36  
37  //串口发送模块    
38  uart_send #(                          
39      .CLK_FREQ       (CLK_FREQ),         //设置系统时钟频率
40      .UART_BPS       (UART_BPS))         //设置串口发送波特率
41  u_uart_send(                 
42      .sys_clk        (sys_clk),
43      .sys_rst_n      (sys_rst_n),
44      
45      .uart_en        (uart_send_en),
46      .uart_din       (uart_send_data),
47      .uart_tx_busy   (uart_tx_busy),
48      .uart_txd       (uart_txd)
49      );
50      
51  //串口环回模块    
52  uart_loop u_uart_loop(
53      .sys_clk        (sys_clk),             
54      .sys_rst_n      (sys_rst_n),           
55  
56      .recv_done      (uart_recv_done),   //接收一帧数据完成标志信号
57      .recv_data      (uart_recv_data),   //接收的数据
58  
59      .tx_busy        (uart_tx_busy),     //发送忙状态标志      
60      .send_en        (uart_send_en),     //发送使能信号
61      .send_data      (uart_send_data)    //待发送数据
62      );
63      
64  endmodule 

在顶层模块中完成了对其余各个子模块的例化。需要注意的是,顶层模块中第10、11行定义了两个变量:系统时钟频率CLK_FREQ与串口波特率UART_BPS,使用时可以根据不同的系统时钟频率以及所需要的串口波特率设置这两个变量。我们可以尝试将串口波特率UART_BPS设置为其他值(如9600),在模块例化时会将这个变量传递到串口接收与发送模块中,从而实现不同速率的串口通信。 串口接收模块的代码如下所示:

1   module uart_recv(
2       input             sys_clk,                  //系统时钟
3       input             sys_rst_n,                //系统复位,低电平有效
4       
5       input             uart_rxd,                 //UART接收端口
6       output  reg       uart_done,                //接收一帧数据完成标志
7       output  reg       rx_flag,                  //接收过程标志信号
8       output  reg [ 3:0] rx_cnt,                  //接收数据计数器
9       output  reg [ 7:0] rxdata,
10      output  reg [7:0] uart_data                 //接收的数据
11      );
12      
13  //parameter define
14  parameter  CLK_FREQ = 50000000;                //系统时钟频率
15  parameter  UART_BPS = 9600;                    //串口波特率
16  localparam  BPS_CNT  = CLK_FREQ/UART_BPS;       //为得到指定波特率,
17                                                  //需要对系统时钟计数BPS_CNT次
18  //reg define
19  reg        uart_rxd_d0;
20  reg        uart_rxd_d1;
21  reg [15:0] clk_cnt;                              //系统时钟计数器
22  
23  //wire define
24  wire       start_flag;
25  
26  //*****************************************************
27  //**                    main code
28  //*****************************************************
29  //捕获接收端口下降沿(起始位),得到一个时钟周期的脉冲信号
30  assign  start_flag = uart_rxd_d1 & (~uart_rxd_d0);    
31  
32  //对UART接收端口的数据延迟两个时钟周期
33  always @(posedge sys_clk or negedge sys_rst_n) begin 
34      if (!sys_rst_n) begin 
35          uart_rxd_d0             
关注
打赏
1665308814
查看更多评论
0.0481s