详解STM32CubeIDE 中 HAL库的串口中断接收函数 HAL_UART_Receive_IT

2023-05-16

MX串口配置方法见:CubeIDE 利用自带HAL库 串口收发

 

一、代码自动生成以后的项目及代码结构:

main.c中,调用了串口初始化

 

串口初始化函数赋值了串口的参数

 

相当于底层的初始化,配置引脚、并开启中断。

至此串口1配置完毕

二、库文件stm32f1xx_hal_uart.c内的秘密

2.1 初始化

1.usart.c中,MX_USART1_UART_Init 调用了库的HAL_UART_Init,将结构体传递进该函数中

2.HAL_UART_Init干了些什么事?

 if (huart->gState == HAL_UART_STATE_RESET)
  {
    huart->Lock = HAL_UNLOCKED;
    HAL_UART_MspInit(huart);
  }
huart->gState = HAL_UART_STATE_BUSY; 
  __HAL_UART_DISABLE(huart);  /* Disable the peripheral */
  UART_SetConfig(huart);/* Set the UART Communication parameters */

  /* In asynchronous mode, the following bits must be kept cleared:
     - LINEN and CLKEN bits in the USART_CR2 register,
     - SCEN, HDSEL and IREN  bits in the USART_CR3 register.*/
  CLEAR_BIT(huart->Instance->CR2, (USART_CR2_LINEN | USART_CR2_CLKEN));
  CLEAR_BIT(huart->Instance->CR3, (USART_CR3_SCEN | USART_CR3_HDSEL | USART_CR3_IREN));
  __HAL_UART_ENABLE(huart);  /* Enable the peripheral */
  huart->ErrorCode = HAL_UART_ERROR_NONE;
  huart->gState = HAL_UART_STATE_READY;
  huart->RxState = HAL_UART_STATE_READY;

调用MspInit-->修改状态忙-->配置寄存器-->清楚标志位 

2.2 先理解HAL_UART_Receive函数

uint32_t tickstart = 0U;

if (huart->RxState == HAL_UART_STATE_READY)  /* Check that a Rx process is not already ongoing */
  {
    __HAL_LOCK(huart);    /* Process Locked */

    huart->ErrorCode = HAL_UART_ERROR_NONE;
    huart->RxState = HAL_UART_STATE_BUSY_RX;

    tickstart = HAL_GetTick();

    huart->RxXferSize = Size;
    huart->RxXferCount = Size;


    while (huart->RxXferCount > 0U)
    {
      huart->RxXferCount--;
      if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_RXNE, RESET, tickstart, Timeout) != HAL_OK)
            return HAL_TIMEOUT;
      *pData++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
      }
}

    huart->RxState = HAL_UART_STATE_READY;
    __HAL_UNLOCK(huart);

判断是否忙-->锁住-->标记接收忙-->获取tick计数

-->赋值RxXferCount有多少数据要接收-->每次从DR内获取一个Byte存在pData指向的空间

2.3 HAL_UART_Receive_IT只是配置了一下参数,并没有做任何处理

/* Check that a Rx process is not already ongoing */
  if (huart->RxState == HAL_UART_STATE_READY)
  {
    __HAL_LOCK(huart);    /* Process Locked */
    huart->pRxBuffPtr = pData;
    huart->RxXferSize = Size;
    huart->RxXferCount = Size;
    huart->ErrorCode = HAL_UART_ERROR_NONE;
    huart->RxState = HAL_UART_STATE_BUSY_RX;
    __HAL_UNLOCK(huart);    /* Process Unlocked */

    /*Error Interrupt */
    __HAL_UART_ENABLE_IT(huart, UART_IT_PE);
    __HAL_UART_ENABLE_IT(huart, UART_IT_ERR);

    /* Enable the UART Data Register not empty Interrupt */
    __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);

    return HAL_OK;
    }

存储在pData指向位置、空间大小RxXferSize 、接收计数RxXferCount ; 接收状态忙;使能接收中断

那么当有数据来的时候,就需要依靠中断函数来处理了。

2.4再看看中断函数在做什么

stm32f1xx_it.c内有定义USART1_IRQHandler,只调用了HAL_UART_IRQHandler函数,下面是

HAL_UART_IRQHandler具体内容

errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
  if (errorflags == RESET)
  {
    if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
    {
      UART_Receive_IT(huart);
      return;
    }
  }

  /* If some errors occur */
  if ((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))
  {
//略过错误处理
    /* Call UART Error Call back function if need be --------------------------*/
    if (huart->ErrorCode != HAL_UART_ERROR_NONE)
    {
      /* UART in mode Receiver -----------------------------------------------*/
      if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
        UART_Receive_IT(huart);
//略过错误处理
        huart->ErrorCode = HAL_UART_ERROR_NONE;
      }
    }
    return;
  } /* End if some error occurs */

  /* UART in mode Transmitter ------------------------------------------------*/
  if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
  {    UART_Transmit_IT(huart);    return;  }

  /* UART in mode Transmitter end --------------------------------------------*/
  if (((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
  {    UART_EndTransmit_IT(huart);    return;  }

无非是三件事,判断是由什么中断响应的,有错误则处理,响应要调用的接收或者发送。

注意区别 UART_Receive_IT 和 HAL_UART_Receive_IT。

HAL_UART_Receive_IT是用户调用的需要接收多少数据存在何处。

UART_Receive_IT是中断调用的有数据收到该如何处理。

2.5 UART_Receive_IT 真正在接收数据的函数,但在最后会关闭中断

  uint16_t *tmp;

  /* Check that a Rx process is ongoing */
  if (huart->RxState == HAL_UART_STATE_BUSY_RX)
  {
    *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
    if (--huart->RxXferCount == 0U)
    {
      __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);
      __HAL_UART_DISABLE_IT(huart, UART_IT_PE);
      __HAL_UART_DISABLE_IT(huart, UART_IT_ERR);

      huart->RxState = HAL_UART_STATE_READY;

#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
      /*Call registered Rx complete callback*/
      huart->RxCpltCallback(huart);
#else
      /*Call legacy weak Rx complete callback*/
      HAL_UART_RxCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */

      return HAL_OK;
    }
    return HAL_OK;
  }

如果是接收状态忙,则从DR中读取1Byte数据。

如果接收计数归零,则使中断失效,并调用回调函数(用户定义则调用用户的,否则调用系统的)

至此,所有用到的代码分析完毕

三、总结

1、HAL_UART_Receive_IT和HAL_UART_Receive的区别就是:中断接收是有数据到了才去读;直接接收是直接读取,如果超时就返回

2、HAL_UART_Receive_IT配置后,有数据来,计数会在调用中断函数之后自动减1。只有到计数为0时,才会关闭中断调用回调函数。至此有数据来不再调用中断函数,因为中断已经失效。

3、HAL_UART_Receive_IT在计数未至0之前,应该可以读取之前接收到的数据,但这样做应该比较危险。

4、在开源电子的例程中,使用 HAL_UART_Receive_IT(&huart1,(uint8_t *)aRxBuffer, 1);  即Size设置为1,只接收1Byte数据,在每次中断结束后重新配置来使能中断。

四、还有必要再看一眼uart的结构体定义

/**
  * @brief  UART handle Structure definition
  */
typedef struct __UART_HandleTypeDef
{
  USART_TypeDef                 *Instance;        /*!< UART registers base address        */

  UART_InitTypeDef              Init;             /*!< UART communication parameters      */

  uint8_t                       *pTxBuffPtr;      /*!< Pointer to UART Tx transfer Buffer */

  uint16_t                      TxXferSize;       /*!< UART Tx Transfer size              */

  __IO uint16_t                 TxXferCount;      /*!< UART Tx Transfer Counter           */

  uint8_t                       *pRxBuffPtr;      /*!< Pointer to UART Rx transfer Buffer */

  uint16_t                      RxXferSize;       /*!< UART Rx Transfer size              */

  __IO uint16_t                 RxXferCount;      /*!< UART Rx Transfer Counter           */

  DMA_HandleTypeDef             *hdmatx;          /*!< UART Tx DMA Handle parameters      */

  DMA_HandleTypeDef             *hdmarx;          /*!< UART Rx DMA Handle parameters      */

  HAL_LockTypeDef               Lock;             /*!< Locking object                     */

  __IO HAL_UART_StateTypeDef    gState;           /*!< UART state information related to global Handle management
                                                       and also related to Tx operations.
                                                       This parameter can be a value of @ref HAL_UART_StateTypeDef */

  __IO HAL_UART_StateTypeDef    RxState;          /*!< UART state information related to Rx operations.
                                                       This parameter can be a value of @ref HAL_UART_StateTypeDef */

  __IO uint32_t                 ErrorCode;        /*!< UART Error code                    */

#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
  void (* TxHalfCpltCallback)(struct __UART_HandleTypeDef *huart);        /*!< UART Tx Half Complete Callback        */
  void (* TxCpltCallback)(struct __UART_HandleTypeDef *huart);            /*!< UART Tx Complete Callback             */
  void (* RxHalfCpltCallback)(struct __UART_HandleTypeDef *huart);        /*!< UART Rx Half Complete Callback        */
  void (* RxCpltCallback)(struct __UART_HandleTypeDef *huart);            /*!< UART Rx Complete Callback             */
  void (* ErrorCallback)(struct __UART_HandleTypeDef *huart);             /*!< UART Error Callback                   */
  void (* AbortCpltCallback)(struct __UART_HandleTypeDef *huart);         /*!< UART Abort Complete Callback          */
  void (* AbortTransmitCpltCallback)(struct __UART_HandleTypeDef *huart); /*!< UART Abort Transmit Complete Callback */
  void (* AbortReceiveCpltCallback)(struct __UART_HandleTypeDef *huart);  /*!< UART Abort Receive Complete Callback  */
  void (* WakeupCallback)(struct __UART_HandleTypeDef *huart);            /*!< UART Wakeup Callback                  */

  void (* MspInitCallback)(struct __UART_HandleTypeDef *huart);           /*!< UART Msp Init callback                */
  void (* MspDeInitCallback)(struct __UART_HandleTypeDef *huart);         /*!< UART Msp DeInit callback              */
#endif  /* USE_HAL_UART_REGISTER_CALLBACKS */

} UART_HandleTypeDef;

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

详解STM32CubeIDE 中 HAL库的串口中断接收函数 HAL_UART_Receive_IT 的相关文章

  • Python 爬虫下一代网络请求库 httpx 和 parsel 解析库测评

    这是 进击的Coder 的第 437 篇技术分享 作者 xff1a 大江狗 来源 xff1a Python Web与Django开发 阅读本文大概需要 8 分钟 Python 网络爬虫领域两个最新的比较火的工具莫过于 httpx 和 par
  • ubuntu下rsync两个服务器同步文件

    前言 文件服务器为ubuntu的 xff0c 客户端为windows的环境 主服务器配置 在Ubuntu下安装rsync通过以步骤可以实现 xff1a span class token function sudo span span cla
  • ROS总结——ROS消息发布和订阅

    消息发布器和订阅器 C 43 43 本博客总结绍如何用 C 43 43 编写消息发布器节点和订阅器节点 1 编写发布器节点 节点 Node 是指 ROS 网络中可执行文件 接下来 xff0c 将会创建一个发布器节点 talker xff0c
  • 无线充电器的CE认证、FCC认证、IC认证测试标准

    无线充电器是指不用传统的充电电源线连接到需要充电的终端设备上的充电器 xff0c 采用电磁感应原理 xff0c 通过线圈进行能量耦合实现能量的传递 从理论来说 xff0c 无线充电技术对人体安全无害处 xff0c 无线充电使用的共振原理是磁
  • STM32 uart空闲中断

    文章目录 目的 xff1a 前提 xff1a 相关代码 xff1a 使能UART IT IDLE中断中断处理函数中添加回调回调处理函数 目的 xff1a 使用UART空闲中断接收不定长消息 前提 xff1a stm32CubeMX工具配置u
  • 远程访问如此简单,通过 ZeroTier 和 Tailscale 轻松组建虚拟局域网,实现内网穿透。

    因为最近用了 Plex 所以研究了一下远程访问 xff0c 经过一番折腾基本上算是搞明白了 xff0c 在这里分享一些自己的经验给和我一样的小白 xff0c 如果有不对的地方欢迎指正 这里的远程访问是指在局域网外通过网络访问局域网 xff0
  • 组网必看,有线 MESH 全攻略。

    之前写过几篇关于 MESH 组网的文章 xff0c 主要讲解了如何布线 xff0c 路由器和光猫 交换机等设备应该怎样连接 xff0c 但通过大家的反馈我发现我漏掉了一个重点 xff0c 就是光猫和路由器应该如何设置 xff0c 这也是很多
  • 给 iOS 装上旧版 APP,十年前的 iPad mini 重获新生!

    不知道有没有人像我一样 xff0c 还留着五年前 十年前的老 iPad 老 iPhone xff0c 如果有 xff0c 你们一定知道有些老 iPad 老 iPhone 已经停在一个系统版本无法再继续升级了 xff0c 或者因为害怕升级变卡
  • Stable Diffusion WebUI 1.4「gradio」报错解决方案

    今天有很多朋友在运行 Stable Diffusion WebUI 1 4 时都遇到了 ModuleNotFoundError No module named 39 gradio 39 这个报错 xff0c 在这里给大家一个解决方案 xff
  • 如何在 macOS 使用 AList + RCLONE 把网盘挂载到本地

    之前接触最多的可能还是百度网盘 xff0c 它的免费容量比较大 xff0c 我们在下载和分享一些文件的时候经常会用到 xff0c 但是如果文件比较大 xff0c 加上限速 xff0c 使用体验并不算太好 其实除了下载文件 xff0c 我很少
  • jdk 安卓sdk 安装

    https www cnblogs com gufengchen p 11038029 html jdk sdk安装详细步骤 https www jianshu com p 8fb367a51b9f utm campaign 61 haru
  • 通过 Plex + Trakt 同步观看状态和评分,轻松记录你的追剧观影史

    喜欢看电影 追剧 追综艺的朋友想必都有做记录的习惯 xff0c Plex 的用户里用豆瓣的人估计不少 xff0c 使用豆瓣标记电影 写影评 短评和参与线上讨论是非常方便的 xff0c 但是豆瓣对电视剧的支持相对还是比较弱 xff0c 很多剧
  • macOS 如何设置 AList、RCLONE、xTeVe 开机启动后台运行

    之前和大家分享了 macOS 上 AList RCLONE xTeVe 的使用教程 xff0c 他们基本上都是通过终端命令或者 Unix 可执行文件运行的 xff0c 启动后需要保持运行状态才能持续提供服务 xff0c 今天分享一下如何让它
  • zynqmp zcu102 SD卡驱动调试

    新板卡使用sdhci0 xff0c 以前是sdhci1 xff0c 由于官方没有使用sdhci0所以需要手动添加设备树 xff1a amp sdhci0 clock frequency 61 lt 60000000 gt status 61
  • zynqmp zcu102 arm linux (uboot网卡输出调试信息)

    需求 xff1a 使用网卡输出自检 调试信息 由于uboot启动完成就退出运行 xff0c 进入Linux启动 xff0c 不是进入消息循环处理网络协议栈 xff0c 且没有现成的udp接口发送数据 xff0c 所以想在启动中输出调试信息调
  • libiec61850-1.4 库的使用和修改(goose)

    目的 xff1a 使用libiec61850 1 4 库接收和发送goose数据 xff0c 环境Ubuntu 18 04 4 LTS 问题 xff1a 使用libiec61850 1 4 examples goose publisher例
  • zynqmp zcu102 arm 裸机SD卡驱动

    1 加载PL端提供的 HDF 2 创建hello world例程 xff08 bsp xff09 3 在main函数中调用驱动初始化sd卡 void mmc test void s32 Status XSdPs InstancePtr XS
  • ubuntu / 麒麟 播放PCM音频文件

    ubuntu18 04 麒麟 播放PCM音频文件 xff0c 源码来源于网友文章再修改 xff0c 仅测试用 xff01 如果应用在产品上需要再优化 最简单的SDL2播放音频的例子 xff08 SDL2播放PCM xff09 Simples
  • QT中关于close()系统调用 和qt close()冲突

    参考 xff1a 点击打开链接 xff08 http bytes com topic c answers 856501 use close int unistd h qt xff09
  • 解决QScrollArea不能出现滚动条的问题

    转载 xff1a QScrollArea实在是一个非常强大的控件 xff0c 节省了很多重复工作 但如果使用Qt Creator中的ui designer来制作界面的话 xff0c 就会出现滚动条无法出现的问题 而在 C 43 43 GUI

随机推荐

  • QT子窗口全屏显示与还原问题

    子窗口全屏显示 vws gt setWindowFlags Qt Dialog vws gt showFullScreen 之后窗口还原时调用 this gt showNormal 对顶级窗口有效 this gt setWindowFlag
  • 设置系统屏幕关闭及系统休眠时间

    include lt Powrprof h gt pragma comment lib 34 PowrProf lib 34 DWORD lockTime 61 0 void SetPowerPolicy SYSTEM POWER POLI
  • 如何编译和运行C++程序

    如何编译和运行C 43 43 程序 C 43 43 和C语言类似 xff0c 也要经过编译和链接后才能运行 我们在C语言课程的时候 xff0c 讲了如何使用 VS VC 6 0 VC 43 43 2010等常见开发工具 xff0c 它们除了
  • 简单理解socket(AF_INET&SOCK_STREAM,SOCK_DGRAM)

    套接字 在任何类型的通信开始之前 xff0c 网络应用程序都必须创建套接字 套接字最初是为同一主机上的应用程序所创建 xff0c 使得主机上运行的一个程序 xff08 又名一个进程 xff09 与另一个运行的程序进行通信 这就是所谓的进程间
  • 为什么编程语言中需要堆和栈

    概述 在我们学习 C C 43 43 和 Java 等编程语言的时候经常要学习一个概念就是堆和栈 xff0c 对于大部分经验丰富的工程师来说 xff0c 堆和栈是再熟悉不过的东西了 xff0c 堆和栈都是存储程序运行时变量的地方 但这个时候
  • GT1050 PointPillar成功运行

    目的 之前在感知这里主要是考传统的算法 xff0c 但是遇到了瓶颈 xff0c 计算效率提不上来 xff0c 所以尝试一下其他的方法 目前看到pointpillar这种方法效果比较好 xff0c 就打算尝试一下 跑通测试一下效果 piont
  • 使用离线数据测试apollo7.0

    https zhuanlan zhihu com p 510712104 cd apollo 视觉测试 xff1a 1 启动dreamview 并选择车辆和地图 scripts bootstrap sh 2 启动transform模块 cy
  • 相机、激光雷达坐标系相互转换

    目录 读入外参和摄像头内参配置文件读入TF读入 激光雷达坐标系转到摄像头坐标系摄像头坐标系转到激光雷达坐标系 读入外参和摄像头内参 配置文件读入 std span class token double colon punctuation s
  • C++ thread的方式

    多线程的实现方式 xff0c 只做记录 xff0c 自己看 目录 第一种 在类中实现多线程第二种 在类外第三种 没有类第四种 pthread 定时触发总结附录 第一种 在类中实现多线程 新建thread对象 xff0c 传入类的成员函数名称
  • zynq 在ubuntu下移植ubuntu操作系统

    米联客的配套的文件是osrc lab 1 配置路径 在setting64 sh中把路径给更改一下 这里就是 改成ubuntu 并运行surce settings64 sh 2 rootfs 执行脚本 cfg rootfs sh 然后make
  • zynq 维修调试记录 客服支持 工作记录

    米联的板子用底板供电 xff0c 用JTAG往里面下程序 的时候也出现了如下问题 xff1a 跟客服进行沟通 xff0c 客服的回答是 xff1a 一般是两种可能 xff0c 一个是开发板坏了 xff0c 进行如下操作 xff0c 操作的程
  • ubuntu 16.04 安装apollo3.0(发布版)

    参考官网文档 xff1a https github com ApolloAuto apollo tree master docs https github com ApolloAuto apollo blob master docs how
  • 关于malloc返回地址无法访问

    正常情况下使用malloc申请内存 xff0c 要么是申请成功返回有效地址 xff0c 要么是内存申请失败 xff08 内存不足 xff09 返回NULL 如果出现返回了地址却无法访问的情况 xff0c 很有可能是前面代码访问内存时出现了越
  • docker里面安装Qt Creator

    sudo apt get install qt5 default qtcreator
  • 软连接ln -s 创建以及删除

    在 usr local 创建软连接 链接到 usr local include test dst文件夹 phe 64 phe usr local sudo ln s usr local include test dst test sourc
  • CAN报文:数据帧详解

    CAN报文 xff1a 数据帧详解 CAN报文CAN帧类型数据帧帧起始 Start Of Frame 仲裁段控制段数据段CRC段ACK段帧结束 End Of Frame CAN报文 CAN使用的是两条差分信号线 xff0c 只能表达一个信号
  • I2C总线和SPI总线

    I2C串行总线一般有两根信号线 xff0c 一根是双向的数据线SDA xff0c 另一根是时钟线SCL I2C协议 2条双向串行线 xff0c 一条数据线SDA xff0c 一条时钟线SCL SDA传输数据是 大端传输 xff08 字节高位
  • APM飞控学习之路:2 四旋翼的工作原理与系统组成

    一叶障目 xff0c 不见泰山 在研究四旋翼飞行器之前 xff0c 有必要从整体介绍其工作原理 主要部件 技术名词等基础知识 不然就像羊入虎口 xff0c 陷入一大堆不同层次的资料 xff0c 难觅出口 接下我就抛砖引玉 xff0c 尽自己
  • APM飞控学习之路:4 源码裁剪与下载

    月盈则亏 xff0c 水满则溢 当博主编译完成 xff0c 以为离成功更近一步准备下载的时候 xff0c 殊不知陷阱也早已准备好 xff0c 等待我的踏入 连上USB线 xff0c 下载 xff0c timeout xff0c timeou
  • 详解STM32CubeIDE 中 HAL库的串口中断接收函数 HAL_UART_Receive_IT

    MX串口配置方法见 xff1a CubeIDE 利用自带HAL库 串口收发 一 代码自动生成以后的项目及代码结构 xff1a main c中 xff0c 调用了串口初始化 串口初始化函数赋值了串口的参数 相当于底层的初始化 xff0c 配置