在之前的章节, 我们接收的都是定长的数据, 即设定好的四个或五个字节.

一旦接收到一定数量的字节之后, 就会触发中断.

而当我们不知道接收的数据有多长的时候, 我们希望在接收完这些数据之后再触发中断.

都要通过不定长数据接收的方法.

串口中断接收不定长数据

在之前的 STM32 HAL 库中, 是没有这种封装的, 需要手动配置空闲中断, 还要去判断并且清除寄存器标志位来管理状态, 并且触发中断.

而现在利用 HAL 库, 就能够自动处理以上的过程.

主要内容:

HAL_UARTEx_ReceiveToldle_IT() 开启不定长数据的中断接收

HAL_UARTEx_RxEventCallback() 不定长数据中断接收的回调函数

什么是空闲中断?

通过硬件自动检测一帧数据的接收结束, 当串口线路(RX引脚)在接收完一个字节后,持续保持高电平(空闲状态)的时间超过一个完整数据帧的传输时间时,硬件就会自动判定“一帧数据已经收完了”,并触发一个中断请求

HAL_UARTEx_ReceiveToldle_IT 详解

该函数在老版本 HAL 库是没有的, 就要我们自己去实现

/**
  * @brief Receive an amount of data in interrupt mode till either the expected number of data is received or an IDLE event occurs.
  * @note   Reception is initiated by this function call. Further progress of reception is achieved thanks
  *         to UART interrupts raised by RXNE and IDLE events. Callback is called at end of reception indicating
  *         number of received data elements.
  * @note   When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M = 01),
  *         the received data is handled as a set of uint16_t. In this case, Size must indicate the number
  *         of uint16_t available through pData.
  * @param huart UART handle.
  * @param pData Pointer to data buffer (uint8_t or uint16_t data elements).
  * @param Size  Amount of data elements (uint8_t or uint16_t) to be received.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_UARTEx_ReceiveToIdle_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

以中断的方式接收不定长数据.

参数只有三个: hart 结构体, 数据接收区, 接收的长度

但是, 既然说是接收不定长数据, 那么这里为什么还要指定接收的长度呢?

因为它要保证有一个最大长度可以提前结束,

比如长度为 10, 当发送 5 个数据的时候, 就相当于不定长数据.

他就接受 5 个数据, 因为 5 个数据之后会有一个空闲中断,

而发送 20 个数据的话, 它就会在第 10 个数据, 也就是我们设定好的最大数据长度进行中断.

HAL_UARTEx_RxEventCallback 详解
/**
  * @brief  Reception Event Callback (Rx event notification called after use of advanced reception service).
  * @param  huart UART handle
  * @param  Size  Number of data available in application reception buffer (indicates a position in
  *               reception buffer until which, data are available)
  * @retval None
  */
__weak void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)

这个函数是回调函数, 主要关注第二个参数.

其实第二个参数就是代表本次接收到的数据的长度. (<= 指定的接收的长度)

项目配置

同样需要配置 USART1 中断使能. 其他无异

代码部分

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

#include <stdio.h>  // 使用 printf 函数
#include <string.h> // 使用 strncmp

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define LENGTH  64   // 接收缓冲区大小
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
uint8_t RxBuff[LENGTH] = { 0 };
/* USER CODE END PV */
  /* USER CODE BEGIN 2 */
  
  HAL_UARTEx_ReceiveToIdle_IT(&huart1, RxBuff, LENGTH);   // 使能接收中断
  printf("当前已开启接收中断, 等待数据发送! \r\n");
  
  /* USER CODE END 2 */
/* USER CODE BEGIN 4 */

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
  if (huart -> Instance == USART1)
  {
    HAL_UART_Transmit(&huart1, RxBuff, LENGTH, HAL_MAX_DELAY);
    memset(RxBuff, 0, 20);
    
    HAL_UARTEx_ReceiveToIdle_IT(&huart1, RxBuff, LENGTH);
  }
}

/**
  * @brief  重定向 printf 的输出到串口
  * @param  ch: 要发送的字符
  * @param  f:  文件指针 (标准库要求的参数, 一般不使用)
  * @retval 返回发送的字符
  */
int fputc(int ch, FILE *f)
{
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
  return ch;
}

/* USER CODE END 4 */

实验现象

当发送数据长度超出设定的 (最大) 接收长度时, 会在接收到指定长度的数据时触发中断回显数据

当发送数据小于设定的 (最大) 接收长度时, 空闲状态会直接触发中断回显数据.

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐