stm32定时器中断回调函数运行时间过长导致定时器不准的一种解决方案

如题,最近在师兄的指导下做一个工程,其中一部分需要用stm32f407单片机的ADC持续读取传感器数据,以20ms/次的频率通过SDIO写入SD卡。

定时器部分的代码如下:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim == (&htim9))//溢出周期为1ms
    {
      my_time += 1;
    }
  
 if (htim == (&htim5))//溢出周期为20ms
    {
  
  test01++;
  if(test01>1)
  {
    /*记录当前时间*/
    memset(my_time_str, 0, sizeof(my_time_str));
    Int_To_Str(my_time,my_time_str);
   
    /*记录当前序号*/
    memset(my_name_txt, 0, sizeof(my_name_txt));
    Int_To_Str(my_name,my_name_txt);
         
    if(my_name%1000==0)//希望在f_open运行时,中断不写入sd卡
    {
     
      /*创建文件*/
      f_res = f_open(&file, my_name_txt, FA_OPEN_ALWAYS | FA_WRITE);//打开要放在中断外面
      if(f_res == FR_OK)
      {
       my_name += 1;
       f_res = 6;
      }
     
    }
    else if(my_name%1000==1||my_name%1000==2)
    {
      my_name += 1;
    }
    else if(my_name%1000 > 2 && my_name%1000 < 999)//现象:第一个30-12-18-20-20,其余的29-12-19-20-20
    {
      
      adcin0=AD_Buf[0];
      adcin1=AD_Buf[1];
      adcin2=AD_Buf[2];
      adcin3=AD_Buf[3];
      adcin4=AD_Buf[4];
      adcin5=AD_Buf[5];
      adcin6=AD_Buf[6];
      adcin7=AD_Buf[7];
      adcin8=AD_Buf[8];
      adcin9=AD_Buf[9];
         
      Int_To_Str(adcin0,char0);
      Int_To_Str(adcin1,char1);
      Int_To_Str(adcin2,char2);
      Int_To_Str(adcin3,char3);
      Int_To_Str(adcin4,char4);
      Int_To_Str(adcin5,char5);
      Int_To_Str(adcin6,char6);
      Int_To_Str(adcin7,char7);
      Int_To_Str(adcin8,char8);
      Int_To_Str(adcin9,char9);
          
      f_puts("time:\n",&file);
      f_puts(my_time_str,&file);
      f_puts("adc:\n",&file);
      f_puts(char0,&file);
      f_puts(char1,&file);
      f_puts(char2,&file);
      f_puts(char3,&file);
      f_puts(char4,&file);
      f_puts(char5,&file);
      f_puts(char6,&file);
      f_puts(char7,&file);
      f_puts(char8,&file);
      f_puts(char9,&file);
      
      f_sync(&file);
      
      my_name += 1;
       
    }
    else if(my_name%1000 == 999)
    {
      f_res = f_close(&file);
      
      if(f_res == FR_OK)
      {
       my_name += 1;
       f_res = 6;
      }
      
    }
  }
    
    } 
}

定时器9以1ms/次的频率计时,理论上SD卡中每组数据的时间都应该递增20ms,但事实并非如此,为此疑惑了很久。

后来想到:中断里面不应该停留太长时间,不如用中断改变标志位,把f_open,f_puts,f_close等可能运行时间较长的函数都放在while(1)循环里面去执行。

因此将上述代码改为:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim == (&htim9))//溢出周期为1ms
    {
      my_time += 1;
    }
		
	if (htim == (&htim5))//溢出周期为20ms
    {
		
		test01++;
		if(test01>1)
		{
				/*记录当前时间*/
				memset(my_time_str, 0, sizeof(my_time_str));
				Int_To_Str(my_time,my_time_str);
			
				/*记录当前序号*/
				memset(my_name_txt, 0, sizeof(my_name_txt));
				Int_To_Str(my_name,my_name_txt);
									
				if(my_name%1000==0)//希望在f_open运行时,中断不写入sd卡
				{
						my_state = 1;
				}
				else if(my_name%1000==1||my_name%1000==2)
				{
						my_name += 1;
				}
				else if(my_name%1000 > 2 && my_name%1000 < 999)
				{
						my_state02 = 1;	
				}
				else if(my_name%1000 == 999)
				{
						my_state03 = 1;	
				}
		}
				
    }	
}


……


while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		if(my_state == 1)
		{
			f_res = f_open(&file, my_name_txt, FA_OPEN_ALWAYS | FA_WRITE);//打开要放在中断外面
			my_state = 0;
			my_name += 1;
		}
		else if(my_state02 == 1)
		{
			adcin0=AD_Buf[0];
			adcin1=AD_Buf[1];
			adcin2=AD_Buf[2];
			adcin3=AD_Buf[3];
			adcin4=AD_Buf[4];
			adcin5=AD_Buf[5];
			adcin6=AD_Buf[6];
			adcin7=AD_Buf[7];
			adcin8=AD_Buf[8];
			adcin9=AD_Buf[9];
						
			Int_To_Str(adcin0,my_char[0]);
			Int_To_Str(adcin1,my_char[1]);
			Int_To_Str(adcin2,my_char[2]);
			Int_To_Str(adcin3,my_char[3]);
			Int_To_Str(adcin4,my_char[4]);
			Int_To_Str(adcin5,my_char[5]);
			Int_To_Str(adcin6,my_char[6]);
			Int_To_Str(adcin7,my_char[7]);
			Int_To_Str(adcin8,my_char[8]);
			Int_To_Str(adcin9,my_char[9]);
			
			concatenate_strings(my_result, my_char);
							
			f_puts(my_time_str,&file);
			f_puts(my_result,&file);
			
			f_sync(&file);
			
			my_state02 = 0;
			my_name += 1;
		}
		else if(my_state03 == 1)
		{
			f_res = f_close(&file);
			my_state03 = 0;
			my_name += 1;
		}
	
	
	}
  /* USER CODE END 3 */

改完之后写入数据的频率非常稳定。

总结:中断只用来改变标志位即可,把运行时间长的代码都放在while(1)循环里面去执行,可以防止定时器不准等一系列复杂问题的出现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值