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();
}
}
效果如下所示:
下一篇: C++ 测量程序运行时间