STM32
直播中

is.milk

12年用户 494经验值
私信 关注
[问答]

如何利用STM32的空闲中断来实现不定长数据的接收?

如何利用STM32的空闲中断来实现不定长数据的接收?

回帖(1)

李悠冉

2021-12-6 14:21:26
        在串口通信中,很多时候我们需要的是接收一帧不确定长度的数据,而不是单个字节或者固定长度,这时我们就需要利用STM32的空闲中断(IDLE)来实现不定长数据的接收,首先我们打开STM32Cumebx建立一个工程,配置管脚图:
  
  

  

  这里我们采用三线SWD下载方式,加一个LED灯交替闪烁,串口中断+DMA来接收不定长数据,串口采用默认配置,打开串口中断,采用DMA方式进行发送和接收:
  
  

  

  
  

  

  
然后保存工程生成代码。


生成代码后先定义以下变量:



uint8_t  rx_buffer[100];                             
char     BUFFER_SIZE=100;   
然后在主函数中加入串口接收回调函数:


void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
        HAL_UART_DMAStop(&huart1);  
        uint8_t data_length  = BUFFER_SIZE - hdma_usart1_rx.Instance->CNDTR;
        HAL_UART_Transmit(&huart1,rx_buffer,data_length,200);
        data_length = 0;
        HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE);
}
我用的Firmware Package 版本是STM32Cube FW_L4 V1.13.0,需要在库函数stm32l4xx_hal_uart.c中的第2366行加入如下代码段



        if(((isrflags & USART_ISR_IDLE)!= RESET) &&((cr1its & USART_CR1_IDLEIE)!=RESET))
        {
                //clear IDLE flag
                        __HAL_UART_CLEAR_IDLEFLAG(huart);
               
#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
    huart->RxCpltCallback(huart);
#else
    HAL_UART_RxCpltCallback(huart);
#endif /* USE_HAL_UART_REGISTER_CALLBACKS */
                return;
        }
这段代码的位置如下图所示:



  
  

  

  
主函数中我们自己添加的代码:


int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
       
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
        //这是我们自己添加的代码,让LED灯循环闪烁。
                HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
                HAL_Delay(200);
                HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
                HAL_Delay(200);
               
  }
  /* USER CODE END 3 */
}
当然我们的主函数没有意义,实际功能是在串口回调函数中实现的,目的就是把接收到的数据重新返回给串口助手,效果图如下:


  
  

  

可以看到   当我们给单片机发送一帧数据时,单片机会把同样的数据返回给我们。


注意:在串口初始化程序中我们一定要添加以下两行代码:


  /* USER CODE BEGIN USART1_Init 2 */
        __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
        HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE);
  /* USER CODE END USART1_Init 2 */
并且在串口回调函数中,接收完一帧数据后,需要重新打开串口的DMA接收。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分