STM32-USART HAL库接收任意长度数据详细解析

前言:

最近在调试STM32L152 HAL库串口接收任意长度数据程序,详细解析下接收任意长度数据的方法。

硬件平台:STM32L152

软件平台:keil v5+cubeMX

函数库:HAL库

STM32L152 —USART

STM32L152  USART 的HAL库中接收函数:

HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

该函数的参数Size固定,使用时很不方便,只能接收固定长度的数据。

本文详细解析HAL库UASRT接收函数并修改成接收任意长度。PS:仅适用于接收数据结尾为换行符0x0a,若接收数据为其他格式,可根据数据的特点进行修改。

1.HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, 200);

开始接收终端,设定一个初始长度200,接收的任意字节数不大于200就行。

2.中断处理函数

void USART1_IRQHandler(void)
{
    HAL_UART_IRQHandler(&huart1); 
}

3.在HAL_UART_IRQHandler(&huart1)的定义找到接收终端函数  :UART_Receive_IT(huart);

void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
  uint32_t tmp_flag = 0, tmp_it_source = 0;


  tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_PE);
  tmp_it_source = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_PE);  
  /* UART parity error interrupt occurred ------------------------------------*/
  if((tmp_flag != RESET) && (tmp_it_source != RESET))
  { 
    huart->ErrorCode |= HAL_UART_ERROR_PE;
  }
  
  tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_FE);
  tmp_it_source = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR);
  /* UART frame error interrupt occurred -------------------------------------*/
  if((tmp_flag != RESET) && (tmp_it_source != RESET))
  {
    huart->ErrorCode |= HAL_UART_ERROR_FE;
  }
  
  tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_NE);
  /* UART noise error interrupt occurred -------------------------------------*/
  if((tmp_flag != RESET) && (tmp_it_source != RESET))
  {
    huart->ErrorCode |= HAL_UART_ERROR_NE;
  }
  
  tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_ORE);
  /* UART Over-Run interrupt occurred ----------------------------------------*/
  if((tmp_flag != RESET) && (tmp_it_source != RESET))
  {
    huart->ErrorCode |= HAL_UART_ERROR_ORE;
  }
  
  tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE);
  tmp_it_source = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_RXNE);
  /* UART in mode Receiver ---------------------------------------------------*/
  if((tmp_flag != RESET) && (tmp_it_source != RESET))
  { 
    UART_Receive_IT(huart);
  }
  
  tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_TXE);
  tmp_it_source = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_TXE);
  /* UART in mode Transmitter ------------------------------------------------*/
  if((tmp_flag != RESET) && (tmp_it_source != RESET))
  {
    UART_Transmit_IT(huart);
  }


  tmp_flag = __HAL_UART_GET_FLAG(huart, UART_FLAG_TC);
  tmp_it_source = __HAL_UART_GET_IT_SOURCE(huart, UART_IT_TC);
  /* UART in mode Transmitter end --------------------------------------------*/
  if((tmp_flag != RESET) && (tmp_it_source != RESET))
  {
    UART_EndTransmit_IT(huart);
  }  


  if(huart->ErrorCode != HAL_UART_ERROR_NONE)
  {
    /* Clear all the error flag at once */
    __HAL_UART_CLEAR_PEFLAG(huart);
    
    /* Set the UART state ready to be able to start again the process */
    huart->State = HAL_UART_STATE_READY;
    
    HAL_UART_ErrorCallback(huart);
  }  
}.

4.接下来是修改UART_Receive_IT(huart) 函数;

u8 flag,Rx_Size;
static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)
{
  uint16_t* tmp;
  uint32_t tmp_state = 0;

  tmp_state = huart->State; 
  if((tmp_state == HAL_UART_STATE_BUSY_RX) || (tmp_state == HAL_UART_STATE_BUSY_TX_RX))
  {
    if(huart->Init.WordLength == UART_WORDLENGTH_9B)
    {
      tmp = (uint16_t*) huart->pRxBuffPtr;
      if(huart->Init.Parity == UART_PARITY_NONE)
      {
        *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x01FF);
        huart->pRxBuffPtr += 2;
      }
      else
      {
        *tmp = (uint16_t)(huart->Instance->DR & (uint16_t)0x00FF);
        huart->pRxBuffPtr += 1;
      }
    }
    else
    {
      if(huart->Init.Parity == UART_PARITY_NONE)//本例串口为非奇偶校验
      {

        *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
if(((uint8_t)(huart->Instance->DR & (uint8_t)0x00FF))==0x0a) flag++;   //当收到0x0A换行符时认为接收结束。
Rx_Size++;

      }
      else
      {
        *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->DR & (uint8_t)0x007F);
      }
    }





//   if(--huart->RxXferCount == 0)    //  原程序根据设定的接收缓存RxXferCount减为0时认为接收结束,注释掉,修改为if(flag== 1);

    if(flag== 1)
    {
      flag=0;
      __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);


      /* Check if a transmit process is ongoing or not */
      if(huart->State == HAL_UART_STATE_BUSY_TX_RX) 
      {
        huart->State = HAL_UART_STATE_BUSY_TX;
      }
      else
      {
        /* Disable the UART Parity Error Interrupt */
        __HAL_UART_DISABLE_IT(huart, UART_IT_PE);


        /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */
        __HAL_UART_DISABLE_IT(huart, UART_IT_ERR);


        huart->State = HAL_UART_STATE_READY;
      }
      HAL_UART_RxCpltCallback(huart);


      return HAL_OK;
    }
    return HAL_OK;
  }
  else
  {
    return HAL_BUSY; 
  }
}

5.编写UART串口回调函数,重新开启接收中断并清标志;

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance==USART1)
    { 
    HAL_UART_Transmit(&huart3 ,(uint8_t *)aRxBuffer,Rx_Size ,200);//用串口3打印出    来接收的数据,可忽略
    HAL_UART_Receive_IT(&huart1,(uint8_t *)aRxBuffer, 200);//重新开中断
    for(u8 i=0;i<Rx_Size;i++)aRxBuffer[i]=0; //清除接收缓存
    Rx_Size=0;//清除接收的计数,下次接收重新计数
    }
}

以上修改,便可接收结尾为0x0a的任意长度的数据。但修改HAL库并不是一个好的解决方法;若别人要移植你的程序,会给别人移植程序带来困难。使用DMA方式进行串口的接收是一个较优的方法,见:传送门

  • 10
    点赞
  • 84
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
针对STM32G4HAL库串口空闲中断接收不定长数据的问题,可以按照以下步骤进行解决: 1. 开启串口空闲中断,即在初始化串口时,将USART_CR1_REG中的USART_CR1_IDLEIE位设置为1。 2. 在串口空闲中断中,通过读取USART_ISR_REG寄存器中的位USART_ISR_RXNE和USART_ISR_IDLE来判断是接收数据还是空闲中断。 3. 如果是接收数据,则读取USART_RDR_REG寄存器中的数据,并将其存储到缓冲区中。 4. 如果是空闲中断,则通过计算接收到的数据长度来确定数据长度,并将其存储到缓冲区中。 5. 在数据长度达到预定长度时,可以通过回调函数或者其他方式来通知数据接收已经完成。 下面是一个示例代码: ```c uint8_t rx_buffer[100]; uint8_t rx_counter = 0; uint8_t rx_length = 0; uint8_t rx_flag = 0; void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USARTx) { if(rx_flag == 0) { //接收数据 if((__HAL_UART_GET_FLAG(huart, UART_FLAG_RXNE) != RESET) && (__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE) == RESET)) { rx_buffer[rx_counter++] = (uint8_t)(huart->Instance->RDR & 0x00FF); } //空闲中断 else if(__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE) != RESET) { rx_length = rx_counter; rx_counter = 0; rx_flag = 1; } } } } ``` 在上面的代码中,当接收数据时,将数据存储到缓冲区中,并将计数器rx_counter加1。当空闲中断发生时,计算接收到的数据长度,并将其存储到rx_length中。在接收完成后,将rx_flag设置为1,表示数据接收已经完成。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值