欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

stm32利用通用定时器实现函数运行时间精确测量

程序员文章站 2022-05-26 23:53:51
...

思路:采用TIM3,设置为向上计数模式,每次计数溢出(因为以72Mhz计数,stm32全为16位定时器,0.9ms就会溢出了),则变量加一,如此来测量。核心代码如下,测试过了,非常准确。

extern u32 cntPeriod;

void TIM3_Int_Init(u16 arr,u16 psc)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
    
    DBGMCU_Config(DBGMCU_TIM3_STOP,ENABLE);
    // 使得调试模式下,定时器也跟着暂停
    
    //定时器TIM3初始化
    TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值    
    TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
    //这条语句之后,定时器3的CNT计数值就为0了,对的
    
    TIM_ClearFlag(TIM3,TIM_FLAG_Update);
    //加入这么一句,就不会立刻事先进入一次中断了
    
    TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断

        
    //中断优先级NVIC设置
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
    NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器
    // 注意:第一次配置时候,此条语句执行完后,就马上进入了中断,原因是,上面TIM_ITConfig配置了

    TIM_Cmd(TIM3, ENABLE);  //使能TIMx                     
}

void TIM3_Int_Close()
{
    NVIC_InitTypeDef NVIC_InitStructure;
    //中断优先级NVIC设置
    
    TIM_Cmd(TIM3, DISABLE);  //停止TIM3                     

    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
    NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE; //IRQ通道被关闭
    NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器

}
//定时器3中断服务程序
void TIM3_IRQHandler(void)   //TIM3中断
{
    if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)  //检查TIM3更新中断发生与否
        {
            TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx更新中断标志 
            
            ++cntPeriod;
        
        }
}




void MeasureTimeStart()
{
    cntPeriod = 0;
    TIM3_Int_Init(64799,0);//1分频,即72Mhz的计数频率,计数到64800为0.9ms  ,64800/72=900us
}



double MeasureTimeEnd()
{
    double runTime;
    u32 cntTmp;
    
    TIM3_Int_Close();             
    printf("TIM3->CNT:%d \r\n",TIM3->CNT);
    cntTmp = cntPeriod*64800 + TIM3->CNT;
    runTime = (double)cntTmp/72.0/1000.0;
    
    return runTime;
}





int main(void)
{        

    double time;
    
    delay_init();             //延时函数初始化      
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    uart_init(115200);     //串口初始化为115200
     LED_Init();                 //LED端口初始化
    KEY_Init();          //初始化与按键连接的硬件接口
    
     
     while(1)
    {
        
        MeasureTimeStart();
        
        delay_1ms_my(1000);
        
        time = MeasureTimeEnd();
        
        printf("time:%f ms\r\n",time);
        delay_ms(500);
    }     
}





注:delay_1ms_my()是我自己写的延时函数,测量后发现非常准确。

void delay_1us_my(void)  //64个nop指令,加上跳转等执行时间,差不多就是72个时钟周期了,stm32f1主频72Mhz,即1us

{  

  __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop();  

  __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop();  

  __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop();  

  __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop();
    
  __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop(); __nop();

  __nop(); __nop(); __nop(); __nop();

}

void delay_1ms_my(u32 nms)
{
    u32 nus=nms*1000;
    while(--nus)
    {
        delay_1us_my();
    }
}

效果如下所示:

stm32利用通用定时器实现函数运行时间精确测量