学习单片机串口协议的都知道,串口接收数据是一个字节一个字节进行接收的。
如果不了解,可以查看文章: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 ;
}
这样子,有了信号量作为同步处理,数据的响应也会更及时。