关于stm32 卡死在串口接收中断中的处理方法。卡死原因是串口自带的BUG出现USART_FLAG_ORE标志位无法清除。

前端时间遇到正常使用的串口一直卡死在USART_FLAG_ORE标志位处,有一定概率发生这个,但在发生后,就会一直进入中断。按照网上的方法做了清除标志位处理,但结果还是解决不了。下面是之前写的代码连接,https://blog.csdn.net/qq_42074368/article/details/103404573

通过调试发现,中断一直进入这个地方

    if(USART_GetFlagStatus(USART1,USART_FLAG_ORE) != RESET)                         
    {                                                                                                   
        USART_ReceiveData(USART1);
        USART_ClearFlag(USART1,USART_FLAG_ORE);                                                                    	
    }    

网上对此的说明很多,但都是指出了问题点,没有解决该问题。其实我理解中该问题的原因很简单,在你使能串口中断USART_ITConfig(USART1 , USART_IT_IDLE, ENABLE);

USART_ITConfig(USART1 ,USART_IT_RXNE , ENABLE);时,

同时会半开启USART_FLAG_ORE中断,这种情况就是BUG,出现溢出会进入中断函数,但是却清除不掉标志位,因为你没有调用开启函数开启该中断。

所以解决办法就是我们必须在开启中断同时,开启错误中断

USART_ITConfig(USART1, USART_IT_ERR, ENABLE);

这个配置设置后就可以使用前面的清除标志位的函数了,不然清除标志位会失效。同时由于开启了该中断会导致其他错误标志位响应中断我们也需要清除标志位。以正确的处理的代码如下:

void USART1_IRQHandler(void)                	//串口1中断服务程序                                      //
{                                                                                                        //
    uint8_t Clear = Clear;                                                                               //
	if (USART_GetFlagStatus(USART1, USART_FLAG_FE) != RESET) 
	{
		USART_ReceiveData(USART1); 
		USART_ClearFlag(USART1, USART_FLAG_FE);
	} 	//
	if(USART_GetFlagStatus(USART1, USART_FLAG_PE) != RESET)         
	{        
		USART_ReceiveData(USART1);  
		USART_ClearFlag(USART1, USART_FLAG_PE);  			  
	}																									 //																									 //
    if(USART_GetFlagStatus(USART1,USART_FLAG_ORE) != RESET)                                             	 //
    {                                                                                                    //
		USART_ReceiveData(USART1);
		USART_ClearFlag(USART1,USART_FLAG_ORE);                                                                    	 //
    }                                                                                                    //
    if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)                                             	 //
    {                                                                                                    //
        Clear=USART1->SR;                                                                             	 //
        Clear=USART1->DR;                                                                              	 //
        int IOT_Uart_Rec_Cnt = blen-DMA_GetCurrDataCounter(DMA1_Channel5);              				 //USART2_IRQHandler
        DMA_Cmd(DMA1_Channel5, DISABLE );//关闭DMA                                                 	     //
        if(IOT_Uart_Rec_Cnt>0)                                                           				 //
        {                                                                                                //
            PushUartMsg1(IOT_Uart_Rec_Cnt);                                                              //
        }                                                                                                //
        USART_ClearITPendingBit(USART1,USART_IT_IDLE);                                                 	 //
        DMA_SetCurrDataCounter(DMA1_Channel5,blen);//重新计数                           				 //
        DMA_Cmd(DMA1_Channel5, ENABLE);                                                           	     //
    }                                                                                                    //
}                                                                                                        //

串口1的配置代码我也贴一下。

#define buff 10
#define blen 350
typedef struct {
	char DMA_Buffer[blen];
	char RxBuffer[buff][blen];
	char read;
	char write;
	char cnt;
}uart_stack;
uart_stack uart1 = {0};

void UART1_init(void)//调试
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	DMA_InitTypeDef DMA_InitStructure;
	
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_USART1, ENABLE);
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	USART_DeInit(USART1);  //复位串口1
	

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    USART_InitStructure.USART_BaudRate   = 115200;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits   = USART_StopBits_1;
    USART_InitStructure.USART_Parity     = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode       = USART_Mode_Rx | USART_Mode_Tx;

    /* Enable the USART1 Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn ;//todo
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    USART_Init(USART1 , &USART_InitStructure);
    USART_ITConfig(USART1 , USART_IT_IDLE, ENABLE);
    USART_ITConfig(USART1, USART_IT_ERR, ENABLE);
    USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
    USART_Cmd(USART1 , ENABLE);
	
    //DMA配置
    DMA_DeInit(DMA1_Channel5);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)uart1.DMA_Buffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = blen;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel5, &DMA_InitStructure);
	
    DMA_Cmd(DMA1_Channel5, ENABLE);
}

关于STM32 5个串口初始化,前三个DMA操作,自制队列缓存机制,可以参考https://blog.csdn.net/qq_42074368/article/details/103404573

  • 24
    点赞
  • 188
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值