STM32接收不定长数据

  • 硬件
    • STM32L475
  •  方案
    • 使用通过修改HAL库,加入IDLE中断,实现不定长数据接收
  • 参考资料
    • LAT0534_UART_IDLE中断使用_接收不定长串口数据_V0.3
  • cubemx配置

  • 实现过程
    • 首先接入接受的数据缓冲区,并设置缓冲区的大小
      //Store the revceived bytes number
      uint32_t Rev_Size = 0;
      //Receive buffer
      uint8_t UART_RX_Buf[15];​
    • 然后修改HAL库的usart.c文件
      • 加入extern uint32_t Rev_Size;变量声明
      • 修改HAL_StatusTypeDef HAL_UART_AbortReceive_IT(UART_HandleTypeDef *huart)该函数

        #else
        //修改后的代码
        	CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE| USART_CR1_IDLEIE));
        //  CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));//修改前的代码
          CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
        #endif /* USART_CR1_FIFOEN */
      • 修改HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)该函数,这里需要注意一下加入代码的位置。
        __HAL_UNLOCK(huart);
        		
        		/* Enable the UART IDLE Interrupt*/   //加入的代码
        		SET_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);
        		
            /* Enable the UART Parity Error Interrupt */
            SET_BIT(huart->Instance->CR1, USART_CR1_PEIE);
        ​
      • 修改void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)函数,光放文档里面的是 USART_SR_IDLE需要换成 USART_ISR_IDLE,NDTR换成CNDTR(具体原因看技术手册和源码)
        #if defined(USART_CR1_FIFOEN)
            if (((isrflags & USART_ISR_RXNE_RXFNE) != 0U)
                && (((cr1its & USART_CR1_RXNEIE_RXFNEIE) != 0U)
                    || ((cr3its & USART_CR3_RXFTIE) != 0U)))
        #else
        		//加入的代码
        		if(((isrflags & USART_ISR_IDLE) != RESET) && ((cr1its & USART_CR1_IDLEIE) != RESET))
         {
        		//Record the received bytes number
        		Rev_Size = huart->RxXferSize - huart->hdmarx->Instance->CNDTR;
        		//clear the IDLE flag
        		__HAL_UART_CLEAR_IDLEFLAG(huart);
        		//Abord the received process
        		HAL_UART_AbortReceive_IT(huart);
        		return;
         }
        
            if (((isrflags & USART_ISR_RXNE) != 0U)
                && ((cr1its & USART_CR1_RXNEIE) != 0U))
        #endif /* USART_CR1_FIFOEN */
            {
              if (huart->RxISR != NULL)
              {
                huart->RxISR(huart);
              }
              return;
            }
          }​
    • 在main.c里面进行函数修改 
      • 添加中断,该中断是在开启接收后,当接收到的数据没有到达最大的接收位的时候,但是总线上停止了数据传输,总线进入空闲状态,则产生中止中断。,并进入该函数进行数据处理。
        void HAL_UART_AbortReceiveCpltCallback (UART_HandleTypeDef *huart)
        {
         //Print received Bytes
        	printf("\n\r[IDLE]Received %d Bytes:",Rev_Size);
        	for(uint16_t i = 0; i < Rev_Size; i++)
        	{
        	printf(" 0x%02X", UART_RX_Buf[i]);
        	}
        	//Re-start receiving
        	HAL_UART_Receive_DMA(&huart1, UART_RX_Buf, 15);
         /* NOTE : This function should not be modified, when the callback is needed,
         the HAL_UART_AbortTransmitCpltCallback can be implemented in the user 
        file.
         */
        }​
      • 该中断的解释
        /**
          * @brief  Abort ongoing Receive transfer (Interrupt mode).
          * @param  huart UART handle.
          * @note   This procedure could be used for aborting any ongoing Rx transfer started in Interrupt or DMA mode.
          * @note   This procedure is executed in Interrupt mode, meaning that abort procedure could be
          *         considered as completed only when user abort complete callback is executed (not when exiting function).
          * @retval HAL status
          */​
      • HAL_UART_Receive_DMA(&huart1, UART_RX_Buf, 15);接收中断的启动函数,通过启动接收,并在中止中断里面再次开启实现循环接收。其中15是最大的可接受的数据。
      • 具体使用,需要注意的是,printf函数需要自己加入printf支持。
        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 */
        	printf("123456789\r\n");
        	HAL_UART_Receive_DMA(&huart1, UART_RX_Buf, 15);
          /* USER CODE END 2 */
        
          /* Infinite loop */
          /* USER CODE BEGIN WHILE */
          while (1)
          {
            /* USER CODE END WHILE */
        
            /* USER CODE BEGIN 3 */
          }
          /* USER CODE END 3 */
        }
        ​
      • 结果

声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
本篇所含全部资料,点击此处留下邮箱我会发给你
资料明细:使用IDLE中断实现不定长数据接收。
觉得内容不错的朋友,别忘了一键三连哦!
赞 3
收藏 2
关注 9
成为作者 赚取收益
全部留言
0/200
  • dy-xGqRDsfq 1星期前
    老师,能不能发我一下资料,谢谢! 11****@****.com
    回复 1条回复
  • zhouspace 2022-03-27 09:07
    老师,能不能发我一下资料,谢谢! 14****@****.com
    回复 3条回复
  • 阿飞的秘术屋 2021-08-27 18:39
    老师,能不能发我一下资料,谢谢! 56****@****.com
    回复 3条回复