使用中断开关实现全局变量互斥访问

  最近在STM32F429平台上实现一套主从机串口库,在开发过程中,出现偶发性丢帧问题,反复核对关键代码,均未发现任何问题,一筹莫展。按照经验第一反应就是互斥访问导致的脏数据问题,但苦于无法锁定问题,因为只有在串口大量数据收发时,才出现偶发性丢帧,无法采取在线调试锁定问题,极其难以抓取。为了能够尽快找到问题关键采取了最费力的办法:

  1. 锁定问题代码,对所有全局变量互斥访问代码逐一注释,同时检测注释后是否停止丢帧:锁定问题代码位置;
  2. 在问题代码处添加调试代码,通过串口重定向打印相关全局变量;

  虽然方法费时费力,但很快有了突破:打印出来的全局变量仅反复的进行加0操作,其未做任何改变,但仍发生丢帧,由此推论:串口丢帧是由于全局变量互斥访问引起的可能性极大。

  解决方法:1、使用中断开关,在进行互斥访问前关闭中断,完成后再开启中断;2、使用LDREX/STREX指令;

  为了最快地解决问题,先暂时采用方法一(以下是部分代码):

void uart_it_sw(FunctionalState state)
{
    USART_ITConfig(USART, USART_IT_RXNE, state);
}

void USART1_IRQHandler(void)
{
  uint8_t ucTemp;
	if(USART_GetITStatus(USART,USART_IT_RXNE)!=RESET)
	{		
		ucTemp = USART_ReceiveData( USART );
		push(ucTemp);		
	}	 
}	

static int front=0;
static int rear=0;
static int count=0;

void push(unsigned char tmp)
{
    recv_buf[rear]=tmp;
    rear++;
    rear%=MAX_QUEUE_LEN;
    
    if (count==MAX_QUEUE_LEN)
    {        
        front++;
        front%=MAX_QUEUE_LEN;
    }
    else
    {
        count++;
    }
}

void pop(int len)
{
    // if (len>0)
    {
        if (len>count)
        {
            len=count;
        }
        uart_it_sw(DISABLE); //互斥访问前关闭串口中断
        front+=len;
        front%=MAX_QUEUE_LEN;
        count-=len;
        uart_it_sw(ENABLE); //互斥访问结束重新打开串口中断
    }    
}

void empty(void)
{
    uart_it_sw(DISABLE);
    front=0;
    rear=0;
    count=0;
    uart_it_sw(ENABLE);
}

  结果:在开启互斥访问中断开关后,长时间大量测试下均未发生丢帧。  

  总结:如何锁定和确定问题和解决问题的最终方法一样的重要;其次大胆猜测,用后验逻辑去解决问题也不失为一种解决问题的好思路。

  

  

原文地址:https://www.cnblogs.com/randyjang/p/8476043.html