学习单片机串口协议的都知道,串口接收数据是一个字节一个字节进行接收的。
如果不了解,可以查看文章:https://blog.csdn.net/morixinguan/article/details/78495494
如果接收的数据协议做如下规定:

序列号    长度   状态字   数据长度  数据1  数据2   数据3\r\n

中间以空格作为分隔符。
那如何来接收这样的一整串数据呢?这串数据的特征就是每次都有\r\n出现。
编程思路:
1、只要分析\n出现了,这个时候就可以认为已经接收到了一包完整的数据,如果没有,则将每次接收到的每一个字节存放在缓存区内。
2、如果\n已经出现了,那么\n对应的上一个字节一定是\r。
源码实现,以下例程在freertos中进行实现。
在freertos例程中,串口中断服务函数接收到了一包数据后,以信号量形式发出。

void USART2_IRQHandler(void)
{
    uint32_t ulReturn;
    uint8_t Res;
    portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
    //进入临界段,不可被中断
    ulReturn = taskENTER_CRITICAL_FROM_ISR();
	if((__HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE) != RESET))
	{
		HAL_UART_Receive(&huart2, &Res, 1, 1000);
		//如果当前接收到的字符不是\n,则不断接收
		if('\n' != Res)
		{
			USART2_RX_BUF[sensor_rx_count++] = Res ;
		}
		else
		{
			//如果接收的是\n,则上一个接收的数据为'\r'
			if('\r' == USART2_RX_BUF[sensor_rx_count-1])
			{
				//添加结束符
				USART2_RX_BUF[sensor_rx_count-1] = 0x00 ;
				//接收计数清0
				sensor_rx_count = 0 ;
				//给出一个信号量
				xSemaphoreGiveFromISR(Sensor_Data_Semaphore, &xHigherPriorityTaskWoken);
			}
		}

	}
    HAL_UART_IRQHandler(&huart2);
    //退出临界段
    taskEXIT_CRITICAL_FROM_ISR( ulReturn );
}

主线程,等待信号量到来。

//传感器数据
void StartSensorTask(void const * argument)
{
    BaseType_t xResult;
    uint8_t *__Sensor_Data_Cpy = NULL ;
    __Sensor_Data_Cpy = malloc(USART_REC_LEN);
    assert_param(NULL != __Sensor_Data_Cpy);
    while(1)
    {
        //等待获取一个信号量,portMAX_DELAY表示无超时限制
        xResult = xSemaphoreTake(Sensor_Data_Semaphore, portMAX_DELAY);
        if(xResult == pdTRUE)
        {
            memset(__Sensor_Data_Cpy, 0, USART_REC_LEN);
            memcpy(__Sensor_Data_Cpy, USART2_RX_BUF, strlen((char *)USART2_RX_BUF));
			printf("传感器数据:%s\n",__Sensor_Data_Cpy);
        }
    }
	free(__Sensor_Data_Cpy);
	__Sensor_Data_Cpy = NULL ;
}

这样子,有了信号量作为同步处理,数据的响应也会更及时。

08-25 17:18