写在前面  

  最近需要使用一款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[]; //用户自定义的缓冲区
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
{
while(HAL_UART_Transmit(UartHandle, (uint8_t*)myBuffer, COUNTOF(myBuffer), )!= HAL_OK); //发送字符串,用户提示信息
while(HAL_UART_Transmit(UartHandle, (uint8_t*)getBuffer, , )!= HAL_OK); //发送用户自定义缓冲区中的数据
while(HAL_UART_Transmit(UartHandle, (uint8_t*)Enter, COUNTOF(Enter), )!= HAL_OK); //发送回车换行
}

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


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

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

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

 

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

  以上代码的作用是接收每个来自用户的字符,并依次存入用户自定义的缓冲区中,数量达到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,则每第十次进入中断处理函数时,才会调用回调函数。方法2使用了标准库中断处理数据的思想。

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

  1. Keil MDK STM32系列(九) 基于HAL和FatFs的FAT格式SD卡TF卡读写

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  2. 【GMT43智能液晶模块】基于HAL库的SDRAM和LCD驱动例程(MDK工程&CubeMX工程)

    说明: 1.该工程基于HAL库实现动态存储器SDRAM驱动以及液晶控制器LCD驱动. 2.工程通过STM32CubeMX(Version 4.22.0)配置生成,可直接打开进行配置. 3.KEIL M ...

  3. STM32F072从零配置工程-基于HAL库的串口UART中断配置

    先上一个采用串口直接传输的Demo: 此处的思路是完全采用HAL库来实现的,核心是运用HAL_UART_Transmit_IT和HAL_UART_Receive_IT两个函数来实现的,可以作为一个De ...

  4. STM32基于HAL库通过DMA读写SDIO

    通过STM32CUBEMX生成DMA读写sdio的工程,再读写过程中总会卡死在DMA中断等待读写完成的while中,最终发现while等待的标志在SDIO的中断里置位的,而SDIO中断优先级如果小于或 ...

  5. 基于HAL库的STM32的DSP库详解(附FFT应用)

    1 . 建立工程,生成代码时选择包含所有库.   2. 打开 option for target 选择 Target 标签,在code generatio中,将floating point hardw ...

  6. stm32串口接收中断协议解析

    借鉴了文章:<stm32串口中断接收方式详细比较> 文章地址:http://blog.csdn.net/kevinhg/article/details/40186169 串口的配置这里不做 ...

  7. STM32 IIC双机通信—— HAL库硬件IIC版

    参考传送门 关于IIC的原理这里我就不多说了,网上有很多很好的解析,如果要看我个人对IIC的理解的话,可以点击查看,这里主要讲一下怎样利用STM32CubeMx实现IIC的通讯,经过个人实践,感觉HA ...

  8. 【stm32】基于hal库使用野火指南者esp8266 WIFI模块进行TCP传输

    UART.c #include "stm32f1xx_it.h" #include "LED.h" #include "UART.h" #i ...

  9. STM32系统时钟RCC(基于HAL库)

    基础认识 为什么要有时钟: 时钟就是单片机的心脏,其每跳动一次,整个单片机的电路就会同步动作一次.时钟的速率决定了两次动作的间隔时间.速率越快,单片机在单位时间内所执行的动作将越多.时钟是单片机运行的 ...

随机推荐

  1. Target Sum

    You are given a list of non-negative integers, a1, a2, ..., an, and a target, S. Now you have 2 symb ...

  2. 【C++札记】new和delete

    介绍 1.malloc,free和new,delete区别. a.malloc,free是C/C++的标准库函数.new,delete是c++的操作符. b.malloc申请的是内存,严格意义不是&q ...

  3. 题目21 包含Min函数的栈

    ///////////////////////////////////////////////////////////////////////////////////// // 3. 题目21  包含 ...

  4. vmstat命令详解--转载

    一.前言 vmstat命令:  用来获得有关进程.虚存.页面交换空间及 CPU活动的信息.这些信息反映了系统的负载情况 二.虚拟内存运行原理 在系统中运行的每个进程都需要使用到内存,但不是每个进程都需 ...

  5. (转)从0移植uboot(六) _实现网络功能

    ref:https://www.cnblogs.com/xiaojiang1025/p/6500532.html 为uboot添加网卡功能可以让uboot通过tftp下载内核, 方便我们的开发, 对于 ...

  6. MySql数据库 优化

    MySQL数据库优化方案 Mysql的优化,大体可以分为三部分:索引的优化,sql慢查询的优化,表的优化. 开启慢查询日志,可以让MySQL记录下查询超过指定时间的语句,通过定位分析性能的瓶颈,才能更 ...

  7. 使用vue-cli创建vue工程

    在Windows环境下,打开命令行窗口,跳转至想创建工程的路径. 如:D:\MyWork\22_Github\rexel-cn\rexel-jarvis 创建vue工程,命令:vue create r ...

  8. (八)装配Bean(2)

    二.在Java类中进行显式的装配 显式配置有两种: 1. 一种是在java(本文讲解)   2. 另一种是xml配置文件(第一章有讲) 案例一: 使用java显式装配+@autowired自动装配的方 ...

  9. (八)Struts标签基础(一)

    一.Struts标签分类 二.标签的使用 2.1 标签的主题 主题的设置与struts.xml中的常量<constant name="struts.ui.theme" val ...

  10. (一)weblogic11g的安装配置

    一.安装 找到weblogic安装包,小编这里用的是wls1034_win32.exe版本,双击打开 完成后运行快速启动,打开快速启动界面,配置weblogic.如果没有打开,还可以在开始菜单中找到q ...