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.