STM32F103, HAL, when the serial port uses idle interrupt, the returned data is incomplete, and the solution to the situation of loss

 

When using the idle interrupt in STM32F103, data loss often occurs. I guess it is because there is a delay in the connection environment, which causes the flag bit to be triggered by mistake.

The solution is to directly use the LL library instead of the HAL library, without DMA or idle interrupts. The most primitive way is to directly receive interrupt triggers.

Use timer 1 for receiving delay processing to achieve the purpose of receiving variable-length character strings.

 

1. CUBEMX configuration

 

no DMA

Interrupt check

Timer configuration

2 part engineering code

Variables that need to be defined

#define DEBUG 1

#define ERROR_LOG(x) if(DEBUG)printf("error_%d:%s.\r\n",__LINE__,x);	

#ifndef NULL
  #define  NULL ((void*)0)
#endif  

//用于包缓冲或者组包的Buf	
#define BUFFER_SIZE   256

int8_t 	S1recvEnd=0;
int8_t  S1TimeOut=0;
int16_t S1recvLen=0;


int8_t 	S2recvEnd=0;
int8_t  S2TimeOut=0;
int16_t S2recvLen=0;

int8_t 	S3recvEnd=0;
int8_t  S3TimeOut=0;
int16_t S3recvLen=0;


uint8_t mS1SendBuf[BUFFER_SIZE];
uint8_t mS1RecvBuf[BUFFER_SIZE];

uint8_t mS2SendBuf[BUFFER_SIZE];
uint8_t mS2RecvBuf[BUFFER_SIZE];

uint8_t mS3SendBuf[BUFFER_SIZE];
uint8_t mS3RecvBuf[BUFFER_SIZE];


void TestUsartRecvTask(void const * argument)
{
	//串口初始化  
    LL_USART_EnableIT_RXNE(USART1);
	LL_USART_EnableIT_PE(USART1);
	
	LL_USART_EnableIT_RXNE(USART2);
	LL_USART_EnableIT_PE(USART2);
	
	LL_USART_EnableIT_RXNE(USART3);
	LL_USART_EnableIT_PE(USART3);
	//定时器开中断
	HAL_TIM_Base_Start_IT(&htim1);
	
	//I2C_Init();
	while(1)
	{
		if(S1recvEnd)
		{
			S1recvEnd = 0;
			USART_SendData(USART1,mS1RecvBuf,S1recvLen);
			
			HAL_GPIO_WritePin(RS485_DE3_GPIO_Port,RS485_DE3_Pin,GPIO_PIN_SET);
			USART_SendData(USART3,mS1RecvBuf,S1recvLen);
			HAL_GPIO_WritePin(RS485_DE3_GPIO_Port,RS485_DE3_Pin,GPIO_PIN_RESET);
			
			HAL_GPIO_WritePin(RS485_DE2_GPIO_Port,RS485_DE2_Pin,GPIO_PIN_SET);
			USART_SendData(USART2,mS1RecvBuf,S1recvLen);
			HAL_GPIO_WritePin(RS485_DE2_GPIO_Port,RS485_DE2_Pin,GPIO_PIN_RESET);
			//HAL_UART_Transmit(&huart1,mS1RecvBuf,S1recvLen,0xFFFFFFFF);			
			//HAL_UART_Receive_DMA(&huart1,mS1RecvBuf,BUFFER_SIZE);	
			S1recvLen = 0;
		}
		if(S2recvEnd)
		{
			S2recvEnd = 0;
			USART_SendData(USART1,mS2RecvBuf,S2recvLen);
			//HAL_UART_Transmit(&huart1,mS2RecvBuf,S2recvLen,0xFFFFFFFF);			
			//HAL_UART_Receive_DMA(&huart2,mS2RecvBuf,BUFFER_SIZE);
			S2recvLen =0;
		}
		if(S3recvEnd)
		{
			S3recvEnd = 0;
			USART_SendData(USART1,mS3RecvBuf,S3recvLen);
			//HAL_UART_Transmit(&huart1,mS3RecvBuf,S3recvLen,0xFFFFFFFF);		
			//HAL_UART_Receive_DMA(&huart3,mS3RecvBuf,BUFFER_SIZE);	
			S3recvLen = 0;
		}
		ReadSensor();
		//HAL_Delay(1000);
	}
	//HAL_Delay(10);
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim==&htim1)
	{
		static uint32_t timeLed=1000;
		static GPIO_PinState msate = GPIO_PIN_RESET;
		if(msate)msate = GPIO_PIN_RESET;
		else msate = GPIO_PIN_SET;
		if(timeLed--==0)
		{
			timeLed = 1000;
			HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,msate);
		}
		
		if(S1TimeOut)S1TimeOut--;
		else if(S1recvLen>1)
		{
			S1recvEnd =1;
		}
		
		if(S2TimeOut)S2TimeOut--;
		else if(S2recvLen>1)
		{
			S2recvEnd =1;
		}
		if(S3TimeOut)S3TimeOut--;
		else if(S3recvLen>1)
		{
			S3recvEnd =1;
		}
		

		//HAL_UART_Transmit(&huart1,"heesl",5,20);		
		//printf("m\r\n");
	}
}


void USART_SendData(USART_TypeDef *uart,uint8_t *tmpData,int16_t len)
{
	int16_t iLen=0;
	
	for(iLen=0;iLen<len;iLen++)
	{
		LL_USART_TransmitData8(uart,tmpData[iLen]);//将数据准备好
		while(!LL_USART_IsActiveFlag_TC(uart));	//发送完数据再返回
	}
}
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
	if(LL_USART_IsActiveFlag_RXNE(USART1))
	{
		S1TimeOut =UART_TIMEOUT;
		mS1RecvBuf[S1recvLen] = LL_USART_ReceiveData8(USART1);
		//LL_USART_TransmitData8(USART1,mS1RecvBuf[S1recvLen]);
		S1recvLen++;
		if(S1recvLen >=BUFFER_SIZE)S1recvLen=0;
		//LL_USART_TransmitData8(USART1,tmp);
	}
  /* USER CODE END USART1_IRQn 0 */
  /* USER CODE BEGIN USART1_IRQn 1 */
  /* USER CODE END USART1_IRQn 1 */
}

/**
* @brief This function handles USART2 global interrupt.
*/
void USART2_IRQHandler(void)
{
  /* USER CODE BEGIN USART2_IRQn 0 */
	if(LL_USART_IsActiveFlag_RXNE(USART2))
	{
		S2TimeOut =UART_TIMEOUT;
		if(S2recvLen >=BUFFER_SIZE)S2recvLen=0;
		mS2RecvBuf[S2recvLen++] = LL_USART_ReceiveData8(USART2);
		//LL_USART_TransmitData8(USART1,tmp);
	}
  /* USER CODE END USART2_IRQn 0 */
  /* USER CODE BEGIN USART2_IRQn 1 */

  /* USER CODE END USART2_IRQn 1 */
}

/**
* @brief This function handles USART3 global interrupt.
*/
void USART3_IRQHandler(void)
{
  /* USER CODE BEGIN USART3_IRQn 0 */
	if(LL_USART_IsActiveFlag_RXNE(USART3))
	{
		S3TimeOut =UART_TIMEOUT;
		if(S3recvLen >=BUFFER_SIZE)S3recvLen=0;
		mS3RecvBuf[S3recvLen++] = LL_USART_ReceiveData8(USART3);
		//LL_USART_TransmitData8(USART1,tmp);
	}
  /* USER CODE END USART3_IRQn 0 */
  /* USER CODE BEGIN USART3_IRQn 1 */

  /* USER CODE END USART3_IRQn 1 */
}

The general idea is: Generate interrupt--"cache-"timer check" timeout reception is completed.

complete project

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Guess you like

Origin blog.csdn.net/wfjdemmye/article/details/88564719
Recommended