双缓冲区

使用场景

在裸机程序中使用IDLE空闲中断串口接收时,同时程序也在循环中不断处理数据。如果刚好运行到数据处理结束,即将清空数据的时候,串口中断产生,并带来了新的数据,返回后新数据就会被清除,导致ERROR发生

原理

通过设置两个缓冲区以及两个缓冲区指针进行交替,一个用于接收数据,另一个用于处理数据,这样就可以一定程度上解决串口中断刚接收到数据就被清空的问题,因为我们接收到的数据存储在接收buffer中,而清空的buffer是数据处理buffer,而这两个buffer在串口接收完数据后角色互换:

代码示例

语言:C
编译器:Keil5
stm32库:HAL-1.5.x
串口:UART1

//全局变量定义 global value
//串口接收buffer
uint8_t rec_buffer1[256];
uint8_t rec_buffer2[256];
uint8_t *current_buffer = rec_buffer1;
uint8_t *processing_buffer = rec_buffer2;

//数据处理示例函数
void Data_Proc(void)
{
    ...

    //对processing_buffer进行处理
    //举例
	//if(strlen((char *)processing_buffer) == 22){}

    //清空
    memset(processing_buffer,0,256*sizeof(char));

    ...
}

//系统初始化函数
void Sys_Init(void)
{
    ...

    HAL_UART_Init(&huart1);
	
	//IDLE接收不定长数据
	HAL_UARTEx_ReceiveToIdle_DMA(&huart1,current_buffer,256);

    ...

}

//串口中断返回函数
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	if(huart == &huart1)
	{
		if(current_buffer == rec_buffer1)
		{
			current_buffer = rec_buffer2;
			processing_buffer = rec_buffer1;
		}
		else if(current_buffer == rec_buffer2)
		{
			current_buffer = rec_buffer1;
			processing_buffer = rec_buffer2;
		}
	}
	HAL_UARTEx_ReceiveToIdle_DMA(&huart1,current_buffer,256);
}	

注意事项

使用双缓冲区接收,开启的空闲接收中断的buffer长度要足够,否则就会导致进入多次接收函数,使双缓冲区再次翻转。
因为空闲中断的最后一个参数是最大一次性接收的数据长度,如果数据过长,则会多次进入该函数进行接收,会导致数据覆盖、双缓冲区重置等问题,所以需要根据我们已知接收数据的长度设置这个参数。