HAL库教程9:串口接收不定长数据

  串口收到的两组数据之间,往往会有一定的时间间隔。可以判断这个间隔,来实现无需结束符,无需指定长度,串口可接收不定长数据的功能。如果串口在一定的时间内没有收到新的数据,可以认为一组数据已经接收完毕了。思路是用定时器来设置一个“闹钟”,连续的一段时间没有收到新的数据,闹钟响起,就把已经收到的数据打包,做相应处理。

定时器溢出时间配置

  首先修改定时器的溢出时间。本文规定使用5ms的间隔。在某些通信协议中,会规定间隔时间。例如Modbus规定两组数据之间要间隔3.5字符。
  实际上,间隔的时间常常与通信的波特率是相关的。在9600波特率下,一个字节的数据共 起始+8数据+结束=10位,一位是104us,所以一个字节的数据是1.04ms,3.5个字节,我们就认为是4ms。有时可能有校验位,稍微保险一点,5ms吧。假如使用115200的波特率,5ms已经算是非常“奢侈”了。
  本文使用定时器3来计时,配置的PSC为8399,ARR为49,可得5ms的溢出时间,配置过程可以参考通用定时器章节。

串口接收中断服务函数

  我们在串口接收中断服务中,把收到的所有数据都放到数组中去,判断收到的是否是第一个字符,如果是则开启定时器。

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

{
  if(huart->Instance==USART1)
  {
    __HAL_TIM_SET_COUNTER(&htim3,0);
    if(0 == UART1_Rx_cnt)//如果是第一个字符,则开启定时器
    {
    __HAL_TIM_CLEAR_FLAG(&htim3,TIM_FLAG_UPDATE);
      HAL_TIM_Base_Start_IT(&htim3);
    }
    UART1_Rx_Buf[UART1_Rx_cnt] = UART1_temp[0];
    UART1_Rx_cnt++;
    HAL_UART_Receive_IT(&huart1,(uint8_t *)UART1_temp,REC_LENGTH);
  }
}

  其中__HAL_TIM_SET_COUNTER是HAL提供的一个宏定义,类似于函数,功能是通过宏来直接修改寄存器的值。
  由于HAL库的串口接收中断在每次执行后都会关闭,所有在串口的中断里要重新手动开启串口接收中断。
  另外,由于定时器中断在开启定时器的时候就会执行,所以需要开启定时器之前就把中断标记位清除。

定时器中断服务

  一旦定时器发生溢出中断,说明已经到了5ms的时间间隔,可以把数据截断,根据业务需求来做相应处理,我的做法是设着一个标志位,然后在主函数的死循环内不断检测标志位,如果标志位被置1,则把收到的数据发送出去。

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if(htim==(&htim3))
  {
    LED1 = !LED1;
    UART1_Rx_flg = 1;
    HAL_TIM_Base_Stop_IT(&htim3);//关闭定时器
  }
}
//main() while(1)
    if(UART1_Rx_flg)
    {
      HAL_UART_Transmit(&huart1,UART1_Rx_Buf,UART1_Rx_cnt,0xffff);    //发送接收到的数据
      for(int i = 0;i<UART1_Rx_cnt;i++)
        UART1_Rx_Buf[i] = 0;
      UART1_Rx_cnt = 0;
      UART1_Rx_flg = 0;
    }   

  功能是串口接收什么就回复什么,但无需结束符,也不用指定长度。当然最长不能超过UART1_Rx_Buf数据的大小。
附上源码

你可能感兴趣的:(STM32,HAL,STM32,串口,不定长)