如题,最近在师兄的指导下做一个工程,其中一部分需要用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)循环里面去执行,可以防止定时器不准等一系列复杂问题的出现。