我的老脸又红了!因为又有人问我 USART 怎么使用

提到单片机开发过程中学的 UART 是什么,大家就会很快的吧啦吧啦的讲了一堆:

UART :Universal Asynchronous Receiver and Transmitter 通用异步收/发器,是一种通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输和接收。一般由波特率产生器(产生的波特率等于传输波特率的 16 倍)、UART 接收器、UART 发送器组成,硬件上有两根线,一根用于发送,一根用于接收。 显然,如果用通用 IO 口模拟 UART 总线,则需一个输入口,一个输出口。
UART 的数据传输可以首先从最低有效位(LSB)开始。然而,有些 UART 允许灵活选择先发送最低有效位或最高有效位(MSB)。 
微控制器中的 UART 传送数据的速度范围为每秒几百位到 1.5Mb,UART 波特率还受发送和接收线对距离(线长度)的影响..... .......

但对于 USART ,是什么,与 UART 有什么区别.....
这时候,小编其实想说:咦!!!不好意思,好像我走错地方了......
事实上 UART 与 USART 都是单片机上的串口通信,当我们使用 USART 在异步通信的时候,它与 UART 没有什么区别,但是用在同步通信的时候,区别就很明显了:大家都知道同步通信需要时钟来触发数据传输,也就是说 USART 相对 UART 的区别之一就是能提供主动时钟。接下来,我们就通过 LPC82x 系列来学习 USART 以及实际应用。

一、USART 模块介绍

1.1、USART 特性介绍:
  • LPC824 中有 3 个 USART 接口可以使用:USART 0/1/2。串口可以支持 异步模式 以及 同步模式。其中异步模式下最高速率可达 875Mbits/s;同步模式下最高速率可达 10Mbits/s.
  • USART 数据格式可以设置为 7、8、9 个数据位,1、2 个停止位。其中校验可以设置为:无校验/奇校验/偶校验。
  • USART 的中断源为:接收就绪、发送就绪、发送器空闲、校验错误,数据帧错误。
  • USART 的波特率可以支持常用的波特率,最高为 921600,最低为 300,并且可以通过设置让其自动监测波特率。
  • USART 具有低功耗模式唤醒的功能,其中在异步通信模式下,能够在睡眠模式下唤醒;在同步通信模式下,能够在全部低功耗模式下唤醒。
二、USART 应用操作

2.1、USART 的功能框图

        如 图 2-1-1 所示:

其中串口的时钟是由两个时钟源提供的,主时钟经过 FRGCLKDIV 分频之后的 U_PCLK 时钟源用于波特率的产生,其他均由系统时钟提供。以下 图 2-1-2 即为异步模式下的波特率产生过程,在 USART 模块得到有主时钟分频之后的 U_PCLK 之后,内部还会经过波特率分频器以及过采样分频器两个分频器进行分频,最后得到的才是波特率。



2.2、设置 USART 模块配置流程


2.3、USART 的详细配置步骤:


      以下我们就以“波特率为 115200、无校验位、数据位为 8 位、停止位为 1 位”的参数进行串口配置。

      1. 基本配置:

          通过 USART 的 CFG 寄存器配置关键参数:

          a. 使能 USART:CFG[0:0] = 1

          b. 配置数据位为 8 位:CFG[3:2]=1

          c. 配置校验为无校验:CFG[5:4]=0

          d. 配置停止位为 1 个:CFG[6:6]=1

          e. 配置为无流控:CFG[9:9]=0

          f. 不使用同步收发模式:CFG[12:11,14]=0

          g. 不使用环回(自发自收):CFG[15:15]=0
 
          h. 不使用 RS-485:CFG[21:18]=0
 
           i. 不反向识别波形极性:CFG[23:22]=0

      综上所述,寄存器的配置为:

          CFG = 1 << 0 | 1 << 2 | 0 << 4 | 0 << 6 | 0 << 9 | 0 << 11 | 0 << 14 | 0 << 15 | 0xF << 18 | 3 << 22;

      其中寄存器里面没有定义的位必须为 0。设置后如下图 2-3-1 所示。

         

      以上关于 CFG 寄存器的配置在代码中可以通过 Chip_UART_ConfigData() 函数进行配置。

      2. 设置波特率:

          在设置波特率时可以有多种解法,现在假设主时钟为 12MHz 时:

      a. 保守解法:先配置整数分频器,有误差时用分数分频器弥补

           SYSCON.UARTCLKDIV = 1

           USART.OSR = 16 - 1 = 15

           USART.BRG = 6 – 1 = 5 (12000000/115200/16 = 6.51)  

           SYSCON.UARTFRAGMULT = 22((6.51/6 - 1)*255 = 22)

            波特率 = 12000000/1/(1+22/255)/6/16 = 115072,误差为 0.12%

      b.“投机”解法:在线路较好时不使用分数分频器,而是减少过采样倍率(该方法对于通讯的信号波形要求较高)

          ON.UARTCLKDIV = 1

          SYSCON.UARTFRAGMULT = 0

          USART.OSR = 13 – 1 = 12 (减少过采样倍率,12000000/115200/13=8.013,除不尽的部分最小)

          USART.BRG = 8 – 1 = 7(最后再确定 BRG 的值)

          波特率 = 12000000/1/(1+0/255)/8/13 = 115384,误差率为 0.3%

          其中减少过采样倍率会提高对信号波形的质量要求。

           以上相关的 API 函数为 Chip_Clock_SetUSARTNBaseClockRate()与Chip_UART_SetBaud()(其中仅支持 16 倍过采样)。

     3. 杂项配置:

          通过 USART 的 CTL 寄存器使能发送器,

  • 解除对发送器的禁用:CTL[6:6] = 0;
  • 不发送断路信号:CTL[1:1] = 0;
  • 不使用 RS-485 的地址检测功能:CTL[2:2] = 0;
  • 不使用同步模式(连续时钟发送):CTL[9:8] = 0
  • 不做自动波特率的检测:CTL[16:16] = 0

          综上所述,CTL 寄存器的配置具体为:  
          UART.CTL = 0<

          在代码中,关于 CTL 寄存器的相关配置函数为 Chip_UART_TXEnable();

         

     4. 中断配置:

          在关于中断的设置中,需要通过两个寄存器 INTENSET 与 INTENCLR 来使能需要的中断,禁止不需要的中断,其中这两个寄存器均为写 1 有效。除此之外,INTENSET 可以通过读取其值来判断当前使能的中断有哪些。在之前的特性的介绍中,我们知道串口的中断源有:接收就绪中断,闲置中断等,现在我们来配置哪一些需要使能,哪一些需要禁用:

          a. 使能接收就绪中断:INTENSET[0:0] = 1

          b. 使能发送器闲置中断:INTENSET[3:3] = 1

              使能:发送器一空闲就会发中断,所以要在发送一个数据后再使能

              禁用:在发送全部数据后,要禁用这个中断。

          c. 使能接收数据溢出中断:INTENSET[8:8] = 1

          d. 禁用发送器就绪中断:INTENSET[2:2] = 1

              发送器就绪中断会有助于提高发送效率,但是中断产生时最后一个数据很可能尚在发送中,容易出错。

          e. 禁用其他中断

              由于这两个寄存器为写 1 有效,我们可以先除能全部的中断,然后再使能我们需要的中断,设置后如下图 2-3-3 所示:

              UART.INTENSET = 1<

              UART.INTENCLR = 0X0001F96D(空白位不能写 1)

         

     5. 标志位:

          在设置完上述的中断设置之后,我们可以通过 STAT 寄存器来查看当前的事件标志,如右图 2-3-4 所示,在 STAT 中,有一些标志需要我们写1来清除标志,有些则由硬件自动设置与清除,我们现在就了解与 USART 相关的几个标志位:

          a. 接收到数据标志:STAT[0:0],这个为只读,当读取串口数据时会自动清除
          b. 发送器闲置标志:STAT[3:3],这个为只读,当写入新数据时会自动清除
          c. 接收数据溢出标志:STAT[8:8],这个需要手动写 1 清除。

          由于我们使用的是中断,所可以在中断处理函数中判断是进入了哪一种的中断,而当我们使用轮询的话,则可以在我们的循环中轮询寄存器中上述的标志位。
         

     6. 数据处理:

          在处理数据中,我们可以分为两部分:发送数据与接收数据。

          a. 发送数据
              在 1.1.5 中介绍到 STAT 寄存器,如果 STAT 中 bit2 (发送器就绪)或者 bit3 (发送器空闲)有被设置的话,这时候说明 USART 能够发送数据,我们可以往 USART 的 TXDAT 寄存器中发送数据。所以在发送数据之前我们需要先判断 STAT 的 bit2 & bit3,确定是空闲之后再发送数据。

          b. 接收数据
               当我们在触发了接收中断,或者是在轮询的过程中检测到 STAT 寄存器的 bit0 被设置之后,这是说明 USART 中接收到了数据。我们有两个寄存器可以读取到 USART 的数据,如右图 2-3-5 所示:

               RXDAT 寄存器:可以读取接收到的纯数据,但是不知道是否有错。

               RXDATSTAT 寄存器:可以读取接收到的数据,并且 RXDATSTAT[15:13] 会表示当前数据的错误状态。其中:

               [13:13]: 存在帧错误(停止位错误)

               [14:14]: 存在奇/偶校验错误

               [15:15]: 在接收该数据时线路中噪声过大(线路质量不好,有可能出现个别数据接收错误)
              

2.4、USART 的 DMA 数据收发

      当我们在使用过程中需要通过串口收发大量数据,如果我们还是使用轮询或者中断的方式来进行处理的话,会占用程序的大部分时间。我们可以通过使能 USART 上的 DMA 进行数据收发。如下图 2-1-9 所示,USART 有 6 个 DMA 通道,分别对应三个 USART 的接收与发送。

         

       在使用 DMA 功能时,不需要在 USART 中进行任何的配置,只需要在 DMA 控制器中进行初始化即可:

  • 填写相应通道的描述符。
  • 配置对应的 DMA 通道(CFG 寄存器)
  • 开启传输完成中断。
  • 使能外设请求。

2.5、USART 对 RS-485 的支持



      RS-485 通讯采用的是主从通讯方式,即为一个主机带多个从机,其中从机不主动发命令与数据,一切由主机控制。在通讯过程中,主设备会通过总线广播发送一个从机地址,与地址相符的从设备会相应请求,然后在进行串口通信。因此对寄存器进行修改:

      作为从设备:

  • 在 CFG[3:2] 位段中,设置数据位为 9 个。
  • 设置 CFG[19:19](AUTOADDR) 为 1
  • 当需要接收地址时,设置 CTL.bit2(ADDRDET)为 1,此时仅当收到的数据第 9 位为 1,且 8 位地址与 ADDR 的设置相匹配时才会接受(产生中断或 DMA)
  • 当需要接受数据时,设置 CTL.bit2(ADDRDET)为 0,此时接收全部数据。

 

      作为主设备:

  • 在 CFG[3:2] 位段中,设置数据位为 9 个
  • 由于主设备负责广播从机地址数据,所以不需要做识别设置。

      除此之外,RS-485 通讯是一种半双工通讯,与 RS-232,RS-422 这些全双工的通讯不一样,需要控制传输方向的流向。因此需要对 USART 进行一些设置修改:

  • 设置 CFG.bit20(OESEL)为 1,把原本 RTS 信号改用为 RS-485 的 OE 信号
  • 根据 RS-485 收发器对 OE 极性的要求设置:0=OE 低电平有效,1=OE 高电平有效。
  • 根据软件反应的延迟设置 CFG.bit18(OETA):当使用 DMA 进行数据发送时,可以 OETA 设置为 0,即发完数据后立即解除 OE 有效;当使用中断发送,最好将 OETA 设置为 1,即发完数据再等一个帧的时间给 ISR 作处理后才解除 OE 有效。


2.6、USART 低功耗模式唤醒

      LPC82x 的休眠模式有三种,分别是睡眠模式,深度睡眠和掉电模式。其中 USART 异步模式与同步模式能够唤醒低功耗模式如下表 2-6-1 所示:

USART 工作模式

能唤醒的低功耗模式

异步模式

睡眠模式

同步模式

睡眠模式、深度睡眠、掉电模式

      睡眠模式唤醒的相关配置流程如下图 2-6-1:
         

      在深度睡眠/掉电模式下唤醒的相关配置流程如下图 2-6-2:

           

三、USART 应用实例

3.1、实验目的

       通过本次实验,了解和掌握 LPC82X USART 的以下几点:

  • 如何配置 USART 的引脚 IO;
  • 如何配置 USART 的参数,如波特率,数据位等;
  • 如何使用板级 API 来发送串口数据;


3.2、实验软/硬件环境搭建

      硬件:LPC82x Xpresso v2/mbed

      软件:SDK 从 NXP 官网下载(https://mcuxpresso.nxp.com/en/select

      工程位置:..\..\boards\lpcxpresso824max\driver_examples \usart\polling\mdk\

      usart_polling_example.uvprojx


3.3、实验描述

      本实验使能 UART0 进行数据收发,使用方式为 polling 的方式。在轮询的过程中会不断的检测 UART0 的 RXDAT 是否有数据,然后将其数据通过 UART0 给上位机。
 
       

3.4、实验结果

      通过串口助手往 LPC82x 板子上发送串口数据后,串口助手会打印出我们发送给设备数据。

3.5、实验代码

      #include "board.h"

      #include "fsl_usart.h"

      #include "pin_mux.h"

      #include

      /*****************************************************************

       * Definitions

       *****************************************************************/

      #define         EXAMPLE_USART                    USART0

       #define         EXAMPLE_USART_CLK_SRC          kCLOCK_MainClk

       #define      EXAMPLE_USART_CLK_FREQ CLOCK_GetFreq(EXAMPLE_USART_CLK_SRC)

 

       /*****************************************************************

        * Prototypes

      *****************************************************************/

 

      /*****************************************************************

       * Variables

      *****************************************************************/

       uint8_t txbuff[] =

          "Usart polling example.\r\nBoard will send back received characters.\r\nNow, please input any character:\r\n";

 

      /*******************************************************************************

       * Code

       ******************************************************************************/

       /*!

       * @brief Main function

       */

      int main(void)

      {

          uint8_t ch;

          usart_config_t config;

      

      //使能 UART0 的时钟

          /* Enable clock of uart0. */

          CLOCK_EnableClock(kCLOCK_Uart0);

          // 对 UART0 的输入时钟进行分频

          CLOCK_SetClkDivider(kCLOCK_DivUsartClk, 1U);

 

              //在该函数里面定义了 UART0 中关于 RX、TX 的引脚

          BOARD_InitPins();

          BOARD_BootClockIRC12M();

          BOARD_InitDebugConsole();

 

          /* Default config by using USART_GetDefaultConfig():

           * config->baudRate_Bps = 9600U;

           * config->parityMode = kUSART_ParityDisabled;

           * config->stopBitCount = kUSART_OneStopBit;

            * config->bitCountPerChar = kUSART_8BitsPerChar;

           * config->loopback = false;

           * config->enableRx = false;

           * config->enableTx = false;

           * config->syncMode = kUSART_SyncModeDisabled;

           */

              /*获取串口参数的默认设置

                串口波特率为 9600

                禁用校验位;

                停止位为 1 个;

                数据位为 8 个;

                禁用环回;

                禁用接收;

                禁用发送;

                设置为异步模式;

              */

          USART_GetDefaultConfig(&config);

              /*

                将得到的默认参数按照我们想要的进行设置:

                使能接收;

                使能发送;

                修改波特率为 115200(通过宏定义)

              */

           config.enableRx     = true;

           config.enableTx     = true;

           config.baudRate_Bps = BOARD_DEBUG_USART_BAUDRATE;

 

          /* Initialize the USART with configuration. */

               // 使能串口。

           USART_Init(EXAMPLE_USART, &config, EXAMPLE_USART_CLK_FREQ);

 

          /* Send data in polling way. */

              // 发送串口数据

          USART_WriteBlocking(EXAMPLE_USART, txbuff, sizeof(txbuff) - 1);

 

          while (1)

          {

              /* Receive a character from USART, this API will wait until one character has been received. */

                       /*在轮询中查看 RXDAT 的 buff 是否有数据*/

               USART_ReadBlocking(EXAMPLE_USART, &ch, 1);

               /* Send the received character to the terminal. */

                       /*将读取的串口数据数据发送出去*/

              USART_WriteBlocking(EXAMPLE_USART, &ch, 1);

          }

      }

 

★博文内容均由个人提供,与平台无关,如有违法或侵权,请与网站管理员联系。

★文明上网,请理性发言。内容一周内被举报5次,发文人进小黑屋喔~

评论