21、STM32F1系列HAL库 源码注释汉化 stm32f1xx_hal_usart.c

压缩包被破解了,摆烂了,链接没了,有需要的直接在文章里复制吧。

到发文时为止,已汉化内容:

  • HAL库驱动头文件(hal.h文件,48个)
  • HAL库驱动文件(hal.c 文件,42个)
  • 外设访问层头文件(stm32f1xxx.h 寄存器宏定义文件,15个)
  • 工具链向量表(.s文件,43个)
  • LL库(正在进行)
  • ...

 本汉化只对库中注释进行汉化,所有原版校对完成的文件,实际代码均与官方原库一致 使用方法按官方库即可。(除部分原版代码报错的调整,修改条目见:使用说明)

源库文件来自ST官网:

版本:V1.8.0 + V1.8.5更新补丁(2023/10/7(官方更新记录2023/4/7))

/**
  ******************************************************************************
  * @file    stm32f1xx_hal_usart.c
  * @author  MCD Application Team
  * @brief   HAL库 USART 模块驱动
  *          该文件提供固件函数,用于管理通用同步/异步接收器/发送器(USART)外设的以下功能:
  *           + 初始化和反初始化函数
  *           + IO 操作函数
  *           + 外设控制函数
  *
  ******************************************************************************
  * @attention
  *
  * 版权所有 (c) 2016 STMicroelectronics。
  * 保留所有权利。
  *
  * 本软件根据可以在此软件组件的根目录中找到的 LICENSE 文件中的条款进行许可。
  * 如果此软件没有附带 LICENSE 文件,则按原样提供。
  *
  ******************************************************************************
  @verbatim
  ==============================================================================
                        ##### 如何使用驱动 #####
  ==============================================================================
  [..]
    USART HAL驱动程序可按以下方式使用:

    (#) 声明一个 USART_HandleTypeDef 句柄结构(例如:USART_HandleTypeDef husart)。
    (#) 通过实现 HAL_USART_MspInit() API来初始化USART底层资源:
        (##) 启用 USARTx 接口时钟。
        (##) USART 引脚配置:
             (+++) 启用 USART GPIO 的时钟。
             (+++) 将 USART 引脚配置为复用上拉功能(通常为复用开漏输出+外部上拉电阻)。
        (##) 如果需要使用中断处理(HAL_USART_Transmit_IT()、HAL_USART_Receive_IT()和HAL_USART_TransmitReceive_IT() API)则需要进行NVIC配置:
             (+++) 配置 USARTx 中断优先级。
             (+++) 启用 NVIC USART IRQ 句柄。
        (##) 如果需要使用DMA处理(HAL_USART_Transmit_DMA()、HAL_USART_Receive_DMA()和HAL_USART_TransmitReceive_DMA() API)则需要进行DMA配置:
             (+++) 为 Tx/Rx 通道声明一个DMA句柄结构。
             (+++) 启用DMAx接口时钟。
             (+++) 使用所需的 Tx/Rx 参数配置声明的DMA句柄结构。
             (+++) 配置DMA Tx/Rx 通道。
             (+++) 将初始化的DMA句柄与 USART DMA Tx/Rx 句柄关联。
             (+++) 配置传输完成中断的优先级并启用 DMA Tx/Rx 通道上的NVIC。
             (+++) 配置USARTx中断优先级并启用 NVIC USART IRQ 句柄
                   (用于在DMA非循环模式下检测最后一个字节的发送完成)

    (#) 在 husart Init 结构中设置波特率、数据位长度、停止位、奇偶校验、硬件流控制和模式(接收器/发送器)

    (#) 通过调用 HAL_USART_Init() API来初始化USART寄存器:
        (++) 这些API还通过调用定制的 HAL_USART_MspInit(&husart) API来配置低级硬件GPIO、时钟、CORTEX等。

        -@@- 特定的USART中断(传输完成中断、RXNE(接收缓冲非空)中断和错误中断)将使用宏 __HAL_USART_ENABLE_IT() 和 __HAL_USART_DISABLE_IT() 在传输和接收过程中进行管理。

    (#) 此驱动程序内可用三种操作模式:

     *** 轮询模式 IO 操作 ***
     =================================
     [..]
       (+) 阻塞模式下发送数据使用 HAL_USART_Transmit()。
       (+) 阻塞模式下接收数据使用 HAL_USART_Receive()。

     *** 中断模式 IO 操作 ***
     ===================================
     [..]
       (+) 非阻塞模式下发送数据使用 HAL_USART_Transmit_IT()。
       (+) 在传输结束时执行 HAL_USART_TxHalfCpltCallback() 并且用户可以通过自定义函数指针 HAL_USART_TxCpltCallback 添加自己的代码。

       (+) 非阻塞模式下接收数据使用 HAL_USART_Receive_IT()。
       (+) 在接收结束时执行 HAL_USART_RxCpltCallback() 并且用户可以通过自定义函数指针 HAL_USART_RxCpltCallback 添加自己的代码。

       (+) 在传输错误时执行 HAL_USART_ErrorCallback() 并且用户可以通过自定义函数指针 HAL_USART_ErrorCallback 添加自己的代码。

     *** DMA 模式 IO 操作 ***
     ==============================
     [..]
       (+) 通过DMA以非阻塞模式发送数据使用 HAL_USART_Transmit_DMA()。
       (+) 在发送过半时执行 HAL_USART_TxHalfCpltCallback() 并且用户可以通过自定义函数指针 HAL_USART_TxHalfCpltCallback 添加自己的代码。
       (+) 在发送结束时执行 HAL_USART_TxCpltCallback() 并且用户可以通过自定义函数指针 HAL_USART_TxCpltCallback 添加自己的代码。

       (+) 通过DMA以非阻塞模式接收数据使用 HAL_USART_Receive_DMA()。
       (+) 在接收过半时执行 HAL_USART_RxHalfCpltCallback() 并且用户可以通过自定义函数指针 HAL_USART_RxHalfCpltCallback 添加自己的代码。
       (+) 在接收结束时执行 HAL_USART_RxCpltCallback() 并且用户可以通过自定义函数指针 HAL_USART_RxCpltCallback 添加自己的代码。

       (+) 在传输错误时执行 HAL_USART_ErrorCallback() 并且用户可以通过自定义函数指针 HAL_USART_ErrorCallback 添加自己的代码。
       (+) 使用 HAL_USART_DMAPause() 暂停DMA传输。
       (+) 使用 HAL_USART_DMAResume() 恢复DMA传输。
       (+) 使用 HAL_USART_DMAStop() 停止DMA传输。

     *** USART HAL 驱动宏列表 ***
     =============================================
     [..]
       下面是USART HAL驱动程序中最常用的宏列表。

       (+) __HAL_USART_ENABLE:      启用USART外设。
       (+) __HAL_USART_DISABLE:     禁用USART外设。
       (+) __HAL_USART_GET_FLAG :   检查指定的USART标志是否已设置。
       (+) __HAL_USART_CLEAR_FLAG : 清除指定的USART挂起标志。
       (+) __HAL_USART_ENABLE_IT:   启用指定的USART中断。
       (+) __HAL_USART_DISABLE_IT:  禁用指定的USART中断。

     [..]
       (@) 您可以参考USART HAL驱动程序头文件以获取更多有用的宏。

    ##### 注册/注销回调 #####
    ==================================

    [..]
    当编译宏 USE_HAL_USART_REGISTER_CALLBACKS 被设置为 1 时,允许用户动态配置驱动程序回调函数。

    [..]
    使用函数 @ref HAL_USART_RegisterCallback() 来注册用户回调函数。
    函数 @ref HAL_USART_RegisterCallback() 允许注册以下回调函数:
    (+) TxHalfCpltCallback        : 发送过半回调
    (+) TxCpltCallback            : 发送完成回调
    (+) RxHalfCpltCallback        : 接收过半回调
    (+) RxCpltCallback            : 接收完成回调
    (+) TxRxCpltCallback          : 发送接收完成回调
    (+) ErrorCallback             : 错误回调
    (+) AbortCpltCallback         : 中止完成回调
    (+) MspInitCallback           : USART MspInit 回调
    (+) MspDeInitCallback         : USART MspDeInit 回调
    该函数的参数包括HAL外设句柄、回调ID和指向用户回调函数的指针。

    [..]
    使用函数 @ref HAL_USART_UnRegisterCallback() 来将回调函数重置为默认的预定义弱回调函数。
    @ref HAL_USART_UnRegisterCallback() 函数的参数包括HAL外设句柄和回调ID。
    该函数允许重置以下回调函数:
    (+) TxHalfCpltCallback        : 发送过半回调
    (+) TxCpltCallback            : 发送完成回调
    (+) RxHalfCpltCallback        : 接收过半回调
    (+) RxCpltCallback            : 接收完成回调
    (+) TxRxCpltCallback          : 发送接收完成回调
    (+) ErrorCallback             : 错误回调
    (+) AbortCpltCallback         : 中止完成回调
    (+) MspInitCallback           : USART MspInit 回调
    (+) MspDeInitCallback         : USART MspDeInit 回调

    [..]
    默认情况下,在 @ref HAL_USART_Init() 之后,当状态为 HAL_USART_STATE_RESET 时,所有回调函数都被设置为预定义弱回调函数:
    例如 @ref HAL_USART_TxCpltCallback()、@ref HAL_USART_RxHalfCpltCallback()。
    MspInit 和 MspDeInit 函数是例外,只有当这些回调函数为空(之前未注册)时,它们在 @ref HAL_USART_Init() 和 @ref HAL_USART_DeInit() 中被分别重置为预定义弱回调函数。
    如果不是,MspInit 或 MspDeInit 不为空,那么 @ref HAL_USART_Init() 和 @ref HAL_USART_DeInit() 将保留并使用用户的 MspInit/MspDeInit 回调函数(之前已注册)。

    [..]
    回调函数只能在 HAL_USART_STATE_READY 状态下注册/注销。
    MspInit/MspDeInit 是例外,它们可以在 HAL_USART_STATE_READY 或 HAL_USART_STATE_RESET 状态下注册/注销,因此注册(用户)的 MspInit/DeInit 回调函数可以在初始化/反初始化期间使用。
    在这种情况下,首先使用 @ref HAL_USART_RegisterCallback() 注册 MspInit/MspDeInit 用户回调函数,然后再调用 @ref HAL_USART_DeInit() 或 @ref HAL_USART_Init() 函数。

    [..]
    当编译宏 USE_HAL_USART_REGISTER_CALLBACKS 被设置为 0 或未定义时,回调注册功能不可用,并且将使用预定义弱回调函数。

  @endverbatim
     [..]
       (@) 附加说明:如果启用了奇偶校验,那么奇偶校验位将被写入数据寄存器中数据的最高位,随后被传输。
           (也就是说数据的最高位将会被奇偶校验位替换,要注意校验位对数据的影响)
           根据由 M 位(8位或9位)定义的帧长度,可能的USART帧格式如下表所示:
    +-----------------------------------------------------------------------+
    |   M 位  |  校验使能  |                        USART 帧                 |
    |---------------------|-------------------------------------------------|
    |    0    |    0      |    | 起始位 | 8 数据位 | 停止位 |                 |
    |---------|-----------|-------------------------------------------------|
    |    0    |    1      |    | 起始位 | 7 数据位 | 奇偶校验位 | 停止位 |     |
    |---------|-----------|-------------------------------------------------|
    |    1    |    0      |    | 起始位 | 9 数据位 | 停止位 |                  |
    |---------|-----------|--------------------------------------------------|
    |    1    |    1      |    | 起始位 | 8 数据位 | 奇偶校验位 | 停止位 |     |
    +------------------------------------------------------------------------+
  ******************************************************************************
  */

/* 头文件 ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"

/** @addtogroup STM32F1xx_HAL_Driver
  * @{
  */

/** @defgroup USART USART
  * @brief HAL USART 同步模块驱动
  * @{
  */
#ifdef HAL_USART_MODULE_ENABLED
/* 私有类型 -----------------------------------------------------------*/
/* 私有定义 ------------------------------------------------------------*/
/** @addtogroup USART_Private_Constants
  * @{
  */
#define DUMMY_DATA           0xFFFFU
#define USART_TIMEOUT_VALUE  22000U
/**
  * @}
  */
/* 私有宏 -------------------------------------------------------------*/
/* 私有变量 ---------------------------------------------------------*/
/* 私有函数原型 -----------------------------------------------*/
/* 私有函数 ---------------------------------------------------------*/
/** @addtogroup USART_Private_Functions
  * @{
  */
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
void USART_InitCallbacksToDefault(USART_HandleTypeDef *husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
static void USART_EndTxTransfer(USART_HandleTypeDef *husart);
static void USART_EndRxTransfer(USART_HandleTypeDef *husart);
static HAL_StatusTypeDef USART_Transmit_IT(USART_HandleTypeDef *husart);
static HAL_StatusTypeDef USART_EndTransmit_IT(USART_HandleTypeDef *husart);
static HAL_StatusTypeDef USART_Receive_IT(USART_HandleTypeDef *husart);
static HAL_StatusTypeDef USART_TransmitReceive_IT(USART_HandleTypeDef *husart);
static void USART_SetConfig(USART_HandleTypeDef *husart);
static void USART_DMATransmitCplt(DMA_HandleTypeDef *hdma);
static void USART_DMATxHalfCplt(DMA_HandleTypeDef *hdma);
static void USART_DMAReceiveCplt(DMA_HandleTypeDef *hdma);
static void USART_DMARxHalfCplt(DMA_HandleTypeDef *hdma);
static void USART_DMAError(DMA_HandleTypeDef *hdma);
static void USART_DMAAbortOnError(DMA_HandleTypeDef *hdma);
static void USART_DMATxAbortCallback(DMA_HandleTypeDef *hdma);
static void USART_DMARxAbortCallback(DMA_HandleTypeDef *hdma);

static HAL_StatusTypeDef USART_WaitOnFlagUntilTimeout(USART_HandleTypeDef *husart, uint32_t Flag, FlagStatus Status,
                                                      uint32_t Tickstart, uint32_t Timeout);
/**
  * @}
  */

/* 导出函数 --------------------------------------------------------*/
/** @defgroup USART_Exported_Functions USART 导出函数
  * @{
  */

/** @defgroup USART_Exported_Functions_Group1 USART 初始化和反初始化函数
  *  @brief    初始化和配置函数
  *
@verbatim
  ==============================================================================
              ##### 初始化和配置函数 #####
  ==============================================================================
  [..]
  本节提供了一组函数,允许在异步和同步模式下初始化USART。
  (+) 仅针对异步模式,可以配置以下参数:
      (++) 波特率
      (++) 数据位长度
      (++) 停止位
      (++) 奇偶校验:如果启用奇偶校验,那么写入数据寄存器的数据的最高位将被传输,但会被奇偶校验位改变。
                    根据由 M 位定义的帧长度(8位或9位),请参考参考手册了解可能的USART帧格式。
      (++) USART极性
      (++) USART相位
      (++) USART最后一位
      (++) 接收器/发送器模式

  [..]
    HAL_USART_Init() 函数遵循USART同步配置过程(有关过程的详细信息,请参阅参考手册(针对STM32F10Xxx微控制器的RM0008和针对STM32F100xx微控制器的RM0041))。

@endverbatim
  * @{
  */

/**
  * @brief  初始化USART模式,并初始化相关的句柄(根据 USART_InitTypeDef 中指定的参数)
  * @param  husart 指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_Init(USART_HandleTypeDef *husart)
{
  /* 检查句柄 */
  if (husart == NULL)
  {
    return HAL_ERROR;
  }

  /* 清除参数 */
  assert_param(IS_USART_INSTANCE(husart->Instance));

  if (husart->State == HAL_USART_STATE_RESET)
  {
    /* 分配锁资源并初始化 */
    husart->Lock = HAL_UNLOCKED;

#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
    USART_InitCallbacksToDefault(husart);

    if (husart->MspInitCallback == NULL)
    {
      husart->MspInitCallback = HAL_USART_MspInit;
    }

    /* 初始化底层硬件 */
    husart->MspInitCallback(husart);
#else
    /* 初始化底层硬件 : GPIO, CLOCK */
    HAL_USART_MspInit(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
  }

  husart->State = HAL_USART_STATE_BUSY;

  /* 设置 USART 通信参数 */
  USART_SetConfig(husart);

  /* 在USART模式下,必须保持以下位清零:
     - USART_CR2(控制寄存器2)中的 LINEN(LIN模式使能)位
     - USART_CR3(控制寄存器3)中的 HDSEL(半双工选择)、SCEN(智能卡模式使能)和 IREN(红外模式使能)位 */
  CLEAR_BIT(husart->Instance->CR2, USART_CR2_LINEN);
  CLEAR_BIT(husart->Instance->CR3, (USART_CR3_SCEN | USART_CR3_HDSEL | USART_CR3_IREN));

  /* 启用外设 */
  __HAL_USART_ENABLE(husart);

  /* 初始化 USART 状态 */
  husart->ErrorCode = HAL_USART_ERROR_NONE;
  husart->State = HAL_USART_STATE_READY;

  return HAL_OK;
}

/**
  * @brief  反初始化 USART 外设
  * @param  husart 指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_DeInit(USART_HandleTypeDef *husart)
{
  /* 检查句柄 */
  if (husart == NULL)
  {
    return HAL_ERROR;
  }

  /* 清除参数 */
  assert_param(IS_USART_INSTANCE(husart->Instance));

  husart->State = HAL_USART_STATE_BUSY;

  /* 禁用外设 */
  __HAL_USART_DISABLE(husart);

#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
  if (husart->MspDeInitCallback == NULL)
  {
    husart->MspDeInitCallback = HAL_USART_MspDeInit;
  }
  /* 反初始化底层硬件 */
  husart->MspDeInitCallback(husart);
#else
  /* 反初始化底层硬件 */
  HAL_USART_MspDeInit(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */

  husart->ErrorCode = HAL_USART_ERROR_NONE;
  husart->State = HAL_USART_STATE_RESET;

  /* 释放锁 */
  __HAL_UNLOCK(husart);

  return HAL_OK;
}

/**
  * @brief  USART MSP 初始化
  * @param  husart 指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @retval None
  */
__weak void HAL_USART_MspInit(USART_HandleTypeDef *husart)
{
  /* 防止未使用参数的编译警告 */
  UNUSED(husart);
  /* NOTE: 当需要回调函数时,不应修改此函数,可以在用户文件中重写以覆盖此函数。
   */
}

/**
  * @brief  USART MSP 反初始化
  * @param  husart 指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @retval None
  */
__weak void HAL_USART_MspDeInit(USART_HandleTypeDef *husart)
{
  /* 防止未使用参数的编译警告 */
  UNUSED(husart);
  /* NOTE: 当需要回调函数时,不应修改此函数,可以在用户文件中重写以覆盖此函数。
   */
}

#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
/**
  * @brief  注册用户的 USART 回调
  *         (替代预定义弱回调函数)
  * @note   在 HAL_USART_STATE_RESET 状态下,可以在 HAL_USART_Init() 之前调用 HAL_USART_RegisterCallback(),
  *         以注册 HAL_USART_MSPINIT_CB_ID 和 HAL_USART_MSPDEINIT_CB_ID 的回调。
  * @param  husart usart 句柄
  * @param  CallbackID 要注册的回调ID
  *         该参数可以是以下数值之一:
  *           @arg @ref HAL_USART_TX_HALFCOMPLETE_CB_ID   发送过半回调 ID
  *           @arg @ref HAL_USART_TX_COMPLETE_CB_ID       发送完成回调 ID
  *           @arg @ref HAL_USART_RX_HALFCOMPLETE_CB_ID   接收过半回调 ID
  *           @arg @ref HAL_USART_RX_COMPLETE_CB_ID       接收完成回调 ID
  *           @arg @ref HAL_USART_TX_RX_COMPLETE_CB_ID    发送接收完成回调 ID
  *           @arg @ref HAL_USART_ERROR_CB_ID             错误回调 ID
  *           @arg @ref HAL_USART_ABORT_COMPLETE_CB_ID    中止完成回调 ID
  *           @arg @ref HAL_USART_MSPINIT_CB_ID           MspInit 回调 ID
  *           @arg @ref HAL_USART_MSPDEINIT_CB_ID         MspDeInit 回调 ID
  * @param  pCallback 回调函数指针
  * @retval HAL status
+  */
HAL_StatusTypeDef HAL_USART_RegisterCallback(USART_HandleTypeDef *husart, HAL_USART_CallbackIDTypeDef CallbackID,
                                             pUSART_CallbackTypeDef pCallback)
{
  HAL_StatusTypeDef status = HAL_OK;

  if (pCallback == NULL)
  {
    /* 更新错误回调 */
    husart->ErrorCode |= HAL_USART_ERROR_INVALID_CALLBACK;

    return HAL_ERROR;
  }

  if (husart->State == HAL_USART_STATE_READY)
  {
    switch (CallbackID)
    {
      case HAL_USART_TX_HALFCOMPLETE_CB_ID :
        husart->TxHalfCpltCallback = pCallback;
        break;

      case HAL_USART_TX_COMPLETE_CB_ID :
        husart->TxCpltCallback = pCallback;
        break;

      case HAL_USART_RX_HALFCOMPLETE_CB_ID :
        husart->RxHalfCpltCallback = pCallback;
        break;

      case HAL_USART_RX_COMPLETE_CB_ID :
        husart->RxCpltCallback = pCallback;
        break;

      case HAL_USART_TX_RX_COMPLETE_CB_ID :
        husart->TxRxCpltCallback = pCallback;
        break;

      case HAL_USART_ERROR_CB_ID :
        husart->ErrorCallback = pCallback;
        break;

      case HAL_USART_ABORT_COMPLETE_CB_ID :
        husart->AbortCpltCallback = pCallback;
        break;

      case HAL_USART_MSPINIT_CB_ID :
        husart->MspInitCallback = pCallback;
        break;

      case HAL_USART_MSPDEINIT_CB_ID :
        husart->MspDeInitCallback = pCallback;
        break;

      default :
        /* 更新错误回调 */
        husart->ErrorCode |= HAL_USART_ERROR_INVALID_CALLBACK;

        /* 返回错误状态 */
        status =  HAL_ERROR;
        break;
    }
  }
  else if (husart->State == HAL_USART_STATE_RESET)
  {
    switch (CallbackID)
    {
      case HAL_USART_MSPINIT_CB_ID :
        husart->MspInitCallback = pCallback;
        break;

      case HAL_USART_MSPDEINIT_CB_ID :
        husart->MspDeInitCallback = pCallback;
        break;

      default :
        /* 更新错误回调 */
        husart->ErrorCode |= HAL_USART_ERROR_INVALID_CALLBACK;

        /* 返回错误状态 */
        status =  HAL_ERROR;
        break;
    }
  }
  else
  {
    /* 更新错误回调 */
    husart->ErrorCode |= HAL_USART_ERROR_INVALID_CALLBACK;

    /* 返回错误状态 */
    status =  HAL_ERROR;
  }

  return status;
}

/**
  * @brief  注销用户的 USART 回调
  *         (重置回调为默认的预定义弱回调函数)
  * @note   在 HAL_USART_STATE_RESET 状态下,可以在 HAL_USART_Init() 之前调用 HAL_USART_UnRegisterCallback(),
  *         以注销 HAL_USART_MSPINIT_CB_ID 和 HAL_USART_MSPDEINIT_CB_ID 的回调。
  * @param  husart usart 句柄
  * @param  CallbackID 要注销的回调ID
  *         该参数可以是以下数值之一:
  *           @arg @ref HAL_USART_TX_HALFCOMPLETE_CB_ID   发送过半回调 ID
  *           @arg @ref HAL_USART_TX_COMPLETE_CB_ID       发送完成回调 ID
  *           @arg @ref HAL_USART_RX_HALFCOMPLETE_CB_ID   接收过半回调 ID
  *           @arg @ref HAL_USART_RX_COMPLETE_CB_ID       接收完成回调 ID
  *           @arg @ref HAL_USART_TX_RX_COMPLETE_CB_ID    发送接收完成回调 ID
  *           @arg @ref HAL_USART_ERROR_CB_ID             错误回调 ID
  *           @arg @ref HAL_USART_ABORT_COMPLETE_CB_ID    中止完成回调 ID
  *           @arg @ref HAL_USART_MSPINIT_CB_ID           MspInit 回调 ID
  *           @arg @ref HAL_USART_MSPDEINIT_CB_ID         MspDeInit 回调 ID
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_UnRegisterCallback(USART_HandleTypeDef *husart, HAL_USART_CallbackIDTypeDef CallbackID)
{
  HAL_StatusTypeDef status = HAL_OK;

  if (husart->State == HAL_USART_STATE_READY)
  {
    switch (CallbackID)
    {
      case HAL_USART_TX_HALFCOMPLETE_CB_ID :
        husart->TxHalfCpltCallback = HAL_USART_TxHalfCpltCallback;               /* 预定义弱回调函数  TxHalfCpltCallback       */
        break;

      case HAL_USART_TX_COMPLETE_CB_ID :
        husart->TxCpltCallback = HAL_USART_TxCpltCallback;                       /* 预定义弱回调函数 TxCpltCallback            */
        break;

      case HAL_USART_RX_HALFCOMPLETE_CB_ID :
        husart->RxHalfCpltCallback = HAL_USART_RxHalfCpltCallback;               /* 预定义弱回调函数 RxHalfCpltCallback        */
        break;

      case HAL_USART_RX_COMPLETE_CB_ID :
        husart->RxCpltCallback = HAL_USART_RxCpltCallback;                       /* 预定义弱回调函数 RxCpltCallback            */
        break;

      case HAL_USART_TX_RX_COMPLETE_CB_ID :
        husart->TxRxCpltCallback = HAL_USART_TxRxCpltCallback;                   /* 预定义弱回调函数 TxRxCpltCallback            */
        break;

      case HAL_USART_ERROR_CB_ID :
        husart->ErrorCallback = HAL_USART_ErrorCallback;                         /* 预定义弱回调函数 ErrorCallback             */
        break;

      case HAL_USART_ABORT_COMPLETE_CB_ID :
        husart->AbortCpltCallback = HAL_USART_AbortCpltCallback;                 /* 预定义弱回调函数 AbortCpltCallback         */
        break;

      case HAL_USART_MSPINIT_CB_ID :
        husart->MspInitCallback = HAL_USART_MspInit;                             /* 预定义弱回调函数 MspInitCallback           */
        break;

      case HAL_USART_MSPDEINIT_CB_ID :
        husart->MspDeInitCallback = HAL_USART_MspDeInit;                         /* 预定义弱回调函数 MspDeInitCallback         */
        break;

      default :
        /* 更新错误回调 */
        husart->ErrorCode |= HAL_USART_ERROR_INVALID_CALLBACK;

        /* 返回错误状态 */
        status =  HAL_ERROR;
        break;
    }
  }
  else if (husart->State == HAL_USART_STATE_RESET)
  {
    switch (CallbackID)
    {
      case HAL_USART_MSPINIT_CB_ID :
        husart->MspInitCallback = HAL_USART_MspInit;
        break;

      case HAL_USART_MSPDEINIT_CB_ID :
        husart->MspDeInitCallback = HAL_USART_MspDeInit;
        break;

      default :
        /* 更新错误回调 */
        husart->ErrorCode |= HAL_USART_ERROR_INVALID_CALLBACK;

        /* 返回错误状态 */
        status =  HAL_ERROR;
        break;
    }
  }
  else
  {
    /* 更新错误回调 */
    husart->ErrorCode |= HAL_USART_ERROR_INVALID_CALLBACK;

    /* 返回错误状态 */
    status =  HAL_ERROR;
  }

  return status;
}
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */

/**
  * @}
  */

/** @defgroup USART_Exported_Functions_Group2 IO 操作函数
  *  @brief   USART 发送和接收函数
  *
@verbatim
  ==============================================================================
                         ##### IO 操作函数 #####
  ==============================================================================
  [..]
    本节提供了一组函数,用于管理 USART 的同步数据传输。

  [..]
    USART 仅支持主模式:它不能 接收或发送 与 输入时钟相关的数据(SCLK 始终是输出)。

    (#) 有两种传输模式:
        (++) 阻塞模式:通信以轮询模式进行。所有数据处理的 HAL 状态在传输完成后由同一函数返回。
        (++) 非阻塞模式:通信使用中断或 DMA 进行。这些 API 返回 HAL 状态。
             数据处理的结束将通过专用的 USART IRQ(使用中断模式)或 DMA IRQ(使用 DMA 模式)指示。
             当使用中断模式时,将分别执行 HAL_USART_TxCpltCallback()、HAL_USART_RxCpltCallback() 和 HAL_USART_TxRxCpltCallback() 用户回调函数,
             在传输或接收过程结束时执行 HAL_USART_ErrorCallback() 用户回调函数,以侦测通信错误。

    (#) 阻塞模式的 API 包括:
        (++) HAL_USART_Transmit()         单工模式下
        (++) HAL_USART_Receive()          全双工接收模式下
        (++) HAL_USART_TransmitReceive()  全双工模式下

    (#) 使用中断的非阻塞模式 API 包括:
        (++) HAL_USART_Transmit_IT()        单工模式下
        (++) HAL_USART_Receive_IT()         全双工接收模式下
        (++) HAL_USART_TransmitReceive_IT() 全双工模式下
        (++) HAL_USART_IRQHandler()

    (#) Non Blocking mode functions with DMA are :
        (++) HAL_USART_Transmit_DMA()         单工模式下
        (++) HAL_USART_Receive_DMA()          全双工接收模式下
        (++) HAL_USART_TransmitReceive_DMA()  全双工模式下
        (++) HAL_USART_DMAPause()
        (++) HAL_USART_DMAResume()
        (++) HAL_USART_DMAStop()

    (#) 非阻塞模式提供了一组传输完成回调函数:
        (++) HAL_USART_TxHalfCpltCallback()
        (++) HAL_USART_TxCpltCallback()
        (++) HAL_USART_RxHalfCpltCallback()
        (++) HAL_USART_RxCpltCallback()
        (++) HAL_USART_ErrorCallback()
        (++) HAL_USART_TxRxCpltCallback()

    (#) 可以使用中止 API 中止非阻塞模式传输:
        (++) HAL_USART_Abort()
        (++) HAL_USART_Abort_IT()

    (#) 对于基于中断的中止服务(HAL_USART_Abort_IT),提供了中止完成回调函数:
        (++) HAL_USART_AbortCpltCallback()

    (#) 在非阻塞模式传输中,可能出现的错误分为两类。
        错误处理如下:
        (++) 错误被视为可恢复且非阻塞:传输可以继续进行,但错误严重程度由用户评估:这涉及中断模式接收中的帧错误、奇偶校验错误或噪声错误。
             然后检索接收到的字符并将其存储在 Rx 缓冲区中,设置错误代码以便用户识别错误类型,并执行 HAL_USART_ErrorCallback() 用户回调函数。
             传输在 USART 端保持进行中。如果用户希望中止它,应由用户调用中止服务。
        (++) 错误被视为阻塞:传输无法正确完成并被中止。这涉及中断模式接收中的溢出错误和 DMA 模式中的所有错误。
             设置错误代码以便用户识别错误类型,并执行 HAL_USART_ErrorCallback() 用户回调函数。

@endverbatim
  * @{
  */

/**
  * @brief  单工 发送一定数量的数据(阻塞模式)
  * @note   当 USART 奇偶校验未启用(PCE = 0)且字长配置为 9 位(M1-M0 = 01)时,
  *         发送的数据将被视为一组 u16。
  *         在这种情况下,Size 必须指示通过 pTxData 提供的 u16 数量。
  * @param  husart  指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @param  pTxData 指向数据缓冲区的指针(u8 或 u16 数据元素)
  * @param  Size    要发送的数据(u8 或 u16)的数量。
  * @param  Timeout 超时持续时间。
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_Transmit(USART_HandleTypeDef *husart, const uint8_t *pTxData, uint16_t Size, uint32_t Timeout)
{
  const uint8_t  *ptxdata8bits;
  const uint16_t *ptxdata16bits;
  uint32_t tickstart;

  if (husart->State == HAL_USART_STATE_READY)
  {
    if ((pTxData == NULL) || (Size == 0))
    {
      return  HAL_ERROR;
    }

    /* 进程锁定 */
    __HAL_LOCK(husart);

    husart->ErrorCode = HAL_USART_ERROR_NONE;
    husart->State = HAL_USART_STATE_BUSY_TX;

    /* 为超时管理初始化滴答 */
    tickstart = HAL_GetTick();

    husart->TxXferSize = Size;
    husart->TxXferCount = Size;

    /* 在使用 9 位&无奇偶校验传输时,pTxData 需要被视为 uint16_t 指针处理。 */
    if ((husart->Init.WordLength == USART_WORDLENGTH_9B) && (husart->Init.Parity == USART_PARITY_NONE))
    {
      ptxdata8bits  = NULL;
      ptxdata16bits = (const uint16_t *) pTxData;
    }
    else
    {
      ptxdata8bits  = pTxData;
      ptxdata16bits = NULL;
    }

    while (husart->TxXferCount > 0U)
    {
      /* 等待 TXE(发送缓冲空)标志位以便向数据寄存器(DR)写入数据 */
      if (USART_WaitOnFlagUntilTimeout(husart, USART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)
      {
        return HAL_TIMEOUT;
      }
      if (ptxdata8bits == NULL)
      {
        husart->Instance->DR = (uint16_t)(*ptxdata16bits & (uint16_t)0x01FF);
        ptxdata16bits++;
      }
      else
      {
        husart->Instance->DR = (uint8_t)(*ptxdata8bits & (uint8_t)0xFF);
        ptxdata8bits++;
      }

      husart->TxXferCount--;
    }

    if (USART_WaitOnFlagUntilTimeout(husart, USART_FLAG_TC, RESET, tickstart, Timeout) != HAL_OK)
    {
      return HAL_TIMEOUT;
    }

    husart->State = HAL_USART_STATE_READY;

    /* 进程解锁 */
    __HAL_UNLOCK(husart);

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

/**
  * @brief  全双工 接收一定数量的数据(阻塞模式)
  * @note   为了接收同步数据,同时传输虚拟数据。
  * @note   当 USART 奇偶校验未启用(PCE = 0)且字长配置为 9 位(M1-M0 = 01)时,
  *         接收到的数据被视为一组 u16。
  *         在这种情况下,Size 必须指示通过 pRxData 可用的 u16 数量。
  * @param  husart  指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @param  pRxData 指向数据缓冲区的指针(u8 或 u16 数据元素)
  * @param  Size    要接收的数据(u8 或 u16)的数量。
  * @param  Timeout 超时持续时间。
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_Receive(USART_HandleTypeDef *husart, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)
{
  uint8_t  *prxdata8bits;
  uint16_t *prxdata16bits;
  uint32_t tickstart;

  if (husart->State == HAL_USART_STATE_READY)
  {
    if ((pRxData == NULL) || (Size == 0))
    {
      return  HAL_ERROR;
    }
    /* 进程锁定 */
    __HAL_LOCK(husart);

    husart->ErrorCode = HAL_USART_ERROR_NONE;
    husart->State = HAL_USART_STATE_BUSY_RX;

    /* 为超时管理初始化滴答 */
    tickstart = HAL_GetTick();

    husart->RxXferSize = Size;
    husart->RxXferCount = Size;

    /* 在使用 9 位&无奇偶校验传输时,pRxData 需要被视为 uint16_t 指针处理。 */
    if ((husart->Init.WordLength == USART_WORDLENGTH_9B) && (husart->Init.Parity == USART_PARITY_NONE))
    {
      prxdata8bits  = NULL;
      prxdata16bits = (uint16_t *) pRxData;
    }
    else
    {
      prxdata8bits  = pRxData;
      prxdata16bits = NULL;
    }

    /* 检查剩余待接收的数据 */
    while (husart->RxXferCount > 0U)
    {
      /* 等待直到 TXE(发送缓冲空)标志位设置,以发送虚拟字节以生成时钟,以便从设备发送数据。
      * 无论帧长度(7、8 或 9 位),都可以为所有情况写入相同的虚拟值。 */
      if (USART_WaitOnFlagUntilTimeout(husart, USART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)
      {
        return HAL_TIMEOUT;
      }
      husart->Instance->DR = (DUMMY_DATA & (uint16_t)0x0FF);

      /* 等待直到 RXNE(接收缓冲非空)标志位设置以接收字节 */
      if (USART_WaitOnFlagUntilTimeout(husart, USART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
      {
        return HAL_TIMEOUT;
      }

      if (prxdata8bits == NULL)
      {
        *prxdata16bits = (uint16_t)(husart->Instance->DR & (uint16_t)0x01FF);
        prxdata16bits++;
      }
      else
      {
        if ((husart->Init.WordLength == USART_WORDLENGTH_9B) || ((husart->Init.WordLength == USART_WORDLENGTH_8B) && (husart->Init.Parity == USART_PARITY_NONE)))
        {
          *prxdata8bits = (uint8_t)(husart->Instance->DR & (uint8_t)0x0FF);
        }
        else
        {
          *prxdata8bits = (uint8_t)(husart->Instance->DR & (uint8_t)0x07F);
        }
        prxdata8bits++;
      }
      husart->RxXferCount--;
    }

    husart->State = HAL_USART_STATE_READY;

    /* 进程解锁 */
    __HAL_UNLOCK(husart);

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

/**
  * @brief  全双工 发送并接收一定数量的数据(阻塞模式)
  * @note   当 USART 奇偶校验未启用(PCE = 0)且字长配置为 9 位(M1-M0 = 01)时,
  *         发送的数据和接收的数据被视为一组 u16。
  *         在这种情况下,Size 必须指示通过 pTxData 和 pRxData 可用的 u16 数量。
  * @param  husart  指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @param  pTxData 指向 TX 数据缓冲区(u8 或 u16 数据元素)的指针。
  * @param  pRxData 指向 RX 数据缓冲区(u8 或 u16 数据元素)的指针。
  * @param  Size    要发送的数据(u8 或 u16)的数量(接收的数量与发送的数量相同)。
  * @param  Timeout 超时时长
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_TransmitReceive(USART_HandleTypeDef *husart, const uint8_t *pTxData, uint8_t *pRxData,
                                            uint16_t Size, uint32_t Timeout)
{
  uint8_t  *prxdata8bits;
  uint16_t *prxdata16bits;
  const uint8_t  *ptxdata8bits;
  const uint16_t *ptxdata16bits;
  uint16_t rxdatacount;
  uint32_t tickstart;

  if (husart->State == HAL_USART_STATE_READY)
  {
    if ((pTxData == NULL) || (pRxData == NULL) || (Size == 0))
    {
      return  HAL_ERROR;
    }

    /* 在进行 9 位&无奇偶校验传输时,作为输入参数提供的 pTxData 和 pRxData 缓冲区应该在 u16 边界上对齐,
       因为要填入 TDR / 从 RDR 检索的数据将通过 u16 强制转换处理。*/
    if ((husart->Init.WordLength == USART_WORDLENGTH_9B) && (husart->Init.Parity == USART_PARITY_NONE))
    {
      if (((((uint32_t)pTxData) & 1U) != 0U) || ((((uint32_t)pRxData) & 1U) != 0U))
      {
        return  HAL_ERROR;
      }
    }
    /* 进程锁定 */
    __HAL_LOCK(husart);

    husart->ErrorCode = HAL_USART_ERROR_NONE;
    husart->State = HAL_USART_STATE_BUSY_RX;

    /* 为超时管理初始化滴答 */
    tickstart = HAL_GetTick();

    husart->RxXferSize = Size;
    husart->TxXferSize = Size;
    husart->TxXferCount = Size;
    husart->RxXferCount = Size;

    /* 在使用 9 位&无奇偶校验传输时,pRxData 需要被视为 uint16_t 指针处理。 */
    if ((husart->Init.WordLength == USART_WORDLENGTH_9B) && (husart->Init.Parity == USART_PARITY_NONE))
    {
      prxdata8bits  = NULL;
      ptxdata8bits  = NULL;
      ptxdata16bits = (const uint16_t *) pTxData;
      prxdata16bits = (uint16_t *) pRxData;
    }
    else
    {
      prxdata8bits  = pRxData;
      ptxdata8bits  = pTxData;
      ptxdata16bits = NULL;
      prxdata16bits = NULL;
    }

    /* 检查剩余待接收的数据 */
    /* rxdatacount 是用于 MISRA C 2012 规则 13.5 的临时变量。 */
    rxdatacount = husart->RxXferCount;
    while ((husart->TxXferCount > 0U) || (rxdatacount > 0U))
    {
      if (husart->TxXferCount > 0U)
      {
        /* 等待 TXE(发送缓冲空)标志位以便向数据寄存器(DR)写入数据 */
        if (USART_WaitOnFlagUntilTimeout(husart, USART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)
        {
          return HAL_TIMEOUT;
        }

        if (ptxdata8bits == NULL)
        {
          husart->Instance->DR = (uint16_t)(*ptxdata16bits & (uint16_t)0x01FF);
          ptxdata16bits++;
        }
        else
        {
          husart->Instance->DR = (uint8_t)(*ptxdata8bits & (uint8_t)0xFF);
          ptxdata8bits++;
        }

        husart->TxXferCount--;
      }

      if (husart->RxXferCount > 0U)
      {
        /* 等待 RXNE(接收缓冲非空)标志置位 */
        if (USART_WaitOnFlagUntilTimeout(husart, USART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
        {
          return HAL_TIMEOUT;
        }
        if (prxdata8bits == NULL)
        {
          *prxdata16bits = (uint16_t)(husart->Instance->DR & (uint16_t)0x01FF);
          prxdata16bits++;
        }
        else
        {
          if ((husart->Init.WordLength == USART_WORDLENGTH_9B) || ((husart->Init.WordLength == USART_WORDLENGTH_8B) && (husart->Init.Parity == USART_PARITY_NONE)))
          {
            *prxdata8bits = (uint8_t)(husart->Instance->DR & (uint8_t)0x0FF);
          }
          else
          {
            *prxdata8bits = (uint8_t)(husart->Instance->DR & (uint8_t)0x07F);
          }

          prxdata8bits++;
        }

        husart->RxXferCount--;
      }
      rxdatacount = husart->RxXferCount;
    }

    husart->State = HAL_USART_STATE_READY;

    /* 进程解锁 */
    __HAL_UNLOCK(husart);

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

/**
  * @brief  单工 发送一定数量的数据 - 中断(非阻塞模式)
  * @note   当 USART 奇偶校验未启用(PCE = 0)且字长配置为 9 位(M1-M0 = 01)时,
  *         发送的数据将被视为一组 u16。
  *         在这种情况下,Size 必须指示通过 pTxData 提供的 u16 数量。
  * @param  husart  指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @param  pTxData 指向数据缓冲区的指针(u8 或 u16 数据元素)
  * @param  Size    要发送的数据(u8 或 u16)的数量。
  * @retval HAL status
  * @note   未对 USART 错误进行处理,以避免溢出错误。
  */
HAL_StatusTypeDef HAL_USART_Transmit_IT(USART_HandleTypeDef *husart, const uint8_t *pTxData, uint16_t Size)
{
  if (husart->State == HAL_USART_STATE_READY)
  {
    if ((pTxData == NULL) || (Size == 0))
    {
      return HAL_ERROR;
    }

    /* 进程锁定 */
    __HAL_LOCK(husart);

    husart->pTxBuffPtr = pTxData;
    husart->TxXferSize = Size;
    husart->TxXferCount = Size;

    husart->ErrorCode = HAL_USART_ERROR_NONE;
    husart->State = HAL_USART_STATE_BUSY_TX;

    /* USART 错误中断(帧错误、噪声错误、溢出错误)未由 USART 发送过程进行管理,以避免溢出中断。
       当 USART 模式配置为发送和接收 "USART_MODE_TX_RX" 时,应该仅配置为仅发送以充分利用帧错误和噪声中断。
       可以使用 __HAL_USART_ENABLE_IT(husart, USART_IT_ERR) 来启用帧错误、噪声错误中断。 */

    /* 进程解锁 */
    __HAL_UNLOCK(husart);

    /* 启用 USART 发送数据寄存器空中断 */
    SET_BIT(husart->Instance->CR1, USART_CR1_TXEIE);

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

/**
  * @brief  单工 接收一定数量的数据 - 中断(非阻塞模式)
  * @note   为了接收同步数据,同时传输虚拟数据。
  * @note   当 USART 奇偶校验未启用(PCE = 0)且字长配置为 9 位(M1-M0 = 01)时,
  *         接收到的数据被视为一组 u16。
  *         在这种情况下,Size 必须指示通过 pRxData 可用的 u16 数量。
  * @param  husart  指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @param  pRxData 指向数据缓冲区的指针(u8 或 u16 数据元素)
  * @param  Size    要接收的数据(u8 或 u16)的数量。
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_Receive_IT(USART_HandleTypeDef *husart, uint8_t *pRxData, uint16_t Size)
{
  if (husart->State == HAL_USART_STATE_READY)
  {
    if ((pRxData == NULL) || (Size == 0))
    {
      return HAL_ERROR;
    }
    /* 进程锁定 */
    __HAL_LOCK(husart);

    husart->pRxBuffPtr = pRxData;
    husart->RxXferSize = Size;
    husart->RxXferCount = Size;

    husart->ErrorCode = HAL_USART_ERROR_NONE;
    husart->State = HAL_USART_STATE_BUSY_RX;

    /* 进程解锁 */
    __HAL_UNLOCK(husart);

    if (husart->Init.Parity != USART_PARITY_NONE)
    {
      /* 启用 USART 奇偶校验错误 和 接收数据寄存器非空中断 */
      SET_BIT(husart->Instance->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE);
    }
    else
    {
      /* 启用 USART 接收数据寄存器非空中断 */
      SET_BIT(husart->Instance->CR1, USART_CR1_RXNEIE);
    }

    /* 启用 USART 错误中断: (帧错误,噪声错误,溢出错误) */
    SET_BIT(husart->Instance->CR3, USART_CR3_EIE);

    /* 发送虚拟字节以生成时钟,以便从设备发送数据。 */
    husart->Instance->DR = (DUMMY_DATA & (uint16_t)0x01FF);

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

/**
  * @brief  全双工 发起并接收一定数量的数据 - (非阻塞模式)
  * @note   当 USART 奇偶校验未启用(PCE = 0)且字长配置为 9 位(M1-M0 = 01)时,
  *         发送的数据和接收的数据被视为一组 u16。
  *         在这种情况下,Size 必须指示通过 pTxData 和 pRxData 可用的 u16 数量。
  * @param  husart  指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @param  pTxData 指向 TX 数据缓冲区(u8 或 u16 数据元素)的指针。
  * @param  pRxData 指向 RX 数据缓冲区(u8 或 u16 数据元素)的指针。
  * @param  Size    要发送的数据(u8 或 u16)的数量(接收的数量与发送的数量相同)。
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_TransmitReceive_IT(USART_HandleTypeDef *husart, const uint8_t *pTxData, uint8_t *pRxData,
                                               uint16_t Size)
{
  if (husart->State == HAL_USART_STATE_READY)
  {
    if ((pTxData == NULL) || (pRxData == NULL) || (Size == 0))
    {
      return HAL_ERROR;
    }
    /* 进程锁定 */
    __HAL_LOCK(husart);

    husart->pRxBuffPtr = pRxData;
    husart->RxXferSize = Size;
    husart->RxXferCount = Size;
    husart->pTxBuffPtr = pTxData;
    husart->TxXferSize = Size;
    husart->TxXferCount = Size;

    husart->ErrorCode = HAL_USART_ERROR_NONE;
    husart->State = HAL_USART_STATE_BUSY_TX_RX;

    /* 进程解锁 */
    __HAL_UNLOCK(husart);

    /* 启用 USART 数据寄存器非空中断 */
    SET_BIT(husart->Instance->CR1, USART_CR1_RXNEIE);

    if (husart->Init.Parity != USART_PARITY_NONE)
    {
      /* 启用 USART 奇偶校验位错误中断 */
      SET_BIT(husart->Instance->CR1, USART_CR1_PEIE);
    }

    /* 启用 USART 错误中断: (帧错误,噪声错误,溢出错误) */
    SET_BIT(husart->Instance->CR3, USART_CR3_EIE);

    /* 启用 USART 发送数据寄存器空中断 */
    SET_BIT(husart->Instance->CR1, USART_CR1_TXEIE);

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

/**
  * @brief  单工 发送一定数量的数据 - DMA(非阻塞模式)
  * @note   当 USART 奇偶校验未启用(PCE = 0)且字长配置为 9 位(M1-M0 = 01)时,
  *         发送的数据将被视为一组 u16。
  *         在这种情况下,Size 必须指示通过 pTxData 提供的 u16 数量。
  * @param  husart  指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @param  pTxData 指向数据缓冲区的指针(u8 或 u16 数据元素)
  * @param  Size    要发送的数据(u8 或 u16)的数量。
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_Transmit_DMA(USART_HandleTypeDef *husart, const uint8_t *pTxData, uint16_t Size)
{
  const uint32_t *tmp;

  if (husart->State == HAL_USART_STATE_READY)
  {
    if ((pTxData == NULL) || (Size == 0))
    {
      return HAL_ERROR;
    }
    /* 进程锁定 */
    __HAL_LOCK(husart);

    husart->pTxBuffPtr = pTxData;
    husart->TxXferSize = Size;
    husart->TxXferCount = Size;

    husart->ErrorCode = HAL_USART_ERROR_NONE;
    husart->State = HAL_USART_STATE_BUSY_TX;

    /* 设置 USART DMA 发送完成回调 */
    husart->hdmatx->XferCpltCallback = USART_DMATransmitCplt;

    /* 设置 USART DMA 发送过半回调 */
    husart->hdmatx->XferHalfCpltCallback = USART_DMATxHalfCplt;

    /* 设置 DMA 错误回调 */
    husart->hdmatx->XferErrorCallback = USART_DMAError;

    /* 设置 DMA 中止回调 */
    husart->hdmatx->XferAbortCallback = NULL;

    /* 启用 USART 发送 DMA 通道 */
    tmp = (const uint32_t *)&pTxData;
    HAL_DMA_Start_IT(husart->hdmatx, *(const uint32_t *)tmp, (uint32_t)&husart->Instance->DR, Size);

    /* 通过向 SR(状态)寄存器写入 0 来清除 TC(发送完成)标志 */
    __HAL_USART_CLEAR_FLAG(husart, USART_FLAG_TC);

    /* 进程解锁 */
    __HAL_UNLOCK(husart);

    /* 通过在 USART CR3(控制寄存器3)中设置 DMAT(DMA使能发送)位来启用 DMA 传输发送请求。 */
    SET_BIT(husart->Instance->CR3, USART_CR3_DMAT);

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

/**
  * @brief  全双工 接收一定数量的数据 - DMA(非阻塞模式)
  * @note   当 USART 奇偶校验未启用(PCE = 0)且字长配置为 9 位(M1-M0 = 01)时,
  *         接收到的数据被视为一组 u16。
  *         在这种情况下,Size 必须指示通过 pRxData 可用的 u16 数量。
  * @param  husart  指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @param  pRxData 指向数据缓冲区的指针(u8 或 u16 数据元素)
  * @param  Size    要接收的数据(u8 或 u16)的数量。
  * @retval HAL status
  * @note   必须配置 USART DMA 发送通道以生成从机的时钟。
  * @note   当启用 USART 奇偶校验 (PCE = 1) 时,接收到的数据包含奇偶校验位。
  */
HAL_StatusTypeDef HAL_USART_Receive_DMA(USART_HandleTypeDef *husart, uint8_t *pRxData, uint16_t Size)
{
  uint32_t *tmp;

  if (husart->State == HAL_USART_STATE_READY)
  {
    if ((pRxData == NULL) || (Size == 0))
    {
      return HAL_ERROR;
    }

    /* 进程锁定 */
    __HAL_LOCK(husart);

    husart->pRxBuffPtr = pRxData;
    husart->RxXferSize = Size;
    husart->pTxBuffPtr = pRxData;
    husart->TxXferSize = Size;

    husart->ErrorCode = HAL_USART_ERROR_NONE;
    husart->State = HAL_USART_STATE_BUSY_RX;

    /* 设置 USART DMA 接收完成回调 */
    husart->hdmarx->XferCpltCallback = USART_DMAReceiveCplt;

    /* 设置 USART DMA 接收过半回调 */
    husart->hdmarx->XferHalfCpltCallback = USART_DMARxHalfCplt;

    /* 设置 USART DMA 接收错误回调 */
    husart->hdmarx->XferErrorCallback = USART_DMAError;

    /* 设置 DMA 中止回调 */
    husart->hdmarx->XferAbortCallback = NULL;

    /* 将 USART Tx DMA 传输完成回调函数设置为 NULL,因为通信的关闭是在 DMA 接收完成回调函数中执行的。  */
    husart->hdmatx->XferHalfCpltCallback = NULL;
    husart->hdmatx->XferCpltCallback = NULL;

    /* 设置 DMA 错误回调 */
    husart->hdmatx->XferErrorCallback = USART_DMAError;

    /* 设置 DMA AbortCpltCallback 中止完成回调 */
    husart->hdmatx->XferAbortCallback = NULL;

    /* 设置 USART 接收 DMA 通道 */
    tmp = (uint32_t *)&pRxData;
    HAL_DMA_Start_IT(husart->hdmarx, (uint32_t)&husart->Instance->DR, *(uint32_t *)tmp, Size);

    /* 启用 USART 发送 DMA 通道:发送通道用于以非阻塞模式为从机设备生成时钟,这种模式不是单工接收模式,而是全双工接收模式。 */
    HAL_DMA_Start_IT(husart->hdmatx, *(uint32_t *)tmp, (uint32_t)&husart->Instance->DR, Size);

    /* 在启用 DMA Rx 请求之前清除溢出标志:这对于第二次传输是必需的。 */
    __HAL_USART_CLEAR_OREFLAG(husart);

    /* 进程解锁 */
    __HAL_UNLOCK(husart);

    if (husart->Init.Parity != USART_PARITY_NONE)
    {
      /* 启用 USART 奇偶校验错误中断 */
      SET_BIT(husart->Instance->CR1, USART_CR1_PEIE);
    }

    /* 启用 USART 错误中断: (帧错误,噪声错误,溢出错误) */
    SET_BIT(husart->Instance->CR3, USART_CR3_EIE);

    /* 通过在 USART CR3(控制寄存器3)中设置 DMAR(DMA发送使能)位来启用接收请求的 DMA 传输。 */
    SET_BIT(husart->Instance->CR3, USART_CR3_DMAR);

    /* 通过在 USART CR3(控制寄存器3)中设置 DMAT(DMA发送使能)位来启用发送请求的 DMA 传输。 */
    SET_BIT(husart->Instance->CR3, USART_CR3_DMAT);

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

/**
  * @brief  全双工 发送并接收一定数量的数据 - 中断(非阻塞模式)
  * @note   当 USART 奇偶校验未启用(PCE = 0)且字长配置为 9 位(M1-M0 = 01)时,
  *         发送的数据和接收的数据被视为一组 u16。
  *         在这种情况下,Size 必须指示通过 pTxData 和 pRxData 可用的 u16 数量。
  * @param  husart  指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @param  pTxData 指向 TX 数据缓冲区(u8 或 u16 数据元素)的指针。
  * @param  pRxData 指向 RX 数据缓冲区(u8 或 u16 数据元素)的指针。
  * @param  Size    要接收/发送的数据数量(u8 或 u16)
  * @note   当启用了 USART 奇偶校验 (PCE = 1) 时,接收到的数据会包含奇偶校验位。
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_TransmitReceive_DMA(USART_HandleTypeDef *husart, const uint8_t *pTxData, uint8_t *pRxData,
                                                uint16_t Size)
{
  const uint32_t *tmp;

  if (husart->State == HAL_USART_STATE_READY)
  {
    if ((pTxData == NULL) || (pRxData == NULL) || (Size == 0))
    {
      return HAL_ERROR;
    }
    /* 进程锁定 */
    __HAL_LOCK(husart);

    husart->pRxBuffPtr = pRxData;
    husart->RxXferSize = Size;
    husart->pTxBuffPtr = pTxData;
    husart->TxXferSize = Size;

    husart->ErrorCode = HAL_USART_ERROR_NONE;
    husart->State = HAL_USART_STATE_BUSY_TX_RX;

    /* 设置 USART DMA 接收完成回调 */
    husart->hdmarx->XferCpltCallback = USART_DMAReceiveCplt;

    /* 设置 USART DMA 发送过半回调 */
    husart->hdmarx->XferHalfCpltCallback = USART_DMARxHalfCplt;

    /* 设置 USART DMA 发送完成回调 */
    husart->hdmatx->XferCpltCallback = USART_DMATransmitCplt;

    /* 设置 USART DMA 发送过半回调 */
    husart->hdmatx->XferHalfCpltCallback = USART_DMATxHalfCplt;

    /* 设置 USART DMA 发送错误回调 */
    husart->hdmatx->XferErrorCallback = USART_DMAError;

    /* 设置 USART DMA 接收传输错误回调 */
    husart->hdmarx->XferErrorCallback = USART_DMAError;

    /* 设置 DMA 中止回调 */
    husart->hdmarx->XferAbortCallback = NULL;

    /* 启用 USART 接收 DMA 通道 */
    tmp = (uint32_t *)&pRxData;
    HAL_DMA_Start_IT(husart->hdmarx, (uint32_t)&husart->Instance->DR, *(const uint32_t *)tmp, Size);

    /* 启用 USART 发送 DMA 通道 */
    tmp = (const uint32_t *)&pTxData;
    HAL_DMA_Start_IT(husart->hdmatx, *(const uint32_t *)tmp, (uint32_t)&husart->Instance->DR, Size);

    /* 通过向 SR(状态)寄存器写入 0 来清除 TC(发送完成)标志 */
    __HAL_USART_CLEAR_FLAG(husart, USART_FLAG_TC);

    /* 清除溢出标志:在循环模式下进行第二次传输时是必需的。 */
    __HAL_USART_CLEAR_OREFLAG(husart);

    /* 进程解锁 */
    __HAL_UNLOCK(husart);

    if (husart->Init.Parity != USART_PARITY_NONE)
    {
      /* 启用 USART 奇偶校验错误中断 */
      SET_BIT(husart->Instance->CR1, USART_CR1_PEIE);
    }

    /* 启用 USART 错误中断: (帧错误,噪声错误,溢出错误) */
    SET_BIT(husart->Instance->CR3, USART_CR3_EIE);

    /* 通过在 USART CR3(控制寄存器3)中设置 DMAR 位来启用接收请求的 DMA 传输。 */
    SET_BIT(husart->Instance->CR3, USART_CR3_DMAR);

    /* 通过在 USART CR3(控制寄存器3)寄存器中设置 DMAT 位来启用发送请求的 DMA 传输。 */
    SET_BIT(husart->Instance->CR3, USART_CR3_DMAT);

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

/**
  * @brief  暂停 DMA 传输
  * @param  husart 指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_DMAPause(USART_HandleTypeDef *husart)
{
  /* 进程锁定 */
  __HAL_LOCK(husart);

  /* 禁用 USART DMA Tx 请求 */
  CLEAR_BIT(husart->Instance->CR3, USART_CR3_DMAT);

  /* 进程解锁 */
  __HAL_UNLOCK(husart);

  return HAL_OK;
}

/**
  * @brief  启用 DMA 传输
  * @param  husart 指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_DMAResume(USART_HandleTypeDef *husart)
{
  /* 进程锁定 */
  __HAL_LOCK(husart);

  /* 启用 USART DMA Tx 请求 */
  SET_BIT(husart->Instance->CR3, USART_CR3_DMAT);

  /* 进程解锁 */
  __HAL_UNLOCK(husart);

  return HAL_OK;
}

/**
  * @brief  停止 DMA 传输
  * @param  husart 指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_DMAStop(USART_HandleTypeDef *husart)
{
  uint32_t dmarequest = 0x00U;
  /* 此 API 中未实现锁定功能,以允许用户应用程序在回调 HAL_USART_TxCpltCallback() / HAL_USART_RxCpltCallback() 中调用 HAL USART API。
     当调用 HAL_DMA_Abort() API 时,将会生成 DMA TX/RX 传输完成中断,并执行相应的回调 HAL_USART_TxCpltCallback() / HAL_USART_RxCpltCallback()。*/

  /* 停止 USART DMA 发送请求,如果正在进行中 */
  dmarequest = HAL_IS_BIT_SET(husart->Instance->CR3, USART_CR3_DMAT);
  if ((husart->State == HAL_USART_STATE_BUSY_TX) && dmarequest)
  {
    USART_EndTxTransfer(husart);

    /* 中止 USART DMA Tx 通道 */
    if (husart->hdmatx != NULL)
    {
      HAL_DMA_Abort(husart->hdmatx);
    }

    /* 禁用 USART Tx DMA 请求 */
    CLEAR_BIT(husart->Instance->CR3, USART_CR3_DMAT);
  }

  /* 停止 USART DMA 接收请求,如果正在进行中。 */
  dmarequest = HAL_IS_BIT_SET(husart->Instance->CR3, USART_CR3_DMAR);
  if ((husart->State == HAL_USART_STATE_BUSY_RX) && dmarequest)
  {
    USART_EndRxTransfer(husart);

    /* 中止 USART DMA 传输通道 */
    if (husart->hdmarx != NULL)
    {
      HAL_DMA_Abort(husart->hdmarx);
    }

    /* 禁用 USART 输入请求 */
    CLEAR_BIT(husart->Instance->CR3, USART_CR3_DMAR);
  }

  return HAL_OK;
}

/**
  * @brief  中止正在进行的传输(则是模式)
  * @param  husart usart 句柄.
  * @note   该过程可用于中止在中断或 DMA 模式下启动的任何正在进行的传输(如由 TransferType 参数描述的 Tx 或 Rx)。
  *         该过程执行以下操作:
  *           - 禁用 PPP 中断(取决于传输方向)
  *           - 在外设寄存器中禁用 DMA 传输(如果已启用)
  *           - 通过调用 HAL_DMA_Abort 中止 DMA 传输(在 DMA 模式下的传输情况)
  *           - 将句柄状态设置为 READY
  * @note   该过程以阻塞模式执行:在退出函数时,中止被视为已完成。
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_Abort(USART_HandleTypeDef *husart)
{
  /* 禁用 TXEIE(发送非空)、TCIE(发送完成)、ERR(错误) (帧错误,噪声错误,溢出错误) 中断 */
  CLEAR_BIT(husart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE | USART_CR1_TXEIE | USART_CR1_TCIE));
  CLEAR_BIT(husart->Instance->CR3, USART_CR3_EIE);

  /* 禁用 USART DMA Tx 请求(如果使能了) */
  if (HAL_IS_BIT_SET(husart->Instance->CR3, USART_CR3_DMAT))
  {
    CLEAR_BIT(husart->Instance->CR3, USART_CR3_DMAT);

    /* 中止 USART DMA Tx 通道 : 使用阻塞的 DMA 中止 API(无回调) */
    if (husart->hdmatx != NULL)
    {
      /* 将 USART DMA 中止回调设置为 Null。
         将 USART DMA 中止在 DMA 中止过程结束时不执行回调。调设置为 Null。 */
      husart->hdmatx->XferAbortCallback = NULL;

      HAL_DMA_Abort(husart->hdmatx);
    }
  }

  /* 禁用 USART DMA Rx 请求(如果启用了)*/
  if (HAL_IS_BIT_SET(husart->Instance->CR3, USART_CR3_DMAR))
  {
    CLEAR_BIT(husart->Instance->CR3, USART_CR3_DMAR);

    /* 中止 USART DMA 传输通道 : 使用阻塞的 DMA 中止 API(无回调) */
    if (husart->hdmarx != NULL)
    {
      /* 将 USART DMA 中止回调设置为 Null。
         将 USART DMA 中止在 DMA 中止过程结束时不执行回调。调设置为 Null。 */
      husart->hdmarx->XferAbortCallback = NULL;

      HAL_DMA_Abort(husart->hdmarx);
    }
  }

  /* 重置 发送和接收传输计数器 */
  husart->TxXferCount = 0x00U;
  husart->RxXferCount = 0x00U;

  /* 将 husart->State 恢复为 Ready 状态 */
  husart->State  = HAL_USART_STATE_READY;

  /* 重置错误代码为 无错误 */
  husart->ErrorCode = HAL_USART_ERROR_NONE;

  return HAL_OK;
}

/**
  * @brief  中止正在进行的传输 - 中断
  * @param  husart usart 句柄.
  * @note   该过程可用于中止在中断或 DMA 模式下启动的任何正在进行的传输(如由 TransferType 参数描述的 Tx 或 Rx)
  *         该过程执行以下操作:
  *           - 禁用 PPP 中断(取决于传输方向)
  *           - 在外设寄存器中禁用 DMA 传输(如果已启用)
  *           - 通过调用 HAL_DMA_Abort_IT 中止 DMA 传输(在 DMA 模式下的传输情况)。
  *           - 将句柄状态设置为 READY
  *           - 在中止完成时,调用用户中止完成回调
  * @note   该过程以中断模式执行,这意味着中止过程只有在执行用户中止完成回调时才被视为已完成(而不是在退出函数时)。
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_Abort_IT(USART_HandleTypeDef *husart)
{
  uint32_t AbortCplt = 0x01U;

  /* 禁用 TXEIE(发送非空)、TCIE(发送完成)、ERR(错误) (帧错误,噪声错误,溢出错误) 中断 */
  CLEAR_BIT(husart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE | USART_CR1_TXEIE | USART_CR1_TCIE));
  CLEAR_BIT(husart->Instance->CR3, USART_CR3_EIE);

  /* 如果 DMA Tx 和/或 DMA Rx 句柄与 USART 句柄相关联,则应在调用任何 DMA 中止函数之前初始化 DMA 中止完成回调。 */
  /* DMA Tx 句柄无效 */
  if (husart->hdmatx != NULL)
  {
    /* 如果启用了 USART DMA Tx 请求,则设置 DMA 中止完成回调。否则,将其设置为 NULL。 */
    if (HAL_IS_BIT_SET(husart->Instance->CR3, USART_CR3_DMAT))
    {
      husart->hdmatx->XferAbortCallback = USART_DMATxAbortCallback;
    }
    else
    {
      husart->hdmatx->XferAbortCallback = NULL;
    }
  }
  /* DMA Rx 句柄无效 */
  if (husart->hdmarx != NULL)
  {
    /* 如果启用了 USART DMA Rx 请求,则设置 DMA 中止完成回调。否则,将其设置为 NULL。 */
    if (HAL_IS_BIT_SET(husart->Instance->CR3, USART_CR3_DMAR))
    {
      husart->hdmarx->XferAbortCallback = USART_DMARxAbortCallback;
    }
    else
    {
      husart->hdmarx->XferAbortCallback = NULL;
    }
  }

  /* 禁用 USART DMA Tx 请求(如果启用了) */
  if (HAL_IS_BIT_SET(husart->Instance->CR3, USART_CR3_DMAT))
  {
    /* 禁用 DMA Tx 请求 */
    CLEAR_BIT(husart->Instance->CR3, USART_CR3_DMAT);

    /* 中止 USART DMA Tx 通道 : 使用非阻塞 DMA 中止 API(回调) */
    if (husart->hdmatx != NULL)
    {
      /* USART Tx DMA 中止回调已经被初始化:
         将在 DMA 中止过程结束时调用 HAL_USART_AbortCpltCallback()。 */

      /* 中止 DMA 发送 */
      if (HAL_DMA_Abort_IT(husart->hdmatx) != HAL_OK)
      {
        husart->hdmatx->XferAbortCallback = NULL;
      }
      else
      {
        AbortCplt = 0x00U;
      }
    }
  }

  /* 禁用 USART DMA Rx 请求(如果启用了) */
  if (HAL_IS_BIT_SET(husart->Instance->CR3, USART_CR3_DMAR))
  {
    CLEAR_BIT(husart->Instance->CR3, USART_CR3_DMAR);

    /* 中止 USART DMA 传输通道 : 使用非阻塞 DMA 中止 API(回调) */
    if (husart->hdmarx != NULL)
    {
      /* USART Rx DMA 中止回调已经被初始化:
         将在 DMA 中止过程结束时调用 HAL_USART_AbortCpltCallback()。 */

      /* Abort DMA 接收 */
      if (HAL_DMA_Abort_IT(husart->hdmarx) != HAL_OK)
      {
        husart->hdmarx->XferAbortCallback = NULL;
        AbortCplt = 0x01U;
      }
      else
      {
        AbortCplt = 0x00U;
      }
    }
  }

  /* 如果不需要执行 DMA 中止完成回调,则调用用户中止完成回调。 */
  if (AbortCplt  == 0x01U)
  {
    /* 重置 Tx 和 Rx 传输计数器 */
    husart->TxXferCount = 0x00U;
    husart->RxXferCount = 0x00U;

    /* 重置错误代码 */
    husart->ErrorCode = HAL_USART_ERROR_NONE;

    /* 将 husart->State 恢复为 Ready 状态 */
    husart->State  = HAL_USART_STATE_READY;

    /* 由于没有要中止的 DMA,直接调用用户中止完成回调。 */
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
    /* 调用注册的中止完成回调 */
    husart->AbortCpltCallback(husart);
#else
    /* 调用预定义弱中止完成回调函数 */
    HAL_USART_AbortCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
  }

  return HAL_OK;
}

/**
  * @brief  处理 USART 中断请求的函数
  * @param  husart 指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @retval None
  */
void HAL_USART_IRQHandler(USART_HandleTypeDef *husart)
{
  uint32_t isrflags = READ_REG(husart->Instance->SR);
  uint32_t cr1its   = READ_REG(husart->Instance->CR1);
  uint32_t cr3its   = READ_REG(husart->Instance->CR3);
  uint32_t errorflags = 0x00U;
  uint32_t dmarequest = 0x00U;

  /* 如果无错误发生 */
  errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
  if (errorflags == RESET)
  {
    /* USART 处于接收机 -------------------------------------------------*/
    if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
    {
      if (husart->State == HAL_USART_STATE_BUSY_RX)
      {
        USART_Receive_IT(husart);
      }
      else
      {
        USART_TransmitReceive_IT(husart);
      }
      return;
    }
  }
  /* 如果有错误发生 */
  if ((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))
  {
    /* USART 奇偶校验错误中断发生 ----------------------------------*/
    if (((isrflags & USART_SR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET))
    {
      husart->ErrorCode |= HAL_USART_ERROR_PE;
    }

    /* USART 噪声错误中断发生 --------------------------------*/
    if (((isrflags & USART_SR_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
    {
      husart->ErrorCode |= HAL_USART_ERROR_NE;
    }

    /* USART 帧错误中断发生 --------------------------------*/
    if (((isrflags & USART_SR_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
    {
      husart->ErrorCode |= HAL_USART_ERROR_FE;
    }

    /* USART 溢出中断发生 -----------------------------------*/
    if (((isrflags & USART_SR_ORE) != RESET) && (((cr1its & USART_CR1_RXNEIE) != RESET) || ((cr3its & USART_CR3_EIE) != RESET)))
    {
      husart->ErrorCode |= HAL_USART_ERROR_ORE;
    }

    if (husart->ErrorCode != HAL_USART_ERROR_NONE)
    {
      /* USART 处于接收机 -----------------------------------------------*/
      if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
      {
        if (husart->State == HAL_USART_STATE_BUSY_RX)
        {
          USART_Receive_IT(husart);
        }
        else
        {
          USART_TransmitReceive_IT(husart);
        }
      }
      /* 如果发生溢出错误,或者在DMA模式接收中发生任何错误,则将错误视为阻塞错误 */
      dmarequest = HAL_IS_BIT_SET(husart->Instance->CR3, USART_CR3_DMAR);
      if (((husart->ErrorCode & HAL_USART_ERROR_ORE) != RESET) || dmarequest)
      {
        /* 将 USART 状态设置为准备就绪,以便能够重新开始该过程,如果正在进行中,禁用 Rx 中断并禁用 Rx DMA 请求。 */
        USART_EndRxTransfer(husart);

        /* 禁用 USART DMA 接收请求(如果启用了) */
        if (HAL_IS_BIT_SET(husart->Instance->CR3, USART_CR3_DMAR))
        {
          CLEAR_BIT(husart->Instance->CR3, USART_CR3_DMAR);

          /* 中止 USART DMA 传输通道 */
          if (husart->hdmarx != NULL)
          {
            /* 设置 USART DMA 中止回调:
            将导致在DMA中止过程结束时调用 HAL_USART_ErrorCallback() */
            husart->hdmarx->XferAbortCallback = USART_DMAAbortOnError;

            if (HAL_DMA_Abort_IT(husart->hdmarx) != HAL_OK)
            {
              /* 在发生错误时直接调用XferAbortCallback函数 */
              husart->hdmarx->XferAbortCallback(husart->hdmarx);
            }
          }
          else
          {
            /* 调用用户错误回调 */
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
            /* 调用注册的错误回调 */
            husart->ErrorCallback(husart);
#else
            /* 调用预定义弱错误回调函数 */
            HAL_USART_ErrorCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
          }
        }
        else
        {
          /* 调用用户错误回调 */
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
          /* 调用注册的错误回调 */
          husart->ErrorCallback(husart);
#else
          /* 调用预定义弱错误回调函数 */
          HAL_USART_ErrorCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
        }
      }
      else
      {
        /* 调用用户错误回调 */
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
        /* 调用注册的错误回调 */
        husart->ErrorCallback(husart);
#else
        /* 调用预定义弱错误回调函数 */
        HAL_USART_ErrorCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
        husart->ErrorCode = HAL_USART_ERROR_NONE;
      }
    }
    return;
  }

  /* USART 处于发送机 -----------------------------------------------*/
  if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
  {
    if (husart->State == HAL_USART_STATE_BUSY_TX)
    {
      USART_Transmit_IT(husart);
    }
    else
    {
      USART_TransmitReceive_IT(husart);
    }
    return;
  }

  /* USART 处于发送机 (发送结束) ----------------------------*/
  if (((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
  {
    USART_EndTransmit_IT(husart);
    return;
  }
}

/**
  * @brief  发送完成回调
  * @param  husart 指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @retval None
  */
__weak void HAL_USART_TxCpltCallback(USART_HandleTypeDef *husart)
{
  /* 防止未使用参数的编译警告 */
  UNUSED(husart);
  /* NOTE: 当需要回调函数时,不应修改此函数,可以在用户文件中重写以覆盖此函数。
   */
}

/**
  * @brief  发送过半回调
  * @param  husart 指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @retval None
  */
__weak void HAL_USART_TxHalfCpltCallback(USART_HandleTypeDef *husart)
{
  /* 防止未使用参数的编译警告 */
  UNUSED(husart);
  /* NOTE: 当需要回调函数时,不应修改此函数,可以在用户文件中重写以覆盖此函数。
   */
}

/**
  * @brief  接收完成回调
  * @param  husart 指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @retval None
  */
__weak void HAL_USART_RxCpltCallback(USART_HandleTypeDef *husart)
{
  /* 防止未使用参数的编译警告 */
  UNUSED(husart);
  /* NOTE: 当需要回调函数时,不应修改此函数,可以在用户文件中重写以覆盖此函数。
   */
}

/**
  * @brief  接收过半回调
  * @param  husart 指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @retval None
  */
__weak void HAL_USART_RxHalfCpltCallback(USART_HandleTypeDef *husart)
{
  /* 防止未使用参数的编译警告 */
  UNUSED(husart);
  /* NOTE: 当需要回调函数时,不应修改此函数,可以在用户文件中重写以覆盖此函数。
   */
}

/**
  * @brief  发送接收完成回调
  * @param  husart 指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @retval None
  */
__weak void HAL_USART_TxRxCpltCallback(USART_HandleTypeDef *husart)
{
  /* 防止未使用参数的编译警告 */
  UNUSED(husart);
  /* NOTE: 当需要回调函数时,不应修改此函数,可以在用户文件中重写以覆盖此函数。
   */
}

/**
  * @brief  USART 错误回调
  * @param  husart 指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @retval None
  */
__weak void HAL_USART_ErrorCallback(USART_HandleTypeDef *husart)
{
  /* 防止未使用参数的编译警告 */
  UNUSED(husart);
  /* NOTE: 当需要回调函数时,不应修改此函数,可以在用户文件中重写以覆盖此函数。
   */
}

/**
  * @brief  USART 中止完成回调
  * @param  husart usart 句柄.
  * @retval None
  */
__weak void HAL_USART_AbortCpltCallback(USART_HandleTypeDef *husart)
{
  /* 防止未使用参数的编译警告 */
  UNUSED(husart);

  /* NOTE : 当需要回调函数时,不应修改此函数,可以在用户文件中重写以覆盖此函数。
   */
}

/**
  * @}
  */

/** @defgroup USART_Exported_Functions_Group3 外设状态和错误函数
  *  @brief   USART 状态和错误函数
  *
@verbatim
  ==============================================================================
                  ##### 外设状态和错误函数 #####
  ==============================================================================
  [..]
    本节提供了一组函数,用于返回 USART 通信过程的状态,返回通信过程中发生的外设错误。
     (+) HAL_USART_GetState() API 可以帮助在运行时检查 USART 外设的状态。
     (+) HAL_USART_GetError() 在运行时检查可能发生的通信错误。
@endverbatim
  * @{
  */

/**
  * @brief  获取 USART 状态
  * @param  husart 指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @retval HAL state
  */
HAL_USART_StateTypeDef HAL_USART_GetState(const USART_HandleTypeDef *husart)
{
  return husart->State;
}

/**
  * @brief  获取 USART 错误代码
  * @param  husart 指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @retval USART 错误代码
  */
uint32_t HAL_USART_GetError(const USART_HandleTypeDef *husart)
{
  return husart->ErrorCode;
}

/**
  * @}
  */

/** @defgroup USART_Private_Functions USART 私有函数
 * @{
 */

/**
  * @brief  初始化回调为默认值
  * @param  husart usart 句柄.
  * @retval none
  */
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
void USART_InitCallbacksToDefault(USART_HandleTypeDef *husart)
{
  /* 初始化 USART 回调设置 */
  husart->TxHalfCpltCallback        = HAL_USART_TxHalfCpltCallback;        /* 预定义弱回调函数 TxHalfCpltCallback        */
  husart->TxCpltCallback            = HAL_USART_TxCpltCallback;            /* 预定义弱回调函数 TxCpltCallback            */
  husart->RxHalfCpltCallback        = HAL_USART_RxHalfCpltCallback;        /* 预定义弱回调函数 RxHalfCpltCallback        */
  husart->RxCpltCallback            = HAL_USART_RxCpltCallback;            /* 预定义弱回调函数 RxCpltCallback            */
  husart->TxRxCpltCallback          = HAL_USART_TxRxCpltCallback;          /* 预定义弱回调函数 TxRxCpltCallback          */
  husart->ErrorCallback             = HAL_USART_ErrorCallback;             /* 预定义弱回调函数 ErrorCallback             */
  husart->AbortCpltCallback         = HAL_USART_AbortCpltCallback;         /* 预定义弱回调函数 AbortCpltCallback         */
}
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */

/**
  * @brief  DMA USART 发送完成回调
  * @param  hdma 指向包含指定DMA模块的配置信息的DMA_HandleTypeDef结构体的指针
  * @retval None
  */
static void USART_DMATransmitCplt(DMA_HandleTypeDef *hdma)
{
  USART_HandleTypeDef *husart = (USART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
  /* DMA 普通模式 */
  if ((hdma->Instance->CCR & DMA_CCR_CIRC) == 0U)
  {
    husart->TxXferCount = 0U;
    if (husart->State == HAL_USART_STATE_BUSY_TX)
    {
      /* 通过在USART的CR3(控制寄存器3)中设置DMAT(DMA使能发送)位来禁用发送请求的DMA传输 */
      CLEAR_BIT(husart->Instance->CR3, USART_CR3_DMAT);

      /* 启用 USART 发送完成中断 */
      SET_BIT(husart->Instance->CR1, USART_CR1_TCIE);
    }
  }
  /* DMA 循环模式 */
  else
  {
    if (husart->State == HAL_USART_STATE_BUSY_TX)
    {
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
      /* 调用注册的发送完成回调 */
      husart->TxCpltCallback(husart);
#else
      /* 调用预定义的弱发送完成回调 */
      HAL_USART_TxCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
    }
  }
}

/**
  * @brief  DMA USART 发送过半回调
  * @param  hdma 指向包含指定DMA模块的配置信息的DMA_HandleTypeDef结构体的指针
  * @retval None
  */
static void USART_DMATxHalfCplt(DMA_HandleTypeDef *hdma)
{
  USART_HandleTypeDef *husart = (USART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;

#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
  /* 调用注册的发送过半回调 */
  husart->TxHalfCpltCallback(husart);
#else
  /* 调用预定义的弱发送过半回调 */
  HAL_USART_TxHalfCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
}

/**
  * @brief  DMA USART 接收完成回调
  * @param  hdma 指向包含指定DMA模块的配置信息的DMA_HandleTypeDef结构体的指针
  * @retval None
  */
static void USART_DMAReceiveCplt(DMA_HandleTypeDef *hdma)
{
  USART_HandleTypeDef *husart = (USART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
  /* DMA 普通模式 */
  if ((hdma->Instance->CCR & DMA_CCR_CIRC) == 0U)
  {
    husart->RxXferCount = 0x00U;

    /* 禁用 RXNE(接收缓冲非空), PE(奇偶校验)和 ERR(错误)(帧错误, 噪声错误, 溢出错误) 中断 */
    CLEAR_BIT(husart->Instance->CR1, USART_CR1_PEIE);
    CLEAR_BIT(husart->Instance->CR3, USART_CR3_EIE);

    /* 通过在USART的CR3寄存器中设置DMAR(DMA接收使能)位来禁用接收请求的DMA传输 */
    CLEAR_BIT(husart->Instance->CR3, USART_CR3_DMAR);
    CLEAR_BIT(husart->Instance->CR3, USART_CR3_DMAT);

    /* 如果 USART 状态为 HAL_USART_STATE_BUSY_RX */
    if (husart->State == HAL_USART_STATE_BUSY_RX)
    {
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
      /* 调用注册的接收完成回调 */
      husart->RxCpltCallback(husart);
#else
      /* 调用预定义弱接收完成回调函数 */
      HAL_USART_RxCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
    }
    /* The USART state is HAL_USART_STATE_BUSY_TX_RX */
    else
    {
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
      /* 调用注册的发送接收完成回调 */
      husart->TxRxCpltCallback(husart);
#else
      /* 调用预定义弱发送接收完成回调函数 */
      HAL_USART_TxRxCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
    }
    husart->State = HAL_USART_STATE_READY;
  }
  /* DMA 循环模式 */
  else
  {
    if (husart->State == HAL_USART_STATE_BUSY_RX)
    {
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
      /* 调用注册的接收完成回调 */
      husart->RxCpltCallback(husart);
#else
      /* 调用预定义弱接收完成回调函数 */
      HAL_USART_RxCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
    }
    /* USART 状态为 HAL_USART_STATE_BUSY_TX_RX */
    else
    {
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
      /* 调用注册的发送接收完成回调 */
      husart->TxRxCpltCallback(husart);
#else
      /* 调用预定义弱发送接收完成回调函数 */
      HAL_USART_TxRxCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
    }
  }
}

/**
  * @brief  DMA USART 接收过半回调
  * @param  hdma 指向包含指定DMA模块的配置信息的DMA_HandleTypeDef结构体的指针
  * @retval None
  */
static void USART_DMARxHalfCplt(DMA_HandleTypeDef *hdma)
{
  USART_HandleTypeDef *husart = (USART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;

#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
  /* 调用注册的接收过半回调 */
  husart->RxHalfCpltCallback(husart);
#else
  /* 调用预定义弱接收过半回调函数 */
  HAL_USART_RxHalfCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
}

/**
  * @brief  DMA USART communication 错误回调
  * @param  hdma 指向包含指定DMA模块的配置信息的DMA_HandleTypeDef结构体的指针
  * @retval None
  */
static void USART_DMAError(DMA_HandleTypeDef *hdma)
{
  uint32_t dmarequest = 0x00U;
  USART_HandleTypeDef *husart = (USART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
  husart->RxXferCount = 0x00U;
  husart->TxXferCount = 0x00U;

  /* 停止 USART DMA 发送请求,如果正在进行中 */
  dmarequest = HAL_IS_BIT_SET(husart->Instance->CR3, USART_CR3_DMAT);
  if ((husart->State == HAL_USART_STATE_BUSY_TX) && dmarequest)
  {
    USART_EndTxTransfer(husart);
  }

  /* 停止 USART DMA 接收请求,如果正在进行中。 */
  dmarequest = HAL_IS_BIT_SET(husart->Instance->CR3, USART_CR3_DMAR);
  if ((husart->State == HAL_USART_STATE_BUSY_RX) && dmarequest)
  {
    USART_EndRxTransfer(husart);
  }

  husart->ErrorCode |= HAL_USART_ERROR_DMA;
  husart->State = HAL_USART_STATE_READY;

#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
  /* 调用注册的错误回调 */
  husart->ErrorCallback(husart);
#else
  /* 调用预定义弱错误回调函数 */
  HAL_USART_ErrorCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
}

/**
  * @brief  这个函数处理USART通信超时。它会等待直到标志不再处于指定的状态。
  * @param  husart 指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @param  Flag 指定要检查的 USART 标志
  * @param  Status 实际的标志状态 (SET 或 RESET).
  * @param  Tickstart 滴答起始值
  * @param  Timeout 超时持续时间。
  * @retval HAL status
  */
static HAL_StatusTypeDef USART_WaitOnFlagUntilTimeout(USART_HandleTypeDef *husart, uint32_t Flag, FlagStatus Status,
                                                      uint32_t Tickstart, uint32_t Timeout)
{
  /* 等待,直到标志为非指定状态 */
  while ((__HAL_USART_GET_FLAG(husart, Flag) ? SET : RESET) == Status)
  {
    /* 检查超时 */
    if (Timeout != HAL_MAX_DELAY)
    {
      if ((Timeout == 0U) || ((HAL_GetTick() - Tickstart) > Timeout))
      {
        /* 禁用 USART 发送缓冲空中断 */
        CLEAR_BIT(husart->Instance->CR1, USART_CR1_TXEIE);

        /* 禁用 USART RXNE(接收缓冲非空)中断 */
        CLEAR_BIT(husart->Instance->CR1, USART_CR1_RXNEIE);

        /* 禁用 USART 奇偶校验错误中断 */
        CLEAR_BIT(husart->Instance->CR1, USART_CR1_PEIE);

        /* 禁用 USART 错误中断: (帧错误,噪声错误,溢出错误) */
        CLEAR_BIT(husart->Instance->CR3, USART_CR3_EIE);

        husart->State = HAL_USART_STATE_READY;

        /* 进程解锁 */
        __HAL_UNLOCK(husart);

        return HAL_TIMEOUT;
      }
    }
  }
  return HAL_OK;
}

/**
  * @brief  结束USART外设上正在进行的Tx传输(在错误检测或传输完成后)。
  * @param  husart usart 句柄.
  * @retval None
  */
static void USART_EndTxTransfer(USART_HandleTypeDef *husart)
{
  /* 禁用 TXEIE(发送缓冲空)和 TCIE(发送完成)中断 */
  CLEAR_BIT(husart->Instance->CR1, (USART_CR1_TXEIE | USART_CR1_TCIE));

  /* 在发送过程结束时, 将 husart->State 恢复为 Ready 状态 */
  husart->State = HAL_USART_STATE_READY;
}

/**
  * @brief  结束USART外设上正在进行的Rx传输(在错误检测或接收完成后)
  * @param  husart usart 句柄.
  * @retval None
  */
static void USART_EndRxTransfer(USART_HandleTypeDef *husart)
{
  /* 禁用 RXNE(接收缓冲非空), PE(奇偶校验)和 ERR(错误)(帧错误, 噪声错误, 溢出错误) 中断 */
  CLEAR_BIT(husart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
  CLEAR_BIT(husart->Instance->CR3, USART_CR3_EIE);

  /* 在接收过程结束时, 将 husart->State 恢复为 Ready 状态 */
  husart->State = HAL_USART_STATE_READY;
}

/**
  * @brief  当由HAL服务在出现错误时启动时,DMA USART通信中止回调(在发生错误后DMA中止过程结束时调用)
  * @param  hdma DMA 句柄
  * @retval None
  */
static void USART_DMAAbortOnError(DMA_HandleTypeDef *hdma)
{
  USART_HandleTypeDef *husart = (USART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;
  husart->RxXferCount = 0x00U;
  husart->TxXferCount = 0x00U;

#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
  /* 调用注册的错误回调 */
  husart->ErrorCallback(husart);
#else
  /* 调用预定义弱错误回调函数 */
  HAL_USART_ErrorCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
}

/**
  * @brief  当由用户发起时,DMA USART Tx通信中止回调(在用户发起中止请求后DMA Tx中止过程结束时调用)
  * @note   当执行此回调时,仅当Rx DMA句柄没有仍在进行中止时,才会调用用户中止完成回调。
  * @param  hdma DMA 句柄
  * @retval None
  */
static void USART_DMATxAbortCallback(DMA_HandleTypeDef *hdma)
{
  USART_HandleTypeDef *husart = (USART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;

  husart->hdmatx->XferAbortCallback = NULL;

  /* 检查中止程序是否正在进行 */
  if (husart->hdmarx != NULL)
  {
    if (husart->hdmarx->XferAbortCallback != NULL)
    {
      return;
    }
  }

  /* 没有仍在进行中止的过程:所有DMA通道都已中止,调用用户中止完成回调 */
  husart->TxXferCount = 0x00U;
  husart->RxXferCount = 0x00U;

  /* 重置错误 */
  husart->ErrorCode = HAL_USART_ERROR_NONE;

  /* 将 husart->State 恢复为 Ready 状态 */
  husart->State  = HAL_USART_STATE_READY;

  /* 调用用户中止完成回调*/
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
  /* 调用注册的中止完成回调 */
  husart->AbortCpltCallback(husart);
#else
  /* 调用预定义弱中止完成回调函数 */
  HAL_USART_AbortCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
}

/**
  * @brief  当由用户发起时,DMA USART Rx通信中止回调(在用户发起中止请求后DMA Rx中止过程结束时调用)
  * @note   当执行此回调时,仅当Tx DMA句柄没有仍在进行中止时,才会调用用户中止完成回调。
  * @param  hdma DMA 句柄
  * @retval None
  */
static void USART_DMARxAbortCallback(DMA_HandleTypeDef *hdma)
{
  USART_HandleTypeDef *husart = (USART_HandleTypeDef *)((DMA_HandleTypeDef *)hdma)->Parent;

  husart->hdmarx->XferAbortCallback = NULL;

  /* 检查中止程序是否正在进行 */
  if (husart->hdmatx != NULL)
  {
    if (husart->hdmatx->XferAbortCallback != NULL)
    {
      return;
    }
  }

  /* 没有仍在进行中止的过程:所有DMA通道都已中止,调用用户中止完成回调 */
  husart->TxXferCount = 0x00U;
  husart->RxXferCount = 0x00U;

  /* 重置错误 */
  husart->ErrorCode = HAL_USART_ERROR_NONE;

  /* 将 husart->State 恢复为 Ready 状态 */
  husart->State  = HAL_USART_STATE_READY;

  /* 调用用户中止完成回调 */
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
  /* 调用注册的中止完成回调 */
  husart->AbortCpltCallback(husart);
#else
  /* 调用预定义弱中止完成回调函数 */
  HAL_USART_AbortCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
}

/**
  * @brief  单工 发送一定数量的数据(非阻塞模式)
  * @param  husart 指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @retval HAL status
  * @note   未对 USART 错误进行处理,以避免溢出错误。
  */
static HAL_StatusTypeDef USART_Transmit_IT(USART_HandleTypeDef *husart)
{
  const uint16_t *tmp;

  if (husart->State == HAL_USART_STATE_BUSY_TX)
  {
    if ((husart->Init.WordLength == USART_WORDLENGTH_9B) && (husart->Init.Parity == USART_PARITY_NONE))
    {
      tmp = (const uint16_t *) husart->pTxBuffPtr;
      husart->Instance->DR = (uint16_t)(*tmp & (uint16_t)0x01FF);
      husart->pTxBuffPtr += 2U;
    }
    else
    {
      husart->Instance->DR = (uint8_t)(*husart->pTxBuffPtr++ & (uint8_t)0x00FF);
    }

    if (--husart->TxXferCount == 0U)
    {
      /* 禁用 USART 发送数据寄存器空 中断 */
      CLEAR_BIT(husart->Instance->CR1, USART_CR1_TXEIE);

      /* 启用 UART 发送完成中断 */
      SET_BIT(husart->Instance->CR1, USART_CR1_TCIE);
    }
    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

/**
  * @brief  以非阻塞模式完成发送
  * @param  husart 指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @retval HAL status
  */
static HAL_StatusTypeDef USART_EndTransmit_IT(USART_HandleTypeDef *husart)
{
  /* 禁用 USART 发送完成中断 */
  CLEAR_BIT(husart->Instance->CR1, USART_CR1_TCIE);

  /* 禁用 USART 错误中断: (帧错误,噪声错误,溢出错误) */
  CLEAR_BIT(husart->Instance->CR3, USART_CR3_EIE);

  husart->State = HAL_USART_STATE_READY;

#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
  /* 调用注册的发送完成回调 */
  husart->TxCpltCallback(husart);
#else
  /* 调用预定义的弱发送完成回调 */
  HAL_USART_TxCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */

  return HAL_OK;
}

/**
  * @brief  单工 接收一定数量的数据(非阻塞模式)
  * @param  husart 指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @retval HAL status
  */
static HAL_StatusTypeDef USART_Receive_IT(USART_HandleTypeDef *husart)
{
  uint8_t  *pdata8bits;
  uint16_t *pdata16bits;

  if (husart->State == HAL_USART_STATE_BUSY_RX)
  {
    if ((husart->Init.WordLength == USART_WORDLENGTH_9B) && (husart->Init.Parity == USART_PARITY_NONE))
    {
      pdata8bits  = NULL;
      pdata16bits = (uint16_t *) husart->pRxBuffPtr;
      *pdata16bits = (uint16_t)(husart->Instance->DR & (uint16_t)0x01FF);
      husart->pRxBuffPtr += 2U;
    }
    else
    {
      pdata8bits = (uint8_t *) husart->pRxBuffPtr;
      pdata16bits  = NULL;

      if ((husart->Init.WordLength == USART_WORDLENGTH_9B) || ((husart->Init.WordLength == USART_WORDLENGTH_8B) && (husart->Init.Parity == USART_PARITY_NONE)))
      {
        *pdata8bits = (uint8_t)(husart->Instance->DR & (uint8_t)0x00FF);
      }
      else
      {
        *pdata8bits = (uint8_t)(husart->Instance->DR & (uint8_t)0x007F);
      }

      husart->pRxBuffPtr += 1U;
    }

    husart->RxXferCount--;

    if (husart->RxXferCount == 0U)
    {
      /* 禁用 USART RXNE(接收缓冲非空)数据寄存器非空中断 */
      CLEAR_BIT(husart->Instance->CR1, USART_CR1_RXNEIE);

      /* 禁用 USART 奇偶校验错误中断 */
      CLEAR_BIT(husart->Instance->CR1, USART_CR1_PEIE);

      /* 禁用 USART 错误中断: (帧错误,噪声错误,溢出错误) */
      CLEAR_BIT(husart->Instance->CR3, USART_CR3_EIE);

      husart->State = HAL_USART_STATE_READY;
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
      /* 调用注册的 Rx 事件回调 */
      husart->RxCpltCallback(husart);
#else
      /* 调用预定义弱 Rx 事件回调函数k */
      HAL_USART_RxCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */

      return HAL_OK;
    }
    else
    {
      /* 发送虚拟字节以生成时钟,以便从机发送下一个数据。
          无论帧长度为多少位(7、8或9位),对于所有情况都可以写入相同的虚拟值。 */
      husart->Instance->DR = (DUMMY_DATA & (uint16_t)0x0FF);
    }
    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

/**
  * @brief  全双工发送接收一定数量的数据 - 中断
  * @param  husart 指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @retval HAL status
  */
static HAL_StatusTypeDef USART_TransmitReceive_IT(USART_HandleTypeDef *husart)
{
  const uint16_t *pdatatx16bits;
  uint16_t *pdatarx16bits;

  if (husart->State == HAL_USART_STATE_BUSY_TX_RX)
  {
    if (husart->TxXferCount != 0x00U)
    {
      if (__HAL_USART_GET_FLAG(husart, USART_FLAG_TXE) != RESET)
      {
        if ((husart->Init.WordLength == USART_WORDLENGTH_9B) && (husart->Init.Parity == USART_PARITY_NONE))
        {
          pdatatx16bits = (const uint16_t *) husart->pTxBuffPtr;
          husart->Instance->DR = (uint16_t)(*pdatatx16bits & (uint16_t)0x01FF);
          husart->pTxBuffPtr += 2U;
        }
        else
        {
          husart->Instance->DR = (uint8_t)(*husart->pTxBuffPtr++ & (uint8_t)0x00FF);
        }

        husart->TxXferCount--;

        /* 检查最后一位发送 */
        if (husart->TxXferCount == 0U)
        {
          CLEAR_BIT(husart->Instance->CR1, USART_CR1_TXEIE);
        }
      }
    }

    if (husart->RxXferCount != 0x00U)
    {
      if (__HAL_USART_GET_FLAG(husart, USART_FLAG_RXNE) != RESET)
      {
        if ((husart->Init.WordLength == USART_WORDLENGTH_9B) && (husart->Init.Parity == USART_PARITY_NONE))
        {
          pdatarx16bits = (uint16_t *) husart->pRxBuffPtr;
          *pdatarx16bits = (uint16_t)(husart->Instance->DR & (uint16_t)0x01FF);
          husart->pRxBuffPtr += 2U;
        }
        else
        {
          if ((husart->Init.WordLength == USART_WORDLENGTH_9B) || ((husart->Init.WordLength == USART_WORDLENGTH_8B) && (husart->Init.Parity == USART_PARITY_NONE)))
          {
            *husart->pRxBuffPtr = (uint8_t)(husart->Instance->DR & (uint8_t)0x00FF);
          }
          else
          {
            *husart->pRxBuffPtr = (uint8_t)(husart->Instance->DR & (uint8_t)0x007F);
          }
          husart->pRxBuffPtr += 1U;
        }

        husart->RxXferCount--;
      }
    }

    /* 检查最后一位接收*/
    if (husart->RxXferCount == 0U)
    {
      /* 禁用 USART RXNE(接收缓冲非空)中断 */
      CLEAR_BIT(husart->Instance->CR1, USART_CR1_RXNEIE);

      /* 禁用 USART 奇偶校验错误中断 */
      CLEAR_BIT(husart->Instance->CR1, USART_CR1_PEIE);

      /* 禁用 USART 错误中断: (帧错误,噪声错误,溢出错误) */
      CLEAR_BIT(husart->Instance->CR3, USART_CR3_EIE);

      husart->State = HAL_USART_STATE_READY;

#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
      /* 调用注册的 Tx Rx 完成回调 */
      husart->TxRxCpltCallback(husart);
#else
      /* 调用预定义弱 Tx Rx 完回调函数 */
      HAL_USART_TxRxCpltCallback(husart);
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */

      return HAL_OK;
    }

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}

/**
  * @brief  配置 USART 外设
  * @param  husart 指向包含指定USART模块的配置信息的USART_HandleTypeDef结构的指针
  * @retval None
  */
static void USART_SetConfig(USART_HandleTypeDef *husart)
{
  uint32_t tmpreg = 0x00U;
  uint32_t pclk;

  /* 清除参数 */
  assert_param(IS_USART_INSTANCE(husart->Instance));
  assert_param(IS_USART_POLARITY(husart->Init.CLKPolarity));
  assert_param(IS_USART_PHASE(husart->Init.CLKPhase));
  assert_param(IS_USART_LASTBIT(husart->Init.CLKLastBit));
  assert_param(IS_USART_BAUDRATE(husart->Init.BaudRate));
  assert_param(IS_USART_WORD_LENGTH(husart->Init.WordLength));
  assert_param(IS_USART_STOPBITS(husart->Init.StopBits));
  assert_param(IS_USART_PARITY(husart->Init.Parity));
  assert_param(IS_USART_MODE(husart->Init.Mode));

  /* LBCL(最后一位时钟脉冲)、CPOL(时钟极性)和CPHA(时钟相位)位必须在发送和接收都被禁用时选择(TE=RE=0),以确保时钟脉冲能够正确运行 */
  CLEAR_BIT(husart->Instance->CR1, (USART_CR1_TE | USART_CR1_RE));

  /*---------------------------- USART CR2(控制寄存器2)配置 ---------------------*/
  tmpreg = husart->Instance->CR2;
  /* 清除 CLKEN(CK引脚使能), CPOL(时钟极性), CPHA(时钟相位)和 LBCL(最后一位时钟脉冲) 位 */
  tmpreg &= (uint32_t)~((uint32_t)(USART_CR2_CPHA | USART_CR2_CPOL | USART_CR2_CLKEN | USART_CR2_LBCL | USART_CR2_STOP));
  /* 配置 USART 时钟, CPOL(时钟极性), CPHA(时钟相位)和 LBCL(最后一位时钟脉冲) -----------------------*/
  /* 根据husart->Init.CLKPolarity           的值设置CPOL(时钟极性)位 */
  /* 根据husart->Init.CLKPhase              的值设置CPHA(时钟相位)位 */
  /* 根据husart->Init.CLKLastBit            的值设置LBCL(最后一位时钟脉冲)位 */
  /* 设置停止位:根据husart->Init.StopBits    的值设置STOP[13:12]位 */
  tmpreg |= (uint32_t)(USART_CLOCK_ENABLE | husart->Init.CLKPolarity |
                       husart->Init.CLKPhase | husart->Init.CLKLastBit | husart->Init.StopBits);
  /* Write to USART CR2 */
  WRITE_REG(husart->Instance->CR2, (uint32_t)tmpreg);

  /*-------------------------- USART CR1(控制寄存器1)配置 -----------------------*/
  tmpreg = husart->Instance->CR1;

  /* 清除 M(数据长度), PCE(奇偶校验控制使能), PS(奇偶校验选择), TE(发送使能)和 RE(接收使能)位 */
  tmpreg &= (uint32_t)~((uint32_t)(USART_CR1_M | USART_CR1_PCE | USART_CR1_PS | USART_CR1_TE | USART_CR1_RE));

  /* 配置USART的数据位长度、奇偶校验和模式:
     根据husart->Init.WordLength  的值设置M(数据长度)位
     根据husart->Init.Parity      的值设置PCE(奇偶校验控制使能)和PS(奇偶校验选择)位
     根据husart->Init.Mode        的值设置TE(发送使能)和RE(接收使能)位
   */
  tmpreg |= (uint32_t)husart->Init.WordLength | husart->Init.Parity | husart->Init.Mode;

  /* 写入 USART CR1(控制寄存器1) */
  WRITE_REG(husart->Instance->CR1, (uint32_t)tmpreg);

  /*-------------------------- USART CR3(控制寄存器3)配置 -----------------------*/
  /* 清除 CTSE(CTS使能)和 RTSE(RTS使能)位 */
  CLEAR_BIT(husart->Instance->CR3, (USART_CR3_RTSE | USART_CR3_CTSE));

  /*-------------------------- USART BRR(波特率寄存器)配置 -----------------------*/
  if((husart->Instance == USART1))
  {
    pclk = HAL_RCC_GetPCLK2Freq();
    husart->Instance->BRR = USART_BRR(pclk, husart->Init.BaudRate);
  }
  else
  {
    pclk = HAL_RCC_GetPCLK1Freq();
    husart->Instance->BRR = USART_BRR(pclk, husart->Init.BaudRate);
  }
}

/**
  * @}
  */

/**
  * @}
  */

#endif /* HAL_USART_MODULE_ENABLED */
/**
  * @}
  */

/**
  * @}
  */

  • 12
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值