STM32串口接收中断——基于HAL库

2023-05-16

写在前面  

  最近需要使用一款STM32L4系列的芯片进行开发,需要学习使用HAL库。在进行串口中断使用的时候遇到了一些小麻烦,写下解决方案供大家参考。

1.UART相关的头文件引用错误

   由于本人直接使用MDK进行开发,没有使用CubeMX,所以一些初始化需要手动进行。在引用UART相关的头文件时,记得将"stm32l4xx_hal_conf.h"文件中的相关引用取消注释,如下图:

2.如何接收字符串(多次进入中断)

  接收字符串主要有两种方法,一种是对中断函数进行改造,另一种是对接收回调函数进行改造。
  在阐述这两种方法之前,需要介绍函数“HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)”。该函数的作用是用户自定义一个缓冲区(即参数pData),接受一定数量(由参数Size决定)的字符存入缓冲区中。同时,参数Size还决定着进入回调函数的频率,即每接收Size个字符,就进入一次回调函数。需要注意的是,Size只决定进入回调函数的频率,而不能影响进入接收中断的频率,无论Size是多少,每接收完成一个字符都会进入一次接收中断。

方法1:改造回调函数

  ①首先在主函数中进入主循环前的位置调用一次 HAL_UART_Receive_IT函数,定义一个字符数组getBuffer[]作为缓冲区,参数Size设定为10。即每接收10个字符,就进入一次回调函数。

  ②注册中断函数   

  void USART1_IRQHandler(void)
  {
    HAL_UART_IRQHandler(&UartHandle); //该函数会清空中断标志,取消中断使能,并间接调用回调函数
  }

  ③在文件“stm32l4xx_hal_uart.h”中,我们可以看到串口接收回调函数的定义。使用“_weak”关键字定义的函数,其具有如下特性: 一般情况下和一般函数相同。但是当有一个同名函数但是不带__weak被定义时,所有对这个函数的调用都是指向后者(不带__weak那个)。也就是说,ST官方提供的这个回调函数需要我们自己进行改写。  

     /**
      * @brief Rx Transfer completed callback.
      * @param huart UART handle.
      * @retval None
      */
    __weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
    {
      /* Prevent unused argument(s) compilation warning */
      UNUSED(huart);
       
     /* NOTE : This function should not be modified, when the callback is needed,
               the HAL_UART_RxCpltCallback can be implemented in the user file.
      */
    }

  我们在主函数所在的文件中对回调函数进行改写:  

   uint8_t myBuffer[] = "I have gotten your message: "; //用户提示信息
   uint8_t Enter[] = "\r\n"; //回车换行
   uint8_t getBuffer[100]; //用户自定义的缓冲区
   void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
   {
    while(HAL_UART_Transmit(UartHandle, (uint8_t*)myBuffer, COUNTOF(myBuffer), 5000)!= HAL_OK); //发送字符串,用户提示信息
    while(HAL_UART_Transmit(UartHandle, (uint8_t*)getBuffer, 10, 5000)!= HAL_OK); //发送用户自定义缓冲区中的数据
    while(HAL_UART_Transmit(UartHandle, (uint8_t*)Enter, COUNTOF(Enter), 5000)!= HAL_OK); //发送回车换行
   }

  以上代码的作用是把用户发送给单片机数据再返回给用户。运行效果如下图:

 


  我们可以看到,用户向单片机发送了10个字符,单片机向串口助手返回了这10个数据。但是以上程序只能实现一次,当我们再次向单片机发送数据时,单片机却不再返回数据。这是因为我们在中断函数中取消了中断使能,所以导致了进入一次中断后,中断被关闭,无法再次进入中断的现象。为了实现多次数据返回,我们要在中断处理函数中添加一行代码: 

  void USART1_IRQHandler(void)
  {
    HAL_UART_IRQHandler(&UartHandle); //该函数会清空中断标志,取消中断使能,并间接调用回调函数
    HAL_UART_Receive_IT(&UartHandle, (uint8_t *)&value,1);  //添加的一行代码
  }

  这样就可以实现多次数据返回了,新的执行结果如下图:

 

  可见,函数HAL_UART_Receive_IT还有中断使能的作用。这一功能的实现我们可以在HAL_UART_Receive_IT函数中找到。

 方法2:改造中断处理函数

  ①首先在主函数中进入主循环前的位置调用一次 HAL_UART_Receive_IT函数,定义一个字符value作为缓冲区,参数Size设定为1。即每接收1个字符,就进入一次回调函数。使得进入回调函数的频率与进入中断处理函数的频率相同。这样,我们就可以直接在中断函数中对接收的数据进行处理了。

  ②注册中断函数    

    uint8_t myBuffer[] = "I have gotten your message: ";
    uint8_t getBuffer[10];
    uint8_t Enter[] = "\r\n";
    void USARTx_IRQHandler(void)
    {
     HAL_UART_IRQHandler(&UartHandle); //该函数会清空中断标志,取消中断使能,并间接调用回调函数
     
     getBuffer[countOfGetBuffer++] = value; 
     if(countOfGetBuffer == 10)
    {
     while(HAL_UART_Transmit(&UartHandle, (uint8_t*)myBuffer, COUNTOF(myBuffer), 5000)!= HAL_OK);
     while(HAL_UART_Transmit(&UartHandle, (uint8_t*)getBuffer, countOfGetBuffer, 5000)!= HAL_OK);
     while(HAL_UART_Transmit(&UartHandle, (uint8_t*)Enter, COUNTOF(Enter), 5000)!= HAL_OK);
     countOfGetBuffer = 0;
    }
    HAL_UART_Receive_IT(&UartHandle, (uint8_t *)&value,1);  //由于接收中断是每接收一个字符便进入一次,所以这一行代码必须添加,否则只能接收一个字符,而无法接收整个字符串
    }

  以上代码的作用是接收每个来自用户的字符,并依次存入用户自定义的缓冲区中,数量达到10个后,将缓冲区中的所有数据返回给用户,同时清空计数,准备接下来10个字符的接收。运行效果如下图:

 

写在最后

  看完本文,大家可能对回调函数和中断处理函数的关系产生了疑问。其实是这样的,单片机每完成接收一个字符,就会进入一次中断处理函数,而在中断处理函数中,我们又调用了函数“void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)”,该函数会间接调用回调函数,也就是说回调函数是由中断处理函数间接调用的。而函数“HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)”决定了中断处理函数调用回调函数的频率,若Size为1,则每进入一次中断处理函数都会调用一次回调函数;若Size为10,则每第十次进入中断处理函数时,才会调用回调函数。

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

STM32串口接收中断——基于HAL库 的相关文章

  • 在地址“0xXXXXXX”处中断,没有可用的调试信息,或在程序代码之外

    配置 使用 Nucleo L476RG 使用 GNU ARM Eclipse 我从 STM32CubeMX 生成了一个极简代码 我已经在我的板载 ST Link 中刷新了 J link 驱动程序 一直在尝试为我的代码运行调试器 但我的程序计
  • 在 MCU 内部 FLASH 中从一个固件跳转到另一个固件

    我目前正在开发针对 STM32F030C8 的引导加载程序固件应用程序 我在分散文件中指定引导加载程序应用程序将占用主内存位置 0x08000000 到 0x08002FFF 扇区 0 到扇区 2 我还编写了一个主固件应用程序 存储在0x0
  • Push_back() 导致程序在进入 main() 之前停止

    我正在为我的 STM32F3 Discovery 板使用 C 进行开发 并使用 std deque 作为队列 在尝试调试我的代码 直接在带有 ST link 的设备上或在模拟器中 后 代码最终在 main 中输入我的代码之前在断点处停止 然
  • STM32F4 通过软复位跳转到引导加载程序,无需 BOOT0 和 BOOT1 引脚

    我问这个问题是因为可以在这里找到类似问题的答案 通过应用程序跳转到 STM32 中的引导加载程序 即从用户闪存在引导模式下使用引导 0 和引导 1 引脚 用户 JF002 JF002回答 当我想跳转到引导加载程序时 我在其中一个备份寄存器中
  • 毕业设计 江科大STM32的智能温室控制蓝牙声光报警APP系统设计

    基于STM32的智能温室控制蓝牙声光报警APP系统设计 1 项目简介 1 1 系统构成 1 2 系统功能 2 部分电路设计 2 1 stm32f103c8t6单片机最小系统电路设计 2 2 LCD1602液晶显示电路设计 2 2 风
  • STM32F103概要

    The STM32F103x4 STM32F103x6 STM32F103xC STM32F103xD and STM32F103xE are a drop in replacement for STM32F103x8 B medium d
  • 解决KEIL编译慢问题

    两种方案 使用v6版本的ARM Compiler 如果v6版本编译不过 必须使用v5版本的 则可以勾选掉Browse Information选项 提升很明显 1分多钟能优化到几秒 看代码量 但是这个有个弊端 在KEIL中会影响函数跳转 建议
  • 在 Atollic TrueStudio、STM32CubeMX 中导入 C 库

    我目前正在开发 STM32F767ZI Nucleo 板和一个小安全芯片 microchip atecc508a 通过 i2c 连接进行连接 该芯片有一个可用的库加密验证库 https github com MicrochipTech cr
  • 最终启动顺序错误 - STM32L476 的 Eclipse System Workbench 调试

    我正在尝试调试和运行 STM32L476 的简单汇编代码 我已经设置了 Eclipse Oxygen 在 Eclipse 中安装了最新版本的 System Workbench 插件并安装了 ST Link 驱动程序 IDE 成功构建了程序
  • 串口通讯第一次发送数据多了一字节

    先初始化IO再初始化串口 导致第一次发送时 多出一个字节数据 优化方案 先初始化串口再初始化IO 即可正常通讯
  • STM32 暂停调试器时冻结外设

    当到达断点或用户暂停代码执行时 调试器可以停止 Cortex 中代码的执行 但是 当皮质停止在暂停状态下执行代码时 调试器是否会冻结其他外设 例如 DMA UART 和定时器 您只能保留时间 r 取决于外围设备 我在进入主函数时调用以下代码
  • STM32的HAL中实现单按、长按和双按功能

    我正在尝试实现单击 双击和长按功能来执行不同的功能 到目前为止 我已经理解了单击和长按的逻辑 但我不知道如何检测双击 至于代码 我使用计数器实现了单击和长按 但代码仅停留在第一个 if 条件上 bool single press false
  • for循环延时时间计算

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 pandas是什么 二 使用步骤 1 引入库 2 读入数据 总结 前言 之前做led点亮的实验 好像是被delay函数影响了 因为delay参数设置的不对
  • systick定时器

    systick定时器 文章目录 前言 一 前期疑惑 二 解答 1 关于systick是阻塞的吗 2 非阻塞 三 软件编写 总结 前言 这边记录systick相关知识点 一 前期疑惑 在学习systick志气啊 其实对于systick还是一脸
  • Cortex-M3与M4权威指南

    处理器类型 所有的ARM Cortex M 处理器是32位的精简指令集处理器 它们有 32位寄存器 32位内部数据路径 32位总线接口 除了32位数据 Cortex M处理器也可以有效地处理器8位和16位数据以及支持许多涉及64位数据的操作
  • STM32 Nucleo 上的上升沿中断多次触发

    我正在使用 STM32 NUCLEO F401RE 微控制器板 我有一个扬声器 经过编程 当向上 向下推操纵杆时 可以按设定的量改变频率 我的问题是 有时 通常 当向上 向下推动操纵杆时 频率会增加 减少多次 这意味着 ISR 正在执行多次
  • 通过JTAG恢复STM32 MCU磨掉的标记

    我有一块可能带有 STM32 MCU 的板 我想为该板制作定制固件 因为库存板有很多问题 不幸的是 电路板制造商很友善地磨掉了所有标记 有没有办法通过 jtag 获取设备 系列 ID 并将其交叉引用到型号 我能找到的一切都是关于获取芯片的唯
  • STM32 上的 ADC 单次转换

    我正在研究 STM32 F103x 上的 ADC 编程 并从最简单的情况 单次转换开始 测量内部温度传感器 连接到 ADC1 的值 并使用 USART 将其发送到 COM 端口 目标似乎很明确 但是当我尝试将源代码下载到闪存时 它不会向 C
  • PWM DMA 到整个 GPIO

    我有一个 STM32F4 我想对一个已与掩码进行 或 运算的 GPIO 端口进行 PWM 处理 所以 也许我们想要 PWM0b00100010一段时间为 200khz 但随后 10khz 后 我们现在想要 PWM0b00010001 然后
  • 当端点和 PMA 地址均更改时,CubeMX 生成的 USB HID 设备发送错误数据

    我正在调试我正在创建的复合设备的问题 并在新生成的仅 CubeMX 代码中重新创建了该问题 以使其更容易解决 我添加了少量代码main 让我发送 USB HID 鼠标点击 并在按下蓝色按钮时使 LED 闪烁 uint8 t click re

随机推荐

  • SDL概念介绍

    下面是我对网上知识的一些总结 xff1a 1 SDL是一套开放源代码的跨平台多媒体开发库 xff0c 使用C语言写成 2 SDL提供了数种控制图像 声音 输入输出的函数 xff0c 可以跨平台进行软件开发 3 目前SDL多用于开发游戏 模拟
  • Python turtle库 写“生日快乐”

    1 首先要CTRL 43 R然后cmd进入命令行 xff0c 输入pip install turtle安装第三方库 2 打开python IDE xff0c 如下图 xff0c 点击 File 34 选择 New File 34 3 复制代
  • 简单回路与初级回路(圈)区别

    1 回路 xff1a 起点终点相同 简单通路 xff1a 起点到终点所经过的边不同 简单回路 xff1a 起点到终点所经过的边不同 43 回路 初级通路 xff1a 起点到终点所经过的顶点各异 43 简单通路 初级回路 圈 xff1a 起点
  • wechaty搭建微信机器人——超详细版

    文章目录 前言一 wechaty是什么 xff1f 二 准备1 安装 Node js xff08 需要10 0版本以上 xff09 2 安装Wechaty 总结 前言 提示 xff1a 这里可以添加本文要记录的大概内容 xff1a 例如 x
  • 离散 排斥或与相容或的区别

    1 相同之处 xff1a 就是 或 2 不同之处 xff1a 一个排斥 xff0c 一个相容 p xff1a 2是偶数 q xff1a 2是奇数 xff0c 这种情况下是排斥或 xff0c 也即一个命题成立 xff0c 则其他命题不成立 p
  • Latex中ACM-Reference-Format顺序与论文引用顺序不一致solution

    在第一次编译的时候 xff0c 先使用 bibliographystyle unsrt 而非模板的 bibliographystyle ACM Reference Format 的进行按顺序的编译 在之后的编译中 xff0c 使用 bibl
  • 正则表达式快速入门

    目录 1 正则表达式是什么 xff0c 有什么作用2 定位符例子2 1想要搜索以 001 开头的文件2 2想要搜索以 ab 结尾的文件2 3搜索单词开头为 zh 34 的文件2 4搜索单词结尾为 zh 34 的文件2 5搜索单词中间为 zh
  • JAVASE基础(一)

    这里写目录标题 一 javaSE基础1 jdk文档2 代码量统计工具3 文档注释4 反编译工具5 JDK JRE JVM xff08 java虚拟环境 xff09 61 61 6 变量命名规则 61 61 7 变量的作用域8 数据类型9 进
  • JAVASE基础(二)

    这里写目录标题 JAVASE基础11 科学计数法12 编码和字符集12 编译格式问题13 类型转换类型级别自动类型转换强制类型转换特殊情况 14 final修饰符a 修饰变量b 修饰方法c 修饰类 15 scanner使用16 两个数交换引
  • 关于gcc编译 -I -L -l的使用

    gcc o hello hello c I home hello include L home hello lib lworld 参数说明 xff1a I home hello include表示将 home hello include 目
  • Matlab彩色图像的rgb分量获取,彩色通道互换

    1 原图像 2 matlab代码 xff0c 将图像的绿色和蓝色通道进行互换 A 61 imread 39 花朵 jpg 39 h w d 61 size A R 61 A 1 获取红色分量 G 61 A 2 获取绿色分量 B 61 A 3
  • 使用Xavier读取RealSense D435i的踩坑经历

    由于项目需要 xff0c 最近开始研究通过Xavier运行VINS的方法 xff0c 使用的传感器是Intel的RealSense xff0c 但是Xavier对RealSense的支持却不怎么好 xff0c 下面介绍一下躲坑方法 xff0
  • 宏函数详解

    宏函数 xff1a STL模板 实现函数的复用性 函数 xff1a 可以传递参数 但是不能将类型作为参数传递 例如 xff1a 一个开辟内存的函数 xff1a define Malloc type size type malloc size
  • UBUNTU将新路径添加到ROS_PACKAGE_PATH中。

    first 查看路径 chen 64 chen HP echo ROS PACKAGE PATH opt ros indigo share opt ros indigo stacks 添加 chen 64 chen HP echo 34 e
  • Visual Studio实现多核并行编译

    Visual Studio 大工程项目的编译时间较长 xff0c 可以利用多核CPU的优势 xff0c 实现并行编译 xff0c 设置并行编译方法示例如下 xff1a 1 在 ClassView 中选取某项目的 Properties xff
  • 五参数超声波风速风向传感器

    五参数超声波风速风向传感器介绍风速风向基于超声波原理研发的风速风向测量仪器 xff0c 利用发送的声波脉冲 xff0c 测量接收端的时间或频率 xff08 多普勒变换 xff09 差别来计算风速和风向 该传感器可以同时测量风速 xff0c
  • Postman 的使用教程(详细)

    Postman 使用教程 1 是什么 Postman 是一个接口测试工具软件 xff0c 可以帮助开发人员管理测试接口 官网 xff1a https www getpostman com 2 安装 建议通过官网下载安装 xff0c 不要去那
  • 《Qt 5.9 C++开发指南》第3章 Qt类库概述【详细摘要】

    Qt是一个用标准C 43 43 编写的跨平台开发类库 xff0c 它对标准C 43 43 进行了扩展 xff0c 引入了元对象系统 信号与槽 属性等特性 xff0c 使得应用程序开发变得更高效 本章介绍Qt的这些核心特点 xff0c 对于理
  • c++中引用相关概念总结

    1 先从下面这两段代码的运行结果开始看起 xff1a int a 61 10 在内存上开辟4个字节 xff0c a就代表这个4个字节内存 int p 61 amp a 让一个指针 指向这个4个字节的空间 p 61 20 cout lt lt
  • STM32串口接收中断——基于HAL库

    写在前面 最近需要使用一款STM32L4系列的芯片进行开发 xff0c 需要学习使用HAL库 在进行串口中断使用的时候遇到了一些小麻烦 xff0c 写下解决方案供大家参考 1 UART相关的头文件引用错误 由于本人直接使用MDK进行开发 x