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

写在前面  

  最近须要使用一款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个字符,就进入一次回调函数。

  ②注册中断函数   数组

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

  ③在文件“stm32l4xx_hal_uart.h”中,咱们能够看到串口接收回调函数的定义。使用“_weak”关键字定义的函数,其具备以下特性: 通常状况下和通常函数相同。可是当有一个同名函数可是不带__weak被定义时,全部对这个函数的调用都是指向后者(不带__weak那个)。也就是说,ST官方提供的这个回调函数须要咱们本身进行改写。  函数

 1    /**  2  * @brief Rx Transfer completed callback.  3  * @param huart UART handle.  4  * @retval None  5     */
 6   __weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)  7  {  8     /* Prevent unused argument(s) compilation warning */
 9  UNUSED(huart); 10       
11     /* NOTE : This function should not be modified, when the callback is needed, 12  the HAL_UART_RxCpltCallback can be implemented in the user file. 13      */
14   }

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

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

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

 
  咱们能够看到,用户向单片机发送了10个字符,单片机向串口助手返回了这10个数据。可是以上程序只能实现一次,当咱们再次向单片机发送数据时,单片机却再也不返回数据。这是由于咱们在中断函数中取消了中断使能,因此致使了进入一次中断后,中断被关闭,没法再次进入中断的现象。为了实现屡次数据返回,咱们要在中断处理函数中添加一行代码: 
1  void USART1_IRQHandler(void) 2  { 3    HAL_UART_IRQHandler(&UartHandle); //该函数会清空中断标志,取消中断使能,并间接调用回调函数
4    HAL_UART_Receive_IT(&UartHandle, (uint8_t *)&value,1);  //添加的一行代码
5  }

  这样就能够实现屡次数据返回了,新的执行结果以下图:spa

 

  可见,函数HAL_UART_Receive_IT还有中断使能的做用。这一功能的实现咱们能够在HAL_UART_Receive_IT函数中找到。code

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

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

  ②注册中断函数    blog

 1   uint8_t myBuffer[] = "I have gotten your message: ";  2   uint8_t getBuffer[10];  3   uint8_t Enter[] = "\r\n";  4   void USARTx_IRQHandler(void)  5  {  6    HAL_UART_IRQHandler(&UartHandle); //该函数会清空中断标志,取消中断使能,并间接调用回调函数
 7    
 8    getBuffer[countOfGetBuffer++] = value;  9    if(countOfGetBuffer == 10) 10  { 11     while(HAL_UART_Transmit(&UartHandle, (uint8_t*)myBuffer, COUNTOF(myBuffer), 5000)!= HAL_OK); 12     while(HAL_UART_Transmit(&UartHandle, (uint8_t*)getBuffer, countOfGetBuffer, 5000)!= HAL_OK); 13     while(HAL_UART_Transmit(&UartHandle, (uint8_t*)Enter, COUNTOF(Enter), 5000)!= HAL_OK); 14     countOfGetBuffer = 0; 15  } 16    HAL_UART_Receive_IT(&UartHandle, (uint8_t *)&value,1);  //因为接收中断是每接收一个字符便进入一次,因此这一行代码必须添加,不然只能接收一个字符,而没法接收整个字符串
17   }

  以上代码的做用是接收每一个来自用户的字符,并依次存入用户自定义的缓冲区中,数量达到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使用了标准库中断处理数据的思想。字符串

相关文章
相关标签/搜索